官方函数文档
304 6.3 xEventGroupCreate()
[[FreeRTOS_Reference_Manual_V10.0.0.pdf#page=304&selection=0,3,4,19|FreeRTOS_Reference_Manual_V10.0.0, page 304]]
FreeRTOS中事件组的目的和功能
FreeRTOS中的事件组时一种用于任务间同步和通信的机制,它允许多个任务通过设置和等待特定的事件来协调它们的行为。
例子:家庭照料
现在有三个任务,它们分别是:
- 妈妈:准备早餐
- 爸爸:送孩子上学
- 孩子:去上学
事件组的功能:
- 创建事件组:
- 事件组类似于一个信号集合,每个信号表示一个特定的事件,例如“早餐准备好了”,“孩子准备好了”。
- 设置事件:
- 当妈妈准备好早餐后,她会发出一个信号表示“早餐准备好了”。
- 当孩子准备好去上学之后,他会发出一个信号表示“孩子准备好了”。
- 等待事件:
- 爸爸需要等待早餐准备好并且孩子准备好,再去送孩子上学。
在FreeRTOS中的实现
- 创建事件组:
EventGroupHandle_t eventGroup = xEventGroupCreate();
- 事件定义:
- 假设用事件位 0 ,表示“早餐准备好了”
- 用事件位 1 ,表示“孩子准备好了”
#define EVENT_BIT_BREAKFAST_READY (1 << 0)
#define EVENT_BIT_CHILD_READY (1 << 1)
- 设置事件:
- 妈妈准备好早餐,设置事件位 0
xEventGroupSetBits(eventGroup, EVENT_BIT_BREAKFAST_READY);
- 孩子准备好上学,设置事件位 1
xEventGroupSetBits(eventGroup, EVENT_BIT_CHILD_READY);
- 等待事件:
- 爸爸任务等待“早餐准备好了”和“孩子准备好了”
xEventGroupWaitBits(eventGroup,
EVENT_BIT_BREAKFAST_READY | EVENT_BIT_CHILD_READY,
pdTRUE,
pdTRUE,
portMAX_DELAY);
优点
- 同步:事件组可以同步多个任务的行为,确保任务安特定顺序执行。
- 灵活:一个事件组可以包含多个事件位,灵活控制不同的事件发生。
- 简化代码:事件组机制是的任务之间的同步变得简单和直观,避免复杂的条件判断。
xEventGroupCreate()
#include "FreeRTOS.h"
#include "event_groups.h"
EventGroupHandle_t xEventGroupCreate( void );
函数说明:
- 创建一个新的事件组。
- RAM needed.
- 事件组数据存储在
EventGroupHandle_t
中。设置configUSE_16_BIT_TICKS
为1
则事件组有8
位,设置为0
则有24
位。
参数:
None
返回值:
NULL:
堆内存不足,创建事件组失败。Any other value:
返回一个事件组句柄。
xEventGroupSetBits()
#include "FreeRTOS.h"
#include "event_groups.h"
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );
函数说明:
- 为RTOS中的事件组设置事件位。
参数:
xEventGroup:
事件组句柄。uxBitsToSet:
要设置的事件位。
返回值:
None
xEventGroupWaitBits()
#include "FreeRTOS.h"
#include "event_groups.h"
EventBits_t xEventGroupWaitBits( const EventGroupHandle_t xEventGroup,
const Eventbits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
TickType_t xTicksToWait );
函数说明:
- 读取RTOS事件组中的位,可以选择进入阻塞状态(带有超时),以等待某个位或一组位被设置。
- 用来一个任务用来检查当前事件组相应的位 是否被设置 或者 是否被清除。如果已经被设置,就继续向下运行;如果没有被设置,就(可选)阻塞当前运行的任务。
- 不能在中断中调用。
参数:
xEventGroup:
事件组句柄。uxBitsToWaitFor:
设置这个值可以检查多个Bit是否被置位。- 设置为
0x05
则意味着检查 bit 0,并且/或者 bit 2。因为 0x05 --> 0101。 - 设置为
0x07
则意味着检查 bit 0 并且/或者 bit 1 并且/或者 bit 3。因为 0x07 --> 0111。 - 这个值不能设置为 0 。
- 设置为
xClearOnExit:
如果此形参被设置为pdTRUE
,是否在退出时清零对应的位。xWaitAllBits:
要求同时满足还是某一个条件满足。设置为pdTRUE
,则意味着要满足所有位是否符合;设置为pdFALSE
则意味着只要要有一个 Bit 被触发。xTicksToWait:
阻塞时间。
返回值:
Any Value:
等待的事件位被设置或阻塞时间到期时事件组的值。如果在调用任务离开阻塞状态和退出此函数之间,优先级更高的任务或者中断更改了事件位的值,则此函数的返回值将不同于事件组的返回值。
示例代码
#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_flash.h"
#include "esp_system.h"
#include "freertos/event_groups.h"
#include "freertos/semphr.h"
static EventGroupHandle_t event_group; // 事件组句柄
static SemaphoreHandle_t recursive_mutex; // 递归互斥锁句柄
#define EVENT_BIT_BREAKFAST_READY (1 << 0) // 早餐准备好事件信号
#define EVENT_BIT_CHILD_READY (1 << 1) // 孩子准备好事件信号
void mom_task(void *pvPara)
{
xSemaphoreTakeRecursive(recursive_mutex, portMAX_DELAY); // 获取递归互斥锁
printf("[MOM TASK]: Begin.\n");
xEventGroupSetBits(event_group, EVENT_BIT_BREAKFAST_READY); // 向事件组发送事件信号,即“早餐准备好了”
vTaskDelay(pdMS_TO_TICKS(2000));
printf("[MOM TASK]: Breakfast ready.\n");
vTaskDelay(pdMS_TO_TICKS(1000));
xSemaphoreGiveRecursive(recursive_mutex); // 释放递归互斥锁
vTaskDelete(NULL);
}
void child_task(void *pvPara)
{
xSemaphoreTakeRecursive(recursive_mutex, portMAX_DELAY); // 获取递归互斥锁
printf("[CHILD TASK]: Begin.\n");
xEventGroupSetBits(event_group, EVENT_BIT_CHILD_READY); // 向事件组发送事件信号,即“孩子准备好了”
vTaskDelay(pdMS_TO_TICKS(2000));
printf("[CHILD TASK]: Child ready.\n");
vTaskDelay(pdMS_TO_TICKS(2000));
xSemaphoreGiveRecursive(recursive_mutex); // 释放递归互斥锁
vTaskDelete(NULL);
}
void father_task(void *pvPara)
{
xSemaphoreTakeRecursive(recursive_mutex, portMAX_DELAY); // 获取递归互斥锁
printf("[FATHER TASK]: Begin.\n");
xEventGroupWaitBits(event_group, 0x03, pdTRUE, pdTRUE, portMAX_DELAY); // 向事件组发送信号,即“可以去学校了”
vTaskDelay(pdMS_TO_TICKS(2000));
printf("[FATHER TASK]: All ready, go to school.\n");
vTaskDelay(pdMS_TO_TICKS(2000));
xSemaphoreGiveRecursive(recursive_mutex); // 释放递归互斥锁
vTaskDelete(NULL);
}
void app_main(void)
{
event_group = xEventGroupCreate();
recursive_mutex = xSemaphoreCreateRecursiveMutex();
vTaskSuspendAll();
xTaskCreate(mom_task, "Mon task", 2048, NULL, 2, NULL);
xTaskCreate(child_task, "Child task", 2048, NULL, 2, NULL);
xTaskCreate(father_task, "Father task", 2048, NULL, 1, NULL);
xTaskResumeAll();
}
代码中同时应用了递归互斥锁来对任务非阻塞。