任务通知简介
任务通知简单来说就是用来通知任务的,在任务控制块中的结构体成员ulNotifiedValue就是通知值。
- 当通知值为 0 时,表示没有任务通知;当通知值不为 0 时,表示有任务通知,并且通知值就是通知的内容。
- 使用队列,信号量,事件标志组都需要新创建一个结构体,通过中间结构体进行间接通信,示意图如下,
- 用任务通知时,任务控制块TCB包含了内部对象,可以直接接收别的任务发来的通知,示意图如下,
任务通知值更新方式
- 不覆盖接收任务的通知值(队列不覆写)
- 覆盖接收任务的通知值(队列覆写)
- 更新接受任务通知值的一个或多个bit(事件标志组)
- 增加接受任务的通知值(计数型信号量)
备注:我们会发现,任务通知值是可以替代队列,信号量,事件标志位的。
任务通知优劣势
优势:
- 效率高:任务通知向任务发送事件或数据比使用队列、事件标志组或信号量快得多;
- 内存小:任务通知代替队列、事件标志组或信号量,可以节省大量的内存
劣势:
- 无法发送数据给中断(ISR):ISR没有任务控制块的结构体,所以无法发送数据,但是任务通知功能可以在任务之间或从中断到任务发送事件或数据。
- 无法广播多个任务:任务通知只能是被指定的一个接收任务接收并处理。
- 无法缓存多个数据:任务通知是通过更新任务通知值来发送事件或数据的,一个任务通知值只能保存一次。
- 发送受阻不支持阻塞:发送方无法进入阻塞状态等待
任务通知状态
任务通知状态有以下三种,
- 任务未等待通知:任务通知默认初始化状态
- 等待通知:接收方已经准备好,等待发送方给个通知
- 等待接收:发送方已经发送数据,等待接收方接收
任务通知相关函数
发送通知函数:
备注:可以看到,发送通知函数可用于任务和中断中,但是接收通知函数只能用在任务中。
发送通知
发送通知的函数如下,
/*发送通知,带有通知值*/
#define xTaskNotify( xTaskToNotify, ulValue, eAction)
xTaskGenericNotify( (xTaskToNotify),
(tskDEFAULT_INDEX_TO_NOTIFY),
(ulValue),
(eAction),
NULL)
/*发送通知,且带有通知值并且保留接收任务的原通知值*/
#define xTaskNotifyAndQuery( xTaskToNotify, ulValue, eAction, pulPreviousNotifyValue)
xTaskGenericNotify( (xTaskToNotify),
(tskDEFAULT_INDEX_TO_NOTIFY),
(ulValue),
(eAction),
(pulPreviousNotifyValue))
/*发送通知,但不带有通知值*/
#define xTaskNotifyGive( xTaskToNotify)
xTaskGenericNotify( (xTaskToNotify),
(tskDEFAULT_INDEX_TO_NOTIFY),
(0),
eIncrement,
NULL)
从上述三个函数我们可以看到,他们其实都是调用同一个函数 xTaskGenericNotify(),只是里面的参数不同而已,下面介绍该函数。
xTaskGenericNotify():
BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify,
UBaseType_t uxIndexToNotify,
uint32_t ulValue,
eNotifyAction eAction,
uint32_t * pulPreviousNotificationValue );
参数:
- xTaskToNotify:接收任务通知的任务句柄,也就是指定哪个任务接收通知
- uxIndexToNotify:任务通知的相关数组成员,固定值0
- ulValue:任务通知值
- pulPreviousNotificationValue:用于保存更新前的任务通知值,不保存就用NULL,需要保存就给一块内存
- eAction:通知值更新方式
接收通知
ulTaskNotifyTake():
#define ulTaskNotifyTake( xClearCountOnExit, xTicksToWait)
ulTaskGenericNotifyTake( (tskDEFAULT_INDEX_TO_NOTIFY),
(xClearCountOnExit),
(xTicksToWait) )
参数:
- tskDEFAULT_INDEX_TO_NOTIFY:任务的指定通知,也就是任务通知相关数组成员
- xClearCountOnExit:指定在成功接收后,将通知值清0还是减1,pdTRUE表示清零。
- xTicksToWait :阻塞超时时间
返回值为0表示接收失败,反之接收成功。
备注:该函数用于获取任务通知,可以设置在成功获取任务通知的通知值后,可以指定将通知值清零或减 1,当任务通知用作二值信号量或者计数型信号量时可以使用
xTaskNotifyWait():
#define xTaskNotifyWait( ulBitsToClearOnEntry,
ulBitsToClearOnExit,
pulNotificationValue,
xTicksToWait)
xTaskGenericNotifyWait( tskDEFAULT_INDEX_TO_NOTIFY,
(ulBitsToClearOnEntry),
(ulBitsToClearOnExit),
(pulNotificationValue),
(xTicksToWait))
参数:
- tskDEFAULT_INDEX_TO_NOTIFY:任务的指定通知,也就是任务通知相关数组成员
- ulBitsToClearOnEntry:等待前清零指定任务通知值的比特位,也就是旧值对应的bit清零
- ulBitsToClearOnExit :成功等待后清零指定任务通知值的比特位,新值清零
- pulNotificationValue:用来取出通知值,不需要的话,设置为NULL
- xTicksToWait:阻塞超时时间
返回值如果是pdTRUE,则等待成功,反之失败
备注:该函数更加复杂,可以获取通知值和清除通知值的指定位,可以模拟事件标志组和队列。
函数内部实现
以下是xTaskGenericNotify()的内部流程,
以下是ulTaskNotifyTake()的内部流程,
第一步时,当为0也就是没有收到任务通知时,进行下面步骤,
第二步时,收到通知值后,需要判断是否需要在成功读取通知后,将通知值清零,操作如下,