FreeRTOS系列第14篇---FreeRTOS任务通知

更新时间:2023-07-01 19:47:33 阅读: 评论:0

FreeRTOS系列第14篇---FreeRTOS任务通知
注:本⽂介绍任务通知的基础知识,详细源码分析见《》
每个RTOS任务都有⼀个32位的通知值,任务创建时,这个值被初始化为0。RTOS任务通知相当于直接向任务发送⼀个事件,接收到通知的任务可以解除阻塞状态,前提是这个阻塞事件是因等待通知⽽引起的。发送通知的同时,也可以可选的改变接收任务的通知值。
可以通过下列⽅法向接收任务更新通知:
不覆盖接收任务的通知值
覆盖接收任务的通知值
设置接收任务通知值的某些位
增加接收任务的通知值
相对于⽤前必须分别创建队列、⼆进制信号量、计数信号量或事件组的情况,使⽤任务通知显然更灵活。更好的是,相⽐于使⽤信号量解除任务阻塞,使⽤任务通知可以快45%、使⽤更少的RAM(使⽤GCC编译器,-o2优化级别)。
使⽤API函数xTaskNotify()和xTaskNotifyGive()(中断保护等价函数为xTaskNotifyFromISR()和vTaskNotifyGiveFromISR())发送通知,在接收RTOS任务调⽤API函数xTaskNotifyWait()或ulTaskNotifyTake()之前,这个通知都被保持着。如果接收RTOS任务已经因为等待通知⽽进⼊阻塞状态,则接收到通知后任务解除阻塞并清除通知。
穿越星空RTOS任务通知功能默认是使能的,可以通过在⽂件FreeRTOSConfig.h中设置宏configUSE_TASK_NOTIFICATIONS为0来禁⽌这个功能,禁⽌后每个任务节省8字节内存。
虽然RTOS任务通知速度更快并且占⽤内存更少,但它也有⼀些限制:
1. 只能有⼀个任务接收通知事件。
2. 接收通知的任务可以因为等待通知⽽进⼊阻塞状态,但是发送通知的任务即便不能⽴即完成通知发送也不能进⼊阻塞状态。
1.发送通知-⽅法1
1.1函数描述
BaType_t xTaskNotify( TaskHandle_txTaskToNotify,
uint32_t ulValue,
eNotifyAction eAction);
向指定任务发送指定的通知值。如果打算使⽤RTOS任务通知实现轻量级的⼆进制或计数信号量,推荐使⽤API函数xTaskNotifyGive()来代替本函数。
此函数不可以在中断服务例程中调⽤,中断保护等价函数为xTaskNotifyFromISR()。
1.2参数描述
xTaskToNotify:被通知的任务句柄。
ulValue:通知更新值
eAction:枚举类型,指明更新通知值的⽅法
枚举变量成员以及作⽤如下表所⽰。
1.3返回值
eAction为eSetValueWithoutOverwrite时,如果被通知任务还没取⾛上⼀个通知,⼜接收到了⼀个通知,则这次通知值未能更新并返回pdFALSE,否则返回pdPASS。
2.发送通知-⽅法2
2.1函数描述
BaType_t xTaskNotifyGive(TaskHandle_t xTaskToNotify );
其实这是⼀个宏,本质上相当于xTaskNotify( ( xTaskToNotify ), ( 0 ), eIncrement )。可以使⽤该API函数代替⼆进制或计数信号量,但速度更快。在这种情况下,应该使⽤API函数ulTaskNotifyTake()来等待通知,⽽不应该使⽤API函数xTaskNotifyWait()。
此函数不可以在中断服务例程中调⽤,中断保护等价函数为vTaskNotifyGiveFromISR()。
2.2参数描述
xTaskToNotify:被通知的任务句柄。
2.3⽤法举例
staticvoid prvTask1( void *pvParameters );
staticvoid prvTask2( void *pvParameters );
/* 保存任务句柄 */
staticTaskHandle_t xTask1 = NULL, xTask2 = NULL;
/* 创建两个任务,它们之间反复发送通知,启动RTOS调度器*/
voidmain( void )
{
xTaskCreate( prvTask1, "Task1",200, NULL, tskIDLE_PRIORITY, &xTask1 );
xTaskCreate( prvTask2, "Task2",200, NULL, tskIDLE_PRIORITY, &xTask2 );
vTaskStartScheduler();
}
/*-----------------------------------------------------------*/
staticvoid prvTask1( void *pvParameters )
{
for( ;; )
{
/*向prvTask2(),发送通知,使其解除阻塞状态 */
xTaskNotifyGive( xTask2 );
/* 等待prvTask2()的通知,进⼊阻塞 */
ulTaskNotifyTake( pdTRUE, portMAX_DELAY);
}
}
/*-----------------------------------------------------------*/
staticvoid prvTask2( void *pvParameters )
{
for( ;; )
{
/* 等待prvTask1()的通知,进⼊阻塞 */
ulTaskNotifyTake( pdTRUE, portMAX_DELAY);
/*向prvTask1(),发送通知,使其解除阻塞状态 */
xTaskNotifyGive( xTask1 );
}
}
3.获取通知
3.1函数描述
uint32_t ulTaskNotifyTake( BaType_txClearCountOnExit,
TickType_txTicksToWait );
ulTaskNotifyTake()是专门为使⽤更轻量级更快的⽅法来代替⼆进制或计数信号量⽽量⾝打造的。FreeRTOS获取信号量的API函数为xSemaphoreTake(),可以使⽤ulTaskNotifyTake()函数等价代替。
当⼀个任务使⽤通知值来实现⼆进制或计数信号量时,其它任务或者中断要使⽤API函数xTaskNotifyGive()或者使⽤参数eAction
小学一年级故事>乡村旅游项目
为eIncrement的API函数xTaskNotify()。推荐使⽤xTaskNotifyGive()函数(其实是个宏,我们这⾥把它看作⼀个API函数)。另外需要注意的是,如果在中断中使⽤,要使⽤它们的中断保护等价函数:vTaskNotifyGiveFromISR()和xTaskNotifyFromISR()。
API函数xTaskNotifyTake()有两种⽅法处理任务的通知值,⼀种⽅法是在函数退出时将通知值清零,这种⽅法适⽤于实现⼆进制信号量;另外⼀种⽅法是在函数退出时将通知值减1,这种⽅法适⽤于实现计数信号量。
如果RTOS任务的通知值为0,使⽤xTaskNotifyTake()可以可选的使任务进⼊阻塞状态,直到该任务的通知值不为0。进⼊阻塞的任务不消耗CPU时间。
植树节看图写话二年级3.2参数描述
xClearCountOnExit:如果该参数设置为pdFALSE,则API函数xTaskNotifyTake()退出前,将任务的通
知值减1;如果该参数设置为
pdTRUE,则API函数xTaskNotifyTake()退出前,将任务通知值清零。
xTicksToWait:因等待通知⽽进⼊阻塞状态的最⼤时间。时间单位为系统节拍周期。宏pdMS_TO_TICKS⽤于将指定的毫秒时间转化为相应的系统节拍数。
3.3返回值
返回任务的当前通知值,为0或者为调⽤API函数xTaskNotifyTake()之前的通知值减1。
3.4⽤法举例
/* 中断处理程序。*/
voidvANInterruptHandler( void )
{
BaType_txHigherPriorityTaskWoken;
prvClearInterruptSource();
/* xHigherPriorityTaskWoken必须被初始化为pdFALSE。如果调⽤vTaskNotifyGiveFromISR()会解除vHandlingTask任务的阻塞状态,并且vHandlingTask任务的优    xHigherPriorityTaskWoken = pdFALSE;
/*向⼀个任务发送通知,xHandlingTask是该任务的句柄。*/
vTaskNotifyGiveFromISR( xHandlingTask,&xHigherPriorityTaskWoken );
/* 如果xHigherPriorityTaskWoken为pdTRUE,则强制上下⽂切换。这个宏的实现取决于移植层,可能会调⽤portEND_SWITCHING_ISR */
portYIELD_FROM_ISR(xHigherPriorityTaskWoken );
}
/*---------------------------------------------------------------------------------------------------*/
/* ⼀个因为等待通知⽽阻塞的任务。*/
voidvHandlingTask( void *pvParameters )
{
BaType_txEvent;
for( ;; )
{
/*等待通知,⽆限期阻塞。参数pdTRUE表⽰函数退出前会清零通知值。这显然是⽤于替代⼆进制信号量的⽤法。需要注意的是,真实的程序⼀般不会⽆限期阻塞        ulTaskNotifyTake( pdTRUE, portMAX_DELAY);
/* 当处理完所有事件后,仍然等待下⼀个通知*/
do
{
xEvent = xQueryPeripheral();
if( xEvent != NO_MORE_EVENTS )
{
vProcessPeripheralEvent( xEvent);
}
} while( xEvent != NO_MORE_EVENTS );
}
}
4.等待通知
4.1函数描述
BaType_t xTaskNotifyWait( uint32_tulBitsToClearOnEntry,
uint32_tulBitsToClearOnExit,
uint32_t*pulNotificationValue,
TickType_txTicksToWait );
如果打算使⽤RTOS任务通知实现轻量级的⼆进制或计数信号量,推荐使⽤API函数ulTaskNotifyTake()来代替本函数。
4.2参数描述
ulBitsToClearOnEntry:在使⽤通知之前,先将任务的通知值与参数ulBitsToClearOnEntry的按位取反值按位与操作。设置参数
ulBitsToClearOnEntry为0xFFFFFFFF(ULONG_MAX),表⽰清零任务通知值。
ulBitsToClearOnExit:在函数xTaskNotifyWait()退出前,将任务的通知值与参数ulBitsToClearOn的按位取反值按位与操作。设置参数
历史词
ulBitsToClearOnExit为0xFFFFFFFF(ULONG_MAX),表⽰清零任务通知值。异想天开意思
pulNotificationValue:⽤于向外回传任务的通知值。这个通知值在参数ulBitsToClearOnExit起作⽤前将通知值拷贝到
*pulNotificationValue中。如果不需要返回任务的通知值,这⾥设置成NULL。
xTicksToWait:因等待通知⽽进⼊阻塞状态的最⼤时间。时间单位为系统节拍周期。宏pdMS_TO_TICKS⽤于将指定的毫秒时间转化为相应的系统节拍数。
4.3返回值
如果接收到通知,返回pdTRUE,如果API函数xTaskNotifyWait()等待超时,返回pdFALSE。
4.4⽤法举例
/*这个任务使⽤任务通知值的位来传递不同的事件,这在某些情况下可以代替事件组。*/
voidvAnEventProcessingTask( void *pvParameters )
{
uint32_tulNotifiedValue;
for( ;; )
{分解的英文
/
*等待通知,⽆限期阻塞(没有超时,所以不⽤检查函数返回值)。其它任务或者中断设置的通知值中的不同位表⽰不同的事件。参数0x00表⽰使⽤通知前不清除        xTaskNotifyWait( 0x00, ULONG_MAX,&ulNotifiedValue, portMAX_DELAY );
/*根据通知值处理事件*/
if( ( ulNotifiedValue & 0x01 ) != 0)
{
prvProcessBit0Event();
}
if( ( ulNotifiedValue & 0x02 ) != 0)
{
国外汇款prvProcessBit1Event();
}
if( ( ulNotifiedValue & 0x04 ) != 0)
{
prvProcessBit2Event();
}
/* ……*/
}
}
5.任务通知并查询
5.1函数描述

本文发布于:2023-07-01 19:47:33,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/82/1072740.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:通知   任务   函数   接收
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图