注:本文介绍任务通知的基础知识,具体源代码分析见《FreeRTOS高级篇8---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函数描写叙述

         BaseType_t xTaskNotify( TaskHandle_txTaskToNotify,
uint32_t ulValue,
eNotifyAction eAction);

向指定任务发送指定的通知值。假设打算使用RTOS任务通知实现轻量级的二进制或计数信号量,推荐使用API函数xTaskNotifyGive()来取代本函数。

此函数不能够在中断服务例程中调用,中断保护等价函数为xTaskNotifyFromISR()。

1.2參数描写叙述

  • xTaskToNotify:被通知的任务句柄。
  • ulValue:通知更新值
  • eAction:枚举类型,指明更新通知值的方法

枚举变量成员以及作用例如以下表所看到的。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />

1.3返回值

參数eAction为eSetValueWithoutOverwrite时,假设被通知任务还没取走上一个通知。又接收到了一个通知,则这次通知值未能更新并返回pdFALSE,否则返回pdPASS。

2.发送通知-方法2

2.1函数描写叙述

BaseType_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( BaseType_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 )
{
BaseType_txHigherPriorityTaskWoken; prvClearInterruptSource(); /* xHigherPriorityTaskWoken必须被初始化为pdFALSE。假设调用vTaskNotifyGiveFromISR()会解除vHandlingTask任务的堵塞状态,而且vHandlingTask任务的优先级高于当前处于执行状态的任务,则xHigherPriorityTaskWoken将会自己主动被设置为pdTRUE。*/
xHigherPriorityTaskWoken = pdFALSE; /*向一个任务发送通知,xHandlingTask是该任务的句柄。 */
vTaskNotifyGiveFromISR( xHandlingTask,&xHigherPriorityTaskWoken ); /* 假设xHigherPriorityTaskWoken为pdTRUE。则强制上下文切换。这个宏的实现取决于移植层。可能会调用portEND_SWITCHING_ISR */
portYIELD_FROM_ISR(xHigherPriorityTaskWoken );
}
/*---------------------------------------------------------------------------------------------------*/ /* 一个由于等待通知而堵塞的任务。 */
voidvHandlingTask( void *pvParameters )
{
BaseType_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函数描写叙述

         BaseType_t xTaskNotifyWait( uint32_tulBitsToClearOnEntry,
uint32_tulBitsToClearOnExit,
uint32_t*pulNotificationValue,
TickType_txTicksToWait );

假设打算使用RTOS任务通知实现轻量级的二进制或计数信号量,推荐使用API函数ulTaskNotifyTake()来取代本函数。

4.2參数描写叙述

  • ulBitsToClearOnEntry:在使用通知之前。先将任务的通知值与參数ulBitsToClearOnEntry的按位取反值按位与操作。

    设置參数ulBitsToClearOnEntry为0xFFFFFFFF(ULONG_MAX),表示清零任务通知值。

  • ulBitsToClearOnExit:在函数xTaskNotifyWait()退出前,将任务的通知值与參数ulBitsToClearOnExit的按位取反值按位与操作。

    设置參数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表示使用通知前不清除任务的通知值位,參数ULONG_MAX 表示函数xTaskNotifyWait()退出前将任务通知值设置为0*/
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函数描写叙述

         BaseType_t xTaskNotifyAndQuery(TaskHandle_t xTaskToNotify,
uint32_tulValue,
eNotifyActioneAction,
uint32_t*pulPreviousNotifyValue );

此函数与任务通知API函数xTaskNotify()很像。仅仅只是此函数具有一个附加參数,用来回传任务当前的通知值,然后依据參数ulValue和eAction更新任务的通知值。

此函数不能在中断服务例程中使用,在中断服务例程中使用xTaskNotifyAndQueryFromISR()函数。

5.2參数描写叙述

  • xTaskToNotify:被通知的任务句柄。

  • ulValue:通知更新值
  • eAction:枚举类型,指明更新通知值的方法,枚举变量成员以及作用见xTaskNotify()一节。

  • pulPreviousNotifyValue:回传未被更新的任务通知值。

    假设不须要回传未被更新的任务通知值,这里设置为NULL,这样就等价于调用xTaskNotify()函数。

5.3返回值

參数eAction为eSetValueWithoutOverwrite时。假设被通知任务还没取走上一个通知。又接收到了一个通知,则这次通知值未能更新并返回pdFALSE,否则返回pdPASS。

FreeRTOS系列第14篇---FreeRTOS任务通知的更多相关文章

  1. FreeRTOS系列第2篇---FreeRTOS入门指南【转】

    转自:http://blog.csdn.net/zhzht19861011/article/details/49819309 版权声明:本文为博主原创文章,未经博主允许不得转载.联系邮箱:zhzhch ...

  2. FreeRTOS系列第17篇---FreeRTOS队列

    本文介绍队列的基本知识,具体源代码分析见<FreeRTOS高级篇5---FreeRTOS队列分析> 1.FreeRTOS队列 队列是基本的任务间通讯方式.能够在任务与任务间.中断和任务间传 ...

  3. FreeRTOS系列第20篇---FreeRTOS信号量API函数

    FreeRTOS的信号量包括二进制信号量.计数信号量.相互排斥信号量(以后简称相互排斥量)和递归相互排斥信号量(以后简称递归相互排斥量).我们能够把相互排斥量和递归相互排斥量看成特殊的信号量. 信号量 ...

  4. FreeRTOS系列第13篇---FreeRTOS内核控制

    内核控制的一些功能须要移植层提供,为了方便移植.这些API函数用宏来实现,比方上下文切换.进入和退出临界区.禁止和使能可屏蔽中断.内核控制函数还包含启动和停止调度器.挂起和恢复调度器以及用于低功耗模式 ...

  5. Mysql高手系列 - 第14篇:详解事务

    这是Mysql系列第14篇. 环境:mysql5.7.25,cmd命令中进行演示. 开发过程中,会经常用到数据库事务,所以本章非常重要. 本篇内容 什么是事务,它有什么用? 事务的几个特性 事务常见操 ...

  6. spring 5.x 系列第14篇 —— 整合RabbitMQ (代码配置方式)

    源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all 一.说明 1.1 项目结构说明 本用例关于rabbitmq的整合提供简单消 ...

  7. java高并发系列 - 第14天:JUC中的LockSupport工具类,必备技能

    这是java高并发系列第14篇文章. 本文主要内容: 讲解3种让线程等待和唤醒的方法,每种方法配合具体的示例 介绍LockSupport主要用法 对比3种方式,了解他们之间的区别 LockSuppor ...

  8. ABP(现代ASP.NET样板开发框架)系列之14、ABP领域层——领域事件(Domain events)

    点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之14.ABP领域层——领域事件(Domain events) ABP是“ASP.NET Boilerplate P ...

  9. 一步一步学Silverlight 2系列(14):数据与通信之WCF

    一步一步学Silverlight 2系列(14):数据与通信之WCF   概述 Silverlight 2 Beta 1版本发布了,无论从Runtime还是Tools都给我们带来了很多的惊喜,如支持框 ...

随机推荐

  1. mysql group_concat函数详解

    group_concat( [DISTINCT]  要连接的字段   [Order BY 排序字段 ASC/DESC]   [Separator '分隔符'] ) 1. --以id分组,把price字 ...

  2. tensorflow ConfigProto

    tf.ConfigProto一般用在创建session的时候.用来对session进行参数配置 with tf.Session(config = tf.ConfigProto(...),...)#tf ...

  3. python Matplotlib 系列教程(三)——绘制直方图和条形图

    在本章节我们将学习如何绘制条形图和直方图 条形图与直方图的区别:首先,条形图是用条形的长度表示各类别频数的多少,其宽度(表示类别)则是固定的: 直方图是用面积表示各组频数的多少,矩形的高度表示每一组的 ...

  4. JavaScript之作用域和闭包

    一.作用域 作用域共有两种主要的工作模型:第一种是最为普遍的,被大多数编程语言所采用的词法作用域,另外一种叫作动态作用域: JavaScript所采用的作用域模式是词法作用域. 1.词法作用域 词法作 ...

  5. mysql 替换数据库字段内容

    去掉数据库字段单引号 update company_info set company=REPLACE(company,"'","");

  6. npm 发包

    前几天封装了公用的locaStorage组件,当然封装后需要发布npm官网,于是摸索了一番终于搞定了,总结下来希望对大家有所帮助 npm安装的package一般支持下面几大类: 本地包 url远程包 ...

  7. Quartz.Net 学习之路01 安装Quartz.Net

    Quartz.Net 系列文章的第一篇,至于Quartz.Net 是做什么的我就不介绍了,相信要用到它的都知道它是用来干嘛的: Quartz.Net安装方法: 1.打开项目,在VS“工具”菜单选中“库 ...

  8. 华中农业大学第四届程序设计大赛网络同步赛-1020: Arithmetic Sequence,题挺好的,考思路;

    1020: Arithmetic Sequence Time Limit: 1 Sec  Memory Limit: 128 MB Submit:  ->打开链接<- Descriptio ...

  9. hdu 1179最大匹配

    #include<stdio.h> #include<string.h> #define N 200 int map[N][N],visit[N],link[N],n,m; i ...

  10. POJ 3680_Intervals

    题意: 给定区间和该区间对应的权值,挑选一些区间,求使得每个数都不被K个区间覆盖的最大权值和. 分析: 如果K=1,即为区间图的最大权独立集问题.可以对区间所有端点排序后利用动态规划的方法,设dp[i ...