嵌入式系统:裸奔还是上OS?十年老鸟的血泪总结

裸机编程:看上去简单其实全是坑

说实话,干了十几年嵌入式,最烦的就是有人问我:“你这个代码为啥不直接轮询?非要上系统?” 好吧,我承认,很多项目确实用个while(1)大循环就够了。尤其是一些简单的家电控制,温控器什么的。但是!一旦你开始玩真的,比如要同时处理Wi-Fi、蓝牙、传感器数据,还要保证按键响应快,裸机的代码就会变成一团乱麻。中断嵌套、全局变量满天飞……改一个bug,整个系统都抖三抖。💥

记得有一次做个工业网关,老板要求成本压到极致,选了颗只有64KB RAM的Cortex-M3。我想,裸机吧,省资源。结果呢?报文解析和Modbus轮询撞在一起,数据包丢了三分之一。后来加了双缓冲和DMA,勉强搞定,但代码读了让人想撞墙。这种经历,干过的人都知道,那种抓狂的感觉。

所以,裸机编程并不是真的“裸”。你要自己实现任务调度、延时、资源互斥。这叫“超级循环”,还美其名曰前后台系统。听起来专业,其实就是在一个大循环里加各种标志位判断。时间长了,标志位比星星还多。关键任务紧迫,你不得不靠中断抢占,然后中断里又调了函数,函数里又调了……重入问题就来了。❗

嵌入式系统前后台程序流程图
嵌入式系统前后台程序流程图

到底什么时候该上RTOS?我个人标准很简单:如果你需要同时做两件以上对实时性有要求的事,而且它们之间还要数据交互,那就别犹豫。继续裸机的代价,是后期维护会让你生不如死。当然,对于功耗有极致要求的设备,比如电池供电且需要休眠的,RTOS的任务唤醒机制反而能帮你更好地管理功耗。这个话题,一会儿细说。

问:我目前用STM32做电机控制,只跑FOC算法,需要RTOS吗?
答:专门搞电机控制,尤其是FOC这种需要高频率电流环的,通常算力要集中。如果只是控制一个电机,没有太多通信任务,裸机完全够用,甚至更好——因为你能精确控制PWM更新时机。但如果要加上CAN总线、人机界面、多个电机协同,那RTOS就可以让你把控制任务隔离出来,防止界面卡顿影响电机性能。不过,选RTOS要注意,有些实时内核的任务切换时间可能比你想象的慢。一定要测试上下文切换开销。😒

RTOS不是银弹,选错就是灾难

一提到RTOS,很多人张嘴就是FreeRTOS。没错,它免费、资料多、占用小。但这就是最佳选择吗?我看未必。我曾经在一个安全关键的项目上,用了FreeRTOS的抢占式调度,结果因为一个算数溢出导致的栈溢出,整个系统死锁了。查了三天三夜,才发现是MPU没有配置好。我就想,要是用了ThreadX或者QNX,也许bug能被提前检测出来。不过话说回来,那些商业系统贵得要死,动不动几万美金,小公司根本用不起。😣

RTOS的世界其实很分裂。一边是FreeRTOS、RT-Thread这类轻量级系统,另一边是SylixOS、VxWorks这类硬实时操作系统。选择哪个,不光看功能,更要看你的团队技术水平。真不是吓唬你,我见过有人上了RT-Thread,结果不会配置优先级,发生了优先级反转,导致无人机炸机。那场面……惨烈。所以说,上了操作系统,不等于实时性就自带了。反而因为任务多了,调度复杂了,你需要更懂并发、中断、内存管理。

优先级反转这个坑,很多人都是摔了才知道。低优先级任务持有信号量,高优先级任务等着,中优先级任务插队,于是高优先级反而被饿死。解决办法是优先级继承。可是,很多RTOS默认并不开启优先级继承!比如FreeRTOS,你得显式配置互斥量类型。这就是为什么我不推荐新手贸然使用操作系统。你没有那个意识,早晚出大事。⚠️

RTOS优先级反转时序图
RTOS优先级反转时序图

