FreeRTOS队列:xQueueCreate(),xQueueSendToBack(),xQueueSendToFront(),xQueueReceive(),xQueueSendFromISR()

FreeRTOS 队列(Queue)是其任务间通信的核心机制之一,用于在任务之间或任务与中断服务程序(ISR)之间安全地传递数据。以下是关于 FreeRTOS 队列的详细介绍:

目录

1. 队列的基本概念

2. 队列的核心特性

3. 队列的工作原理

4. 主要 API 函数

创建队列

发送数据

接收数据

中断专用函数

其他常用函数

5. 使用场景

6. 示例代码

创建队列并发送数据

接收数据

7. 注意事项

8. 队列 vs 其他通信机制

总结



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. 使用场景

  1. 任务间通信:例如生产者-消费者模型,生产者任务向队列发送数据,消费者任务接收。

  2. 中断与任务通信:中断服务程序通过队列将数据传递给任务。

  3. 替代信号量:通过传输无意义的数据(如 0)模拟二值信号量或计数信号量。

  4. 事件通知:传递结构体或枚举值表示不同事件。


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 队列是灵活且强大的通信工具,适用于需要传输数据的场景。通过合理使用阻塞机制和中断安全函数,可以实现高效的任务间协作。在设计时需权衡队列长度、内存占用和实时性要求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值