FreeRTOS 消息队列

本章节为大家讲解 FreeRTOS 的一个重要的通信机制----消息队列,初学者要熟练掌握,因为消息队
列在实际项目中应用较多。

消息队列的概念及其作用
消息队列就是通过 RTOS 内核提供的服务,任务或中断服务子程序可以将一个消息(注意,FreeRTOS
消息队列传递的是实际数据,并不是数据地址,RTX,uCOS-II 和 uCOS-III 是传递的地址)放入到队列。
同样,一个或者多个任务可以通过 RTOS 内核服务从队列中得到消息。通常,先进入消息队列的消息先传
给任务,也就是说,任务先得到的是最先进入到消息队列的消息,即先进先出的原则(FIFO),FreeRTOS
的消息队列支持 FIFO 和 LIFO 两种数据存取方式。
也许有不理解的初学者会问采用消息队列多麻烦,搞个全局数组不是更简单,其实不然。在裸机编程
时,使用全局数组的确比较方便,但是在加上 RTOS 后就是另一种情况了。 相比消息队列,使用全局数组
主要有如下四个问题:

? 使用消息队列可以让 RTOS 内核有效地管理任务,而全局数组是无法做到的,任务的超时等机制需要用户自己去实现。
? 使用了全局数组就要防止多任务的访问冲突,而使用消息队列则处理好了这个问题,用户无需担心。
? 使用消息队列可以有效地解决中断服务程序与任务之间消息传递的问题。
? FIFO 机制更有利于数据的处理。

FreeRTOS 任务间消息队列的实现
任务间消息队列的实现是指各个任务之间使用消息队列实现任务间的通信。 下面我们通过如下的框图
来说明一下 FreeRTOS 消息队列的实现,让大家有一个形象的认识。

运行条件:
? 创建消息队列,可以存放 10 个消息。
? 创建 2 个任务 Task1 和 Task2,任务 Task1 向消息队列放数据,任务 Task2 从消息队列取数据。
? FreeRTOS 的消息存取采用 FIFO 方式。
运行过程主要有以下两种情况:
? 任务 Task1 向消息队列放数据,任务 Task2 从消息队列取数据,如果放数据的速度快于取数据的速
度,那么会出现消息队列存放满的情况,FreeRTOS 的消息存放函数 xQueueSend 支持超时等待,
用户可以设置超时等待,直到有空间可以存放消息或者设置的超时时间溢出。
? 任务 Task1 向消息队列放数据,任务 Task2 从消息队列取数据,如果放数据的速度慢于取数据的速
度,那么会出现消息队列为空的情况,FreeRTOS 的消息获取函数 xQueueReceive 支持超时等待,
用户可以设置超时等待,直到消息队列中有消息或者设置的超时时间溢出。

FreeRTOS 中断方式消息队列的实现
FreeRTOS 中断方式消息队列的实现是指中断函数和 FreeRTOS 任务之间使用消息队列。 下面我们通
过如下的框图来说明一下 FreeRTOS 消息队列的实现,让大家有一个形象的认识。

运行条件:
? 创建消息队列,可以存放 10 个消息。

? 创建 1 个任务 Task1 和一个串口接收中断。
? FreeRTOS 的消息存取采用 FIFO 方式。
运行过程主要有以下两种情况:
? 中断服务程序向消息队列放数据,任务 Task1 从消息队列取数据,如果放数据的速度快于取数据的速
度,那么会出现消息队列存放满的情况。由于中断服务程序里面的消息队列发送函数
xQueueSendFromISR 不支持超时设置,所以发送前要通过函数 xQueueIsQueueFullFromISR 检测
消息队列是否满。
? 中断服务程序向消息队列放数据,任务 Task1 从消息队列取数据,如果放数据的速度慢于取数据的速
度,那么会出现消息队列存为空的情况。在 FreeRTOS 的任务中可以通过函数 xQueueReceive 获取
消息,因为此函数可以设置超时等待,直到消息队列中有消息存放或者设置的超时时间溢出。