还有内存管理。在资源受限的MCU上,malloc是绝对的毒药。这种话不好听,但真就是这样。动态内存分配导致的内存碎片,会让一个跑了一年的设备莫名其妙挂掉。所以要么全用静态分配,要么用一个内存池管理。我在嵌入式Linux上看到太多人直接把桌面端的习惯带过来,new完忘delete,内核oom killer就来了。等等,我是不是扯到Linux了?好,下一节就说它。

问:嵌入式Linux和RTOS的区别到底是什么?选哪个更合适?
答:这就像问“摩托车和卡车哪个好”一样,得看你要干嘛。RTOS是硬实时,微秒级响应,资源占用小,适合MCU;Linux是软实时,带完整的网络协议栈、文件系统、驱动模型,适合需要图形界面、复杂网络、多核应用处理器的场景。但Linux的实时性很难保证,即使打了PREEMPT_RT补丁,中断延迟也在几十微秒级别。如果你要做高精度运动控制,老老实实用RTOS或裸机。但如果要做工业HMI、数据网关,Linux丰富的开源软件能让你事半功倍。选错就是灾难。我曾在一年内踩过这两个坑:用RTOS做复杂的JSON解析,代码量爆炸;用Linux做电机控制,断了好几根皮带。😂

嵌入式系统的未来:当Linux遇到MCU,以及RISC-V的搅局

最近几年,嵌入式领域最大的变化,就是MCU的性能越来越高,ARM Cortex-M7、M85已经能跑一些轻量级Linux了。不过,真要在MCU上跑Linux,我觉得有点赶鸭子上架。你根本没有MMU,跑的是uClinux,很多程序会出问题。但是,有一些混合系统出现了,比如Zephyr,它既不是传统RTOS,也不是Linux,而是为了物联网设计的可配置实时操作系统。这玩意儿功能强到可以跑TCP/IP、蓝牙Mesh,却又轻量到能在Cortex-M0上运行。我刚接触时很惊异——这怎么可能?!然后我试了它的内核,发现确实优秀,但资料少得可怜,出了bug根本找不到人问,全靠自己啃。这就是新一代技术的尴尬。😖

说到未来,不能不说RISC-V。这玩意儿是开源的指令集,现在国内的MCU厂商像打了鸡血一样推出RISC-V芯片。价格便宜,有些带AI加速器。我在一个视觉检测项目上用了RISC-V的处理器跑FreeRTOS,心里还是有点忐忑的。毕竟ARM的生态太完善了,从调试器到编译器,都好用得不想换。RISC-V的工具链还在追赶,有时候GCC编译出来的代码优化不够,让我怀念Keil的丝滑。但,开源的力量不容小觑,五年后可能就完全不同。嵌入式工程师,永远在学习的路上。对吗?

现在我想谈谈低功耗。别以为嵌入式就是随便弄个休眠模式。在边缘AI设备上,你得让设备大部分时间睡觉,几毫秒醒来处理传感器数据,然后用NPU跑个小模型,再睡。这需要系统级的设计。RTOS的tickless模式能极大降低功耗,因为系统不必周期性地被时钟中断唤醒。FreeRTOS和RT-Thread都支持tickless,但是配置起来有很多坑,比如定时器补偿不准。说实话,直到现在我还在摸索。每次功耗降了一点点,就高兴得像个孩子。👏

嵌入式系统,说到底,就是资源的艺术。在有限的MCU、内存、电量下,实现那个看似简单的需求。它不炫,不像前端那些花花绿绿的框架,但哪一天你家里没有嵌入式设备了?从冰箱到电梯,从呼吸机到火箭,处处都有。干这行,要沉得住气,也要经常抬头看看,别被裸机束缚,也别被操作系统套住。🛠️

工业现场嵌入式系统控制柜内部接线图
工业现场嵌入式系统控制柜内部接线图

好了,写了这么多,回看一眼,通篇都是我的吐槽和感慨。不过这就是真实的嵌入式开发,不是教科书,是实战。希望这些文字能给你一点启发,哪怕只是让你少踩一个优先级反转的坑。我也算没白费口舌。下回聊。👋

免责声明:市场有风险,选择需谨慎!此文仅供参考,不作买卖依据。如有侵权请联系删除。
文章名称:嵌入式系统:裸奔还是上OS?十年老鸟的血泪总结
文章链接:https://www.zystgy.cn/a/51926