当前位置: 首页> 科技> 互联网 > 赚钱项目_中国高清vpswindows在线观看_百度地图导航2021最新版_昆明网络营销

赚钱项目_中国高清vpswindows在线观看_百度地图导航2021最新版_昆明网络营销

时间:2025/9/12 11:05:12来源:https://blog.csdn.net/songjun007/article/details/145861999 浏览次数:0次
赚钱项目_中国高清vpswindows在线观看_百度地图导航2021最新版_昆明网络营销

我们从 事件组数据结构核心API源码解析应用场景示例Demo 四个维度,结合 FreeRTOS v10.4.3 源码及流程图,详细讲解事件组(Event Group)的实现原理和应用。


1. 事件组核心原理

1.1 事件组数据结构

源码位置:FreeRTOS/Source/include/event_groups.h

typedef struct EventGroupDef_t {EventBits_t uxEventBits;       // 当前事件位(32位)List_t xTasksWaitingForBits;   // 等待事件位的任务链表uint8_t ucEventGroupNumber;    // 调试用的事件组编号
} EventGroup_t;
  • uxEventBits:32位无符号整数,每位(bit)代表一个事件(BIT0~BIT31)。
  • xTasksWaitingForBits:链表保存因等待事件而阻塞的任务。
1.2 事件组操作流程
事件未满足
事件满足
条件达成
创建事件组
任务设置事件位
触发等待任务唤醒
任务等待事件位
任务进入阻塞状态
任务恢复运行

2. 源码级实现分析

2.1 创建事件组

源码位置:xEventGroupCreate()

EventGroupHandle_t xEventGroupCreate( void ) {EventGroup_t *pxEventBits = pvPortMalloc( sizeof( EventGroup_t ) );pxEventBits->uxEventBits = 0; // 初始事件位清零vListInitialise( &( pxEventBits->xTasksWaitingForBits ) );return pxEventBits;
}
  • 关键点:动态分配内存并初始化事件位和任务链表。
2.2 设置事件位

源码位置:xEventGroupSetBits()

EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ) {ListItem_t *pxListItem;List_t *pxList = &( pxEventGroup->xTasksWaitingForBits );// 原子操作设置事件位pxEventGroup->uxEventBits |= uxBitsToSet;// 遍历等待链表,检查是否有任务满足条件pxListItem = listGET_HEAD_ENTRY( pxList );while( pxListItem != listGET_END_MARKER( pxList ) ) {// 获取任务TCB并判断条件是否满足if( ( pxTask->uxBitsToWaitFor & pxEventGroup->uxEventBits ) == pxTask->uxBitsToWaitFor ) {// 唤醒任务并从链表中移除xTaskResumeFromISR( pxTask );}pxListItem = listGET_NEXT( pxListItem );}return pxEventGroup->uxEventBits;
}
  • 核心逻辑:设置指定位,唤醒所有等待条件满足的任务。
2.3 等待事件位

源码位置:xEventGroupWaitBits()

EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToWaitFor,BaseType_t xClearOnExit,BaseType_t xWaitForAllBits,TickType_t xTicksToWait ) {EventBits_t uxReturn;// 检查当前事件位是否满足条件uxReturn = pxEventGroup->uxEventBits;if ( ( ( uxReturn & uxBitsToWaitFor ) == uxBitsToWaitFor ) && ( xWaitForAllBits != pdFALSE ) ) {// 条件满足,直接返回} else if ( ( uxReturn & uxBitsToWaitFor ) != 0 && ( xWaitForAllBits == pdFALSE ) ) {// 条件满足(任一bit)} else {// 条件不满足,任务进入阻塞链表vTaskSuspend( xTaskGetCurrentTaskHandle() );prvAddTaskToWaitingList( pxEventGroup, uxBitsToWaitFor, xWaitForAllBits );xTaskResumeAll();}return uxReturn;
}
  • 阻塞逻辑:若事件位不满足条件,任务挂起并加入等待链表。

3. 事件组应用场景

3.1 多任务同步
  • 场景:多个任务需要等待不同事件触发后才执行。
