FreeRTOS-事件标志组
- 在前面我们已经学习了信号量,我们知道信号量可以用来做任务同步,但是这种任务同步有一个缺点,就是只能在两个任务之间进行同步,所以为了解决这个问题,FreeRTOS提供了事件标志组,使得多任务之间进行同步。
事件标志组表示方法
- 事件标志组由若干个事件标志位组成,每个事件标志位表示某个事件是否发生。事件标志组的数据类型为EventBits_t,具体定义如下
typedef TickType_t EventBits_t;
#if( configUSE_16_BIT_TICKS == 1 )
typedef uint16_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffff
#else
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
#define portTICK_TYPE_IS_ATOMIC 1
#endif
- 从上面可以看出,当configUSE_16_BIT_TICKS =0时,EventBits_t为32位,否则EventBits_t为16位。但是,EventBits_t中的高8位有其他作用,不能用来表示事件,所以当EventBits_t为32位时,最多能用来表示24个事件。
事件标志组相关API
- 本章不会深入分析这些API的源码,只是在使用上做一个介绍
xEventGroupCreate()
- 函数作用:创建时间标志组
- 函数声明:EventGroupHandle_t xEventGroupCreate( void )
- 输入参数:无
- 返回参数:事件标志组句柄
xEventGroupSetBits()
- 函数作用:设置事件标志位
- 函数声明:EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet )
- 输入参数 xEventGroup:事件标志组句柄
- 输入参数 uxBitsToSet :事件标志组所要置1的位,比如要使bit2置1,那么uxBitsToSet=0x04=0000 0100
- 返回参数:事件标志组句柄
xEventGroupClearBits()
- 函数作用:清除事件标志位
- 函数声明:EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )
- 输入参数 xEventGroup:事件标志组句柄
- 输入参数 uxBitsToClear :事件标志组所要清零的位,比如要使bit2置0,那么uxBitsToClear=0x04=0000 0100
- 返回参数:事件标志组句柄
xEventGroupWaitBits()
- 函数作用:等待事件标志位
- 函数声明:EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait )
- 输入参数 xEventGroup:事件标志组句柄
- 输入参数 uxBitsToWaitFor:所要等待的事件标志位,比如要等待bit2,则uxBitsToWaitFor = 0x04,如果既要等待bit2也要等待bit4,则uxBitsToWaitFor = 0x04|0x10
- 输入参数 xClearOnExit:事件等待完毕后是否清除标志位,如果输入参数为pdTRUE是表示清除,否则不清除。
- xWaitForAllBits:是否要等待所有标志位,设置为pdTRUE时,需要等待所设置的所有标志位此时相当于与运算,否则只需要等待一个,此时相当于或运算
- xTicksToWait:设置阻塞时间
- 返回参数:事件标志组的值
用法示例
实验目的:创建3个事件,分别等待bit0置位,等待bit1置位,等待bit0和bit1均置位,通过按键将bit0和bit1置位
u8 keyFlag=0;
void key_task(void* pvParameters)
{
EventBits_t Ebit;
while(1)
{
if (Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON)
{
if ( (keyFlag&0x01) == 0x01)
keyFlag &= ~(0x01<<0);
else
keyFlag |= (0x01<<0);
if ( (keyFlag&0x01) == 0x01)
{
Ebit = xEventGroupSetBits(Event_Handler,(0x01<<0));
printf("current Ebit = %#x\r\n",Ebit);
}
else
{
Ebit = xEventGroupClearBits(Event_Handler,(0x01<<0));
printf("current Ebit = %#x\r\n",Ebit);
}
}
if (Key_Scan(KEY2_GPIO_PORT,KEY2_GPIO_PIN) == KEY_ON)
{
if ( (keyFlag&0x02) == 0x02)
keyFlag &= ~(0x01<<1);
else
keyFlag |= (0x01<<1);
if ( (keyFlag&0x02) == 0x02)
{
Ebit = xEventGroupSetBits(Event_Handler,(0x01<<1));
printf("current Ebit = %#x\r\n",Ebit);
}
else
{
Ebit = xEventGroupClearBits(Event_Handler,(0x01<<1));
printf("current Ebit = %#x\r\n",Ebit);
}
}
vTaskDelay(10);
}
}
void event1_task(void* pvParameters)
{
while(1)
{
if ( (keyFlag&0x01) == 0x01)
LED0 = 0;
else
LED0 = 1;
xEventGroupWaitBits(Event_Handler,(0x01<<0),pdFALSE,pdTRUE,portMAX_DELAY);
printf("event1 task running!!\r\n");
vTaskDelay(1000);
}
}
void event2_task(void* pvParameters)
{
while(1)
{
if ( (keyFlag&0x02) == 0x02)
LED1 = 0;
else
LED1 = 1;
xEventGroupWaitBits(Event_Handler,(0x01<<1),pdFALSE,pdTRUE,portMAX_DELAY);
printf("event2 task running!!\r\n");
vTaskDelay(1000);
}
}
void event3_task(void* pvParameters)
{
while(1)
{
if ( (keyFlag&0x03) == 0x03)
LED2 = 0;
else
LED2 = 1;
xEventGroupWaitBits(Event_Handler,(0x01<<1)|(0x01<<0),pdFALSE,pdTRUE,portMAX_DELAY);
printf("event3 task running!!\r\n");
vTaskDelay(1000);
}
}
void start_task(void *pvParameters)
{
Event_Handler = xEventGroupCreate();
xTaskCreate((TaskFunction_t )key_task, //任务函数
(const char* )"key_task", //任务名称
(uint16_t )KEY_STACK_SIZE, //任务堆栈大小
(void* )NULL, //传递给任务函数的参数
(UBaseType_t )KEY_TASK_PRIO, //任务优先级
(TaskHandle_t* )&KeyTask_Handler); //任务句柄
xTaskCreate((TaskFunction_t )event1_task, //任务函数
(const char* )"event1_task", //任务名称
(uint16_t )EVENT1_STACK_SIZE, //任务堆栈大小
(void* )NULL, //传递给任务函数的参数
(UBaseType_t )EVENT1_TASK_PRIO, //任务优先级
(TaskHandle_t* )&Event1Task_Handler); //任务句柄
xTaskCreate((TaskFunction_t )event2_task, //任务函数
(const char* )"event2_task", //任务名称
(uint16_t )EVENT2_STACK_SIZE, //任务堆栈大小
(void* )NULL, //传递给任务函数的参数
(UBaseType_t )EVENT2_TASK_PRIO, //任务优先级
(TaskHandle_t* )&Event2Task_Handler); //任务句柄
xTaskCreate((TaskFunction_t )event3_task, //任务函数
(const char* )"event3_task", //任务名称
(uint16_t )EVENT3_STACK_SIZE, //任务堆栈大小
(void* )NULL, //传递给任务函数的参数
(UBaseType_t )EVENT3_TASK_PRIO, //任务优先级
(TaskHandle_t* )&Event3Task_Handler); //任务句柄
vTaskDelete(StartTask_Handler);
}