2025最新超详细FreeRTOS入门教程:第七章 FreeRTOS事件组
FreeRTOS事件组入门指南摘要 事件组是FreeRTOS中用于任务同步的重要机制,适合需要等待多个事件组合的场景。它本质是一个32位变量(实际可用24位),每位代表一个事件。关键特性包括: 支持OR/AND两种等待模式 提供创建/删除、设置/等待事件位的API 特别适合WiFi+MQTT等多条件同步场景 支持中断服务程序设置事件 相比信号量,事件组优势在于能同时管理多个事件,但不适合传递数据。
·
2025最新超详细FreeRTOS入门教程:第七章 FreeRTOS事件组
摘要
在前面几章中,我们学习了 信号量与互斥量,它们可以解决任务间同步和资源保护的问题。但在一些复杂系统中,我们需要让多个任务 等待多个事件的组合,例如:
- 一个任务需要等 多个外设都准备好 才能继续运行
- 一个通信任务需要等到 接收完成 + 校验成功 后才能继续处理
- 一个控制任务需要等到 多个信号同时到达 才能执行逻辑
这时候,使用 事件组(Event Group) 是最佳选择。
事件组 允许我们以“位”的方式管理多个事件,任务可以等待某些事件的 任意组合(OR关系) 或 全部满足(AND关系)。
文章目录
一、事件组的基本概念
1. 什么是事件组
- 事件组本质上是一个 32位变量(最多 24 位可用,低 8 位由系统保留)
- 每一位(bit)代表一个事件
- 任务可以等待 一个或多个事件位 置位后再继续执行
2. 应用场景
- 多任务同步:多个任务等待同一个事件
- 多事件同步:一个任务等待多个事件组合
- 中断与任务同步:ISR 设置事件,任务响应事件
二、事件组 API
1. 创建与删除
EventGroupHandle_t xEventGroupCreate(void);
void vEventGroupDelete(EventGroupHandle_t xEventGroup);
2. 设置事件位
EventBits_t xEventGroupSetBits(
EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet
);
ISR 中使用:
BaseType_t xEventGroupSetBitsFromISR(
EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet,
BaseType_t *pxHigherPriorityTaskWoken
);
3. 等待事件位
EventBits_t xEventGroupWaitBits(
EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
TickType_t xTicksToWait
);
参数说明:
uxBitsToWaitFor
:等待的事件位(如BIT_0 | BIT_1
)xClearOnExit
:是否在退出时自动清除事件位xWaitForAllBits
:是否等待所有位满足(AND)xTicksToWait
:阻塞时间
4. 清除事件位
EventBits_t xEventGroupClearBits(
EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToClear
);
三、事件组使用示例
示例:等待 WiFi 和 MQTT 同时连接成功
#include "FreeRTOS.h"
#include "task.h"
#include "event_groups.h"
#define WIFI_CONNECTED_BIT (1 << 0)
#define MQTT_CONNECTED_BIT (1 << 1)
EventGroupHandle_t xEventGroup;
void vTaskWiFi(void *pvParameters)
{
vTaskDelay(2000);
printf("WiFi 连接成功\n");
xEventGroupSetBits(xEventGroup, WIFI_CONNECTED_BIT);
vTaskDelete(NULL);
}
void vTaskMQTT(void *pvParameters)
{
vTaskDelay(3000);
printf("MQTT 连接成功\n");
xEventGroupSetBits(xEventGroup, MQTT_CONNECTED_BIT);
vTaskDelete(NULL);
}
void vTaskMain(void *pvParameters)
{
EventBits_t uxBits;
printf("等待WiFi和MQTT连接...\n");
uxBits = xEventGroupWaitBits(
xEventGroup,
WIFI_CONNECTED_BIT | MQTT_CONNECTED_BIT,
pdTRUE, // 清除位
pdTRUE, // 等待所有位
portMAX_DELAY
);
if((uxBits & (WIFI_CONNECTED_BIT | MQTT_CONNECTED_BIT)) ==
(WIFI_CONNECTED_BIT | MQTT_CONNECTED_BIT))
{
printf("网络环境就绪,开始业务处理\n");
}
vTaskDelete(NULL);
}
int main(void)
{
HAL_Init();
SystemClock_Config();
xEventGroup = xEventGroupCreate();
xTaskCreate(vTaskWiFi, "WiFi", 128, NULL, 2, NULL);
xTaskCreate(vTaskMQTT, "MQTT", 128, NULL, 2, NULL);
xTaskCreate(vTaskMain, "Main", 128, NULL, 1, NULL);
vTaskStartScheduler();
while(1) {}
}
运行结果
- WiFi 和 MQTT 任务分别连接
- Main 任务阻塞,直到两者都完成
- Main 任务开始执行业务逻辑
四、事件组的工作机制
- OR模式:任意一个事件满足即可继续
- AND模式:所有事件满足才继续
五、事件组的应用场景
场景 | 描述 | 示例 |
---|---|---|
多任务同步 | 多个任务等待相同事件 | 多个消费者等待生产者事件 |
多事件组合 | 一个任务等待多个事件同时满足 | WiFi+MQTT+传感器就绪 |
ISR 通知任务 | 中断触发事件,任务等待事件位 | 按键中断触发任务执行 |
六、调试与监控
1. 获取事件组当前值
EventBits_t xEventGroupGetBits(EventGroupHandle_t xEventGroup);
2. ISR 中获取
EventBits_t xEventGroupGetBitsFromISR(EventGroupHandle_t xEventGroup);
七、事件组与信号量的比较
特性 | 信号量 | 事件组 |
---|---|---|
单一事件 | ✅ | ❌(可多位) |
多事件组合 | ❌ | ✅ |
资源保护 | ✅ | ❌ |
ISR 使用 | ✅ | ✅ |
内部机制 | 队列 | 位图 |
八、常见问题与解决方法
问题 | 可能原因 | 解决方法 |
---|---|---|
任务一直阻塞 | 等待模式设置错误 | 检查 xWaitForAllBits 参数 |
事件位丢失 | 设置时清除位 | 确认 xClearOnExit 使用正确 |
ISR 中报错 | 使用了非 ISR API | 改用 xEventGroupSetBitsFromISR |
占用内存过多 | 创建多个事件组 | 尽量合并事件位,节省资源 |
九、经验总结
📌 开发建议
- 对于 需要多个事件联合触发 的场景,优先使用事件组
- 避免过度依赖事件组来传递数据,事件组只适合布尔型事件
- 建议将事件位定义为宏,避免混淆
- 配合信号量和队列使用,可以构建更复杂的任务调度体系
十、总结
通过本章学习,你已经掌握:
- 事件组的基本原理与 API
- 使用
xEventGroupWaitBits
实现任务等待多个事件 - 中断中使用
xEventGroupSetBitsFromISR
- 事件组与信号量的区别
事件组是构建复杂任务同步关系的重要工具,在物联网、通信、传感器融合等场景中非常常见。
🔗 FreeRTOS专栏👉 下一章:2025最新超详细FreeRTOS入门教程:第八章 FreeRTOS任务通知 ——我们将学习更轻量级的任务间通信方式:任务通知。
更多推荐
所有评论(0)