FreeRTOS_信号量_学习笔记

信号量的特性

消息队列用于传输多个数据,但是有时候我们只需要传递状态,这个状态值需要用一个数值表示。套用队列笔记中的流水线例子,可以理解为流水线上工件的数量。
信号:起通知作用
量:还可以用来表示资源的数量
当"量"没有限制时,它就是"计数型信号量"(Counting Semaphores)
当"量"只有0、1两个取值时,它就是"二进制信号量"(Binary Semaphores)
支持的动作:"give"给出资源,计数值加1;"take"获得资源,计数值减1。
在这里插入图片描述

队列信号量
数据存储可容纳多个数据。创建时要分配队列结构体和存储数据的空间只有计数值。创建时只需要分配信号量结构体
生产者没有空间存入时可以阻塞不阻塞,计数值最大时返回失败
消费者没有数据时可阻塞计数值最小时可阻塞

信号量分为二进制信号量和计数型信号量。二进制信号量初始值为0,计数型信号量的最大值不是1。

信号量函数

创建

 // 动态创建二进制信号量
SemaphoreHandle_t xSemaphoreCreateBinary( void );
 // 静态创建二进制信号量
SemaphoreHandle_t xSemaphoreCreateBinaryStatic( StaticSemaphore_t *pxSemaphoreBuffer );

//动态创建计数型信号量
SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount, UBaseType_t uxInitialCount);
//静态创建计数型信号量
SemaphoreHandle_t xSemaphoreCreateCountingStatic( UBaseType_t uxMaxCount, 
                                                 UBaseType_t uxInitialCount, 
                                                 StaticSemaphore_t *pxSemaphoreBuffer );

删除

void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );

存取

/*在任务中使用*/
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );
/*在中断中使用*/
BaseType_t xSemaphoreGiveFromISR(
                        SemaphoreHandle_t xSemaphore,
                        BaseType_t *pxHigherPriorityTaskWoken
                    );

xSemaphore:信号量句柄
*pxHigherPriorityTaskWoken:如果在信号量操作中唤醒了一个更高优先级的任务,会被设置为 pdTRUE,否则为pdFALSE

/*在任务中使用*/
BaseType_t xSemaphoreTake(
                   SemaphoreHandle_t xSemaphore,
                   TickType_t xTicksToWait
               );
/*在中断中使用*/
BaseType_t xSemaphoreTakeFromISR(
                        SemaphoreHandle_t xSemaphore,
                        BaseType_t *pxHigherPriorityTaskWoken
                    );

xTicksToWait:阻塞的时间

信号量实验

模拟车辆进站,假设车辆要有票才能同行,用一个信号量来模拟总共有多少票。当有票的时候,车拿走一张并开出,当其到达终点,就把票放回票仓,下一辆车再开出。

static SemaphoreHandle_t g_xSemTicks; 
static uint32_t g_xres, g_yres, g_bpp;
static uint8_t *g_framebuffer;
// 定义汽车结构体,包括位置和控制键
struct car {
	int x;
	int y;
	int control_key;
};
// 定义三辆汽车的初始位置和控制键
struct car g_cars[3] = {
	{0, 0, IR_KEY_1},
	{0, 17, IR_KEY_2},
	{0, 34, IR_KEY_3},
};
// 汽车图片的二进制数据
static const byte carImg[] = {
	0x40,0xF8,0xEC,0x2C,0x2C,0x38,0xF0,0x10,0xD0,0x30,0xE8,0x4C,0x4C,0x9C,0xF0,
	0x02,0x1F,0x37,0x34,0x34,0x1C,0x0F,0x08,0x0B,0x0C,0x17,0x32,0x32,0x39,0x0F,
};
// 清除区域的图像数据,用于隐藏汽车
static const byte clearImg[30] = {0};
// 显示汽车
static void ShowCar(struct car *pcar)
{
	draw_bitmap(pcar->x, pcar->y, carImg, 15, 16, false, 0);
	draw_flushArea(pcar->x, pcar->y, 15, 16);
}
// 隐藏汽车
static void HideCar(struct car *pcar)
{
	draw_bitmap(pcar->x, pcar->y, clearImg, 15, 16, false, 0);
	draw_flushArea(pcar->x, pcar->y, 15, 16);
}

// 每辆汽车的任务
static void CarTask(void *params)
{
	struct car *pcar = params;
	
	// 任务开始时等待信号量,以同步启动所有车辆
	xSemaphoreTake(g_xSemTicks, portMAX_DELAY);
	
	while (1)
	{
		if (pcar->x < g_xres - CAR_LENGTH)
		{
			HideCar(pcar);  // 隐藏汽车以更新位置
			
			// 更新汽车位置
			pcar->x += 1;
			
			ShowCar(pcar);  // 显示新位置的汽车
			
			vTaskDelay(50); // 控制更新频率
			
			if (pcar->x == g_xres - CAR_LENGTH)
			{
				xSemaphoreGive(g_xSemTicks); // 到达屏幕边缘时释放信号量并结束任务
				vTaskDelete(NULL);
			}
		}
	}
}
// 主游戏函数,初始化并启动任务
void car_game(void)
{
	g_framebuffer = LCD_GetFrameBuffer(&g_xres, &g_yres, &g_bpp);
	draw_init();
	draw_end();
	
	// 创建信号量,开始计数为2,最大计数为3
	g_xSemTicks = xSemaphoreCreateCounting(3, 2);
	
    // 创建每辆汽车的任务
    xTaskCreate(CarTask, "car1", 128, &g_cars[0], osPriorityNormal, NULL);
    xTaskCreate(CarTask, "car2", 128, &g_cars[1], osPriorityNormal, NULL);
    xTaskCreate(CarTask, "car3", 128, &g_cars[2], osPriorityNormal, NULL);	
}

可以通过改变g_xSemTicks = xSemaphoreCreateCounting(3, 2);的参数,来改变有多少张票。

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值