FreeRTOS 任务通知

FreeRTOS的任务通知功能提供了一种高效、节省内存的通信方式。本文详细介绍了任务通知的API、数据结构以及如何使用它来实现轻量级的二进制信号量、计数信号量和事件标记组。通过实例分析,展示了任务通知如何替代传统的信号量和队列,实现一对一的任务同步和事件管理。
摘要由CSDN通过智能技术生成

@(嵌入式)

Freertos
FreeRtos

简述

FreeRTOS 从版本 V8.2.0开始提供任务通知这个功能,每个任务都有一个32位的通知值。按照 FreeRTOS 官方的说法,使用消息通知比通过二进制信号量方式解除阻塞任务快 45%, 并且更加省内存(无需创建队列)。

FreeRTOS 提供以下几种方式发送通知给任务 :
* 发送消息给任务, 如果有通知未读, 不覆盖通知值
* 发送消息给任务,直接覆盖通知值
* 发送消息给任务,设置通知值的一个或者多个位
* 发送消息给任务,递增通知值

通过对以上方式的合理使用,可以在一定场合下替代原本的信号量,队列等。

当然,消息通知也有其限制 :
* 通知只能一对一,因为通知必须指定任务
* 等待通知的任务可以被阻塞, 但是发送消息的任务,任何情况下都不会被阻塞等待

分析的源码版本是 v9.0.0

通知 API

FreeRTOS 关于任务通知的 API 如下

API 功能
xTaskNotifyGive() 发送通知,没有通知值 (信号量类型)
ulTaskNotifyTake() 获取通知,(对应 Give)
xTaskNotify() 发送通知, 带通知值
xTaskNotifyAndQuery() 发送通知,带通知值,并且返回原通知值
xTaskNotifyWait() 等待通知
vTaskNotifyGiveFromISR() xTaskNotifyGive 的中断版本
xTaskNotifyAndQueryFromISR() xTaskNotifyAndQuery 的中断版本
xTaskNotifyFromISR() ulTaskNotifyTake 的中断版本
xTaskNotifyStateClear() 清除所有未读消息

可能你会想,消息通知就一个发送一个接收 API 不就好了,为什么要搞出这么多个 API ?
实际上, 以上的 API,有的是宏定义,而如此实现是方便特定情况下使用,比如用通知去实现轻量化的二进制信号量,计数信号量,队列等。

数据结构

方便下文叙述,先介绍下实现的相关变量定义。
为了实现任务通知,任务控制块 TCB_t 结构体中有两个任务通知的相关变量, 默认情况下, 任务通知这个功能是打开的,也就是宏 configUSE_TASK_NOTIFICATIONS 设置为 1
源码

#if( configUSE_TASK_NOTIFICATIONS == 1 )
    volatile uint32_t ulNotifiedValue;
    volatile uint8_t ucNotifyState;
#endif
  1. 变量 ulNotifiedValue 存储任务通知的数值, 初始化为 0。
  2. 变量 ucNotifyState 存储当前任务通知的状态,对应存在以下三种状态
// 1 没有未读通知,任务没有等待通知
#define taskNOT_WAITING_NOTIFICATION    ( ( uint8_t ) 0 )
// 2 任务等待通知
#define taskWAITING_NOTIFICATION        ( ( uint8_t ) 1 )
// 3 通知等待任务读取
#define taskNOTIFICATION_RECEIVED       ( ( uint8_t ) 2 )

该变量初始化为 taskNOT_WAITING_NOTIFICATION

文章开头提到发送任务通知的几种方式,对应系统源码中定义了如下 5 种命令类型 :

typedef enum
{
    // 1 发送通知,但是没有更新通知值
    eNoAction = 0,              
    // 2 发送通知,将新通知值与原通知值或操作(置位)
    eSetBits,                   
    // 3 发送通知,原通知值加 1
    eIncrement,                 
    // 4 发送通知,直接修改通知值(不过上次通知是否已经读取)
    eSetValueWithOverwrite,     
    // 5 发送通知,如果没有未读消息,设置通知值
    eSetValueWithoutOverwrite   
} eNotifyAction;

轻量级二进制信号量

我在 << FreeRTOS 信号量 >> 一文中举过一个例子,用二进制信号量进行同步。
这里,我们使用任务通知来实现同样的任务同步功能。

先看例子源码 :

// 等待通知的任务句柄
static TaskHandle_t xTaskToNotify = NULL;

void vATask( void * pvParameters )
{
    uint32_t ulNotificationValue;
    // 设置等待通知阻塞时间
    const TickType_t xMaxBlockTime = pdMS_TO_TICKS( 200 );
    // 获取任务句柄
    xTask
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值