FreeRTOS的任务通知

一、简介(了解)

任务通知:用来通知任务的,任务控制块中的结构体成员变量 ulNotifiedValue就是这个通知值。

1. 队列、信号量、事件标志组与任务通知的区别

使用队列、信号量、事件标志组时都需另外创建一个结构体,通过中间的结构体进行间接通信!

 使用任务通知时,任务结构体TCB中就包含了内部对象,可以直接接收别人发过来的"通知"


2. 任务通知值的更新方式 

 只要合理,灵活的利用任务通知的特点,可以在一些场合中替代队列、信号量、事件标志组!

3. 任务通知的优势

效率更高使用任务通知向任务发送事件或数据比使用队列、事件标志组或信号量快得多
使用内存更小使用其他方法时都要先创建对应的结构体,使用任务通知时无需额外创建结构体

4. 任务通知的劣势

无法发送数据给ISRISR没有任务结构体,所以无法给ISR发送数据。但是ISR可以使用任务通知的功能,发数据给任务。
无法广播给多个任务任务通知只能是被指定的一个任务接收并处理
无法缓存多个数据任务通知是通过更新任务通知值来发送数据的,任务结构体中只有一个任务通知值,只能保持一个数据。
发送受阻不支持阻塞发送方无法进入阻塞状态等待

二、任务通知值和通知状态(熟悉)

任务都有一个结构体:任务控制块TCB,它里边有两个结构体成员变量:

