【FreeRTOS】任务间通讯6: 任务通知- Task Notification
先看个收快递的例子:
快递柜 → Task Notification
就像小区里的智能快递柜(每个柜子只能存一个包裹),Task Notification 是任务专属的“数据柜”,只能存一条通知信息(比如一个数字或标志位)。快递员(发送者) → 其他任务/中断
快递员(其他任务或中断)把你的包裹(通知数据)塞进你的专属柜子(xTaskNotify()
),并生成一个取件码(唤醒任务)。你(接收者) → 等待通知的任务
你本来在沙发上睡觉(任务阻塞中,ulTaskNotifyTake()
),突然手机收到取件码(通知到达),立马跳起来开柜取包裹(任务被唤醒,处理通知)。
FreeRTOS中的任务通知,就是像快递柜这样的一个装置。
一. Task Notification 简介
Task Notification 是 FreeRTOS 提供的一种轻量级任务间通信(IPC)机制,它允许任务或中断直接向另一个任务发送通知(Notification),而无需使用队列、信号量或事件组等中间对象。
1.1 功能与作用
轻量级通信:比队列、信号量更高效,节省内存和 CPU 开销。
直接唤醒任务:通知可以解除目标任务的阻塞状态(类似二进制信号量)。
携带数据:可以传递一个 32 位整数值(类似队列,但只能存一个值)。
多种通知模式:
覆盖模式(
eSetValueWithOverwrite
):新通知覆盖旧值(默认)。累积模式(
eSetValueWithoutOverwrite
):新通知不覆盖旧值(类似计数信号量)。增量模式(
eIncrement
):每次通知使目标任务的ulNotifiedValue
+1(类似计数信号量)。设置位模式(
eSetBits
):按位设置目标任务的通知值(类似事件组)。
二. Task Notification 使用流程
2.1 创建任务
Task Notification 是 FreeRTOS 任务的 内置功能,不需要显式创建,每个任务自带一个通知状态:
ulNotifiedValue
:存储通知值(32 位整数)。ucNotifyState
:记录通知状态(taskNOT_WAITING_NOTIFICATION
、taskWAITING_NOTIFICATION
等)。
2.2 发送通知
使用 xTaskNotify()
或 xTaskNotifyFromISR()
(中断中使用)发送通知:
BaseType_t xTaskNotify(TaskHandle_t xTaskToNotify, // 目标任务句柄uint32_t ulValue, // 通知值eNotifyAction eAction // 通知模式(如 eSetValueWithOverwrite) );
2.3 接收通知
目标任务使用 ulTaskNotifyTake()
或 xTaskNotifyWait()
接收通知:
uint32_t ulTaskNotifyTake(BaseType_t xClearCountOnExit, // pdTRUE:清零计数器;pdFALSE:减1TickType_t xTicksToWait // 超时时间(portMAX_DELAY 表示永久阻塞) );
2.4 销毁
Task Notification 是任务的内置功能,无需销毁,任务删除时会自动清理。
三. 实战 Demo:任务通知模拟按键触发 LED
场景
任务 1(
vSenderTask
):模拟按键检测,检测到按键后发送通知。任务 2(
vReceiverTask
):等待通知,收到通知后切换 LED 状态。
代码实现
#include "FreeRTOS.h" #include "task.h" #include "stdio.h"// 假设 LED 和按键的硬件操作函数 void LED_Toggle(void); int Key_Scan(void); // 返回 1 表示按键按下TaskHandle_t xReceiverHandle;// 发送任务(模拟按键检测) void vSenderTask(void *pvParameters) {while (1) {if (Key_Scan() == 1) {printf("按键按下,发送通知!\n");xTaskNotify(xReceiverHandle, 0, eNoAction); // 仅唤醒任务,不传值}vTaskDelay(pdMS_TO_TICKS(100)); // 100ms 检测一次按键} }// 接收任务(控制 LED) void vReceiverTask(void *pvParameters) {while (1) {// 等待通知(类似二进制信号量)ulTaskNotifyTake(pdTRUE, portMAX_DELAY);LED_Toggle();printf("收到通知,LED 状态切换!\n");} }int main() {// 创建接收任务(优先级较高)xTaskCreate(vReceiverTask, "Receiver", 128, NULL, 2, &xReceiverHandle);// 创建发送任务(优先级较低)xTaskCreate(vSenderTask, "Sender", 128, NULL, 1, NULL);// 启动调度器vTaskStartScheduler();return 0; }
四. Task Notification 的优缺点
4.1 优点
- 高效:比队列、信号量快,减少上下文切换和内存占用。
- 灵活:支持多种通知模式(覆盖、累积、位操作等)。
- 内置功能:无需额外对象,直接绑定到任务。
- 低延迟:直接唤醒目标任务,适合实时响应场景。
4.2 缺点
- 单接收者:只能一对一通信,不能像队列或事件组那样广播。
- 数据限制:只能携带一个 32 位值,无法传递复杂数据。
- 无历史记录:新通知可能覆盖旧值(除非使用累积模式)。
五. 总结
适用场景:
轻量级任务同步(替代二进制/计数信号量)。
高速事件通知(如中断唤醒任务)。
不适用场景:
需要传递大数据(用队列)。
多任务监听同一事件(用事件组或队列)。
Task Notification 是 FreeRTOS 中 最快、最省资源 的 IPC 机制,合理使用能大幅提升系统性能!