1 事件标志组简介:
事件标志组:
之前介绍了使用信号量来完成同步,但是使用信号量来同步的话,任务只能与单个的事件或任务进行同步。有时候某个任务可能会需要与多个事件或任务进行同步,此时信号量就无能为力了。FreeRTOS 提供了一个可选的解决方法,那就是事件标志组。
事件位和事件组:
事件组数据结构:
2 创建事件标志组:
事件标志组结构体(包括一个变量和一个等待事件的任务列表):
typedef struct xEventGroupDefinition
{
EventBits_t uxEventBits;
List_t xTasksWaitingForBits; /*< List of tasks waiting for a bit to be set. */
#if( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxEventGroupNumber;
#endif
} EventGroup_t;
3 设置 / 清除事件位:
4 获取事件标志组值:
5 等待指定的事件位:
参数说明:
事件标志组测试实验:
start_task:用来创建其他两个个任务和事件标志组;
eventsetbit_task:读取按键值和串口指令,根据不同的按键值将事件标志组中相应的事件位置 1,用来模拟事件的发生;
eventgroup_task:同时等待事件标志组中的多个事件位,当这些事件位都置 1 的话就执行相应的处理;
代码如下所示:
#define EVENT_BIT_1 (1 << 1)
#define EVENT_BIT_2 (1 << 2)
void event_set_bit_task(void *pvParameters)
{
EventBits_t event_value;
for (;;)
{
if (key_scan(KEY1_GPIO_Port, KEY1_Pin) == KEY_ON)
{
xEventGroupSetBits(event_group_handle, EVENT_BIT_1);
event_value = xEventGroupGetBits(event_group_handle);
printf("发送事件位EVENT_BIT_1,事件位的值为%#X\n", event_value & (0X0F));
}
vTaskDelay(50);
}
}
void event_group_task(void *pvParameters)
{
EventBits_t uxBits;
for (;;)
{
uxBits = xEventGroupWaitBits(event_group_handle,
EVENT_BIT_1 | EVENT_BIT_2,
pdTRUE,
pdTRUE,
portMAX_DELAY);
printf("全部事件位获取成功,事件组的值为%#x\r\n", uxBits);
vTaskDelay(50);
}
}
void EXTI15_10_IRQHandler(void)
{
BaseType_t xHigherPriorityTaskWoken, xResult;
/* USER CODE BEGIN EXTI15_10_IRQn 0 */
if (__HAL_GPIO_EXTI_GET_FLAG(KEY2_Pin))
{
xHigherPriorityTaskWoken = pdFALSE;
xResult = xEventGroupSetBitsFromISR(
event_group_handle,
EVENT_BIT_2,
&xHigherPriorityTaskWoken);
if (xResult == pdPASS)
{
printf("KEY2外部中断出发,发送事件位EVENT_BIT_2,事件组的值为%#X\r\n",
xEventGroupGetBits(event_group_handle));
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}
__HAL_GPIO_EXTI_CLEAR_FLAG(KEY2_Pin);
}
测试结果如下所示:
注意,这里出现了FreeRTOS的报错,原因是在中断中进入了临界段。外部中断的优先级为6,而屏蔽优先级的值为5,所以会因为冲突而报错,导致第二次获取事件值出错,但最后的运行结果是正确的。
#define xEventGroupGetBits( xEventGroup ) xEventGroupClearBits( xEventGroup, 0 )
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )
{
EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
EventBits_t uxReturn;
taskENTER_CRITICAL();
{
traceEVENT_GROUP_CLEAR_BITS( xEventGroup, uxBitsToClear );
/* The value returned is the event group value prior to the bits being
cleared. */
uxReturn = pxEventBits->uxEventBits;
/* Clear the bits. */
pxEventBits->uxEventBits &= ~uxBitsToClear;
}
taskEXIT_CRITICAL();
return uxReturn;
}