上面就是一个简单的 FreeRTOS 中断方式消息队列通信过程。 实际应用中,中断方式的消息机制要注意以
下四个问题:
? 中断函数的执行时间越短越好,防止其它低于这个中断优先级的异常不能得到及时响应。
? 实际应用中,建议不要在中断中实现消息处理,用户可以在中断服务程序里面发送消息通知任务,在
任务中实现消息处理,这样可以有效地保证中断服务程序的实时响应。同时此任务也需要设置为高优
先级,以便退出中断函数后任务可以得到及时执行。
? 中断服务程序中一定要调用专用于中断的消息队列函数,即以 FromISR 结尾的函数。
? 在操作系统中实现中断服务程序与裸机编程的区别。
? 如果 FreeRTOS 工程的中断函数中没有调用 FreeRTOS 的消息队列 API 函数,与裸机编程是一
样的。
? 如果 FreeRTOS 工程的中断函数中调用了 FreeRTOS 的消息队列的 API 函数,退出的时候要检
测是否有高优先级任务就绪,如果有就绪的,需要在退出中断后进行任务切换,这点与裸机编程
稍有区别,详见 20.4 小节实验例程说明(中断方式):
? 另外强烈推荐用户将 Cortex-M3 内核的 STM32F103 和 Cortex-M4 内核的 STM32F407, F429
的 NVIC 优先级分组设置为 4,即:NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);这样中
断优先级的管理将非常方便。
? 用户要在 FreeRTOS 多任务开启前就设置好优先级分组,一旦设置好切记不可再修改。

消息队列 API 函数
使用如下 23 个函数可以实现 FreeRTOS 的消息队列:
? xQueueCreateStatic()
? vQueueDelete()
? xQueueSend()

? xQueueSendFromISR()
? xQueueSendToBack()
? xQueueSendToBackFromISR()
? xQueueSendToFront()
? xQueueSendToFrontFromISR()
? xQueueReceive()
? xQueueReceiveFromISR()
? uxQueueMessagesWaiting()
? uxQueueMessagesWaitingFromISR()
? uxQueueSpacesAvailable()
? xQueueReset()
? xQueueOverwrite()
? xQueueOverwriteFromISR()
? xQueuePeek()
? xQueuePeekFromISR()
? vQueueAddToRegistry()
? vQueueUnregisterQueue()
? pcQueueGetName()
? xQueueIsQueueFullFromISR()
? xQueueIsQueueEmptyFromISR()
关于这 23 个函数的讲解及其使用方法可以看 FreeRTOS 在线版手册 。

这里我们重点的说以下 4 个函数:
? xQueueCreate ()
? xQueueSend ()
? xQueueSendFromISR ()
? xQueueReceive ()
因为本章节配套的例子使用的是这 4 个函数。

函数 xQueueCreate

函数描述:
函数 xQueueCreate 用于创建消息队列。
? 第 1 个参数是消息队列支持的消息个数。

? 第 2 个参数是每个消息的大小,单位字节。

? 返回值, 如果创建成功会返回消息队列的句柄,如果由于 FreeRTOSConfig.h 文件中 heap 大小不足,
无法为此消息队列提供所需的空间会返回 NULL。
使用这个函数要注意以下问题:
1. FreeRTOS 的消息传递是数据的复制,而不是传递的数据地址,这点要特别注意。 每一次传递都是
uxItemSize 个字节。

函数 xQueueSend

函数描述:
函数 xQueueSend 用于任务中消息发送。
? 第 1 个参数是消息队列句柄。
? 第 2 个参数要传递数据地址, 每次发送都是将消息队列创建函数 xQueueCreate 所指定的单个消息大
小复制到消息队列空间中。

? 第 3 个参数是当消息队列已经满时,等待消息队列有空间时的最大等待时间,单位系统时钟节拍。
? 返回值,如果消息成功发送返回 pdTRUE,否则返回 errQUEUE_FULL。
使用这个函数要注意以下问题:
1. FreeRTOS 的消息传递是数据的复制,而不是传递的数据地址。
2. 此函数是用于任务代码中调用的,故不可以在中断服务程序中调用此函数,中断服务程序中使用的是
xQueueSendFromISR。
3. 如果消息队列已经满且第三个参数为 0,那么此函数会立即返回。
4. 如果用户将 FreeRTOSConfig.h 文件中的宏定义 INCLUDE_vTaskSuspend 配置为 1 且第三个参数配
置为 portMAX_DELAY,那么此发送函数会永久等待直到消息队列有空间可以使用。
5. 消息队列还有两个函数 xQueueSendToBack 和 xQueueSendToFront,函数 xQueueSendToBack
实现的是 FIFO 方式的存取,函数 xQueueSendToFront 实现的是 LIFO 方式的读写。我们这里说的函
数 xQueueSend 等效于 xQueueSendToBack,即实现的是 FIFO 方式的存取。

