当前位置: 首页 > news >正文

FreeRTOS事件组的本质

FreeRTOS事件组的本质

  • FreeRTOS事件组的本质
    • **1. 事件组的核心概念**
    • **2. 事件组与传统同步机制的对比**
      • **事件组的优势**
    • **3. 事件组的实现细节**
      • **3.1 事件组的位数与配置**
    • **4. 事件组的典型应用场景**
      • **4.1 多任务协同**
      • **4.2 多条件触发**
    • **5. 事件组的核心API**
      • **5.1 创建事件组**
      • **5.2 设置事件位**
      • **5.3 等待事件位**
    • **6. 事件组的代码示例**
      • **示例1:一对多广播**
      • **示例2:多条件等待**
    • **7. 事件组的注意事项**
    • **8. 事件组与队列/信号量的对比总结**
    • **9. 总结**

FreeRTOS事件组的本质


1. 事件组的核心概念

事件组(Event Group)是FreeRTOS中一种高效的一对多通信机制,其本质是一个位掩码(bitmask),用于表示多个事件的状态。每个位(bit)可以独立表示一个事件的发生与否,允许任务或中断服务程序(ISR)通过设置或等待这些位来实现广播式唤醒


2. 事件组与传统同步机制的对比

机制特性唤醒方式
队列存储数据,按FIFO顺序传递数据写入数据时唤醒一个任务
信号量计数信号量或二值信号量,用于资源管理或任务同步释放信号量时唤醒一个任务
互斥量用于保护共享资源,确保同一时间只有一个任务访问释放互斥量时唤醒一个任务
事件组多事件状态管理,支持一对多唤醒(多个任务可同时响应同一事件)设置事件位时唤醒多个任务

在这里插入图片描述

事件组的优势

  • 一对多广播:当某个事件位被设置时,所有等待该事件的任务都会被唤醒。
  • 多条件等待:任务可以等待任意一个事件位多个事件位同时满足
  • 灵活的位操作:程序员可以自定义每个位的含义(如Bit0表示串口就绪,Bit1表示按键按下)。
    在这里插入图片描述

3. 事件组的实现细节

3.1 事件组的位数与配置

事件组的大小由FreeRTOS的配置参数 configUSE_16_BIT_TICKS 决定:

  • 16位事件组
    • configUSE_16_BIT_TICKS == 1 时,事件组为16位整数
    • 高8位(bit15bit8)**保留给内核使用**,用户可用的事件位为**低8位**(bit7bit0)。
  • 32位事件组
    • configUSE_16_BIT_TICKS == 0 时,事件组为32位整数
    • 高8位(bit31bit24)**保留给内核使用**,用户可用的事件位为**低24位**(bit23bit0)。

注意configUSE_16_BIT_TICKS 的主要目的是优化系统效率,而非直接影响事件组功能。16位系统更适合处理16位数据,32位系统则更适合处理32位数据。


4. 事件组的典型应用场景

4.1 多任务协同

  • 场景:多个任务需要等待同一事件(如按键按下)。
  • 实现
    • 任务A和任务B均调用 xEventGroupWaitBits() 等待Bit0。
    • 中断服务程序(ISR)在检测到按键按下时调用 xEventGroupSetBitsFromISR() 设置Bit0。
    • 结果:任务A和任务B均被唤醒,实现一对多广播。

4.2 多条件触发

  • 场景:任务需要等待多个事件同时发生(如串口就绪且网络连接成功)。
  • 实现
    • 任务调用 xEventGroupWaitBits() 等待Bit0(串口)和 Bit1(网络)。
    • 事件位被逐步设置后,任务被唤醒。

5. 事件组的核心API

5.1 创建事件组

EventGroupHandle_t xEventGroupCreate(void);
  • 功能:创建一个新的事件组。
  • 返回值:事件组句柄(NULL 表示失败)。

5.2 设置事件位

EventBits_t xEventGroupSetBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet);
  • 功能:设置事件组中的指定位。
  • 参数
    • xEventGroup:事件组句柄。
    • uxBitsToSet:要设置的位掩码(如 BIT_0 | BIT_1)。

5.3 等待事件位

EventBits_t xEventGroupWaitBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait);
  • 功能:等待事件组中指定的事件位。
  • 参数
    • xEventGroup:事件组句柄。
    • uxBitsToWaitFor:要等待的位掩码。
    • xClearOnExit:退出时是否清除已等待的事件位。
    • xWaitForAllBits:是否要求所有指定位都满足(pdTRUE 表示“与”逻辑,pdFALSE 表示“或”逻辑)。
    • xTicksToWait:等待超时时间。

