FreeRTOS事件组详解:从创建到等待与设置位操作(包括ISR环境下的使用)

事件组是一个32位的位掩码,用于任务之间的事件通知或同步。

1. xEventGroupCreate

功能:创建一个新的事件组。

参数:无

返回值

  • 成功时返回 EventGroupHandle_t 类型的事件组句柄。
  • 失败时返回 NULL,通常是由于内存分配失败。
  • 示例

    EventGroupHandle_t xEventGroup;
    xEventGroup = xEventGroupCreate();
    if (xEventGroup == NULL) {
        // 处理错误
    }
    

    2. xEventGroupSetBits

    功能:设置事件组中的一个或多个位。

    EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );
    

    参数

  • xEventGroup:要操作的事件组句柄。
  • uxBitsToSet:要设置的位的位掩码。
  • 返回值:事件组在调用此函数之前的值。

    示例

    #define BIT_0 (1 << 0)
    xEventGroupSetBits(xEventGroup, BIT_0);
    

    3. xEventGroupClearBits

    功能:清除事件组中的一个或多个位。

    EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear );
    

    参数

  • xEventGroup:要操作的事件组句柄。
  • uxBitsToClear:要清除的位的位掩码。
  • 返回值:事件组在调用此函数之前的值。

    示例

    #define BIT_0 (1 << 0)
    xEventGroupClearBits(xEventGroup, BIT_0);
    

    4. xEventGroupWaitBits

    功能:等待指定的位被设置,带有可选的超时参数。

    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:是否等待所有指定的位被设置。
  • xTicksToWait:等待的最大时间(以系统tick计时)。超时后放回0,再次调用后继续等待。
  • 返回值:满足条件时事件组的值。

    示例

    #define BIT_0 (1 << 0)
    xEventGroupWaitBits(xEventGroup, BIT_0, pdTRUE, pdFALSE, portMAX_DELAY);
    

    5. xEventGroupGetBits

    功能:获取当前事件组的值。

    参数

  • xEventGroup:要操作的事件组句柄。
  • 返回值:当前事件组的值。

    示例

    EventBits_t uxBits;
    uxBits = xEventGroupGetBits(xEventGroup);
    

    6. xEventGroupDelete

    功能:删除一个事件组。

    参数

  • xEventGroup:要删除的事件组句柄。
  • 返回值:无

    示例

    vEventGroupDelete(xEventGroup);
    

    xEventGroupSetBitsFromISR 函数说明

    功能: 在中断上下文中设置事件组中的一个或多个位。

    BaseType_t xEventGroupSetBitsFromISR(
        EventGroupHandle_t xEventGroup,
        const EventBits_t uxBitsToSet,
        BaseType_t *pxHigherPriorityTaskWoken
    );
    

    参数

  • xEventGroup:要操作的事件组句柄。
  • uxBitsToSet:要设置的位的位掩码。
  • pxHigherPriorityTaskWoken:这是一个输出参数,如果调用这个函数后需要切换上下文来唤醒一个更高优先级的任务,它将被设置为 pdTRUE。在中断处理函数结束时应调用 portYIELD_FROM_ISR 以进行实际的上下文切换。
  • 返回值

  • pdPASS:表示位成功设置。
  • pdFAIL:表示位未设置(可能因为中断上下文中事件组管理内存不足等原因)。
  • 使用示例

    假设我们有一个中断服务例程(ISR),它需要通知一个任务某个事件发生,可以使用 xEventGroupSetBitsFromISR 进行设置。

    #include "FreeRTOS.h"
    #include "event_groups.h"
    #include "task.h"
    
    // 定义事件位
    #define BIT_0 (1 << 0)
    
    // 声明事件组句柄
    extern EventGroupHandle_t xEventGroup;
    
    // 中断服务例程
    void vISRHandler(void) {
        BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    
        // 在中断中设置事件位
        xEventGroupSetBitsFromISR(xEventGroup, BIT_0, &xHigherPriorityTaskWoken);
    
        // 如果需要,执行上下文切换
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
    
    // 任务函数
    void vTaskFunction(void *pvParameters) {
        EventBits_t uxBits;
    
        for (;;) {
            // 等待BIT_0被设置
            uxBits = xEventGroupWaitBits(
                xEventGroup,
                BIT_0,
                pdTRUE,
                pdFALSE,
                portMAX_DELAY
            );
    
            if ((uxBits & BIT_0) != 0) {
                // 处理事件
                printf("Task received BIT_0\n");
            }
        }
    }
    
    int main(void) {
        // 创建事件组
        xEventGroup = xEventGroupCreate();
        if (xEventGroup == NULL) {
            // 处理事件组创建失败的情况
            printf("Event group creation failed!\n");
            return 1;
        }
    
        // 创建任务
        xTaskCreate(vTaskFunction, "Task", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);
    
        // 启动调度器
        vTaskStartScheduler();
    
        // 永远不会运行到这里
        for (;;);
        return 0;
    }
    

    下面是一个使用事件组的完整示例:

    这个示例展示了如何创建事件组,设置和清除事件位,等待事件位,以及删除事件组:

    #include "FreeRTOS.h"
    #include "task.h"
    #include "event_groups.h"
    
    // 定义事件位
    #define BIT_0 (1 << 0)
    #define BIT_1 (1 << 1)
    
    // 定义任务优先级
    #define TASK_PRIORITY (tskIDLE_PRIORITY + 1)
    
    // 声明事件组句柄
    EventGroupHandle_t xEventGroup;
    
    void vTask1(void *pvParameters) {
        for (;;) {
            // 模拟一些工作
            vTaskDelay(pdMS_TO_TICKS(1000));
            // 设置BIT_0
            xEventGroupSetBits(xEventGroup, BIT_0);
            printf("Task 1 set BIT_0\n");
        }
    }
    
    void vTask2(void *pvParameters) {
        for (;;) {
            // 模拟一些工作
            vTaskDelay(pdMS_TO_TICKS(2000));
            // 设置BIT_1
            xEventGroupSetBits(xEventGroup, BIT_1);
            printf("Task 2 set BIT_1\n");
        }
    }
    
    void vTask3(void *pvParameters) {
        EventBits_t uxBits;
        for (;;) {
            // 等待BIT_0和BIT_1被设置,并在退出时清除这些位
            uxBits = xEventGroupWaitBits(
                xEventGroup,
                BIT_0 | BIT_1,
                pdTRUE,  // 在退出时清除这些位
                pdTRUE,  // 等待所有指定的位
                portMAX_DELAY  // 永久等待
            );
    
            if ((uxBits & (BIT_0 | BIT_1)) == (BIT_0 | BIT_1)) {
                // 所有指定的事件位都被设置
                printf("Task 3: All bits are set. Proceeding...\n");
            }
        }
    }
    
    int main(void) {
        // 创建事件组
        xEventGroup = xEventGroupCreate();
        if (xEventGroup == NULL) {
            // 处理事件组创建失败的情况
            printf("Event group creation failed!\n");
            return 1;
        }
    
        // 创建任务
        xTaskCreate(vTask1, "Task 1", configMINIMAL_STACK_SIZE, NULL, TASK_PRIORITY, NULL);
        xTaskCreate(vTask2, "Task 2", configMINIMAL_STACK_SIZE, NULL, TASK_PRIORITY, NULL);
        xTaskCreate(vTask3, "Task 3", configMINIMAL_STACK_SIZE, NULL, TASK_PRIORITY, NULL);
    
        // 启动调度器
        vTaskStartScheduler();
    
        // 永远不会运行到这里
        for (;;);
        return 0;
    }
    

     

    作者:浮若于心

    物联沃分享整理
    物联沃-IOTWORD物联网 » FreeRTOS事件组详解:从创建到等待与设置位操作(包括ISR环境下的使用)

    发表回复