FreeRTOS——事件标志组

一、事件标志组

        前面所介绍的队列、信号量,只能实现与单个任务进行同步。而有时候某个任务可能需要与多个事件或任务进行同步,此时,事件标志组的作用就凸显出来

1.1 事件标志组简介

事件标志位:用一个位,来表示事件是否发生

事件标志组:一组事件标志位的集合, 可以简单的理解事件标志组,就是一个(16/32)整数

事件标志组是一种实现任务/中断间通信的机制,主要用于实现多任务间的同步

根据configUSE_16_BIT_TICKS 的宏定义不同,每个事件标志组的位数也就不同

        虽然使用了 32 位无符号的数据类型变量来存储事件标志, 但其中的8用作存储事件标志组的控制信息,低24位用作存储事件标志 ,所以说一个事件组最多可以存储 24 个事件标志

        可以发现,事件标志组与外设的状态寄存器SR非常类似,每一位都代表一个事件是否发生(高8位除外) 

1.2 事件标志组与队列、信号量的区别

此外:设置事件不会阻塞等待事件标志支持阻塞 

 

二、事件组结构体

typedef struct EventGroupDef_t
{
    EventBits_t uxEventBits;
    List_t xTasksWaitingForBits; /*< List of tasks waiting for a bit to be set. */

    #if ( configUSE_TRACE_FACILITY == 1 )
        UBaseType_t uxEventGroupNumber;
    #endif

    /* 如果事件组是静态分配,则设置为pdTURE,以确保不尝试释放内存 */
    #if ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
        uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the event group is statically allocated to ensure no attempt is made to free the memory. */
    #endif
} EventGroup_t;
成员 说明
uxEventBits

EventBits_t类型的变量,其中,

高八位:事件标志组的控制信息

剩余位:存储事件标志(1:发生;2:未发生)

xTasksWaitingForBits 链表,等待事件标志位的任务的链表

三、相关API

函数

描述

xEventGroupCreate()

使用动态方式创建事件标志组

xEventGroupCreateStatic()

使用静态方式创建事件标志组

xEventGroupClearBits()

清零事件标志位

xEventGroupClearBitsFromISR()

在中断中清零事件标志位

xEventGroupSetBits()

设置事件标志位

xEventGroupSetBitsFromISR()

### FreeRTOS 中信号量与事件标志的区别和使用场景 #### 信号量 (Semaphores) 信号量主要用于两个方面:任务间的同步和互斥访问临界资源。根据用途不同,信号量分为几种类型: - **二值信号量**:类似于操作系统中的互斥锁(Mutex)。这种类型的信号量只有两种状态——可用或不可用。当一个任务获得这个信号量时,其他尝试获取同一信号量的任务会被挂起直到前一个持有者释放它[^1]。 - **计数型信号量**:允许超过一次的“占有”,即可以多次给予而不会立即变为不可用的状态。这对于管理多个相同类型的资源非常有用,比如缓冲区池中的空闲项数量[^3]。 对于同步目的来说,无论是哪种形式的信号量,在某个特定条件满足之前都可以让调用方等待;而对于互斥,则是用来确保在同一时刻只有一个线程能够进入某段代码区域从而防止并发冲突的发生[^2]。 ```c // 创建一个二值信号量的例子 SemaphoreHandle_t xBinarySemaphore; void setup() { // 在初始化阶段创建信号量 xBinarySemaphore = xSemaphoreCreateBinary(); } void loop() { if (xSemaphoreTake(xBinarySemaphore, portMAX_DELAY) == pdTRUE) { // 执行受保护的操作... // 完成后记得释放信号量 xSemaphoreGive(xBinarySemaphore); } } ``` #### 事件标志 (Event Groups) 相比之下,事件标志提供了一种更灵活的方式来进行多条件的通知机制。通过合不同的位掩码来代表各种可能发生的独立事件,并且可以在单次操作中检查任意数量的不同条件是否已被触发。这使得复杂的应用逻辑变得简单明了,尤其是在需要监听多种外部输入的情况下特别有效。 例如在一个智能家居控制系统里,可以通过设置相应的位来反映门窗传感器、温度感应器等多个设备的状态变化,之后由中央处理单元统一判断并作出响应动作而不必逐一查询每一个单独的数据源。 ```c // 使用事件标志的一个例子 #define BIT0 (1 << 0) #define BIT1 (1 << 1) EventGroupHandle_t event_group; const EventBits_t button_press_bit = BIT0; const EventBits_t temperature_alert_bit = BIT1; void taskA(void *pvParameters){ while(1){ // 当按钮按下时设置相应位 vTaskDelay(pdMS_TO_TICKS(500)); xEventGroupSetBits(event_group, button_press_bit); } } void taskB(void *pvParameters){ while(1){ // 如果检测到高温则置定位 vTaskDelay(pdMS_TO_TICKS(1000)); xEventGroupSetBits(event_group, temperature_alert_bit); } } void main_task(void *pvParameters){ // 初始化事件标志 event_group = xEventGroupCreate(); // 启动子任务 xTaskCreate(taskA, "taskA", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL ); xTaskCreate(taskB, "taskB", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL ); while(true){ EventBits_t uxBits; // 等待任一位被设置 uxBits = xEventGroupWaitBits( event_group, button_press_bit | temperature_alert_bit, pdFALSE, /* 不清除已读取的位 */ pdFALSE, /* 只要有一个匹配就返回 */ portMAX_DELAY); if((uxBits & button_press_bit)!=0){ printf("Button pressed\n"); } if((uxBits & temperature_alert_bit)!=0){ printf("Temperature alert!\n"); } } } ``` #### 主要差异 | 特征 | 信号量 | 事件标志 | |--------------------|----------------------------------|-----------------------------------| | 数据结构 | 整形变量 | 每个成员都是布尔值的一系列位 | | 功能 | 控制对共享资源的独占使用权 | 多重条件下的通知 | | API | `xSemaphoreCreate`/`Take`/`Give` | `xEventGroupCreate`/`SetBits`/`ClearBits`/`WaitBits` | #### 应用场合的选择依据 选择使用何种工具取决于具体需求: - 若仅需简单的锁定机制以避免竞态条件发生,应考虑采用**信号量**; - 对于涉及较多异步事件协调的情况,尤其是那些需要同时监视几个不同来源的信息流时,推荐选用更为强大的**事件标志**解决方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值