目录
一、简介
FreeRTOS 的消息队列(Message Queue)是任务之间通信的一种常用机制,允许任务或中断将数据发送到队列中,其他任务从队列中读取数据。
消息队列在嵌入式实时操作系统中非常重要,因为它提供了一种任务间的异步通信方式,同时可以确保数据的顺序性和完整性。
二、特点
- 先进先出 :消息按照发送到队列的顺序存储,先发送的消息会先被读取。消息队列保证了消息的顺序性。当然FreeRTOS 也支持后进先出模式,需要进行设置。
- 数据存储的缓冲区:消息队列为数据提供了一个缓冲区,这意味着任务可以将数据发送到队列,即使接收任务没有立即运行。数据在队列中暂存,直到接收任务准备好处理它。
- 可配置的队列大小:在创建消息队列时,可以指定队列的最大长度(即可以存储的消息个数)和每条消息的大小。这让开发者可以根据需求来调整队列的容量,从而控制内存使用。
- 线程安全:FreeRTOS的消息队列是线程安全的。即便多个任务或中断同时访问队列,FreeRTOS也能通过内部的机制确保数据的一致性和完整性。
- 阻塞和非阻塞操作:发送数据到队列的操作可以是阻塞的或者非阻塞的。阻塞操作会让任务等待,直到有空间可以存储新的消息,而非阻塞操作会立即返回。接收数据的操作也可以是阻塞或非阻塞的。任务可以选择阻塞等待直到有新的数据,或者立即返回。
- 值传递:数据发送到消息队列中会导致数据拷贝,也就是将要发送的数据拷贝到队列中,这就意味着在队列中存储的是数据的原始值,而不是原数据的引用,这个也叫做值传递。μC/OS的消息队列采用的是引用传递,传递的是消息指针。FreeRTOS的消息队列也可以使用引用来传递消息,直接往队列中发送指向这个消息的地址指针就可以了。
三、消息队列控制块
在 FreeRTOS 中,消息队列控制块(Queue Control Block)是实现消息队列的核心数据结构。消息队列控制块的存在使得任务或中断能够通过统一的接口与消息队列进行交互,而无需直接处理底层的内存和队列操作。
消息队列控制块在创建队列时分配,当一个队列被创建时,FreeRTOS 会为该队列分配一个控制块,该控制块中初始化所有需要的信息,如消息存储的缓冲区指针、队列的大小、消息的大小、任务等待队列等,确保队列可以正确地被发送数据或从中读取数据。 消息队列控制块是 FreeRTOS 消息队列操作的核心,所有关于队列的操作都是通过它来完成的。FreeRTOS 会自动管理这个控制块。
四、相关API
使用队列的典型流程如下:
- 创建队列。
- 写队列操作。
- 读队列操作。
- 删除队列。
1.创建队列
- 其中,uxQueueLength用于指定队列中的最大条目数,uxItemSize指定每个条目的大小(以字节为单位)。
- 返回值是队列句柄,用于后续的发送、接收等操作。
- 该创建队列的方法使用的是动态内存分配,当然也有使用静态内存分配的API,但是不常用,这里暂不介绍。
QueueHandle_t xQueue; //定义一个队列句柄
xQueue = xQueueCreate(10, sizeof(int)); // 创建一个最多存储10个整型消息的队列
2.发送消息到队列
- 其中,xQueue是队列句柄(使用上面创建的队列),pvItemToQueue 是指向要发送的数据的指针,xTicksToWait是发送任务可以等待的时间(取0~ portMAX_DELAY),如果队列满了,任务可能会阻塞等待。
- 成功发送则返回pdTURE,否则返回errQUEUE_FULL。
- 发送消息的API除了xQueueSend()之外还有一些比如向队头发送消息的队列等其他API,这里暂不介绍。
int value = 100;
xQueueSend(xQueue, &value, 0);
//发送整数值100到队列,0表示不等待(不阻塞),队列满则立即返回
3.从队列接收消息
- 其中,xQueue是队列句柄(使用上面创建的队列),pvBuffer用于存放接收到的数据,xTicksToWait是接收任务可以等待的时间(0~ portMAX_DELAY),如果队列为空,任务可能会阻塞等待。
- 成功接收则返回pdTRUE,否则返回errQUEUE_EMPTY。
- xQueueReceive()在接收消息后,队列中的该消息会被删除,若不想删除可以使用取队头的API:xQueuePeek(),用法与xQueueReceive()完全一致。
int receivedValue; //用于接收数据 if(xQueueReceive(xQueue, &receivedValue, portMAX_DELAY) == pdTRUE) { //接收数据并判断是否接收成功 //若成功接收到数据,此处可以处理数据receivedValue } //portMAX_DELAY表示一直等待直到接收成功(一直阻塞)
4.从中断服务例程(ISR)中发送消息
- 同上述发送消息的API,只是用于在中断上下文中发送消息,允许中断在较高优先级任务执行期间发送数据到队列。pxHigherPriorityTaskWoken一般设置为NULL即可。
5.从中断服务例程(ISR)中接收消息
- 类似于xQueueReceive,但适用于中断上下文
- pxHigherPriorityTaskWoken一般设置为NULL即可。
6.删除队列
- void vQueueDelete( QueueHandle_t xQueue )
- 其中,xQueue是队列句柄,使用创建消息队列时得到的队列句柄。
五、使用场景
-
任务间通信:任务A产生数据,任务B处理数据,任务A可以通过队列将数据发送给任务B。这样可以解耦任务的执行时序,让任务A和任务B独立运行。
-
中断和任务的通信:中断产生的数据通常是实时的,可能需要快速传递给某个任务处理。中断可以通过队列将数据发送给任务,而任务从队列中读取并处理这些数据。
-
事件通知:队列不仅可以传递数据,还可以传递事件通知。例如,某个任务完成了特定操作,可以通过队列通知另一个任务开始新的操作。
标签:FreeRTOS,队列,阻塞,任务,消息,数据 From: https://blog.csdn.net/han2205277149/article/details/142966737