FreeRTOS 生产落地案例:工业 RS485 采集网关
生产落地案例:工业 RS485 采集网关
背景。一台基于 Cortex-M4 的采集网关,通过 RS485 轮询多个从站,把数据打包上报,同时要响应本地按键与指示灯。最初是裸机大循环:随着从站数量增加,轮询周期被拉长,按键响应变得迟钝,上报周期开始抖动,通信超时也难以及时重试。
怎么做。按职责切任务:串口采集任务(发帧、等回帧、超时重试)、协议解析任务(把原始字节流攒成完整帧再解析)、上报任务、按键与显示任务,另加空闲钩子做低功耗。串口采用「DMA 接收加空闲中断」:中断里只把收到的字节丢进队列,解析全部放到任务里做,中断服务程序尽可能短。
关键配置。
- 堆用 heap_4,configTOTAL_HEAP_SIZE 按「全部任务栈 + 队列 + 内核对象」估算后留三成余量;运行期不再创建对象。
- 优先级分配上,上报任务最低,采集稍高,协议解析更高;「等外部事件」的任务放在低优先级,它们阻塞时不占 CPU。
- configCHECK_FOR_STACK_OVERFLOW 设为 2,接上
vApplicationStackOverflowHook,把出错任务信息存进备份寄存器后复位。 - configASSERT 打开,配合调试器断点,把「中断里用错 API」这类问题在开发期就拦住。
- 打开 configGENERATE_RUN_TIME_STATS,并用
uxTaskGetStackHighWaterMark定期把各任务 CPU 占用与栈余量打到调试串口,据此收窄栈空间。 - configUSE_TICKLESS_IDLE 打开,空闲时进低功耗模式,靠串口中断与低功耗定时器唤醒。
效果。采集与上报解耦之后,按键响应不再受轮询周期影响,上报周期的抖动收敛,超时重试也能按预期触发。空闲期进入低功耗模式后整机功耗下降,具体幅度依硬件与唤醒频率而异,需要实测。各任务栈的余量也可以从水位统计里读出来,据此把 RAM 还给其他模块。
踩的坑与解决。
- 栈深度当成字节填,任务一进函数就溢出。解决:统一按字换算,并用栈水位统计核对。
- 用二值信号量保护共享的通信缓冲,出现上报任务长时间拿不到锁。解决:改成 mutex,启用优先级继承。
- 在串口中断里直接调用非 FromISR 版本的发送函数,偶发死机。解决:全部改为 FromISR 版本,并加 configASSERT 校验中断优先级。
- 打开 tickless 后系统时间变慢。解决:低功耗定时器的时钟源与唤醒补偿没配对,按官方文档的 tickless 移植说明逐项核对,端口相关细节以所用 SDK 文档为准。
- 一开始用 heap_1,后期想动态创建临时队列才发现根本没有 vPortFree。解决:除非明确要求全静态,否则起步就选 heap_4。

