嵌入式实时操作系统为任务交互提供了通用的队列和信号量机制,FreeRTOS也不例外。新接触FreeRTOS的开发人员通常会选择这两种熟悉的机制实现应用。但在大多数应用场景中,我们可以使用FreeRTOS的直接任务通知实现更高效的交互,与信号量相比,通知机制内存占用更小,速度可提高45%。架构良好的FreeRTOS应用程序很少需要使用信号量。我们了解一下如何使用直接任务通知代替信号量来创建更小更快的应用程序。
背景
FreeRTOS仅提供了队列原语,在V1.2.0版本中,FreeRTOS将信号量API 实现为一组调用队列API的宏,引入了信号量功能。这种设计在不增加代码大小的情况下,添加了信号量功能,但导致信号量继承了队列的所有功能。例如,队列包括事件机制和等待发送到队列和从队列接收数据的任务优先级列表。一些信号量应用受益于这些功能,但常见的信号量场景并不需要如此复杂的实现机制。因此,在为驱动程序库寻找一个精简的事件机制时,FreeRTOS提供了新的原语 - 直接任务通知。
直接任务通知
大多数任务间的通信是通过中间对象实现,例如队列、信号量或事件组。发送任务将信息写入通信对象,接收任务从对象中读取信息。当使用直接任务通知时,顾名思义,发送任务可以直接向接收任务发送一个通知,无需中间对象。
FreeRTOS从V8.20开始增加了通知功能,每个任务包含一个通知。从FreeRTOS V10.4.0开始,更新为每个任务提供一组通知。每个通知包含一个32位值和一个状态,它们只消耗5个字节的RAM。
如同任务可以阻塞在二进制信号量上,以等待该信号量可用,任务可以阻塞在通知,以等待该通知的状态变为pending。同样,正如任务可以阻塞在计数信号量上,以等待该信号量的计数值为非零,任务可以阻塞通知,以等待通知值为非零。
通知不仅可以传达事件,还可以通过多种方式传达数据。我们通过两个例子演示一下通知的使用。
1、使用通知同步中断与任务
任务等待通知值不为0。代码清单1显示了等待通知的任务的结构。任务可以通过调用xSemaphoreTake() API 函数阻塞在信号量上,如果使用通知,任务将调用ulTaskNotifyTake() API。ulTaskNotifyTake() 将使用索引0的通知。使用ulTaskNotifyTakeIndexed()代替ulTaskNotifyTake(),可使用指定数组索引的通知。
代码清单1
代码清单2显示了发送通知的中断实现。
代码清单2
2、使用通知从ISR发送数据到任务
通过通知发送32位值,相对于队列机制,发送数据的额外开销最小。代码清单3展示了返回模数 (ADC)转换结果的函数的结构。任务阻塞等待转换结果,阻塞期间不消耗任何CPU周期。转换结果通过转换结束中断服务程序(ISR) 发送给任务。该应用场景需要使用稍微复杂的xTaskNotify()和xTaskNotifyWait() API函数。xTaskNotify()和xTaskNotifyWait()默认对通知数组索引0的通知进行操作。可以使用xTaskNotifyIndexed()和xTaskNotifyWaitIndexed()对数组中的指定索引进行操作。
代码清单3
代码清单4显示了中断服务例程的结构,该例程使用通知将转换结果发送给等待的任务。
代码清单4
标准的FreeRTOS机制可用于涵盖所有应用,但在大多数应用程序中,无需使用队列和信号量。FreeRTOS增加的可选功能,包括直接任务通知、消息缓冲区(message buffer)和流缓冲区(stream buffer)机制,可以满足许多应用场景需求,相比标准的RTOS机制,这些定制功能更小更快。
引用: ddllxxrr 发表于 2022-4-14 16:28 我不用什么信号量,只用全局变量,每个进程只读取本进程的变量这样行不????
信号量可以睡眠呀,全局变量你得不断的轮询。
引用: lugl4313820 发表于 2022-4-14 16:22 普及FreeRTOS的知识,能让传统的祼机跑任务系统,是成熟开发者的标志呀。期待后续精彩作品哦!
感谢关注和夸奖哦~~
FreeRTOS,smart OS!