6. 事件组的代码示例

示例1:一对多广播

// 创建事件组
EventGroupHandle_t xEventGroup = xEventGroupCreate();// 任务A:等待Bit0
void vTaskA(void *pvParameters) {while (1) {EventBits_t uxBits = xEventGroupWaitBits(xEventGroup, BIT_0,           // 等待Bit0pdTRUE,          // 退出时清除Bit0pdFALSE,         // 任意一个位满足即可portMAX_DELAY    // 无限等待);if (uxBits & BIT_0) {// 处理事件}}
}// 任务B:等待Bit0
void vTaskB(void *pvParameters) {while (1) {EventBits_t uxBits = xEventGroupWaitBits(xEventGroup, BIT_0, pdTRUE, pdFALSE, portMAX_DELAY);if (uxBits & BIT_0) {// 处理事件}}
}// 中断服务程序:设置Bit0
void vButtonISRHandler(void) {BaseType_t xHigherPriorityTaskWoken = pdFALSE;xEventGroupSetBitsFromISR(xEventGroup, BIT_0, &xHigherPriorityTaskWoken);portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

示例2:多条件等待

// 任务C:等待Bit0和Bit1同时发生
void vTaskC(void *pvParameters) {while (1) {EventBits_t uxBits = xEventGroupWaitBits(xEventGroup, BIT_0 | BIT_1,  // 等待Bit0和Bit1pdTRUE,         // 退出时清除事件位pdTRUE,         // 要求所有位满足portMAX_DELAY   // 无限等待);if ((uxBits & BIT_0) && (uxBits & BIT_1)) {// 所有条件满足,执行操作}}
}

7. 事件组的注意事项

  1. 事件位的清除
    • xClearOnExit 参数决定是否在任务退出等待时清除事件位。
    • 若不清除,其他任务可能会重复响应同一事件。
  2. 优先级继承
    • 事件组不支持优先级继承,需避免在高优先级任务中等待低优先级任务设置的事件位。
  3. 中断中使用
    • 在ISR中设置事件位需使用 xEventGroupSetBitsFromISR(),并处理上下文切换标志。

8. 事件组与队列/信号量的对比总结

特性事件组队列/信号量
通信类型广播(一对多)点对点(一对一)
数据存储无数据,仅状态位可存储数据(队列)或计数(信号量)
等待条件多事件组合(与/或)单条件(资源可用或信号触发)
适用场景多任务协同、多事件触发资源管理、任务同步

9. 总结

  • 事件组的本质:一个位掩码,通过位操作实现多事件状态管理。
  • 核心优势:一对多广播、多条件等待、轻量高效。
  • 适用场景:多任务协同、复杂事件触发、替代传统信号量/队列的广播需求。
  • 注意事项:合理配置位数、处理事件位清除、避免优先级问题。

通过灵活使用事件组,可以显著简化多任务协作和事件驱动的设计逻辑,是FreeRTOS中不可或缺的工具之一。

相关文章:

  • Flink 的状态机制
  • DeepSeek实战--LLM微调
  • 【算法基础】递归算法 - JAVA
  • 《Java高级编程:从原理到实战 - 进阶知识篇四》
  • 【c语言】数据在内存中的存储
  • [Linux开发工具]gcc/g++
  • wpf CommandParameter 传递MouseWheelEventArgs参数
  • [Vue]编程式导航
  • 回溯算法详解(Java实现):从组合到排列的全面解析
  • 延时启动windows中程序
  • MARM:推荐系统中的记忆增强突破
  • Cycleresearcher:通过自动化评审改进自动化研究
  • C# 方法(控制流和方法调用)
  • SQL笔记——左连接、右连接、内连接
  • pip命令
  • #Paper Reading# DeepSeek-R1
  • 在 Trae CN IDE 中配置 Python 3.11的指南
  • 修改ollama.service都可以实现什么?
  • 【网络编程】HTTP(超文本传输协议)详解
  • 头歌数据库课程实验(索引与数据库完整性)
  • 上海乐高乐园度假区将于7月5日开园
  • 央行行长详解降准:将释放长期流动性1万亿,整体存款准备金率平均水平降至6.2%
  • 娱见 | 为了撕番而脱粉,内娱粉丝为何如此在乎番位
  • “两高”出台司法解释,严打破坏黑土地资源犯罪
  • 缅甸国防军继续延长临时停火期限至5月31日
  • 印巴军事对峙加剧,小规模冲突收场还是走向大战?