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

FreeRTOS事件组-笔记

FreeRTOS事件组-笔记

    • **一、事件组的核心概念**
      • **1. 定义与特性**
    • **二、事件组的存储结构**
      • **1. 位数与配置**
    • **三、事件组的核心API函数**
      • **1. 创建与删除**
      • **2. 事件位操作**
      • **3. 读取事件组当前值**
      • **4. 等待事件条件成立**
    • **四、事件组的典型应用场景**
      • **1. 多事件组合触发**
      • **2. 事件广播**
      • **3. 任务同步**
    • **五、ISR中使用事件组的注意事项**
    • **六、事件组与队列/信号量的对比**
    • **七、代码示例**
      • **1. 按键事件触发多个任务**
      • **2. 等待多个事件同时发生**


一、事件组的核心概念

1. 定义与特性

  • 事件组是FreeRTOS中一种进程间通信技术,用于处理多个事件触发一个或多个任务运行的情况。与队列和信号量不同,事件组允许任务等待一个或多个事件的组合,并能解除所有等待同一事件的任务的阻塞状态,适用于事件的广播和多个任务的同步运行。其特性使得事件组适用于等待一组事件中某个事件发生后做出响应、一组事件都发生后的响应、事件广播和任务间的同步等场景。
    在这里插入图片描述

  • 事件组(Event Group):本质是一个位掩码(bitmask),用于表示多个事件的状态(每个位代表一个事件)。支持一对多广播,可同时唤醒多个任务。

  • 与传统同步机制的对比

    • 队列/信号量:仅支持一对一唤醒(一个任务被唤醒),且每次操作消耗资源(如队列数据被读走)。
    • 事件组:支持一对多唤醒(多个任务可同时响应同一事件),且事件位可保留或清除,无需消耗资源。

例如1:
先后按下左键和右键,或者只按下其中一个键,那事件组会解除所有等待同一事件的任务的阻塞状态。
例如2:
在任务1中使用LED1来闪烁报警,任务2中使用蜂鸣器报警。当报警事件发生时,两个任务同时解除阻塞状态,两个任务都开始运行。
在这里插入图片描述

在这里插入图片描述


二、事件组的存储结构

在这里插入图片描述

在这里插入图片描述

1. 位数与配置

  • 32位事件组
    • 低24位(bit0-bit23):用户可用事件位(表示具体事件,如按键、串口就绪)。
    • 高8位(bit24-bit31):保留给内核使用(如任务阻塞状态)。
  • 16位事件组(若 configUSE_16_BIT_TICKS == 1):
    • 低8位(bit0-bit7):用户可用事件位。
    • 高8位(bit8-bit15):保留给内核使用。

三、事件组的核心API函数

在这里插入图片描述

1. 创建与删除

  • 创建
    EventGroupHandle_t xEventGroupCreate(void);  // 动态分配内存
    EventGroupHandle_t xEventGroupCreateStatic(StaticEventGroup_t *pxEventGroupBuffer);  // 静态分配
    
  • 删除
    void vEventGroupDelete(EventGroupHandle_t xEventGroup);
    

2. 事件位操作

  • 设置事件位
    EventBits_t xEventGroupSetBits(EventGroupHandle_t xEventGroup, EventBits_t uxBitsToSet);  // 任务中使用
    BaseType_t xEventGroupSetBitsFromISR(EventGroupHandle_t xEventGroup, EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken);  // ISR中使用
    
  • 清除事件位
    EventBits_t xEventGroupClearBits(EventGroupHandle_t xEventGroup, EventBits_t uxBitsToClear);  // 任务中使用
    BaseType_t xEventGroupClearBitsFromISR(EventGroupHandle_t xEventGroup, EventBits_t uxBitsToClear);  // ISR中使用
    

3. 读取事件组当前值

#define xEventGroupGetBits(xEventGroup) xEventGroupClearBits(xEventGroup, 0)  // 不清除事件位,仅读取当前值

4. 等待事件条件成立

  • 通用等待函数
    EventBits_t xEventGroupWaitBits(EventGroupHandle_t xEventGroup,EventBits_t uxBitsToWaitFor,          // 需要等待的事件位掩码BaseType_t xClearOnExit,              // pdTRUE:退出时清除指定事件位;pdFALSE:不清除BaseType_t xWaitForAllBits,           // pdTRUE:需所有事件位都置位;pdFALSE:任一事件位置位即可TickType_t xTicksToWait               // 超时时间(portMAX_DELAY表示无限等待)
    );
    
  • 同步等待函数(用于同步点):
    EventBits_t xEventGroupSync(EventGroupHandle_t xEventGroup,EventBits_t uxBitsToSet,            // 需要置位的事件位EventBits_t uxBitsToWaitFor,        // 需要等待的事件位TickType_t xTicksToWait             // 超时时间
    );
    

四、事件组的典型应用场景

1. 多事件组合触发

  • 或关系:等待任意一个事件发生(如按键按下或串口数据到达)。
  • 与关系:等待所有事件发生(如左键和右键同时按下)。
    // 等待 BIT_0 或 BIT_1 中任意一个事件
    EventBits_t xBits = xEventGroupWaitBits(xEventGroup, BIT_0 | BIT_1, pdFALSE, pdFALSE, portMAX_DELAY);
    if (xBits & BIT_0) { /* BIT_0 触发 */ }
    if (xBits & BIT_1) { /* BIT_1 触发 */ }// 等待 BIT_0 和 BIT_1 同时发生
    xBits = xEventGroupWaitBits(xEventGroup, BIT_0 | BIT_1, pdTRUE, pdTRUE, portMAX_DELAY);
    

