FreeRTOS 队列(Queue)是其任务间通信的核心机制之一,用于在任务之间或任务与中断服务程序(ISR)之间安全地传递数据。以下是关于 FreeRTOS 队列的详细介绍:
目录
1. 队列的基本概念
-
作用:队列是一种先进先出(FIFO)的缓冲区,允许多个任务或中断以线程安全的方式发送和接收数据。
-
数据类型:队列可以传输任意类型的数据(如整型、结构体、指针等)。
-
容量:队列有固定长度,每个队列项的大小在创建时指定。当队列满时,发送操作可阻塞;队列空时,接收操作可阻塞。
-
多任务安全:队列通过内部锁机制(如互斥锁)确保并发访问的安全性。
2. 队列的核心特性
-
阻塞机制:
-
发送阻塞:当队列已满时,发送任务可选择等待指定时间(直到有空间)。
-
接收阻塞:当队列为空时,接收任务可选择等待指定时间(直到有数据)。
-
阻塞时间可设置为
0
(不等待)或portMAX_DELAY
(无限等待)。
-
-
多发送者/多接收者:支持多个任务或中断同时操作同一队列。
-
中断安全:提供
xQueueSendFromISR()
和xQueueReceiveFromISR()
函数,专门用于中断服务程序。 -
覆盖发送(Overwrite):当队列满时,
xQueueOverwrite()
会覆盖最旧的数据(适用于传输最新状态,如传感器数据)。 -
紧急发送(Front):
xQueueSendToFront()
将数据插入队列头部,优先被接收。
3. 队列的工作原理
-
存储结构:队列内部使用环形缓冲区(Circular Buffer)实现。
-
内存分配:队列在创建时动态分配内存(通过
xQueueCreate()
),需指定队列长度和每个队列项的大小。 -
锁机制:FreeRTOS 使用临界区(Critical Section)或调度器锁保护队列操作,防止多任务竞争。
4. 主要 API 函数
创建队列
QueueHandle_t xQueueCreate(
UBaseType_t uxQueueLength, // 队列长度(最大可存项数)
UBaseType_t uxItemSize // 每个队列项的大小(字节)
);
-
返回队列句柄,失败返回
NULL
。
发送数据
BaseType_t xQueueSend(
QueueHandle_t xQueue, // 队列句柄
const void *pvItemToQueue, // 待发送数据的指针
TickType_t xTicksToWait // 阻塞时间(以系统节拍为单位)
);
-
类似函数:
xQueueSendToBack()
(默认)、xQueueSendToFront()
(紧急发送)。
接收数据
BaseType_t xQueueReceive(
QueueHandle_t xQueue, // 队列句柄
void *pvBuffer, // 接收数据的缓冲区指针
TickType_t xTicksToWait // 阻塞时间
);
中断专用函数
BaseType_t xQueueSendFromISR(
QueueHandle_t xQueue,
const void *pvItemToQueue,
BaseType_t *pxHigherPriorityTaskWoken // 是否唤醒更高优先级任务
);
其他常用函数
-
uxQueueMessagesWaiting()
:获取队列中当前有效项数。 -
xQueueReset()
:重置队列为空状态。 -
vQueueDelete()
:删除队列并释放内存。
5. 使用场景
-
任务间通信:例如生产者-消费者模型,生产者任务向队列发送数据,消费者任务接收。
-
中断与任务通信:中断服务程序通过队列将数据传递给任务。
-
替代信号量:通过传输无意义的数据(如
0
)模拟二值信号量或计数信号量。 -
事件通知:传递结构体或枚举值表示不同事件。
6. 示例代码
创建队列并发送数据
// 定义队列句柄
QueueHandle_t xDataQueue;
// 创建队列:长度5,每个项为int类型
xDataQueue = xQueueCreate(5, sizeof(int));
// 任务发送数据
int value = 100;
xQueueSend(xDataQueue, &value, portMAX_DELAY);
接收数据
int receivedValue;
if (xQueueReceive(xDataQueue, &receivedValue, 100 / portTICK_PERIOD_MS) == pdTRUE) {
// 成功接收到数据
}
7. 注意事项
-
内存管理:队列占用动态内存,需确保系统有足够堆空间。
-
性能:频繁操作队列可能影响实时性,需合理设计队列长度和项大小。
-
中断中使用:在ISR中必须使用
FromISR
结尾的函数,且不可阻塞。 -
优先级反转:若多个高优先级任务依赖同一队列,需考虑优先级继承机制(如使用互斥锁)。
8. 队列 vs 其他通信机制
机制 | 特点 |
---|---|
队列 | 传输数据,支持阻塞,多任务安全。 |
信号量 | 仅传递计数,轻量级同步。 |
事件组 | 通过位标志传递多事件,无数据负载。 |
任务通知 | 直接向任务发送通知,效率最高,但功能单一。 |
总结
FreeRTOS 队列是灵活且强大的通信工具,适用于需要传输数据的场景。通过合理使用阻塞机制和中断安全函数,可以实现高效的任务间协作。在设计时需权衡队列长度、内存占用和实时性要求。