目录
前言:本篇参考,韦东山开发文档,连接放在最后
基本概念
在FreeRtos操作系统里面,任务通知(Task Notification)是一种专门用在任务间的任务通信机制,被用在任务间的发送信号或者传输数据,特点是效率高,占用内存和cpu非常少。
虽然在FreeRtos中队列(Queue)信号量(Semaphore)事件组(Event Group)都可以实现任务间的通信(唤醒),但是没有使用任务通知,占用内存小和速度快,队列(Queue)信号量(Semaphore)事件组(Event Group)来通知任务的时候,只是将阻塞列表里面的第一个阻塞的任务唤醒,但是不知道这个任务是哪个任务。
任务通知特性
使用任务通知效率更高相对于,队列,事件,信号量,更加节省内存,不需要创建结构体,不能发送数据给ISR,数据只能被任务独享,发送数据只能被目标人物访问,无法缓冲数据,任务通知只有一个任务通知值,只能保持一个数据,无法广播发送给多个任务,只能实现发送给一个任务。
tskTaskControlBlock简称tskTCB,是任务通知控制块(Task Control Block)的结构体,包含任务的各种状态信息,成员属性有 ulNotifiedValue 和 ucNotifyState。
typedef struct tskTaskControlBlock
{
// configTASK_NOTIFICATION_ARRAY_ENTRIES = 1
volatile uint32_t ulNotifiedValue[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
volatile uint8_t ucNotifyState[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
} tskTCB;
ulNotifiedValue 任务通知的数值的取值范围,这个成员属性用来存储任务通知的数据,因为是 uint32_t 类型 取值范围在 0x000000 ~ 0xffffff 之间。
ucNotifyState这个成员属性类型代表着任务通知的状态,能取值的状态类型有三种,taskNOT_WAITING_NOTIFICATION:任务不处于等待通知状态
taskWAITING_NOTIFICATION:任务等待通知状态
taskNOTIFICATION_RECEIVED:任务接受通知状态,也称为peding状态
如果任务状态为 taskNOT_WAITING_NOTIFICATION 期间有任务通知,并不会转换状态为taskNOTIFICATION_RECEIVED 保持状态,只有任务状态为taskWAITING_NOTIFICATION,这个时候有任务通知,才会转变任务状态为 taskNOTIFICATION_RECEIVED。
函数原型
任务通知函数分为,简化版,专业版,后者参数更多实现功能更多,同样的前者,实现的是简化版的功能。
简化版 | 专业版 | |
发出通知 | xTaskNotifyGive() vTaskNotifyGiveFromISR() |
xTaskNotify() xTaskNotifyFromISR() |
取出通知 | ulTaskNotifyTake() | xTaskNotifyWait() |
简化版函数
简化版函数在任务中给其他任务发送任务通知时,使用 xTaskNotifyGive() ,在ISR(中断)中使用 vTaskNotifyGiveFromISR() 函数,效果为如下所示。
BaseType_t xTaskNotifyGive(TaskHandle_t xTaskToNotify);
void vTaskNotifyGiveFromISR(TaskHandle_t xTaskToNotify, BaseType_t *pxHigherPriorityTaskWoken);
· 使得通知值加一,也就是 ulNotifiedValue 的数值加1
·使 ucNotifyState 的值改变为 taskNOTIFICATION_RECEIVED 也是 pending状态
这里需要注意的是,当任务的状态为 taskNOT_WAITING_NOTIFICATION 发送的通知会被记录在通知值当中,但任务自身状态不会改变为,taskNOTIFICATION_RECEIVED 只有当任务调用ulTaskNotifyTake() 或者 xTaskNotifyWait() 函数,这个时候自身状态才会转变为 Peding 状态。
简化版函数使用 ulTaskNotifyTake() 用来接受任务通知,当调用函数时,作用如下所示。
·使任务状态从taskNOT_WAITING_NOTIFICATION变为 taskWAITING_NOTIFICATION1
·当任务在 taskWAITING_NOTIFICATION 接到通知,可以获取通知值进行处理
uint32_t ulTaskNotifyTake(BaseType_t xClearCountOnExit, TickType_t xTicksToWait);
参数中,BaseType_t xClearCountOnExit 类型为 BaseType_t 作用为 指示在任务退出等待状态时是否清除通知计数值
值为 pdTRUE
:在任务接收到通知并退出等待状态后,清除通知计数(即将通知值重置为0)。
值为 pdFALSE
:保留通知计数。即使任务接收到通知,计数仍然保持不变。
这里需要注意的是,当设置参数的值为pdTRUE,会将 ulNotifiedValue 的数值清除为 0,如果设置为 pdFALSE,这里是不会改变 ulNotifiedValue 里面的数值的。
同样的参数里面 xTicksToWait 就是设置等待时间,设置为 0 不等待立刻返回,同样的设置为portMAX_DELAY:一直等待
专业版函数
xTaskNotify/xTaskNotifyWait 这两个函数相对于简单版来说,提供了更多的参数去选择,下满是函数原型。
BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction );
BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify,uint32_t ulValue,eNotifyAction eAction,BaseType_t *pxHigherPriorityTaskWoken );
这里专业版函数,多出来一个 eAction 参数,参数有着不同的取值,有着不同的效果,表格如下
eAction取值 | 参数效果 |
eNoAction | 更新状态为peding,未使用ulValue |
eSetBits | 通知值 = 原来的通知值 | ulValue |
eIncrement | 通知值 = 原来的通知值 + 1 |
eSetValueWithoutOverwrite | 不覆盖。 |
eSetValueWithOverwrite | 覆盖。 |
同样的 xTaskNotifyFromISR 函数和 xTaskNotify 很相似,多出来 pxHigherPriorityTaskWoken这个参数,用来指示ISR是否唤醒了一个优先级更高的任务,如果该任务优先级高于当前正在运行的任务,FreeRtos会在ISR结束的时候进行上下文切换,确保最高优先级的任务能够尽快运行。
BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry,uint32_t ulBitsToClearOnExit,uint32_t *pulNotificationValue,TickType_t xTicksToWait );
专业版的等待函数,也多了很多的参数,具体参数详解如下所示
ulBitsToClearOnEntry :指定任务在等待状态,需要清除的通知位
ulBitsToClearOnExit:指定任务在等待期间要等待通知的位,当指定位被改变时,才会唤醒
pulNotificationValue:参数用来传入,任务发送的通知值
xTicksToWait:函数最大的等待时间,0不等待,portMAX_DELAY 陷入阻塞一直等待。
欢迎指正,希望对你,有所帮助!!!
FreeRTOS入门与工程实践 --由浅入深带你学习FreeRTOS(FreeRTOS教程 基于STM32,以实际项目为导向)_哔哩哔哩_bilibili