1. 事件组的概念
事件组是一种任务间通信机制,主要用于多任务的同步操作。它通过设置和清除事件标志来实现任务间的协同工作,而不传递数据。事件组可以让一个任务等待一个或多个事件发生,然后根据预设的条件(如所有事件都发生或任意一个事件发生)唤醒任务执行相应的操作。
2. 事件组的特点
- 无数据传输:事件组只用于任务同步,不涉及数据的传递。
- 多对多同步:事件组允许多个任务同步多个事件。一个任务可以同时等待多个事件的发生,也可以多个任务同时等待某个事件的发生。
- 独立型同步与关联型同步:
- 独立型同步(逻辑或):任务对多个事件感兴趣,当其中任何一个事件发生时,任务会被唤醒。
- 关联型同步(逻辑与):任务对多个事件感兴趣,只有当所有事件都发生后,任务才会被唤醒,且事件发生的顺序可以不同步。
3. 事件组的实现
事件组在 FreeRTOS 中以一个 EventGroupHandle_t
类型的变量表示。事件的状态保存在一个 EventBits_t
类型的变量中,这个变量位于事件组的结构体中。
- 事件位 (Event Bits):每个事件组的事件状态由一个变量
uxEventBits
保存。这个变量的位数取决于宏configUSE_16_BIT_TICKS
的定义:- 如果
configUSE_16_BIT_TICKS
定义为 1,则uxEventBits
为 16 位,其中有 8 位可用于事件标志组。 - 如果
configUSE_16_BIT_TICKS
定义为 0,则uxEventBits
为 32 位,其中有 24 位可用于事件标志组(在 STM32 中通常是这种情况)。
- 如果
每一位代表一个事件,任务可以通过逻辑操作(如逻辑与 &
或逻辑或 |
)来检查这些位,并与一个或多个事件关联,形成一个事件组。
4. 事件组的API函数
1. 创建事件组
EventGroupHandle_t xEventGroupCreate(void);
- 该函数创建一个新的事件组,并返回事件组的句柄。
2. 设置事件
EventBits_t xEventGroupSetBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet);
//在中断中使用事件组置位函数
BaseType_t xEventGroupSetBitsFromISR(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken);
- 该函数用于设置指定事件组中的一个或多个事件位。
xEventGroup
:事件组句柄。uxBitsToSet
:要设置的事件位。pxHigherPriorityTaskWoken
:pxHigherPriorityTaskWoken 在使 用之前 必须初始 化成 pdFALSE。
3. 等待事件
EventBits_t xEventGroupWaitBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait);
- 该函数用于等待一个或多个事件发生。
uxBitsToWaitFor
:任务感兴趣的事件位。xClearOnExit
:如果为pdTRUE
,则在退出时清除事件位。xWaitForAllBits
:如果为pdTRUE
,则任务等待所有感兴趣的事件发生;如果为pdFALSE
,则任务等待任意一个事件发生。xTicksToWait
:任务等待的最大时间(以Tick数表示)。
4. 清除事件
EventBits_t xEventGroupClearBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear);
- 该函数用于清除指定事件组中的一个或多个事件位。
5. 删除事件组
void vEventGroupDelete(EventGroupHandle_t xEventGroup);
- 该函数删除一个事件组,并释放与之相关的资源。
5. 事件组的使用场景
- 同步多个任务:多个任务可以等待同一个事件组中的不同事件发生,并在事件发生后执行相应的任务操作。
- 复杂条件同步:事件组允许任务等待多个事件的组合发生,例如一个任务可能需要在接收到多个传感器的信号后才开始数据处理。
6. 事件组的示例代码
#define BIT_0 (0x01 << 0)
#define BIT_1 (0x01 << 1)
// 创建事件组
EventGroupHandle_t xEventGroup = NULL;
void vTask1(void *pvParameters) {
// 设置事件位
xEventGroupSetBits(xEventGroup, BIT_0);
while (1) {
vTaskDelay(20);
}
}
void vTask2(void *pvParameters) {
EventBits_t r_event;
while (1) {
// 等待事件发生
r_event = xEventGroupWaitBits(xEventGroup, BIT_0 | BIT_1, pdTRUE, pdFALSE, portMAX_DELAY);
if ((r_event & (BIT_0 | BIT_1)) == (BIT_0 | BIT_1)) {
// 任务代码
} else {
}
}
}
void main(void) {
// 创建任务
xEventGroup = xEventGroupCreate();
xTaskCreate(vTask1, "Task1", 100, NULL, 1, NULL);
xTaskCreate(vTask2, "Task2", 100, NULL, 1, NULL);
// 启动调度器
vTaskStartScheduler();
}
7. 总结
事件组是 FreeRTOS 中一个强大且灵活的同步工具,它提供了多任务环境下任务间同步的高效机制,允许复杂的同步条件和多任务、多事件的协同处理。在实际应用中,合理利用事件组可以简化任务间的同步操作,提升系统的响应效率。
欢迎指出博客中的错误,如果你觉得对你有用,记得点赞三连,有问题可留言,会及时回复