目录标题
1、简介
我们使用队列、信号量、事件组时,都需要提前创建对应的结构体,双方通过中间的结构体进行通信。
使用任务通知时,允许一个任务直接通知另一个任务进行操作,不需要经过中间结构体。任务通知的结构体是由FreeRTOS内核在任务创建时自动创建的,并且会直接关联到相应的任务句柄上。(TCB结构体中包括两个成员:一个8位的通知状态变量;一个32位的通知值变量)
- ISR只能发送任务通知,无法接收任务通知。
- 通知的数据只能由相应的任务独享。
- 发送方无法进入堵塞状态,接收方可以堵塞等待。
2、TCB成员
TCB(Task Control Block)结构体中有两个成员:
- uint8_t类型,用来表示通知状态
- uint32_t类型,用来表示通知值
typedef struct tskTaskControlBlock
{
···
#if( configUSE_TASK_NOTIFICATIONS == 1 )
volatile uint32_t ulNotifiedValue;
volatile uint8_t ucNotifyState;
#endif
···
} tskTCB;
通知状态有以下三种取值:
- taskNOT_WAITING_NOTIFICATION 表示接收任务未等待任何通知
- taskWAITING_NOTIFICATION 表示接收任务当前正在等待通知
- taskNOTIFICATION_RECEIVED 表示接收任务已经收到通知。
通知值可以有很多类型:
- 计数值
- 位(类似事件组)
- 任意数值
所以任务通知可以取代信号量、事件组使用。
3、任务通知API
任务通知也有两套函数,一套简化版、一套专业版。
简化版本 | 专业版本 | |
---|---|---|
发送通知 | xTaskNotifyGive/ vTaskNotifyGiveFromISR | xTaskNotify /xTaskNotifyFromISR |
等待通知 | ulTaskNotifyTake | xTaskNotifyWait |
3.1、简化版
3.1.1、xTaskNotifyGive()
发送通知:
- 使得通知值加一
- 使对应任务的通知状态变为taskNOTIFICATION_RECEIVED ,表示接收到数据了。
/*任务用*/
BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify );
/*ISR用*/
void vTaskNotifyGiveFromISR(
TaskHandle_t xTaskHandle,
BaseType_t *pxHigherPriorityTaskWoken );
参数 | 描述 |
---|---|
xTaskToNotify | 任务句柄,表示给哪个任务发通知 |
pxHigherPriorityTaskWoken | 被通知的任务,可能正处于阻塞状态。 此函数发出通知后,会把它从阻塞状态切换为就绪态。 如果被唤醒的任务的优先级,高于当前任务的优先级, 则"*pxHigherPriorityTaskWoken"被设置为pdTRUE, 这表示在中断返回之前要进行任务切换。 |
返回值 | xTaskNotifyGive返回pdPASS ;vTaskNotifyGiveFromISR无返回值 |
3.1.2、ulTaskNotifyTake()
接收通知:
- 如果通知值等于0,可以进入阻塞;若通知值大于0,则进入就绪态
- 在函数返回前,可以将通知值减一或清零
- 相当于二进制、计数型信号量。
uint32_t ulTaskNotifyTake(
BaseType_t xClearCountOnExit,
TickType_t xTicksToWait );
参数 | 描述 |
---|---|
xClearCountOnExit | pdTRUE:函数返回前将通知值清零;pdFALSE,若通知值大于0,将其减一 |
xTicksToWait | 如果无法获得通知,可以进入阻塞态,xTicksToWait 表示阻塞时间。若设为0,则会直接返回;若设为portMAX_DELAY,则一直等待到有通知。 |
返回值 | 函数返回之前,在清零或减一之前的通知值。 如果xTicksToWait非0,则返回值有2种情况: 1. 大于0:在超时前,通知值被增加了 2. 等于0:一直没有其他任务增加通知值,最后超时返回0 |
3.2、专业版
专业版本的发送通知函数xTaskNotify可以实现更多的功能:
- 让接收任务的通知值加一:这时 xTaskNotify() 等同于 xTaskNotifyGive()
- 设置接收任务的通知值的某一位、某些位,这就是一个轻量级的、更高效的事件组
- 把一个新值写入接收任务的通知值:上一次的通知值被读走后,写入才成功。这就是轻量级的、长度为1的队列
- 用一个新值覆盖接收任务的通知值:无论上一次的通知值是否被读走,覆盖都成功。类似 xQueueOverwrite() 函数,这就是轻量级的邮箱。
接收通知函数功能:
- 可以让任务等待(可以加上超时时间),等到任务状态为"pending"(也就是有数据)
- 还可以在函数进入、退出时,清除通知值的指定位
3.2.1、xTaskNotify()
发送通知函数:
/*任务中使用*/
BaseType_t xTaskNotify(
TaskHandle_t xTaskToNotify,
uint32_t ulValue,
eNotifyAction eAction );
/*ISR中使用*/
BaseType_t xTaskNotifyFromISR(
TaskHandle_t xTaskToNotify,
uint32_t ulValue,
eNotifyAction eAction,
BaseType_t *pxHigherPriorityTaskWoken );
参数 | 描述 |
---|---|
xTaskToNotify | 任务句柄,表示给哪个任务发通知 |
ulValue | 参数ulValue的使用由 eAction决定 |
eAction | 见下表 |
pxHigherPriorityTaskWoken | 一旦pxHigherPriorityTaskWoken 被设置为 pdTRUE,FreeRTOS 内核将根据被通知任务的优先级和其他任务的优先级进行上下文切换,将控制权交给被唤醒的高优先级任务。这样可以确保高优先级任务尽快运行,提高系统的响应性和实时性 |
返回值 | pdPASS:成功 |
eAction 参数说明:
eAction 取值 | 描述 |
---|---|
eNoAction | 仅仅是更新通知状态为"pending",未使用ulValue。 这个选项相当于轻量级的、更高效的二进制信号量。 |
eSetBits | 通知值 = 原来的通知值 |
eIncrement | 通知值 = 原来的通知值 + 1,未使用ulValue。 相当于轻量级的、更高效的二进制信号量、计数型信号量。 相当于**xTaskNotifyGive()**函数。 |
eSetValueWithoutOverwrite | 不覆盖。 如果通知状态为"pending"(表示有数据未读), 则此次调用xTaskNotify不做任何事,返回pdFAIL。 如果通知状态不是"pending"(表示没有新数据), 则:通知值 = ulValue。 |
eSetValueWithOverwrite | 覆盖。 无论如何,不管通知状态是否为"pendng", 通知值 = ulValue。 |
3.2.2、xTaskNotifyWait()
接收通知函数:
BaseType_t xTaskNotifyWait(
uint32_t ulBitsToClearOnEntry,
uint32_t ulBitsToClearOnExit,
uint32_t *pulNotificationValue,
TickType_t xTicksToWait );
参数 | 描述 |
---|---|
ulBitsToClearOnEntry | 在等待事件发生之前,需要清除旧通知值的特定位。只有当通知状态不是"pending"时,才会执行清零操作。 如果传入值是 0x01,表示要清除通知值的 bit0。如果传入值是 0xffffffff 或者 ULONG_MAX,表示要清除所有位,即将通知值设置为0 |
ulBitsToClearOnExit | 在函数退出前,如果不是因为超时推出,而是因为得到了数据而退出时: 通知值 = 通知值 & ~(ulBitsToClearOnExit)。 在清除某些位之前,通知值先被赋给"*pulNotificationValue"。 比如入0x03,表示清除通知值的bit0、bit1; 传入0xffffffff即ULONG_MAX,表示清除所有位,即把值设置为0 |
pulNotificationValue | 用来取出通知值。 在函数退出时,使用ulBitsToClearOnExit清除之前,把通知值赋给"*pulNotificationValue"。 如果不需要取出通知值,可以设为NULL |
xTicksToWait | 任务进入阻塞态的超时时间,它在等待通知状态变为"pending"。 0:不等待,即刻返回; portMAX_DELAY:一直等待,直到通知状态变为"pending"; 其他值:Tick Count,可以用*pdMS_TO_TICKS()*把ms转换为Tick Count |
返回值 | pdPASS:成功 这表示xTaskNotifyWait成功获得了通知: pdFAIL:没有得到通知。 |