现象
- LCD 显示明显滞后于串口输出
- LCD 偶尔丢失 M1 的 PWM 更新,RPM 刷新不稳定
根因
status_queue(1 个队列)被 USART 和 LCD 两个任务同时消费:
MotorCtrlTask --→ status_queue --+--→ UartCommTask(printf,微秒级)+--→ LcdDisplayTask(SPI 绘制,毫秒级)
- UartCommTask 仅做
printf(),微秒级完成,立刻回到等待队列 - LcdDisplayTask 需
lcd_fill()+lcd_show_string()等 SPI 逐像素绘制,毫秒级耗时 - 结果:USART 几乎每次都能抢到消息,LCD 只能拿到 USART 处理间隙的少数消息
本质问题:多消费者单队列 + 消费者处理速度差异 → 竞争消费,慢消费者丢包。
修复
拆分为两路独立队列,各消费者持有专属队列:
MotorCtrlTask --+--→ usart_status_queue (16) --→ UartCommTask(独立消费)+--→ lcd_status_queue (16) --→ LcdDisplayTask(独立消费)
| 文件 | 改动 |
|---|---|
freertos.c |
用户区新增 usart_status_queue / lcd_status_queue,xQueueCreate(16, sizeof(motor_status_t)) |
motor_app.c |
每条状态 xQueueSend 到两个队列各一份 |
usart_app.c |
改为 xQueueReceive(usart_status_queue, ...),osStatus_t/osOK → BaseType_t/pdPASS |
lcd_app.c |
改为 xQueueReceive(lcd_status_queue, ...),osStatus_t/osOK → BaseType_t/pdPASS |
经验
- FreeRTOS 队列是点对点通信机制,一条消息只能被一个消费者取走
- 需要广播数据给多个消费者时,必须用多队列分发或 Event Group + 共享内存
- CubeMX 生成的
status_queueHandle保留在非用户区无法删除,但可弃用
