聊一下FreeRTOS 的 EventGroup
FreeRTOS 的 EventGroup 是啥,怎么用。EventGroup 是 FreeRTOS 提供的一个同步工具,特别适合多个任务之间通过“事件标志”来协调工作。
啥是 EventGroup?
想象你在组织一个饭局,几个朋友得同时准备好(桌子订好、菜点好、人到齐)才能开吃。EventGroup 就像一个“准备清单”,每个任务负责勾一个“准备好了”的标志,等所有标志都勾上,大家才能一起干活。它比信号量(Semaphore)高级点,因为能同时管多个条件。
简单说:EventGroup 是一个“多位标志”的工具,用来通知和等待多个事件。
基本概念 事件组:一个 EventGroup 里有 24 位(ESP32 上,通常是 32 位架构,但 FreeRTOS 限制为 24 位可用),每位是一个“标志位”,可以代表一个条件或事件。 设置标志:某个任务完成时,可以“点亮”某个位(置 1)。 等待标志:其他任务可以等某些位(或所有位)点亮再干活。
怎么用? ESP32 的 FreeRTOS 提供了几个关键函数,咱们边讲边试。
- 创建 EventGroup 先得有个“清单”:
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
EventGroupHandle_t my_event_group;
void app_main() {
my_event_group = xEventGroupCreate(); // 创建事件组
if (my_event_group == NULL) {
printf("创建失败,内存不够!\n");
}
}
xEventGroupCreate():创建事件组,返回一个句柄。 检查返回值,内存不够会返回 NULL。
2. 设置标志位
任务干完活后,可以点亮某个位:
#define WIFI_CONNECTED_BIT BIT0 // 第0位:WiFi连上了
#define DATA_READY_BIT BIT1 // 第1位:数据准备好
void wifi_task(void *pvParameters) {
// 假装连WiFi
vTaskDelay(2000 / portTICK_PERIOD_MS); // 等2秒
printf("WiFi 连上了\n");
xEventGroupSetBits(my_event_group, WIFI_CONNECTED_BIT); // 点亮第0位
vTaskDelete(NULL);
}
BIT0 是 1 << 0(第0位),BIT1 是 1 << 1(第1位)。 xEventGroupSetBits(事件组, 位):设置指定位为 1。
3. 等待标志位
另一个任务等着条件满足:
void main_task(void *pvParameters) {
EventBits_t bits;
const EventBits_t WAIT_BITS = (WIFI_CONNECTED_BIT | DATA_READY_BIT); // 等第0和第1位
while (1) {
// 等待所有标志位都亮
bits = xEventGroupWaitBits(my_event_group, WAIT_BITS, pdTRUE, pdTRUE, portMAX_DELAY);
printf("收到事件: 0x%x\n", bits);
printf("WiFi和数据都准备好,开始干活!\n");
}
}
xEventGroupWaitBits(事件组, 等哪些位, 是否清零, 是否全等, 超时):
等 WAIT_BITS(第0和第1位)。
pdTRUE(清零):等到了自动清标志。
pdTRUE(全等):所有位都得亮才行。
portMAX_DELAY:一直等。
返回亮起的位,比如 0x3(二进制 11)表示第0和第1位都亮。
4. 完整例子
把 WiFi 和数据准备的任务组合起来:
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#define WIFI_CONNECTED_BIT BIT0
#define DATA_READY_BIT BIT1
EventGroupHandle_t my_event_group;
void wifi_task(void *pvParameters) {
vTaskDelay(2000 / portTICK_PERIOD_MS);
printf("WiFi 连上了\n");
xEventGroupSetBits(my_event_group, WIFI_CONNECTED_BIT);
vTaskDelete(NULL);
}
void data_task(void *pvParameters) {
vTaskDelay(3000 / portTICK_PERIOD_MS);
printf("数据准备好了\n");
xEventGroupSetBits(my_event_group, DATA_READY_BIT);
vTaskDelete(NULL);
}
void main_task(void *pvParameters) {
EventBits_t bits;
const EventBits_t WAIT_BITS = (WIFI_CONNECTED_BIT | DATA_READY_BIT);
while (1) {
bits = xEventGroupWaitBits(my_event_group, WAIT_BITS, pdTRUE, pdTRUE, portMAX_DELAY);
printf("所有条件满足: 0x%x\n", bits);
printf("开始干活!\n");
}
}
void app_main() {
my_event_group = xEventGroupCreate();
xTaskCreate(wifi_task, "WiFi", 2048, NULL, 1, NULL);
xTaskCreate(data_task, "Data", 2048, NULL, 1, NULL);
xTaskCreate(main_task, "Main", 2048, NULL, 1, NULL);
}
输出:
(等2秒)
WiFi 连上了
(再等1秒)
数据准备好了
所有条件满足: 0x3
开始干活!
WiFi 任务 2 秒后点亮 BIT0。 数据任务 3 秒后点亮 BIT1。 主任务等到两个位都亮(3秒后),开始干活。
高级用法
1. 等待部分标志
如果只等一个条件,用 pdFALSE(非全等):
bits = xEventGroupWaitBits(my_event_group, WAIT_BITS, pdTRUE, pdFALSE, portMAX_DELAY);
pdFALSE:只要 WAIT_BITS 中任意一位亮就行。 比如只等 WiFi,连上就跑。
2. 不清标志
如果想保留标志位状态:
bits = xEventGroupWaitBits(my_event_group, WAIT_BITS, pdFALSE, pdTRUE, portMAX_DELAY);
pdFALSE(不清零):标志位保持亮,适合重复检查。
3. 加超时
不想一直等:
bits = xEventGroupWaitBits(my_event_group, WAIT_BITS, pdTRUE, pdTRUE, 5000 / portTICK_PERIOD_MS);
if (bits == WAIT_BITS) {
printf("5秒内条件满足\n");
} else {
printf("超时了\n");
}
需要掌握啥?
创建和销毁:
xEventGroupCreate() 创建。 vEventGroupDelete() 销毁(用完别忘了)。
设置标志:
xEventGroupSetBits() 点亮位。
等待标志:
xEventGroupWaitBits() 等条件,搞懂参数(清零、全等、超时)。
位操作:
用 BIT0、BIT1 定义标志,懂位运算(|、&)。
实际场景:
比如 WiFi 连接、传感器就绪、用户按键,用 EventGroup 同步。
总结
EventGroup 是 FreeRTOS 的“多条件开关”,比信号量灵活。
核心用法:创建 -> 设置标志 -> 等待标志。
ESP32 上用它能轻松管多个任务的同步,比如网络+数据处理。
文档信息
版权声明:可自由转载(请注明转载出处)-非商用-非衍生
发表时间:2025年7月1日 11:09