事件组
7.1 事件组的本质¶
事件组可以实现一次唤醒多个任务。
关于事件组:
- 事件组用一个整数来表示,高八位留给内核使用,其他的位每一个Bit代表一个事件。
- 如果configUSE_16_BIT_TICKS是1,那么这个整数就是16位的,低8位用来表示事件。
- 如果configUSE_16_BIT_TICKS是0,那么这个整数就是32位的,低24位用来表示事件。
- configUSE_16_BIT_TICKS是用来表示Tick Count,整数位基于效率来考虑,比如configUSE_16_BIT_TICKS是1,就表示该处理器使用16位更高效。
- 有一个链表用来链接任务。
- 任务有自己需要等待的事件,可以是多个,任务中的高八位决定等待的多个事件是 “or” 还是 “and” 关系。
例如,任务A、B中等待的事件均是 “or” 关系,有一个任务C写事件:
① 若C写 Bit0 ,则A、B均被唤醒。
② 若C写 Bit1 ,则只有B被唤醒。
③ 若C写 Bit7 ,则只有A被唤醒。
7.2 事件组函数¶
7.2.1 创建事件组¶
7.2.2 删除事件组¶
7.2.3 设置事件¶
C
BaseType_t xEventGroupSetBitsFromISR(
EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet,
BaseType_t *pxHigherPriorityTaskWoken );
7.2.4 等待事件¶
C
EventBits_t xEventGroupWaitBits(
EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
const TickType_t xTicksToWait );
7.3 事件组示例¶
7.3.1 示例 1¶
car1运行到终点后,会设置bit0事件;car2、car3都等待bit0事件。
定义事件组句柄
创建事件组
C
void MX_FREERTOS_Init(void) {
/* USER CODE BEGIN Init */
// g_xSemaphoreHandle = xSemaphoreCreateMutex();
// xSemaphoreGive(g_xSemaphoreHandle);
// GameInit();
g_xEventCarHandle = xEventGroupCreate();
/* USER CODE END Init */
...
}
设置和等待事件
C
void OLED_PrintTask1(void *params) {
Car *car = params;
ShowCar(car);
while (1) {
HideCar(car);
car->x += 1;
if (car->x > 128) { car->x = 120; }
ShowCar(car);
vTaskDelay(100);
if (car->x == 120) {
/* 设置事件0 */
xEventGroupSetBits(g_xEventCarHandle, (1<<0));
vTaskDelete(NULL);
}
}
}
void OLED_PrintTask2(void *params) {
Car *car = params;
ShowCar(car);
/* 等待事件0 */
xEventGroupWaitBits(g_xEventCarHandle, (1<<0), pdTRUE, pdTRUE, portMAX_DELAY);
while (1) {
HideCar(car);
car->x += 1;
if (car->x > 128) { car->x = 120; }
ShowCar(car);
// vTaskDelay(100);
HAL_Delay(100);
if (car->x == 120) {
vTaskDelete(NULL);
}
}
}
void OLED_PrintTask3(void *params) {
Car *car = params;
ShowCar(car);
/* 等待事件0 */
xEventGroupWaitBits(g_xEventCarHandle, (1<<0), pdTRUE, pdTRUE, portMAX_DELAY);
while (1) {
HideCar(car);
car->x += 1;
if (car->x > 128) { car->x = 120; }
ShowCar(car);
// vTaskDelay(100);
HAL_Delay(100);
if (car->x == 120) {
vTaskDelete(NULL);
}
}
}
此时现象为,car1先到达终点然后,car3优先级高且无阻塞先行,到达终点后,car2运行;可以修改优先级让car3和car2同时运行。
为什么事件 0 会表达为 (1<<0)
,这里可以看FreeRTOS的源码示例:
C
* Example usage:
<pre>
#define BIT_0 ( 1 << 0 )
#define BIT_4 ( 1 << 4 )
void aFunction( EventGroupHandle_t xEventGroup )
{
EventBits_t uxBits;
const TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS;
// Wait a maximum of 100ms for either bit 0 or bit 4 to be set within
// the event group. Clear the bits before exiting.
uxBits = xEventGroupWaitBits(
xEventGroup, // The event group being tested.
BIT_0 | BIT_4, // The bits within the event group to wait for.
pdTRUE, // BIT_0 and BIT_4 should be cleared before returning.
pdFALSE, // Don't wait for both bits, either bit will do.
xTicksToWait ); // Wait a maximum of 100ms for either bit to be set.
...
}
7.3.2 示例 2¶
car1运行到终点后,会设置bit0事件;car2运行到终点后,会设置bit1事件;car3等待bit0、bit1的所有事件。
C
void OLED_PrintTask1(void *params) {
Car *car = params;
ShowCar(car);
while (1) {
HideCar(car);
car->x += 1;
if (car->x > 128) { car->x = 120; }
ShowCar(car);
vTaskDelay(120);
if (car->x == 120) {
/* 设置事件 */
xEventGroupSetBits(g_xEventCarHandle, (1<<0));
vTaskDelete(NULL);
}
}
}
void OLED_PrintTask2(void *params) {
Car *car = params;
ShowCar(car);
// xEventGroupWaitBits(g_xEventCarHandle, (1<<0), pdTRUE, pdTRUE, portMAX_DELAY);
while (1) {
HideCar(car);
car->x += 1;
if (car->x > 128) { car->x = 120; }
ShowCar(car);
vTaskDelay(100);
if (car->x == 120) {
xEventGroupSetBits(g_xEventCarHandle, (1<<1));
vTaskDelete(NULL);
}
}
}
void OLED_PrintTask3(void *params) {
Car *car = params;
ShowCar(car);
xEventGroupWaitBits(g_xEventCarHandle, (1<<0)|(1<<1), pdTRUE, pdTRUE, portMAX_DELAY);
while (1) {
HideCar(car);
car->x += 1;
if (car->x > 128) { car->x = 120; }
ShowCar(car);
// vTaskDelay(100);
HAL_Delay(100);
if (car->x == 120) {
vTaskDelete(NULL);
}
}
}
xEventGroupWaitBits(g_xEventCarHandle, (1<<0)|(1<<1), pdTRUE, pdTRUE, portMAX_DELAY)
的第四个参数为控制等待 事件0 或 事件1 还是 事件0 和 事件1 。
C
/**
* @param xWaitForAllBits If xWaitForAllBits is set to pdTRUE then
* xEventGroupWaitBits() will return when either all the bits in uxBitsToWaitFor
* are set or the specified block time expires. If xWaitForAllBits is set to
* pdFALSE then xEventGroupWaitBits() will return when any one of the bits set
* in uxBitsToWaitFor is set or the specified block time expires. The block
* time is specified by the xTicksToWait parameter.
*/