typedef  struct  tskTaskControlBlock 
{
	… …
    #if ( configUSE_TASK_NOTIFICATIONS  ==  1 )
        volatile  uint32_t  ulNotifiedValue [ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
        volatile  uint8_t   ucNotifyState [ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
    endif
	… …
} tskTCB;
#define  configTASK_NOTIFICATION_ARRAY_ENTRIES	1  	/* 定义任务通知数组的大小, 默认: 1

 一个是 uint32_t 类型,用来表示通知值

一个是 uint8_t 类型,用来表示通知状态

1. 任务通知值

任务通知值的更新方式有多种类型:

  • 计数值(数值累加,类似信号量)
  • 相应位置一(类似事件标志组)
  • 任意数值(支持覆写和不覆写,类似队列)

2. 任务通知状态

其中任务通知状态共有3种取值:

#define	taskNOT_WAITING_NOTIFICATION  	( ( uint8_t ) 0 )		 /* 任务未等待通知 */
#define 	taskWAITING_NOTIFICATION	( ( uint8_t ) 1 )		 /* 任务在等待通知 */
#define 	taskNOTIFICATION_RECEIVED   ( ( uint8_t ) 2 )		 /* 任务在等待接收 */
  • 任务未等待通知 :任务通知默认的初始化状态
  • 等待通知:接收方已经准备好了(调用了接收任务通知函数),等待发送方给个通知
  • 等待接收:发送方已经发送出去(调用了发送任务通知函数),等待接收方接收

三、任务通知相关API函数介绍(熟悉) 

任务通知API函数主要有两类:①发送通知②接收通知

注意:发送通知API函数可以用于任务和中断服务函数中;接收通知API函数只能用在任务中。


1. 发送通知相关API函数: 

函数描述
xTaskNotify()发送通知,带有通知值
xTaskNotifyAndQuery()发送通知,带有通知值并且保留接收任务的原通知值
xTaskNotifyGive()发送通知,不带通知值
xTaskNotifyFromISR()

在中断中发送任务通知

xTaskNotifyAndQueryFromISR()
vTaskNotifyGiveFromISR()

(1)发送通知,带有通知值

#define  xTaskNotify( xTaskToNotify , ulValue , eAction )

                 xTaskGenericNotify(  ( xTaskToNotify ),
                                                   ( tskDEFAULT_INDEX_TO_NOTIFY ), 
                                                   ( ulValue ),
                                                   ( eAction ), 
                                                     NULL  
                                                )

参数描述
xTaskToNotify正在通知的 RTOS 任务的句柄。 这是目标任务。当前执行的 RTOS 任务的句柄通过以下方式 由 xTaskGetCurrentTaskHandle() API 函数返回。
uxIndexToNotify目标任务通知值数组中的索引, 通知值将发送给该索引。

uxIndexToNotify 必须小于 configTASK_NOTIFICATION_ARRAY_ENTRIES。

xTaskNotify() 没有此参数,并且始终向索引 0 发送通知。

ulValue用于更新目标任务的通知值。 请参阅下面 eAction 参数的说明。
eAction一种枚举类型,可以采用下表中记录的值之一来执行相关操作。
eAction 设置已执行的操作
eNoAction目标任务接收事件,但其通知值未更新。 在这种情况下,不使用 ulValue。
eSetBits目标任务的通知值 使用 ulValue 按位或运算。 例如, 如果 ulValue 设置为 0x01,则将在 目标任务的通知值中设置位 0。 同样,如果 ulValue 为 0x04,则将在 目标任务的通知值中设置位 2。 通过这种方式,RTOS 任务通知机制 可以用作 事件组的轻量级替代方案。
eIncrement目标任务的通知值 自增 1,使得调用 xTaskNotify() 相当于调用 xTaskNotifyGive()。 在这种情况下,不使用 ulValue。
eSetValueWithOverwrite目标任务的通知值 无条件设置为 ulValue。 因此, RTOS 任务通知机制可用作 xQueueOverwrite() 的轻量级替代方案。
eSetValueWithoutOrwrite如果目标任务没有 挂起的通知,则其通知值 将设置为 ulValue。

如果目标任务已经有 挂起的通知,则不会更新其通知值, 因为这样做会覆盖 之前使用的值。 在这种情况下, 调用 xTaskNotify() 失败,返回 pdFALSE。

因此,RTOS 任务通知机制可 在长度为 1 的队列上用作 xQueueSend() 在长度为 的轻量级替代方案。 

返回
除了 eAction 被设置为 eSetValueWithoutOverwrite 且目标任务的通知值 因目标任务已有挂起的通知而无法更新之外, 在所有情况下均返回 pdPASS。

每个任务都有一个“任务通知”数组(或简称为“通知”),每个 通知都包含状态和一个 32 位值。 直达任务通知是直接发送至任务的事件, 可以取消阻塞接收任务,并 可以选择通过多种方式更新接收任务的某个通知值。 例如,通知可覆盖接收任务的通知值中的一个,或仅设置 接收任务的通知值中的一个或多个比特位。

xTaskNotify() 用于将事件 直接发送到 RTOS 任务并可能取消该任务的阻塞状态,还可选择 以下列方式更新接收任务的通知值:

  • 将 32 位数字写入通知值
  • 添加一个(递增)通知值
  • 设置通知值中的一个或多个位
  • 保持通知值不变

xTaskNotify() 和 xTaskNotifyIndexed() 是等效的函数 - 唯一的区别 是 xTaskNotifyIndexed() 可以对数组内的任何任务通知进行操作, 而 xTaskNotify() 始终对数组索引 0 处的任务通知进行操作。

不得从中断服务例程 (ISR) 调用此函数。 使用 xTaskNotifyFromISR() 代替。

configUSE_TASK_NOTIFICATIONS 必须在 FreeRTOSConfig.h 中设置为 1(或保留为未定义)以使这些函数可用。 常量 configTASK_NOTIFICATION_ARRAY_ENTRIES 设置 任务通知的每个任务数组中的索引数量。


(2)发送通知,带有通知值并且保留接收任务的原通知值

#define  xTaskNotifyAndQuery( xTaskToNotify , ulValue , eAction , pulPreviousNotifyValue )

                xTaskGenericNotify( ( xTaskToNotify ), 
                                                 ( tskDEFAULT_INDEX_TO_NOTIFY ), 
                                                 ( ulValue ), 
                                                 ( eAction ),
                                                 ( pulPreviousNotifyValue
                                               )

参数描述
......与xTaskNotify()参数相同
pulPreviousNotifyValue可用于在 xTaskNotifyAndQuery() 操作修改任何位之前 传递目标任务的通知值。

pulPreviousNotifyValue 是一个可选参数, 如不需要,可设置为 NULL。 如果未使用 pulPreviousNotifyValue, 则考虑使用 xTaskNotify() 来 代替 xTaskNotifyAndQuery()。 

eAction 设置已执行的操作
......见xTaskNotify表格
返回
除了 eAction 被设置为 eSetValueWithoutOverwrite 且目标任务的通知值 因目标任务已有挂起的通知而无法更新之外, 在所有情况下均返回 pdPASS。

xTaskNotifyAndQueryIndexed() 执行的 操作与 xTaskNotifyIndexed() 相同, 还会在附加的 pulPreviousNotifyValue 参数中 返回目标任务的上一个通知值 (调用函数时的通知值,而不是函数返回时的通知值)。

xTaskNotifyAndQuery() 执行的 操作与 xTaskNotify() 相同, 同样,还会在附加的 pulPreviousNotifyValue 参数中 返回目标任务的上一个通知值 (调用函数时的通知值, 而不是函数返回时的通知值)。

不得从中断服务程序 (ISR) 调用此函数。 使用 xTaskNotifyAndQueryFromISR() 代替。


(3)发送通知,不带通知值

#define  xTaskNotifyGive(  xTaskToNotify  )

xTaskNotifyGiveIndexed( TaskHandle_t xTaskToNotify, UBaseType_t uxIndexToNotify );

                 xTaskGenericNotify(  ( xTaskToNotify ) ,  

                                                   ( tskDEFAULT_INDEX_TO_NOTIFY ) ,  

                                                   ( 0/ uxIndexToNotify ) ,  

                                                     eIncrement ,  

                                                     NULL

                                                )

参数描述
xTaskToNotify

正被通知的 RTOS 任务的句柄,且该任务的通知值正在递增;

当前执行的 RTOS 任务的句柄通过以下方式 由 xTaskGetCurrentTaskHandle() API 函数返回。

uxIndexToNotify目标任务通知值数组中的索引, 通知值将发送给该索引。

uxIndexToNotify 必须小于 configTASK_NOTIFICATION_ARRAY_ENTRIES。 xTaskNotifyGive () 没有此参数,并且总是向索引 0 发送通知。

返回
xTaskNotifyGiveIndexed () 是用 eAction 参数调用 xTaskNotifyIndexed() 的宏, eAction 参数设置为 eIncrement,因此所有调用都返回 pdPASS。

每个任务都有一组“任务通知” (或仅“通知” ) ,每个 通知都包含状态和一个 32 位值。 直达任务通知是直接发送至任务的事件, 可以取消阻塞接收任务,并 可以选择通过多种方式更新接收任务的某个通知值。 例如,通知可覆盖接收任务的通知值中的一个,或仅设置 更多位。

当任务通知 用作轻量级且更快的二进制或计数信号量 替代方案时,可以使用宏 xTaskNotifyGive ()。 FreeRTOS 信号用通过使用 xSemaphoreGive () API 函数给出,而 xTaskNotifyGive () 与其等效,使用接收 RTOS 任务的一个通知值代替信号量。

xTaskNotifyGive () 和 xTaskNotifyGiveIndexed () 是等效宏——唯一的区别是 xTaskNotifyGiveIndexed () 可以在始终在数组内任何任务通知上操作 ,而 xTaskNotifyGive () 始终在数组索引 0 处的任务通知上运行。

当任务通知值用作二进制或等效计数信号量时, 则被通知的任务应等待 使用 ulTaskNotifyTake() API 函数的通知,而不是 xTaskNotifyWait() API 函数。

注意: 数组中每个通知都独立运行——任务一次只能阻止数组中的一个通知,并且不会被发送到任何其他数组索引的通知取消阻止。

xTaskNotifyGive () 不能从中断服务例程调用。 使用 vTaskNotifyGiveFromISR() 代替。

configUSE_TASK_NOTIFICATIONS 必须在 FreeRTOSConfig.h 中设置为 1(或保留为未定义)才能使用这些宏。 常量 configTASK_NOTIFICATION_ARRAY_ENTRIES 设置 任务通知的每个任务数组中的索引数量。


BaseType_t  xTaskGenericNotify(TaskHandle_t  xTaskToNotify, /*接收任务通知的任务句柄*/

                               UBaseType_t  uxIndexToNotify,/*任务的指定通知(任务通知相关数组成员)*/   

                               uint32_t  ulValue,           /*任务通知值*/
    
                               eNotifyAction  eAction,      /*通知方式(通知值更新方式)*/

                               uint32_t *  pulPreviousNotificationValue  )/*用于保存更新前的任务通知值(为NULL则不保存)*/
形参描述
xTaskToNotify接收任务通知的任务句柄
uxIndexToNotify任务的指定通知(任务通知相关数组成员)
ulValue任务通知值
eAction通知方式(通知值更新方式)
pulPreviousNotificationValue用于保存更新前的任务通知值(为NULL则不保存)
typedef  enum
{    
	eNoAction = 0, 			/* 无操作 */
	eSetBits				/* 更新指定bit */
	eIncrement				/* 通知值加一 */
 	eSetValueWithOverwrite		/* 覆写的方式更新通知值 */
	eSetValueWithoutOverwrite	/* 不覆写通知值 */
} eNotifyAction;

2. 接收通知相关API函数: 

函数描述
ulTaskNotifyTake()

获取任务通知,可以设置在退出此函数的时候将任务通知值清零或者减一。

当任务通知用作二值信号量或者计数信号量的时候,使用此函数来获取信号量。

xTaskNotifyWait()获取任务通知,比 ulTaskNotifyTake()更为复杂,可获取通知值和清除通知值的指定位

总结:当任务通知用作于信号量时,使用函数获取信号量:ulTaskNotifyTake()

           当任务通知用作于事件标志组队列时,使用此函数来获取: xTaskNotifyWait()


(1)任务通知用作于信号量时

 #define ulTaskNotifyTake( xClearCountOnExit  ,   xTicksToWait )

ulTaskGenericNotifyTake( ( tskDEFAULT_INDEX_TO_NOTIFY ),

                                          ( xClearCountOnExit ), 

                                          ( xTicksToWait ) )

参数描述
uxIndexToWaitOn任务的指定通知(任务通知相关数组成员)
xClearCountOnExit指定在成功接收通知后,将通知值清零或减 1, pdTRUE:把通知值清零;pdFALSE:把通知值减一
xTicksToWait阻塞等待任务通知值的最大时间
返回值描述
0接收失败
非0接收成功,返回任务通知的通知值

(2)当任务通知用作于事件标志组队列时

#define xTaskNotifyWait( ulBitsToClearOnEntry,

                                         ulBitsToClearOnExit,

                                         pulNotificationValue,

                                         xTicksToWait )

xTaskGenericNotifyWait(  tskDEFAULT_INDEX_TO_NOTIFY,

                                       ( ulBitsToClearOnEntry ),

                                       ( ulBitsToClearOnExit ),

                                       ( pulNotificationValue ),

                                       ( xTicksToWait )               )

形参描述
uxIndexToWaitOn 任务的指定通知(任务通知相关数组成员)
ulBitesToClearOnEntry 等待前清零指定任务通知值的比特位(旧值对应bit清0)
ulBitesToClearOnExit 成功等待后清零指定的任务通知值比特位(新值对应bit清0)
pulNotificationValue 用来取出通知值(如果不需要取出,可设为NULL)
xTicksToWait 阻塞等待任务通知值的最大时间
返回值描述
pdTRUE 等待任务通知成功
pdFALSE 等待任务通知失败

此函数用于获取通知值和清除通知值的指定位值,适用于模拟队列事件标志组使用该函数来获取任务通知 。

  • 28
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

DDKevin19

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

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

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

打赏作者

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

抵扣说明:

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

余额充值