2. 事件广播

  • 多任务响应同一事件:当某个事件位被置位时,所有等待该事件的任务都会被唤醒。
    // 任务A:等待 BIT_0
    xEventGroupWaitBits(xEventGroup, BIT_0, pdFALSE, pdFALSE, portMAX_DELAY);// 任务B:等待 BIT_0
    xEventGroupWaitBits(xEventGroup, BIT_0, pdFALSE, pdFALSE, portMAX_DELAY);// 中断中置位 BIT_0
    xEventGroupSetBitsFromISR(xEventGroup, BIT_0, &xHigherPriorityTaskWoken);
    

3. 任务同步

  • 同步点:多个任务在某个同步点等待其他任务完成后再继续执行。
    // 任务1:设置 BIT_0 并等待 BIT_1
    xEventGroupSync(xEventGroup, BIT_0, BIT_1, portMAX_DELAY);// 任务2:设置 BIT_1 并等待 BIT_0
    xEventGroupSync(xEventGroup, BIT_1, BIT_0, portMAX_DELAY);
    

五、ISR中使用事件组的注意事项

  1. 非确定性操作:FreeRTOS禁止在ISR中直接执行非确定性操作(如唤醒多个任务)。因此,xEventGroupSetBitsFromISR 实际通过定时器守护任务异步执行事件位设置。
  2. 上下文切换:若唤醒的高优先级任务需要立即运行,需在ISR中调用 portYIELD_FROM_ISR(xHigherPriorityTaskWoken)

六、事件组与队列/信号量的对比

特性事件组队列/信号量
唤醒方式多任务唤醒(一对多广播)单任务唤醒(一对一)
事件组合支持或/与关系(多个事件组合触发)仅支持单一事件触发
资源消耗低(仅需一个位掩码)高(需存储数据或计数)
适用场景多任务同步、事件广播、多条件等待数据传递、资源管理、简单同步

七、代码示例

1. 按键事件触发多个任务

// 创建事件组
EventGroupHandle_t xButtonEventGroup = xEventGroupCreate();// 任务A:LED闪烁报警
void vLEDTask(void *pvParameters) {while (1) {xEventGroupWaitBits(xButtonEventGroup, BIT_0, pdTRUE, pdFALSE, portMAX_DELAY);// LED闪烁}
}// 任务B:蜂鸣器报警
void vBuzzerTask(void *pvParameters) {while (1) {xEventGroupWaitBits(xButtonEventGroup, BIT_0, pdTRUE, pdFALSE, portMAX_DELAY);// 蜂鸣器响}
}// 中断服务程序:按键按下触发事件
void GPIO_IRQHandler(void) {BaseType_t xHigherPriorityTaskWoken = pdFALSE;xEventGroupSetBitsFromISR(xButtonEventGroup, BIT_0, &xHigherPriorityTaskWoken);portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

2. 等待多个事件同时发生

// 任务A:等待 BIT_0 和 BIT_1 同时发生
void vTaskA(void *pvParameters) {while (1) {EventBits_t xBits = xEventGroupWaitBits(xEventGroup, BIT_0 | BIT_1, pdTRUE, pdTRUE, portMAX_DELAY);if ((xBits & BIT_0) && (xBits & BIT_1)) {// 执行操作}}
}

http://www.lqws.cn/news/215407.html

相关文章:

  • AI大神吴恩达-提示词课程笔记
  • 【Go语言基础【14】】defer与异常处理(panic、recover)
  • 深入剖析MySQL存储架构,索引结构,日志机制,事务提交流程
  • 【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
  • KTO: Model Alignment as Prospect Theoretic Optimization
  • [总结篇]个人网站
  • XGBoost时间序列预测之-未来销量的预测
  • 【氧化镓】HTFB应力对β - Ga2O3 SBD的影响
  • 【JavaSE】泛型学习笔记
  • GIC700组件
  • 什么是预训练?深入解读大模型AI的“高考集训”
  • Python抽象基类实战:构建广告轮播框架ADAM的核心逻辑
  • 数据类型-整型
  • python怎么读shape文件?
  • Java 并发编程系列(上篇):多线程深入解析
  • 高级数据结构与算法期末考试速成记录2
  • 获取环境变量的两种方式:getenv()和environ
  • 【C/C++】STL实现版本为什么比手写版本高?
  • SWE-Dev:开启自主特征驱动软件开发新纪元,重新定义大模型编码能力边界
  • IOS性能优化
  • 【Linux庖丁解牛】—系统文件I/O !
  • Python网页自动化测试,DrissonPage库入门说明文档
  • 从零开始的python学习(七)P102+P103+P104+P105+P106+P107
  • [SNOI2024] 公交线路 题解(观察,点减边容斥,优化trick)
  • 【分销系统商城】
  • Python Robot Framework【自动化测试框架】简介
  • c++ —— 内存管理
  • 人工智能赋能高中学科教学的应用与前景研究
  • ThinkPHP 5.1 中的 error 和 success 方法详解
  • 运行示例程序和一些基本操作