14、任务通知
1、 任务通知的基本概念
FreeRTOS 从 V8.2.0 版本开始提供任务通知这个功能,每个任务都有一个 32 位的通知值,在大多数情况下,任务通知可以替代二值信号量、计数信号量、事件组, 也可以替代长度为 1 的队列(可以保存一个 32 位整数或指针值) 。
相对于以前使用 FreeRTOS 内核通信的资源,必须创建队列、二进制信号量、计数信号量或事件组的情况,使用任务通知显然更灵活。 按照 FreeRTOS 官方的说法,使用任务通知比通过信号量等 ICP 通信方式解除阻塞的任务要快 45%,并且更加省 RAM 内存空间(使用 GCC 编译器, -o2 优化级别) ,任务通知的使用无需创建队列。 想要使用任务通知,必须将 FreeRTOSConfig.h 中的宏定义 configUSE_TASK_NOTIFICATIONS 设置为 1,其实FreeRTOS 默认是为 1 的, 所以任务通知是默认使能的。
FreeRTOS 提供以下几种方式发送通知给任务 :
- 发送通知给任务, 如果有通知未读,不覆盖通知值。
- 发送通知给任务,直接覆盖通知值。
- 发送通知给任务,设置通知值的一个或者多个位 ,可以当做事件组来使用。
- 发送通知给任务,递增通知值,可以当做计数信号量使用。
通过对以上任务通知方式的合理使用,可以在一定场合下替代 FreeRTOS 的信号量,队列、事件组等。
当然, 凡是都有利弊,不然的话 FreeRTOS 还要内核的 IPC 通信机制干嘛, 消息通知虽然处理更快, RAM 开销更小,但也有以下限制 :
- 只能有一个任务接收通知消息, 因为必须指定接收通知的任务。
- 只有等待通知的任务可以被阻塞, 发送通知的任务,在任何情况下都不会因为发送失败而进入阻塞态。
2、 任务通知的运作机制
顾名思义,任务通知是属于任务中附带的资源, 所以在任务被创建的时候,任务通知也被初始化的, 而在分析队列和信号量的章节中,我们知道在使用队列、信号量前,必须先创建队列和信号量,目的是为了创建队列数据结构。比如使用 xQueueCreate()函数创建队列,用 xSemaphoreCreateBinary()函数创建二值信号量等等。再来看任务通知,由于任务通知的数据结构包含在任务控制块中,只要任务存在,任务通知数据结构就已经创建完毕,可以直接使用, 所以使用的时候很是方便。
任务通知可以在任务中向指定任务发送通知,也可以在中断中向指定任务发送通知,FreeRTOS 的每个任务都有一个 32 位的通知值,任务控制块中的成员变量 ulNotifiedValue就是这个通知值。只有在任务中可以等待通知,而不允许在中断中等待通知。如果任务在等待的通知暂时无效,任务会根据用户指定的阻塞超时时间进入阻塞状态,我们可以将等待通知的任务看作是消费者;其它任务和中断可以向等待通知的任务发送通知,发送通知的任务和中断服务函数可以看作是生产者,当其他任务或者中断向这个任务发送任务通知,任务获得通知以后,该任务就会从阻塞态中解除,这与 FreeRTOS 中内核的其他通信机制一致。
3、 任务通知的数据结构
从前文我们知道,任务通知是任务控制块的资源,那它也算任务控制块中的成员变量,包含在任务控制块中, 我们将其拿出来看看,具体见下面代码清单加粗部分。
typedef struct tskTaskControlBlock { volatile StackType_t *pxTopOfStack; #if ( portUSING_MPU_WRAPPERS == 1 ) xMPU_SETTINGS xMPUSettings; #endif ListItem_t xStateListItem; ListItem_t xEventListItem; UBaseType_t uxPriority; StackType_t *pxStack; char pcTaskName[ configMAX_TASK_NAME_LEN ]; #if ( portSTACK_GROWTH > 0 ) StackType_t *pxEndOfStack; #endif #if ( portCRITICAL_NESTING_IN_TCB == 1 ) UBaseType_t uxCriticalNesting; #endif #if ( configUSE_TRACE_FACILITY == 1 ) UBaseType_t uxTCBNumber; UBaseType_t uxTaskNumber; #endif #if ( configUSE_MUTEXES == 1 ) UBaseType_t uxBasePriority; UBaseType_t uxMutexesHeld; #endif #if ( configUSE_APPLICATION_TASK_TAG == 1 ) TaskHookFunction_t pxTaskTag; #endif #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) void *pvThreadLocalStoragePointers[configNUM_THREAD_LOCAL_STORAGE_POINTERS]; #endif #if( configGENERATE_RUN_TIME_STATS == 1 ) uint32_t ulRunTimeCounter; #endif #if ( configUSE_NEWLIB_REENTRANT == 1 ) struct _reent xNewLib_reent; #endif #if( configUSE_TASK_NOTIFICATIONS == 1 ) volatile uint32_t ulNotifiedValue; (1) volatile uint8_t ucNotifyState; (2) #endif #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) uint8_t ucStaticallyAllocated; #endif #if( INCLUDE_xTaskAbortDelay == 1 ) uint8_t ucDelayAborted; #endif }tskTCB; typedef tskTCB TCB_t;
代码清单 22-1(1):任务通知的值, 可以保存一个 32 位整数或指针值。 代码清单 22-1(2): 任务通知状态, 用于标识任务是否在等待通知。
4、任务通知的函数接口讲解
4.1、发送任务通知函数 xTaskGenericNotify()
我们先看一下发送通知 API 函数。这类函数比较多,有 6 个。但仔细分析会发现它们只能完成 3 种操作,每种操作有两个 API 函数,分别为带中断保护版本和不带中断保护版本。 FreeRTOS 将 API 细分为带中断保护版本和不带中断保护版本是为了节省中断服务程序处理时间, 提升性能。通过前面通信机制的学习,相信大家都了解了 FreeRTOS 的风格,这里的任务通知发送函数也是利用宏定义来进行扩展的,所有的函数都是一个宏定义, 在任务中发送任务通知的函数均是调用 xTaskGenericNotify()函数进行发送通知。
/******************************************************************************************************* *@ 函数功能:释放内存 *@ 函数参数:xTaskToNotify:被通知的任务句柄,指定通知的任务。 ulValue:发送的通知值。 eAction:枚举类型,指明更新通知值的方式。 pulPreviousNotificationValue:任务原本的通知值返回。 *@ 返 回 值: *******************************************************************************************************/ BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue );
xTaskGenericNotify()函数是一个通用的任务通知发送函数,在任务中发送通知的 API函 数 , 如 xTaskNotifyGive() 、 xTaskNotify() 、 xTaskNotifyAndQuery() , 都 是 以xTaskGenericNotify()为原型的,只不过指定的发生方式不同而已。
(1)、xTaskNotifyGive()
xTaskNotifyGive()是一个宏,宏展开是调用函数 xTaskNotify( ( xTaskToNotify ), ( 0 ),eIncrement ), 即向一个任务发送通知,并将对方的任务通知值加 1。该函数可以作为二值信号量和计数信号量的一种轻量型的实现,速度更快, 在这种情况下对象任务在等待任务通 知 的 时 候 应 该 是 使 用 函 数 ulTaskNotifyTake() 而 不 是 xTaskNotifyWait() 。
xTaskNotifyGive() 不 能 在 中 断 里 面 使 用 , 而 是 使 用 具 有 中 断 保 护 功 能 的vTaskNotifyGiveFromISR()来代替。
/******************************************************************************************************* *@ 函数功能:用于在任务中向指定任务发送任务通知,并更新对方的任务通知值(加 1 操作)。 *@ 函数参数:xTaskToNotify :接收通知的任务句柄, 并让其自身的任务通知值加 1。 *@ 返 回 值:总是返回 pdPASS。 *******************************************************************************************************/ #define xTaskNotifyGive( xTaskToNotify ) xTaskGenericNotify( ( xTaskToNotify ), ( 0 ), eIncrement, NULL )
(2)、vTaskNotifyGiveFromISR()
vTaskNotifyGiveFromISR()是 vTaskNotifyGive()的中断保护版本。 用于在中断中向指定任务发送任务通知,并更新对方的任务通知值(加 1 操作) ,在某些场景中可以替代信号量操作,因为这两个通知都是不带有通知值的。
/******************************************************************************************************* *@ 函数功能:用于在中断中向一个任务发送任务通知,并更新对方的任务通知值(加 1 操作)。 *@ 函数参数:xTaskToNotify:接收通知的任务句柄, 并让其自身的任务通知值加 1。 pxHigherPriorityTaskWoken:该参数在使用之前必须先初始化为pdFALSE。当调用该函数发送一个任务通知时,目标任务接收到通知后将从阻塞态变为就绪态, 并且如果其优先级比当前运行的任务的优先级高,那么*pxHigherPriorityTaskWoken 会被设置为 pdTRUE, 然后在中断退出前执行一次上下文切换,去执 行刚刚被唤醒的中断优先级较高的任务。 pxHigherPriorityTaskWoken是一个可选的参数可以设置为 NULL。 *@ 返 回 值:总是返回 pdPASS。 *******************************************************************************************************/ void vTaskNotifyGiveFromISR(TaskHandle_t xTaskToNotify,BaseType_t *pxHigherPriorityTaskWoken);
从上面的函数说明我们大概知道 vTaskNotifyGiveFromISR()函数作用, 每次调用该函数都会增加任务的通知值, 任务通过接收函数返回值是否大于零,判断是否获取到了通知,任务通知值初始化为 0, (如果与信号量做对比)则对应为信号量无效。当中断调用vTaskNotifyGiveFromISR()通知函数给任务的时候,任务的通知值增加,使其大于零,使其表示的通知值变为有效,任务获取有效的通知值将会被恢复。 那么该函数是怎么实现的呢?
(3)、xTaskNotify()
FreeRTOS 每个任务都有一个 32 位的变量用于实现任务通知,在任务创建的时候初始化为 0。 这个 32 位的通知值在任务控制块 TCB 里面定义,具体见代码清单 22-6。xTaskNotify()用于在任务中直接向另外一个任务发送一个事件, 接收到该任务通知的任务有可能解锁。 如果你想使用任务通知来实现二值信号量和计数信号量,那么应该使用更加简单的函数 xTaskNotifyGive() , 而不是使用 xTaskNotify(), xTaskNotify()函数在发送任务通知的时候会指定一个通知值, 并且用户可以指定通知值发送的方式。
注意: 该函数不能在中断里面使用, 而是使用具体中断保护功能的版本函数xTaskNotifyFromISR()。
#if( configUSE_TASK_NOTIFICATIONS == 1 ) volatile uint32_t ulNotifiedValue; volatile uint8_t ucNotifyState; #endif
/******************************************************************************************************* *@ 函数功能:向指定的任务发送一个任务通知, 带有通知值并且用户可以指定通知值的发送方式。 *@ 函数参数:xTaskToNotify :需要接收通知的任务句柄。 ulValue 用于更新接收任务通知的任务通知值, 具体如何更新由形参 eAction决定。 eAction 任务通知值更新方式 *@ 返 回 值:参数 eAction 为 eSetValueWithoutOverwrite 时,如果被通知任务还没取走上一个通知,又接收到了一个通知,则这次通知值未能更新并返回 pdFALSE, 而其他情况均返回pdPASS。 *******************************************************************************************************/ BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify,uint32_t ulValue,eNotifyAction eAction );
eAction取值 含义 eNoAction 对象任务接收任务通知,但是任务自身的任务通知值不更新,即形参 ulValue 没有用。 eSetBits 对象任务接收任务通知, 同时任务自身的任务通知值与ulValue 按位或。 如果 ulValue 设置为 0x01, 那么任务的通知值的位 0 将被置为 1。同样的如果 ulValue 设置为 0x04, 那么任务的通知值的位 2 将被置为 1。 在这种方式下,任务通知可以看成是事件标志的一种轻量型的实现, 速度更快。 eIncrement 对象任务接收任务通知, 任务自身的任务通知值加 1,即形参ulValue 没有用。 这个时候调用 xTaskNotify()等同于调用xTaskNotifyGive()。 eSetValueWithOverwrite 对象任务接收任务通知,且任务自身的任务通知值会无条件的被设置为 ulValue。在这种方式下,任务通知可以看成是函数 xQueueOverwrite()的一种轻量型的实现, 速度更快。 eSetValueWithoutOverwrite 对象任务接收任务通知, 且对象任务没有通知值,那么通知值就会被设置为 ulValue。 对象任务接收任务通知, 但是上一次接收到的通知值并没有取走 , 那么本次的通知值将不会更新,同时函数返回pdFALSE。 在这种方式下,任务通知可以看成是函数 xQueueSend() 应用在队列深度为 1 的队列上的一种轻量型实现,速度更快。
(4)、xTaskNotifyFromISR()
xTaskNotifyFromISR()是 xTaskNotify()的中断保护版本,真正起作用的函数是中断发送任务通知通用函数 xTaskGenericNotifyFromISR(),而 xTaskNotifyFromISR()是一个宏定义, 用于在中断中向指定的任务发送一个任务通知, 该任务通知是带有通知值并且用户可以指定通知的发送方式, 不返回上一个任务在的通知值。
/******************************************************************************************************* *@ 函数功能:在中断中向指定的任务发送一个任务通知。 *@ 函数参数:xTaskToNotify 指定接收通知的任务句柄。 ulValue 用于更新接收任务通知的任务通知值, 具体如何更新由形参 eAction 决定。 eAction 任务通知值的状态, 具体见表格 22-4。 pxHigherPriorityTaskWoken *pxHigherPriorityTaskWoken 在使用之前必须先初始化为pdFALSE。 当调用该函数发送一个任务通知时, 目标任务接收到通知后将从阻塞态变为就绪态,并且如果其优先 级 比 当 前 运 行 的 任 务 的 优 先 级 高 , 那 么*pxHigherPriorityTaskWoken 会被设置为 pdTRUE, 然后在中断退出前执行一次上下文切换,去执行刚刚被唤醒的中断优先级较高的任务。 pxHigherPriorityTaskWoken是一个可选的参数可以设置为 NULL。 *@ 返 回 值:参数 eAction 为 eSetValueWithoutOverwrite 时,如果被通知任务还没取走上一个通知,又接收到了一个通知,则这次通知值未能更新并返回 pdFALSE,其他情况均返回pdPASS。 *******************************************************************************************************/ #define xTaskNotifyFromISR(xTaskToNotify, ulValue, eAction, pxHigherPriorityTaskWoken ) xTaskGenericNotifyFromISR( ( xTaskToNotify ), ( ulValue ), ( eAction ), NULL, ( pxHigherPriorityTaskWoken ) ) BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify,uint32_t ulValue,eNotifyAction eAction,BaseType_t *pxHigherPriorityTaskWoken );
(5)、中断中发送任务通知通用函数 xTaskGenericNotifyFromISR()
xTaskGenericNotifyFromISR() 是 一 个 在 中 断 中 发 送 任 务 通 知 的 通 用 函 数 ,xTaskNotifyFromISR()、 xTaskNotifyAndQueryFromISR()等函数都是以其为基础,采用宏定义的方式实现。
/******************************************************************************************************* *@ 函数功能:在 中 断 中 发 送 任 务 通 知 的 通 用 函 数 *@ 函数参数:xTaskToNotify:指定接收通知的任务句柄。 ulValue:用于更新接收任务通知值, 具体如何更新由形参 eAction 决定。 eAction:任务通知值更新方式 pulPreviousNotificationValue:用于保存上一个任务通知值 pxHigherPriorityTaskWoken:该参数在使用之前必须先初始化为 pdFALSE。当调用该函数发送一个任务通知时, 目标任务接收到通知后将从阻塞态变为就绪态,并且如果其优先级比当前运行的任务的优先级高,那么*pxHigherPriorityTaskWoken 会被设置为pdTRUE, 然后在中断退出前执行一次上下文切换,去执行刚刚被唤醒的中断优先级较高的任务。 pxHigherPriorityTaskWoken 是一个可选的参数可以设置为 NULL。 *@ 返 回 值:无 *******************************************************************************************************/ BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify,uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue,BaseType_t *pxHigherPriorityTaskWoken );
(6)、xTaskNotifyAndQuery()
xTaskNotifyAndQuery()与 xTaskNotify()很像,都是调用通用的任务通知发送函数xTaskGenericNotify() 来 实 现 通 知 的 发 送 , 不 同 的 是 多 了 一 个 附 加 的 参 数pulPreviousNotifyValue 用于回传接收任务的上一个通知值。 xTaskNotifyAndQuery()函数不能用在中断中,而是必须使用带中断保护功能的xTaskNotifyAndQuery()FromISR 来代替。
#define xTaskNotifyAndQuery( xTaskToNotify, ulValue, eAction, pulPreviousNotifyValue ) xTaskGenericNotify( ( xTaskToNotify ), ( ulValue ), ( eAction ), ( pulPreviousNotifyValue ) ) /******************************************************************************************************* *@ 函数功能:向指定的任务发送一个任务通知, 并返回对象任务的上一个通知值。 *@ 函数参数:xTaskToNotify:需要接收通知的任务句柄。 ulValue:用于更新接收任务通知的任务通知值, 具体如何更新由形参eAction 决定。 eAction:任务通知值更新方式, 具体见表格 22-4。 pulPreviousNotifyValue:对象任务的上一个任务通知值,如果为 NULL, 则不需要回传, 这个时候就等价于函数 xTaskNotify()。 *@ 返 回 值:参数 eAction 为 eSetValueWithoutOverwrite 时,如果被通知任务还没取走上一个通知,又接收到了一个通知,则这次通知值未能更新并返回 pdFALSE,其他情况均返回pdPASS。 *******************************************************************************************************/ BaseType_t xTaskNotifyAndQuery( TaskHandle_t xTaskToNotify,uint32_t ulValue,eNotifyAction eAction,uint32_t *pulPreviousNotifyValue );
(7)、xTaskNotifyAndQueryFromISR()
xTaskNotifyAndQueryFromISR()是 xTaskNotifyAndQuery ()的中断版本,用于向指定的任务发送一个任务通知, 并返回对象任务的上一个通知值, 该函数也是一个宏定义, 真正实现发送通知的是 xTaskGenericNotifyFromISR()。
/******************************************************************************************************* *@ 函数功能:在中断中向指定的任务发送一个任务通知, 并返回对象任务的上一个通知值。 *@ 函数参数:xTaskToNotify:需要接收通知的任务句柄。 ulValue 用于更新接收任务通知的任务通知值, 具体如何更新由形参 eAction 决定。 eAction 任务通知值的状态, 具体见表格 22-4。 pulPreviousNotifyValue 对象任务的上一个任务通知值。 如果为 NULL, 则不需要回传。 pxHigherPriorityTaskWoken *pxHigherPriorityTaskWoken 在使用之前必须先初始化为pdFALSE。 当调用该函数发送一个任务通知时, 目标任务接收到通知后将从阻塞态变为就绪态,并且如果其优先 级 比 当 前 运 行 的 任 务 的 优 先 级 高 , 那 么*pxHigherPriorityTaskWoken 会被设置为 pdTRUE, 然后在中断退出前执行一次上下文切换,去执行刚刚被唤醒的中断优先级较高的任务。 pxHigherPriorityTaskWoken是一个可选的参数可以设置为 NULL。 *@ 返 回 值:参数 eAction 为 eSetValueWithoutOverwrite 时,如果被通知任务还没取走上一个通知,又接收到了一个通知,则这次通知值未能更新并返回 pdFALSE,其他情况均返回pdPASS。 *******************************************************************************************************/ BaseType_t xTaskNotifyAndQueryFromISR(TaskHandle_t xTaskToNotify,uint32_t ulValue,eNotifyAction eAction,uint32_t *pulPreviousNotifyValue,BaseType_t *pxHigherPriorityTaskWoken );
4.2 获取任务通知函数
既然 FreeRTOS 中发送任务的函数有那么多个,那么任务怎么获取到通知呢?我们说了,任务通知在某些场景可以替代信号量、消息队列、事件等。获取任务通知函数只能用在任务中,没有带中断保护版本,因此只有两个 API 函数: ulTaskNotifyTake()和xTaskNotifyWait ()。前者是为代替二值信号量和计数信号量而专门设计的,它和发送通知API 函数 xTaskNotifyGive()、 vTaskNotifyGiveFromISR()配合使用;后者是全功能版的等待通知,可以根据不同的参数实现轻量级二值信号量、计数信号量、事件组和长度为 1 的队列。
所有的获取任务通知 API 函数都带有指定阻塞超时时间参数,当任务因为等待通知而进入阻塞时,用来指定任务的阻塞时间,这些超时机制与 FreeRTOS 的消息队列、信号量、事件等的超时机制一致。
(1)、ulTaskNotifyTake()
ulTaskNotifyTake()作为二值信号量和计数信号量的一种轻量级实现,速度更快。 如果FreeRTOS 中使用函数 xSemaphoreTake() 来获取信号量, 这个时候则可以试试使用函数ulTaskNotifyTake()来代替。
对于这个函数,任务通知值为 0,对应信号量无效,如果任务设置了阻塞等待,任务被阻塞挂起。当其他任务或中断发送了通知值使其不为 0 后,通知变为有效,等待通知的任务将获取到通知, 并且在退出时候根据用户传递的第一个参数 xClearCountOnExit 选择清零通知值或者执行减一操作。
xTaskNotifyTake()在退出的时候处理任务的通知值的时候有两种方法,一种是在函数退出时将通知值清零,这种方法适用于实现二值信号量;另外一种是在函数退出时将通知值减 1,这种方法适用于实现计数信号量。
当一个任务使用其自身的任务通知值作为二值信号量或者计数信号量时, 其他任务应该使用函数 xTaskNotifyGive()或者 xTaskNotify( ( xTaskToNotify ), ( 0 ), eIncrement )来向其发送信号量。 如果是在中断中,则应该使用他们的中断版本函数。
/******************************************************************************************************* *@ 函数功能:用于获取一个任务通知, 获取二值信号量、计数信号量类型的任务通知。 *@ 函数参数:xClearCountOnExit:设置为 pdFALSE 时,函数 xTaskNotifyTake()退出前,将任务的通知值减 1,可以用来实现计数信号量;设置为 pdTRUE 时,函数xTaskNotifyTake()退出前,将任务通知值清零,可以用来实现二值信号量。 xTicksToWait 超时时间, 单位为系统节拍周期。宏 pdMS_TO_TICKS 用于将毫秒转化为系统节拍数。 *@ 返 回 值:返回任务的当前通知值, 在其减 1 或者清 0 之前。 *******************************************************************************************************/ uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit,TickType_t xTicksToWait );
(2)、xTaskNotifyWait()
xTaskNotifyWait()函数用于实现全功能版的等待任务通知,根据用户指定的参数的不同,可以灵活的用于实现轻量级的消息队列队列、二值信号量、计数信号量和事件组功能,并带有超时等待。
/******************************************************************************************************* *@ 函数功能:用于等待一个任务通知,并带有超时等待。 *@ 函数参数:ulBitsToClearOnEntry ulBitsToClearOnEntry 表示在使用通知之前,将任务通知值的哪些 位 清 0 , 实 现 过 程 就 是 将 任 务 的 通 知 值 与 参 数ulBitsToClearOnEntry 的按位取反值按位与操作。如果 ulBitsToClearOnEntry 设置为 0x01, 那么在函数进入前,任 务 通 知 值 的 位 1 会 被 清 0 , 其 他 位 保 持 不 变 。 如 果ulBitsToClearOnEntry 设置为 0xFFFFFFFF (ULONG_MAX), 那么在进入函数前任务通知值的所有位都会被清 0, 表示清零任务通知值。 ulBitsToClearOnExit ulBitsToClearOnExit 表示在函数 xTaskNotifyWait()退出前, 决定任务接收到的通知值的哪些位会被清 0,实现过程就是将任务的通知值与参数 ulBitsToClearOnExit 的按位取反值按位与操作。 在清 0 前,接收到的任务通知值会先被保存到形参*pulNotificationValue 中。如果 ulBitsToClearOnExit 设置为 0x03, 那么在函数退出前, 接收到的任务通知值的位 0 和位 1 会被清 0, 其他位保持不变。如 果 ulBitsToClearOnExi 设 置 为 0xFFFFFFFF(ULONG_MAX), 那么在退出函数前接收到的任务通知值的所有位都会被清 0, 表示退出时清零任务通知值。 pulNotificationValue 用于保存接收到的任务通知值。 如果接收到的任务通知不需要使 用 , 则 设 置 为 NULL 即 可 。 这 个 通 知 值 在 参 数ulBitsToClearOnExit 起 作 用 前 将 通 知 值 拷 贝 到*pulNotificationValue 中。 xTicksToWait 等待超时时间, 单位为系统节拍周期。宏 pdMS_TO_TICKS 用于将单位毫秒转化为系统节拍数。 *@ 返 回 值:如果获取任务通知成功则返回 pdTRUE,失败则返回 pdFALSE。 *******************************************************************************************************/ BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry,uint32_t ulBitsToClearOnExit,uint32_t *pulNotificationValue,TickType_t xTicksToWait );

浙公网安备 33010602011771号