在 FreeRTOS 中,事件组(Event Group) 是一种高效的同步机制,允许多个任务或中断通过 事件位(Event Bits) 进行通信和同步。以下是事件组的详细使用方法:
1. 事件组的基本操作
1.1 创建事件组
#include "FreeRTOS.h"
#include "event_groups.h"
// 创建事件组句柄
EventGroupHandle_t xEventGroup = xEventGroupCreate();
1.2 设置事件位
-
在任务中设置事件位:
// 设置指定的事件位(例如 BIT_0 和 BIT_1) xEventGroupSetBits(xEventGroup, BIT_0 | BIT_1);
-
在中断中设置事件位(需使用中断安全版本):
void IRAM_ATTR HardwareISR() { BaseType_t xHigherPriorityTaskWoken = pdFALSE; xEventGroupSetBitsFromISR(xEventGroup, BIT_0, &xHigherPriorityTaskWoken); portYIELD_FROM_ISR(xHigherPriorityTaskWoken); // 触发任务切换 }
1.3 等待事件位
- 阻塞等待事件位:
// 等待 BIT_0 和 BIT_1 中的任意一个事件位被置位,最多阻塞 100ms EventBits_t xBits = xEventGroupWaitBits( xEventGroup, // 事件组句柄 BIT_0 | BIT_1, // 要等待的事件位 pdFALSE, // 是否在等待成功后清除事件位(pdTRUE 为清除) pdFALSE, // 是否需要所有事件位都被置位(pdTRUE 为全部) pdMS_TO_TICKS(100) // 超时时间(单位:系统节拍) ); if (xBits & BIT_0) { // BIT_0 被置位 }
1.4 清除事件位
// 清除 BIT_0 事件位
xEventGroupClearBits(xEventGroup, BIT_0);
2. 事件组的典型使用场景
2.1 任务同步
多个任务等待某个事件触发:
// 任务1:等待事件
void vTask1(void *pvParameters) {
while (1) {
xEventGroupWaitBits(xEventGroup, BIT_0, pdTRUE, pdTRUE, portMAX_DELAY);
// 执行事件触发后的操作
}
}
// 任务2:触发事件
void vTask2(void *pvParameters) {
while (1) {
// 触发 BIT_0
xEventGroupSetBits(xEventGroup, BIT_0);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
2.2 多事件组合触发
需要同时满足多个事件才触发:
// 等待 BIT_0 和 BIT_1 同时被置位
xEventGroupWaitBits(xEventGroup, BIT_0 | BIT_1, pdTRUE, pdTRUE, portMAX_DELAY);
3. 事件组的注意事项
-
事件位管理:
- 事件位是 按位操作 的,建议使用
#define
定义事件位:#define BIT_0 (1 << 0) // 第0位 #define BIT_1 (1 << 1) // 第1位
- 避免事件位冲突(例如同时使用 BIT_0 和 BIT_1)。
- 事件位是 按位操作 的,建议使用
-
线程安全:
- 若多个任务或中断同时操作同一事件组,需确保操作的原子性(FreeRTOS 事件组函数本身是线程安全的)。
-
优先级反转:
- 高优先级任务等待低优先级任务设置事件时可能发生优先级反转,可通过合理设计任务优先级避免。
-
性能优化:
- 事件组的操作是 轻量级 的,适合高频事件同步。
4. 完整示例
场景:两个任务通过事件组同步
EventGroupHandle_t xEventGroup;
void vSenderTask(void *pvParameters) {
while (1) {
// 设置 BIT_0
xEventGroupSetBits(xEventGroup, BIT_0);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void vReceiverTask(void *pvParameters) {
while (1) {
// 等待 BIT_0 被置位
xEventGroupWaitBits(xEventGroup, BIT_0, pdTRUE, pdTRUE, portMAX_DELAY);
printf("Event BIT_0 received!\n");
}
}
int main() {
xEventGroup = xEventGroupCreate();
xTaskCreate(vSenderTask, "Sender", 1024, NULL, 1, NULL);
xTaskCreate(vReceiverTask, "Receiver", 1024, NULL, 2, NULL);
vTaskStartScheduler();
return 0;
}
5. 事件组的优势
- 轻量高效:事件组的操作时间复杂度为 O(1)。
- 多任务同步:支持多任务同时等待/设置不同事件位。
- 灵活性:可组合事件位(AND/OR 逻辑)。
总结
FreeRTOS 事件组是任务间通信和同步的核心工具,适用于需要 多事件触发 或 多任务同步 的场景。使用时需注意事件位的定义和线程安全,合理设计任务优先级即可高效利用。