FreeRTOS操作系统学习
前言
在FreeRTOS中可以使用任务通知来代替信号量、消息队列、事件标志组等这些东西。使用任务通知的话效率会更高
一、任务通知简介
任务通知在 FreeRTOS 中是一个可选的功能,要使用任务通知的话就需要将宏configUSE_TASK_NOTIFICATIONS 定义为 1。FreeRTOS 的每个任务都有一个 32 位的通知值,任务控制块中的成员变量 ulNotifiedValue就是这个通知值。任务通知是一个事件,假如某个任务通知的接收任务因为等待任务通知而阻塞的话,向这个接收任务发送任务通知以后就会解除这个任务的阻塞状态。 也可以更新接收任务的任务通知值。
任务通知可以通过如下方法更新接收任务的通知值:
● 不覆盖接收任务的通知值(如果上次发送给接收任务的通知还没被处理)。 ● 覆盖接收任务的通知值。 ● 更新接收任务通知值的一个或多个 bit。 ● 增加接收任务的通知值。
合理、灵活的使用上面这些更改任务通知值的方法可以在一些场合中替代队列、二值信号量、计数型信号量和事件标志组。使用任务通知来实现二值信号量功能的时候,解除任务阻塞的时间比直接使用二值信号量要快 45%。 虽然FreeRTOS任务通知速度更快并且占用内存更少,但它也有一些限制: 只能有一个任务接收通知事件。(只能给一个任务发送,消息队列可以多任务) 接收通知的任务可以因为等待通知而进入阻塞状态,但是发送通知的任务即便不能立即完成通知发送也不能进入阻塞状态。
每个RTOS任务都有一个32位的通知值,任务创建时,这个值被初始化为0。FreeRTOS任务通知相当于直接向任务发送一个事件,接收到通知的任务可以解除阻塞状态,前提是这个阻塞事件是因等待通知而引起的。发送通知的同时,也可以可选的改变接收任务的通知值。
二、相关API函数
1.发送任务通知函数
xTaskNotify()
发送通知,带有通知值并且不保留接收任务原通知值,用在任务中。
xTaskNotifyFromISR() 发送通知,函数 xTaskNotify()的中断版本。
xTaskNotifyGive()
发送通知,不带通知值并且不保留接收任务的通知值,此函数会将接收任务的通知值加一,用于任务中。
vTaskNotifyGiveFromISR() 发送通知,函数 xTaskNotifyGive()的中断版本。
xTaskNotifyAndQuery()
发送通知,带有通知值并且保留接收任务的原通知值,用在任务中。
xTaskNotiryAndQueryFromISR()
发送通知,函数 xTaskNotifyAndQuery()的中断版本,用在中断服务函数中
1、函数 xTaskNotify()
函数原型
BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify,
uint32_t ulValue,
eNotifyAction eAction )
参数: xTaskToNotify: 任务句柄,指定任务通知是发送给哪个任务的。 ulValue: 任务通知值。 eAction: 任务通知更新的方法,eNotifyAction 是个枚举类型 返回值: pdFAIL: 当参数 eAction 设置为 eSetValueWithoutOverwrite 的时候,如果任务通知值没有更新成功就返回 pdFAIL。 pdPASS: eAction 设置为其他选项的时候统一返回 pdPASS。
向指定任务发送指定的通知值。如果打算使用RTOS任务通知实现轻量级的二进制或计数信号量,推荐使用API函数xTaskNotifyGive()来代替本函数。
2、函数 xTaskNotifyFromISR()
发送任务通知,是函数 xTaskNotify()的中断版本
BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify,
uint32_t ulValue,
eNotifyAction eAction,
BaseType_t * pxHigherPriorityTaskWoken );
参数: xTaskToNotify: 任务句柄,指定任务通知是发送给哪个任务的。 ulValue: 任务通知值。 eAction: 任务通知更新的方法。 pxHigherPriorityTaskWoken: 记退出此函数以后是否进行任务切换,这个变量的值函数会自动设置的,用户不用进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为 pdTRUE 的时候在退出中断服务函数之前一定要进行一次任务切换。
返回值: pdFAIL: 当参数 eAction 设置为 eSetValueWithoutOverwrite 的时候,如果任务通知值没有 更新成功就返回 pdFAIL。 pdPASS: eAction 设置为其他选项的时候统一返回 pdPASS。
3、函数 xTaskNotifyGive()
发送任务通知,相对于函数 xTaskNotify(),此函数发送任务通知的时候不带有通知值。此 函数只是将任务通知值简单的加一
BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify );
参数: xTaskToNotify: 任务句柄,指定任务通知是发送给哪个任务的。 返回值: pdPASS: 此函数只会返回 pdPASS。 4、函数 vTaskNotifyGiveFromISR() 此函数为 xTaskNotifyGive()的中断版本,用在中断服务函数中,函数原型如下:
void vTaskNotifyGiveFromISR( TaskHandle_t xTaskHandle,
BaseType_t * pxHigherPriorityTaskWoken );
参数: xTaskToNotify: 任务句柄,指定任务通知是发送给哪个任务的。 pxHigherPriorityTaskWoken: 记退出此函数以后是否进行任务切换,这个变量的值函数会自动设置的,用户不用进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为 pdTRUE 的时候在退出中断服务函数之前一定要进行一次任务切换。
4、函数 vTaskNotifyGiveFromISR()
此函数为 xTaskNotifyGive()的中断版本
void vTaskNotifyGiveFromISR( TaskHandle_t xTaskHandle,
BaseType_t * pxHigherPriorityTaskWoken );
参数: xTaskToNotify: 任务句柄,指定任务通知是发送给哪个任务的。 pxHigherPriorityTaskWoken: 记退出此函数以后是否进行任务切换,这个变量的值函数会自动设置的,用户不用进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为 pdTRUE 的时候在退出中断服务函数之前一定要进行一次任务切换。
5、函数 xTaskNotifyAndQuery()
此函数和 xTaskNotify()很类似,此函数比 xTaskNotify()多一个参数,此参数用来保存更新 前的通知值。
BaseType_t xTaskNotifyAndQuery ( TaskHandle_t xTaskToNotify,
uint32_t ulValue,
eNotifyAction eAction
uint32_t * pulPreviousNotificationValue);
参数: xTaskToNotify: 任务句柄,指定任务通知是发送给哪个任务的 ulValue: 任务通知值。 eAction: 任务通知更新的方法。 pulPreviousNotificationValue:用来保存更新前的任务通知值。 返回值: pdFAIL: 当参数 eAction 设置为 eSetValueWithoutOverwrite 的时候,如果任务通知值没有更新成功就返回 pdFAIL。 pdPASS: eAction 设置为其他选项的时候统一返回 pdPASS
6、函数 xTaskNotifyAndQueryFromISR()
此函数为 xTaskNorityAndQuery()的中断版本
BaseType_t xTaskNotifyAndQueryFromISR ( TaskHandle_t xTaskToNotify,
uint32_t ulValue,
eNotifyAction eAction,
uint32_t * pulPreviousNotificationValue
BaseType_t * pxHigherPriorityTaskWoken );
参数: xTaskToNotify: 任务句柄,指定任务通知是发送给哪个任务的。 ulValue: 任务通知值。 eAction: 任务通知更新的方法。 pulPreviousNotificationValue:用来保存更新前的任务通知值。 pxHigherPriorityTaskWoken: 记退出此函数以后是否进行任务切换,这个变量的值函数会自动设置的,用户不用进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为 pdTRUE 的时候在退出中断服务函数之前一定要进行一次任务切换。 返回值: pdFAIL: 当参数 eAction 设置为 eSetValueWithoutOverwrite 的时候,如果任务通知值没有更新成功就返回 pdFAIL。 pdPASS: eAction 设置为其他选项的时候统一返回 pdPASS。
2.获取任务通知
ulTaskNotifyTake()
获取任务通知,可以设置在退出此函数的时候将任务通知值清零或者减一。当任务通知用作二值信号量或者计数信号量的时候使用此函数来获取信号量。
xTaskNotifyWait()
等待任务通知,比 ulTaskNotifyTak()更为强大,全功能版任务通知获取函数。
1、函数 ulTaskNotifyTake()
此函数为获取任务通知函数,当任务通知用作二值信号量或者计数型信号量的时候可以使 用此函数来获取信号量
uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit,
TickType_t xTicksToWait );
参数: xClearCountOnExit: 参数为 pdFALSE 的话在退出函数 ulTaskNotifyTake()的时候任务通知值减一,类似计数型信号量。当此参数为 pdTRUE 的话在退出函数的时候任务任务通知值清零,类似二值信号量。
xTickToWait: 阻塞时间。
2、函数 xTaskNotifyWait()
此函数也是用来获取任务通知的,不过此函数比 ulTaskNotifyTake()更为强大,不管任务通知用作二值信号量、计数型信号量、队列和事件标志组中的哪一种,都可以使用此函数来获取任务通知。但是当任务通知用作位置信号量和计数型信号量的时候推荐使用函数ulTaskNotifyTake()。
BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry,
uint32_t ulBitsToClearOnExit,
uint32_t * pulNotificationValue,
TickType_t xTicksToWait );
参数: ulBitsToClearOnEntry:当没有接收到任务通知的时候将任务通知值与此参数的取反值进行按位与运算,当此参数为 0xffffffff 或者 ULONG_MAX 的时候就会将任务通知值清零。 ulBitsToClearOnExit:如果接收到了任务通知,在做完相应的处理退出函数之前将任务通知值与此参数的取反值进行按位与运算,当此参数为 0xffffffff 或者ULONG_MAX 的时候就会将任务通知值清零。 pulNotificationValue:此参数用来保存任务通知值。 xTickToWait: 阻塞时间 返回值: pdTRUE: 获取到了任务通知。 pdFALSE: 任务通知获取失败。
3.任务通知模拟二值信号量实验
(1)、调用函数 vTaskNotifyGiveFromISR()向任务 DataProcess_task 发送任务通知,此处取代 的是二值信号量发送函数。 使用任务通知替代二值信号量的过程还是非常简单的,只需要替换掉几个API函数。
4、任务通知模拟计数型信号量实验
计数型信号量通常用于资源管理和事件计数,在使用资源管理时不可用任务通知,只能用计数型信号量,在事件计数时,可以使用任务通知 (1)、调用函数 xTaskNotify()发送任务通知,任务通知值为按键值,发送方式采用覆写的方式。 (2)、调用函数 xTaskNotifyWait()获取任务通知,获取到的任务通知其实就是(1)中发送的按键值,然后根据不同的按键值做不同的处理。
总结
任务通知很简单,就是将原有的信号量通知函数变成任务通知函数,注意计数型信号量用于资源管理时不可以使用任务通知。
|