一句话概括
xQueueCreate 是 FreeRTOS 实时操作系统中用于动态创建消息队列的函数。它负责分配内存并返回一个可以用于发送和接收数据的队列句柄。
详细解释
1. 什么是消息队列?
在深入函数本身之前,理解“队列”的概念至关重要。你可以把它想象成一个管道或传送带:
-
生产者:任务或中断服务程序将数据(消息)放入队列的一端(发送)。
-
消费者:任务从队列的另一端取出数据(接收)。
-
先进先出:数据按照被送入队列的顺序被取出,就像在超市排队结账一样。
队列是 FreeRTOS 中最重要的任务间通信机制之一,它允许任务安全、有序地传递信息,而不用担心并发访问导致的数据损坏。
2. xQueueCreate 的作用
xQueueCreate 就是用来创建这样一个“管道”的工具。它主要做两件事:
-
分配内存:从 FreeRTOS 的堆中分配两块内存。
-
一块用于存储队列的结构体,其中包含了管理队列所需的所有信息(如头指针、尾指针、队列长度、项目大小等)。
-
另一块用于作为队列的存储区,这是一个字节数组,实际的数据就存储在这里。
-
-
初始化队列:将队列结构体中的各个字段设置为初始状态(例如,队列为空)。
-
返回句柄:如果创建成功,它返回一个指向这个队列的句柄。后续所有对队列的操作(如发送、接收)都需要使用这个句柄来指定操作哪个队列。
函数原型
QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength, // 队列长度UBaseType_t uxItemSize // 每个队列项目的大小(字节));
参数说明
-
uxQueueLength:-
队列能够存储的最大项目数量。
-
例如,如果你设置为 5,那么这个队列最多可以同时存放 5 条消息。
-
-
uxItemSize:-
队列中每个项目所占的字节数。
-
如果你要发送一个整数,在 32 位系统上就是
sizeof(int)= 4 字节。 -
如果你要发送一个结构体,就是
sizeof(my_struct_t)。
-
返回值
-
成功:返回一个非 NULL 的
QueueHandle_t类型的句柄。这个句柄需要被你保存起来,供后续使用。 -
失败:返回
NULL。失败通常是因为没有足够的堆内存来创建队列。
工作流程示意图
假设我们创建一个队列:xQueueCreate(3, sizeof(int))
这表示一个能存放 3 个整数的队列。
-
创建后(初始状态):
队列存储区: [ 空 | 空 | 空 ]^写指针 & 读指针队列为空,读写指针都指向起始位置。
-
发送一个数据(例如 10):
队列存储区: [ 10 | 空 | 空 ]^ ^读指针 写指针 -
再发送一个数据(例如 20):
队列存储区: [ 10 | 20 | 空 ]^ ^读指针 写指针 -
接收一个数据:
-
从读指针位置取出数据
10。 -
读指针移动到下一个位置。
队列存储区: [ 空 | 20 | 空 ]^ ^读指针 写指针现在队列里只有一个数据
20。 -
代码示例
下面是一个简单的示例,演示如何创建和使用队列。
#include <FreeRTOS.h>
#include <task.h>
#include <queue.h>// 1. 定义队列句柄变量
QueueHandle_t xIntegerQueue;// 发送任务
void vSenderTask(void *pvParameters) {int value_to_send = 0;for(;;) {// 2. 发送数据到队列if(xQueueSend(xIntegerQueue, &value_to_send, portMAX_DELAY) == pdPASS) {// 发送成功}value_to_send++;vTaskDelay(pdMS_TO_TICKS(1000)); // 每隔1秒发送一次}
}// 接收任务
void vReceiverTask(void *pvParameters) {int received_value = 0;for(;;) {// 3. 从队列接收数据if(xQueueReceive(xIntegerQueue, &received_value, portMAX_DELAY) == pdPASS) {// 成功接收到数据,可以处理 received_value// 例如,打印出来}}
}void main(void) {// 4. 创建队列:长度为5,每个项目是一个intxIntegerQueue = xQueueCreate(5, sizeof(int));// 检查队列是否创建成功if(xIntegerQueue != NULL) {// 创建任务...xTaskCreate(vSenderTask, "Sender", 1000, NULL, 1, NULL);xTaskCreate(vReceiverTask, "Receiver", 1000, NULL, 1, NULL);// 启动调度器vTaskStartScheduler();} else {// 队列创建失败!可能是内存不足// 处理错误}// 程序不应该运行到这里for(;;);
}
重要注意事项
-
动态内存:
xQueueCreate使用pvPortMalloc动态分配内存,因此你需要确保 FreeRTOS 的堆配置得足够大。 -
替代函数:
xQueueCreateStatic。这是一个静态创建版本,它允许你提供存储队列结构体和存储区的内存缓冲区,而不是由函数内部动态分配。这在内存受限或不允许动态分配的系统中非常有用。 -
线程安全:队列的发送和接收函数是原子的,可以被多个任务或中断安全地调用,无需额外的保护。
-
阻塞:当队列已满时尝试发送,或者队列为空时尝试接收,任务可以进入阻塞状态等待,直到条件满足。这由
xQueueSend和xQueueReceive的第三个参数(阻塞时间)控制。
总结
xQueueCreate 是 FreeRTOS 中构建任务间通信桥梁的基石函数。通过指定队列的容量和每个消息的大小,它为你创建了一个安全、可靠的数据通道,是多任务程序设计中不可或缺的工具。