函数 xQueueSendFromISR

函数描述:
函数 xQueueSendFromISR 用于中断服务程序中消息发送。
? 第 1 个参数是消息队列句柄。
? 第 2 个参数要传递数据地址, 每次发送都是将消息队列创建函数 xQueueCreate 所指定的单个消息大
小复制到消息队列空间中。
? 第 3 个参数用于保存是否有高优先级任务准备就绪。如果函数执行完毕后,此参数的数值是 pdTRUE,
说明有高优先级任务要执行,否则没有。
? 返回值,如果消息成功发送返回 pdTRUE,否则返回 errQUEUE_FULL。
使用这个函数要注意以下问题:
1. FreeRTOS 的消息传递是数据的复制,而不是传递的数据地址。 正因为这个原因,用户在创建消息队
列时单个消息大小不可太大,因为一定程度上面会增加中断服务程序的执行时间。
2. 此函数是用于中断服务程序中调用的,故不可以在任务代码中调用此函数,任务代码中使用的是
xQueueSend。
3. 消息队列还有两个函数 xQueueSendToBackFromISR 和 xQueueSendToFrontFromISR,函数
xQueueSendToBackFromISR 实现的是 FIFO 方式的存取,函数 xQueueSendToFrontFromISR 实
现的是 LIFO 方式的读写。我们这里说的函数 xQueueSendFromISR 等效于
xQueueSendToBackFromISR,即实现的是 FIFO 方式的存取。

函数 xQueueReceive

函数描述:
函数 xQueueReceive 用于接收消息队列中的数据。
? 第 1 个参数是消息队列句柄。
? 第 2 个参数是从消息队列中复制出数据后所储存的缓冲地址,缓冲区空间要大于等于消息队列创建函
数 xQueueCreate 所指定的单个消息大小,否则取出的数据无法全部存储到缓冲区,从而造成内存溢
出。
? 第 3 个参数是消息队列为空时,等待消息队列有数据的最大等待时间,单位系统时钟节拍。
? 返回值,如果接到到消息返回 pdTRUE,否则返回 pdFALSE。
使用这个函数要注意以下问题:
1. 此函数是用于任务代码中调用的,故不可以在中断服务程序中调用此函数,中断服务程序使用的是
xQueueReceiveFromISR。
2. 如果消息队列为空且第三个参数为 0,那么此函数会立即返回。
3. 如果用户将 FreeRTOSConfig.h 文件中的宏定义 INCLUDE_vTaskSuspend 配置为 1 且第三个参数配
置为 portMAX_DELAY,那么此函数会永久等待直到消息队列有数据。

STM32F429 开发板实验

时间: 2024-10-12 21:06:17

FreeRTOS 消息队列的相关文章

Freertos-事件标志组,消息队列,信号量,二值信号量,互斥信号量

任务间的通信和同步机制  在裸机编程时,使用全局变量的确比较方便,但是在加上 RTOS 后就是另一种情况了. 使用全局变量相比事件标志组主要有如下三个问题: 1.使用事件标志组可以让 RTOS 内核有效地管理任务,而全局变量是无法做到的,任务的超时等机制需要用户自己去实现.2.使用了全局变量就要防止多任务的访问冲突,而使用事件标志组则处理好了这个问题,用户无需担心.3.使用事件标志组可以有效地解决中断服务程序和任务之间的同步问题. 事件标志组:事件标志组是实现多任务同步的有效机制之一. 每创建一

Azure Messaging-ServiceBus Messaging消息队列技术系列6-消息回执

