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;
}
作者:浮若于心