做平面有什么好的网站,怎么免费建立网店网站,国际重大新闻,免费做一个自己app1、前言
(1)所谓“任务通知”#xff0c;可以反过来读通知任务。我们使用队列、信号量、事件组等等方法时#xff0c;并不知道对方是谁。使用任务通知时#xff0c;可以明确指定#xff1a;通知哪个任务。
(2)使用队列、信号量、事件组时#xff0c;我们都需…1、前言
(1)所谓“任务通知”可以反过来读通知任务。我们使用队列、信号量、事件组等等方法时并不知道对方是谁。使用任务通知时可以明确指定通知哪个任务。
(2)使用队列、信号量、事件组时我们都需要实先创建对应的结构体双方通过中间的结构体通信 (3)使用任务通知时任务结构体TCB中就包含了内部对象可以直接接收别人发过来的“通知” (4)本文涉及的内容
任务通知通知状态、通知值任务通知的使用场合任务通知的优势及限制
2、任务通知的特性
2.1、优势及限制
(1)任务通知的优势
效率更高使用任务通知来发送事件、数据给某个任务时效率更高。比队列、信号量、事件组都有优势。更节省内存使用其他方法时都要先创建对应的结构体使用任务通知时无需额外创建结构体。
(2)任务通知的限制
不能发送数据给ISRISR并没有任务结构体所以无法使用任务通知的功能给ISR发送数据。但ISR可以使用任务通知的功能发送数据给任务。数据只能给该任务独享使用队列、信号量、事件组时数据保存在这些结构体中其他任务、ISR都可以访问这些数据。使用任务通知时数据存放在目标任务中只有它可以访问这些数据。在日常工作中这个限制影响不大。因为很多场合是从多个数据源把数据发给某个任务而不是把一个数据源发给多个任务。无法缓冲数据使用队列时假设队列深度为N那么它可以保持N个数据。使用任务通知时任务结构体中只有一个任务通知值只能保持一个数据。无法广播给多个任务使用事件组可以同时给多个任务发送事件。使用任务通知只能发给一个任务。如果发送受阻发送方无法进入阻塞状态等待假设队列已经满了使用 xQueueSendToBack() 给队列发送数据时任务可以进入阻塞状态等待发送完成。使用任务通知时即使对方无法接收数据发送方也无法阻塞等待只能即刻返回错误。
2.2、通知状态和通知值
(1)每个任务都有一个结构体TCB(Task Control Block)里面有2个成员
一个是uint8_t类型用来表示通知状态一个是uint32_t类型用来表示通知值
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;
(2)通知状态有3种取值
taskNOT_WAITING_NOTIFICATION任务没有在等待通知taskWAITING_NOTIFICATION任务在等待通知taskNOTIFICATION_RECEIVED任务接收到了通知也被称为pending(有数据了待处理)
##define taskNOT_WAITING_NOTIFICATION ( ( uint8_t ) 0 ) /* 也是初始状态 */
##define taskWAITING_NOTIFICATION ( ( uint8_t ) 1 )
##define taskNOTIFICATION_RECEIVED ( ( uint8_t ) 2 )
(3)通知值可以有很多种类型
计数值位(类似事件组)任意数值
3、任务通知的使用
3.1、两类函数
(1)任务通知有2套函数简化版、专业版列表如下
简化版函数的使用比较简单它实际上也是使用专业版函数实现的专业版函数支持很多参数可以实现很多功能
简化板专业板发出通知 xTaskNotifyGive vTaskNotifyGiveFromISR xTaskNotify xTaskNotifyFromISR 取出通知ulTaskNotifyTakexTaskNotifyWait
3.2、简化版
(1)在任务中使用xTaskNotifyGive函数在ISR中使用vTaskNotifyGiveFromISR函数两个函数都是直接给其他任务发送通知
使得通知值加1。并使得通知状态变为“pending”也就是 taskNOTIFICATION_RECEIVED 表示有数据了待处理。
(2)可以使用 ulTaskNotifyTake 函数来取出通知值
如果通知值等于0则阻塞(可以指定超时时间)当通知值大于0时任务从阻塞状态进入就绪态在 ulTaskNotifyTask 返回之前还可以做些清理工作把通知值减1或者把通知值清零。
(3)使用ulTaskNotifyTask函数可以实现轻量级的、高效的二进制信号量、计数型信号量。
(4)函数原型如下
BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify );
void vTaskNotifyGiveFromISR( TaskHandle_t xTaskHandle, BaseType_t *pxHigherPriorityTaskWoken );
uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait );
(5)xTaskNotifyGive函数的参数说明如下
参数说明xTaskToNotify任务句柄(创建任务时得到)给哪个任务发通知返回值必定返回pdPASS
(6)vTaskNotifyGiveFromISR函数的参数说明如下
参数说明xTaskHandle任务句柄(创建任务时得到)给哪个任务发通知xTaskHandle 被通知的任务可能正处于阻塞状态。 此函数发出通知后会把它从阻塞状态切换为就绪态。 如果被唤醒的任务的优先级高于当前任务的优先级 则 *pxHigherPriorityTaskWoken 被设置为pdTRUE 这表示在中断返回之前要进行任务切换。
(7)ulTaskNotifyTake函数的参数说明如下
参数说明xClearCountOnExit函数返回前是否清零 pdTRUE把通知值清零 pdFALSE如果通知值大于0则把通知值减1xTicksToWait 任务进入阻塞态的超时时间它在等待通知值大于0。 0不等待即刻返回 portMAX_DELAY一直等待直到通知值大于0 其他值Tick Count可以用 pdMS_TO_TICKS() 把ms转换为Tick Count 返回值 函数返回之前在清零或减1之前的通知值。 如果xTicksToWait非0则返回值有2种情况 1. 大于0在超时前通知值被增加了 2. 等于0一直没有其他任务增加通知值最后超时返回0
3.3、专业版
(1)xTaskNotify函数功能更强大可以使用不同参数实现各种功能比如
让接收任务的通知值加1这时 xTaskNotify() 等同于 xTaskNotifyGive() 。设置接收任务的通知值得某一位、某些位这就是一个轻量级的、更高效的事件组。把一个新值写入接收任务的通知值上一次的通知值被读走后写入才成功。这就是轻量级的、长度为1的队列。用一个新值覆盖接收任务的通知值无论上一次的通知值是否被读走覆盖都成功。类似xQueueOverwrite() 函数这就是轻量级的邮箱。
(2)xTaskNotify() 比 xTaskNotifyGive() 更灵活、强大使用上也就更复杂。
(3)xTaskNotifyFromISR() 是 xTaskNotify() 对应的ISR版本。
(4)xTaskNotifyFromISR() 和 xTaskNotify() 函数用来发出通知任务使用 xTaskNotifyWait() 函数来取出任务通知。xTaskNotifyWait() 比 ulTaskNotifyTake() 更复杂
和 ulTaskNotifyTake() 一样可以让任务等待(可以加上超时时间)等到任务状态为“pending”(也就是有数据)。还可以在函数进入、退出时清除通知值得指定位。
(5)这几个函数的原型如下
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 );BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry,uint32_t ulBitsToClearOnExit,uint32_t *pulNotificationValue,TickType_t xTicksToWait );
(6)xTaskNotify函数的参数说明如下
参数说明xTaskToNotify任务句柄(创建任务时得到)给哪个任务发通知ulValue怎么使用ulValue由eAction参数决定eAction见下表返回值 pdPASS成功大部分调用都会成功 pdFAIL只有一种情况会失败当eAction为eSetValueWithoutOverwrite 并且通知状态为pending(表示有新数据未读)这时就会失败。
eAction参数说明
eAction取值说明eNoAction 仅仅是更新通知状态为“pending”未使用ulValue。 这个选项相当于轻量级的、更高效的二进制信号量。 eSetBits通知值 原来的通知值 | ulValue按位或。 相当于轻量级的、更高效的事件组。eIncrement通知值 原来的通知值 1未使用ulValue。 相当于轻量级的、更高效的二进制信号量、计数型信号量。 相当于 xTaskNotifyGive() 函数。eSetValueWithoutOverwrite 不覆盖。 如果通知状态为pending(表示有数据未读) 则此次调用xTaskNotify不做任何事返回pdFAIL。 如果通知状态不是pending(表示没有新数据) 则通知值 ulValue。 eSetValueWithOverwrite覆盖。 无论如何不管通知状态是否为pendng 通知值 ulValue。
(7)xTaskNotifyFromISR函数跟xTaskNotify很类似就多了最后一个参数pxHigherPriorityTaskWoken 。在很多ISR函数中这个参数的作用都是类似的使用场景如下
被通知的任务可能处于阻塞状态xTaskNotifyFromISR 函数发出通知后会把接收任务从阻塞状态切换为就绪态如果被唤醒的任务的优先级高于当前任务的优先级则*pxHigherPriorityTaskWoken被设置为pdTRUE这表示在中断返回之前要进行任务切换。
(8)xTaskNotifyWait 函数列表如下
参数说明ulBitsToClearOnEntry 在xTaskNotifyWait入口处要清除通知值的哪些位 通知状态不是pending的情况下才会清除。 它的本意是我想等待某些事件发生所以先把旧数据的某些位清零。 能清零的话通知值 通知值 ~(ulBitsToClearOnEntry)。 比如传入0x01表示清除通知值的bit0 传入0xFFFFFFFF即ULONG_MAX表示清除所有位即把值设置为0 ulBitsToClearOnExit 在xTaskNotifyWait出口处如果不是因为超时退出 而是因为得到了数据而退出时 通知值 通知值 ~(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返回值1. pdPASS成功 这表示xTaskNotifyWait成功获得了通知 可能是调用函数之前通知状态就是pending 也可能是在阻塞期间通知状态变为了pending。 2. pdFAIL没有得到通知。