// 任务1等待BIT0 | BIT1
xEventGroupWaitBits(xEventGroup, BIT0 | BIT1, pdTRUE, pdTRUE, portMAX_DELAY);// 任务2设置BIT0,任务3设置BIT1
xEventGroupSetBits(xEventGroup, BIT0);
xEventGroupSetBits(xEventGroup, BIT1);
3.2 复合事件触发
  • 场景:任务需要同时满足多个条件(如传感器数据就绪+网络连接成功)。
// 等待BIT2(传感器就绪)和BIT3(网络连接)
xEventGroupWaitBits(xEventGroup, BIT2 | BIT3, pdTRUE, pdTRUE, portMAX_DELAY);
3.3 超时事件处理
  • 场景:任务在指定时间内等待事件,超时后执行备用逻辑。
EventBits_t uxBits = xEventGroupWaitBits(xEventGroup, BIT4, pdTRUE, pdTRUE, 1000);
if ((uxBits & BIT4) != 0) {// 正常处理
} else {// 超时处理
}

4. 示例Demo:多传感器数据采集

4.1 场景描述
  • 任务1:温度传感器数据采集(触发BIT0)。
  • 任务2:湿度传感器数据采集(触发BIT1)。
  • 任务3:等待BIT0和BIT1同时就绪后处理数据。
4.2 完整代码
#include "FreeRTOS.h"
#include "task.h"
#include "event_groups.h"#define BIT0 (1 << 0) // 温度就绪
#define BIT1 (1 << 1) // 湿度就绪EventGroupHandle_t xEventGroup;void vTempSensorTask(void *pvParams) {while (1) {// 模拟温度采集vTaskDelay(pdMS_TO_TICKS(100));xEventGroupSetBits(xEventGroup, BIT0);}
}void vHumiditySensorTask(void *pvParams) {while (1) {// 模拟湿度采集vTaskDelay(pdMS_TO_TICKS(200));xEventGroupSetBits(xEventGroup, BIT1);}
}void vDataProcessorTask(void *pvParams) {while (1) {// 等待BIT0和BIT1同时就绪xEventGroupWaitBits(xEventGroup, BIT0 | BIT1, pdTRUE, pdTRUE, portMAX_DELAY);// 处理数据printf("Data Ready: Temp + Humidity\n");}
}int main(void) {xEventGroup = xEventGroupCreate();xTaskCreate(vTempSensorTask, "Temp", 128, NULL, 1, NULL);xTaskCreate(vHumiditySensorTask, "Humi", 128, NULL, 1, NULL);xTaskCreate(vDataProcessorTask, "Proc", 128, NULL, 2, NULL);vTaskStartScheduler();return 0;
}
4.3 运行结果
  • 温度任务每100ms设置BIT0。
  • 湿度任务每200ms设置BIT1。
  • 数据处理任务每200ms(当BIT0和BIT1均被设置时)打印一次数据。

5. 关键设计技巧

5.1 事件位复用
  • 技巧:使用宏定义管理事件位:
    #define TEMP_READY_BIT    (1 << 0)
    #define NET_CONNECT_BIT   (1 << 1)
    
5.2 原子操作优化
  • 源码实现:FreeRTOS使用 taskENTER_CRITICAL()taskEXIT_CRITICAL() 保护事件位操作。
5.3 中断安全版本
  • API:使用 xEventGroupSetBitsFromISR() 在中断中设置事件位:
    void ADC_ISR() {BaseType_t xHigherPriorityTaskWoken = pdFALSE;xEventGroupSetBitsFromISR(xEventGroup, BIT2, &xHigherPriorityTaskWoken);portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
    

6. 事件组 vs 信号量/队列

特性事件组信号量
同步对象数量最多32个独立事件单一计数器
等待条件按位与/或逻辑计数器大于0
资源消耗较高(维护任务链表)较低
适用场景多条件复杂同步单一资源管理

总结

FreeRTOS 事件组通过 位操作任务链表管理 实现高效的多事件同步,其核心优势在于:

  1. 灵活的事件组合:支持按位与(xWaitForAllBits=pdTRUE)或按位或(xWaitForAllBits=pdFALSE)触发。
  2. 低延迟唤醒:事件位更新后立即唤醒符合条件的任务。
  3. 中断安全:提供 FromISR 版本用于中断上下文。

在实际项目中,事件组常用于 多传感器数据融合复合状态机触发 等需要多条件协作的场景。

关键字:赚钱项目_中国高清vpswindows在线观看_百度地图导航2021最新版_昆明网络营销

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: