任务通知相关的 API 函数详解

FreeRTOS 中的 任务通知(Task Notification) 是一种轻量级的高效通信机制,允许任务之间或中断直接向特定任务发送事件或数据。相比队列、信号量等传统机制,任务通知具有 更快的速度和更低的内存开销(无需额外创建对象),但功能相对受限(如仅支持单向通信)。以下是任务通知相关的 API 函数详解及使用指南。


任务通知的核心特性

  1. 轻量高效:每个任务自带通知值(32位),无需额外内存分配。
  2. 多种模式:支持数值更新、事件标志位、计数器等多种操作模式。
  3. 直接通信:可直接指定目标任务,无需中间对象(如队列)。
  4. 适用场景
    • 替代二值信号量/计数信号量。
    • 轻量级事件标志组。
    • 单次数据传输(类似轻量队列)。

任务通知 API 函数详解

1. 发送任务通知
基础发送函数
BaseType_t xTaskNotify(
    TaskHandle_t xTaskToNotify, // 目标任务句柄
    uint32_t ulValue,           // 通知值(或掩码)
    eNotifyAction eAction       // 操作类型
);
  • 功能:向指定任务发送通知,并根据 eAction 更新目标任务的通知值。
  • 参数
    • eAction:指定更新方式,可选:
      • eNoAction:仅触发通知,不修改通知值。
      • eSetBits:按位或(ulValue 为掩码)。
      • eIncrement:通知值加 1(ulValue 被忽略)。
      • eSetValueWithOverwrite:直接覆盖通知值。
      • eSetValueWithoutOverwrite:仅当通知值未被读取时覆盖。
  • 返回值
    • pdPASS:发送成功(某些模式下可能返回失败,如 eSetValueWithoutOverwrite 时通知值已存在)。
中断安全版本
BaseType_t xTaskNotifyFromISR(
    TaskHandle_t xTaskToNotify,
    uint32_t ulValue,
    eNotifyAction eAction,
    BaseType_t *pxHigherPriorityTaskWoken
);
  • pxHigherPriorityTaskWoken:标记是否需触发上下文切换(调用 portYIELD_FROM_ISR())。
简化发送函数(类似信号量)
void vTaskNotifyGiveFromISR(
    TaskHandle_t xTaskToNotify,
    BaseType_t *pxHigherPriorityTaskWoken
);

BaseType_t xTaskNotifyGive(TaskHandle_t xTaskToNotify);
  • 等效于 xTaskNotify(..., eIncrement),用于替代计数信号量。

2. 接收任务通知
等待通知(阻塞)
BaseType_t xTaskNotifyWait(
    uint32_t ulBitsToClearOnEntry,  // 进入前清除的位掩码
    uint32_t ulBitsToClearOnExit,   // 退出前清除的位掩码
    uint32_t *pulNotificationValue, // 存储接收到的通知值
    TickType_t xTicksToWait         // 阻塞时间
);
  • 功能:等待任务通知到达,并可按掩码清除通知值的某些位。
  • 返回值
    • pdTRUE:成功接收到通知。
    • pdFALSE:超时或任务句柄无效。
快速接收(非阻塞)
uint32_t ulTaskNotifyTake(
    BaseType_t xClearCountOnExit, // 是否清零计数器(pdTRUE清零,pdFALSE减1)
    TickType_t xTicksToWait       // 阻塞时间
);
  • 功能:等待通知值递增(类似计数信号量),返回接收前的计数值。
  • 典型用途:替代 xSemaphoreTake()

3. 查询通知状态
uint32_t ulTaskNotifyValueClear(
    TaskHandle_t xTask,
    uint32_t ulBitsToClear
);
  • 功能:清除目标任务通知值的指定位。
  • 示例ulTaskNotifyValueClear(NULL, 0xFF) 清除当前任务通知值的低8位。

任务通知使用示例

替代二值信号量
// 任务A发送通知(释放信号量)
void vTaskSender(void *pvParam) {
    while (1) {
        xTaskNotifyGive(xReceiverTaskHandle); // 等效于释放信号量
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

// 任务B等待通知(获取信号量)
void vTaskReceiver(void *pvParam) {
    while (1) {
        // 等待通知(类似xSemaphoreTake)
        ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
        // 处理事件...
    }
}
传递数据(轻量队列)
// 发送端
void vTaskSender(void *pvParam) {
    uint32_t data = 42;
    xTaskNotify(xReceiverTaskHandle, data, eSetValueWithOverwrite);
}

// 接收端
void vTaskReceiver(void *pvParam) {
    uint32_t receivedData;
    xTaskNotifyWait(0, 0, &receivedData, portMAX_DELAY);
    // 使用 receivedData...
}
事件标志组
// 设置事件位(发送端)
xTaskNotify(xTaskHandle, (1 << EVENT_BIT), eSetBits);

// 等待事件位(接收端)
uint32_t flags;
xTaskNotifyWait(0, (1 << EVENT_BIT), &flags, portMAX_DELAY);
if (flags & (1 << EVENT_BIT)) {
    // 事件触发...
}

注意事项

  1. 单接收者限制
    每个通知只能由一个任务接收,无法像队列一样广播给多个任务。

  2. 不可在中断中等待通知
    任务通知的接收函数(如 xTaskNotifyWait)不能在中断服务程序(ISR)中调用。

  3. 数据竞争风险
    若多次快速发送通知(如使用 eSetValueWithOverwrite),可能导致数据覆盖。需根据场景选择合适的 eAction

  4. 替代信号量的限制

    • 任务通知无法在多个任务间共享(如信号量可被多个任务获取)。
    • 无法查询当前计数值(需自行维护状态)。
  5. 任务句柄管理
    需确保发送方持有正确的目标任务句柄(可通过 xTaskGetHandle() 获取)。


任务通知 vs 传统机制

特性任务通知队列/信号量
内存占用无额外内存(内建于任务TCB)需要动态/静态分配内存
速度更快(直接操作任务TCB)较慢(需通过中间对象)
通信方向单向(一对一)多向(多对多)
功能复杂度简单(轻量级)复杂(支持多种同步模式)

通过合理使用任务通知,可以在资源受限或性能敏感的场景中显著提升效率,但需注意其适用边界,避免滥用导致代码可维护性下降。




ulBitsToClearOnEntry(进入前清除的位掩码):
这是一个位掩码,用于指定在函数开始执行并任务进入阻塞状态之前,应该清除任务通知值中的哪些位。如果某个位在掩码中被设置为1,那么在任务开始等待之前,相应的位会被清除(设置为0)。
例如,如果通知值是 0b10101010,而 ulBitsToClearOnEntry 设置为 0b00001111,那么在任务开始等待之前,通知值会被更新为 0b10100000。
ulBitsToClearOnExit(退出前清除的位掩码):
这同样是一个位掩码,用于指定在任务因为接收到通知而退出阻塞状态之前,应该清除任务通知值中的哪些位。如果某个位在掩码中被设置为1,那么在任务退出等待之前,相应的位会被清除(设置为0)。
例如,如果任务在等待期间收到了一个通知,并且通知值变为 0b11001100,而 ulBitsToClearOnExit 设置为 0b11110000,那么在任务退出等待状态之前,通知值会被更新为 0b00001100。
位掩码:
位掩码是一个用于操作位序列(如一个整数的位)的数值,其中每一位的值(0或1)对应于一个特定的操作或属性。在位掩码中,位设置为1表示需要执行某个操作或检查某个条件,而位设置为0则表示不执行或不检查。
例如,一个8位的位掩码 0b00101010 可以用来表示“操作第2位、第5位,不操作其他位”。
在FreeRTOS的任务通知机制中,位掩码提供了一种灵活的方式来指定哪些特定的通知位是相关的,以及如何在不同的阶段(进入和退出阻塞状态)对这些位进行操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

九层指针

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值