在STM32项目开发中,经常会遇到多个传感器、多个中断同时产生数据的场景。比如红外接收、旋转编码器、MPU6050六轴传感器,三路信号来源不同。

如果用普通队列,任务只能轮询逐个查询队列,CPU空转浪费资源。FreeRTOS的队列集(QueueSet) 就是用来解决:一个任务阻塞等待,同时监听多个队列。

一、队列集核心原理
重点:队列集不存储业务数据,只存放队列的句柄。
1. 多个独立队列加入同一个队列集;

2. 当任意一个队列成功写入数据,FreeRTOS自动将该队列的句柄放入队列集;

3. 业务任务阻塞读取队列集,拿到句柄后,就能判断是哪一路设备上报数据;

4. 根据句柄,读取对应队列里真实传感器数据,完成业务处理。
类比:队列集相当于通知栏,句柄就是消息来源图标;真正的数据保存在原始队列。
二、项目框图

三路信号源:红外接收中断、旋转编码器中断、MPU6050传感器驱动

• 底层中断:采集原始数据,写入各自独立队列

• 队列集:绑定3个队列,接收队列句柄

• InputTask输入任务:阻塞等待队列集,拿到句柄,读取数据、解析处理

• 处理完成后,将控制指令写入g_xQueuePlatform,交给挡球板任务platform_task执行硬件控制

三、代码示例
// 1. 定义队列句柄
QueueHandle_t xQueueIR;
QueueHandle_t xQueueEncoder;
QueueHandle_t xQueueMPU6050;
QueueHandle_t xQueueSet;
QueueHandle_t g_xQueuePlatform;

// 创建队列集,最多容纳3个句柄
xQueueSet = xQueueCreateSet(3);

// 创建3个原始队列
xQueueIR = xQueueCreate(10, sizeof(uint16_t));
xQueueEncoder = xQueueCreate(10, sizeof(int16_t));
xQueueMPU6050 = xQueueCreate(10, sizeof(MPU_Data_t));

// 将队列加入队列集
xQueueAddToSet(xQueueIR, xQueueSet);
xQueueAddToSet(xQueueEncoder, xQueueSet);
xQueueAddToSet(xQueueMPU6050, xQueueSet);

// InputTask任务函数
void InputTask(void *param)
{
    QueueHandle_t xRecvQueueHandle;
    uint16_t ir_data;
    int16_t enc_data;
    MPU_Data_t mpu_data;
    Platform_Cmd_t cmd;

    while(1)
    {
        // 阻塞等待队列集,有消息才唤醒任务
        xRecvQueueHandle = xQueueSelectFromSet(xQueueSet, portMAX_DELAY);
        
        if(xRecvQueueHandle == xQueueIR)
        {
            xQueueReceive(xRecvQueueHandle, &ir_data, portMAX_DELAY);
            // 红外数据处理
        }
        else if(xRecvQueueHandle == xQueueEncoder)
        {
            xQueueReceive(xRecvQueueHandle, &enc_data, portMAX_DELAY);
            // 编码器数据处理
        }
        else if(xRecvQueueHandle == xQueueMPU6050)
        {
            xQueueReceive(xRecvQueueHandle, &mpu_data, portMAX_DELAY);
            // MPU6050姿态数据处理
        }

        // 生成控制指令,下发挡球板任务
        cmd.type = PLATFORM_MOVE;
        xQueueSend(g_xQueuePlatform, &cmd, 0);
    }
}
四、开发要点

1. 中断里只写队列,禁止复杂运算。中断执行时间要短,解析、业务逻辑全部放到任务。

2. 加入队列集的队列,不能使用xQueueSendFromISR之外的中断API,遵循FreeRTOS规范。

3. 队列集容量 >= 加入的队列数量,避免句柄存放溢出

4. 任务拿到句柄后,一定要读取对应队列的数据,否则队列一直有数据,会反复触发唤醒。

五、总结

队列集的优势:任务休眠等待,不需要轮询查询多路队列,降低CPU占用。适合多传感器、多路外部事件需要统一处理的嵌入式项目。
适合机器人、平衡车、电赛项目做多源消息调度。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