上篇博文中我们介绍了Azure Messaging的重复消息机制.At most once 和At least once. Azure Messaging-ServiceBus Messaging消息队列技术系列5-重复消息:at-least-once at-most-once 本文中我们主要研究并介绍Azure Messaging的消息回执机制:实际应用场景: 同步收发场景下,消息生产者和消费者双向应答模式,例如:张三写封信送到邮局中转站,然后李四从中转站获得信,然后在写一份回执信,放到中转站

【转】MSMQ 微软消息队列 简单 示例

MSMQ它的实现原理是:消息的发送者把自己想要发送的信息放入一个容器中(我们称之为Message),然后把它保存至一个系统公用空间的消息队列(Message Queue)中:本地或者是异地的消息接收程序再从该队列中取出发给它的消息进行处理. 我个人的理解,你可以把他当做一种,把数据打包后,发送到一个地方,程序也可以去取到这个打包的程序,队列的机制就不讲了,并发问题荡然无存.呵呵. 上代码: 首先 using System.Messaging; public class MsmqManagerHe

消息队列(msg)

一.消息队列:从一个进程向另一个进程发送数据块,读取不一定是先入先出. 管道与消息队列区别:管道基于字节流的,消息队列基于消息: 管道只能发送字符串,消息队列有类型: 管道随进程,消息队列随内核. 二.创建函数原型:int msgget(key_t key, int msgflg);    //key由ftok生成,IPC_CREAT|IPC_EXCL 接收消息:ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, in

第15章 进程间通行 15.6 XSI IPC 15.7 消息队列

15.6 XSI IPC (1)3种称作XSI IPC的IPC是: 1)消息队列 2)信号量 3)共享存储器 (2)标识符和键 1)标识符:是一个非负整数,用于引用IPC结构.是IPC对象的内部名. 2)键:IPC对象的外部名.可使多个合作进程能够在同一IPC对象上汇聚. (3)IPC_PRIVATE键: 用于创建一个新的IPC结构.不能指定此键来引用一个现有的IPC结构. (4)ftok函数: 由一个路径名和项目ID产生一个键. (5)ipc_perm结构体 规定了ipc结构的权限和所有者.

XSI进程间通信-----消息队列

1. 基本特点 1) 消息队列是一个由系统内核负责存储和管理,并通过消息队列标识引用的数据链表,消息队列 和有名管道fifo的区别在: 后者一次只能放一个包,而前者则可以放很多包,这样就能处理发包快,哪包慢的问题 2) 可以通过msgget函数创建一个新的消息队列, 或获取一个已有的消息队列. 通过msgsnd函数 (send)向消息队列的后端追加消息, 通过msgrcv(receive)函数从消息队列的前端提取消息. 3) 消息队列中的每个消息单元除包含消息数据外,还包含消息类型和数据长度.消

android 中使用View的消息队列api更新数据

基本上只要继承自View的控件,都具有消息队列或者handler的一些处理方法,下面是一些handler方法以及被View封装了的方法,其底层用的基本都是handler的api. 我么开一下postDelay的定义 android.view.View  public boolean postDelayed(Runnable action, long delayMillis) {         final AttachInfo attachInfo = mAttachInfo;         

消息队列实现订单异步提交

what MSMQ(Microsoft Message Queue),微软消息队列,用于应用程序之间相互通信的一种异步传输模式.应用程序可以分布在同台机器上,也可以分布于互联的网络中的任意位置.基本原理:消息发送者把要发送的消息放入容器,也就是Message(消息),然后保存到系统公用空间的消息队列中(Message Queue)中,本地或互联位置上的消息接收程序再从队列中取出发给它的消息进行处理.消息类型可以是文本,图像,自定义对象等.消息队列分为公共队列和私有队列. why 一.用于进程间的

Windows消息队列

一 Windows中有一个系统消息队列,对于每一个正在执行的Windows应用程序,系统为其建立一个"消息队列",即应用程序队列,用来存放该程序可能 创建的各种窗口的消息.应用程序中含有一段称作"消息循环"的代码,用来从消息队列中检索这些消息并把它们分发到相应的窗口函数中.  二 Windows为当前执行的每个Windows程序维护一个「消息队列」.在发生输入事件之后,Windows将事件转换为一个「消息」并将消息放入程序的消息队列中.程序通过执行一块称之为「消息循