點(diǎn)擊上方藍(lán)色字體,關(guān)注我們
作為一名常年和 MCU、寄存器、中斷打交道的嵌入式軟件工程師,我們幾乎每個(gè)項(xiàng)目都會(huì)面臨一個(gè)靈魂拷問(wèn):這個(gè)項(xiàng)目,到底用裸機(jī)還是上 RTOS?
一邊是裸機(jī)的極簡(jiǎn)可控,幾行代碼就能點(diǎn)亮硬件,沒(méi)有內(nèi)核開(kāi)銷(xiāo),不用操心任務(wù)調(diào)度;另一邊是 RTOS 的強(qiáng)大靈活,卻也伴隨著優(yōu)先級(jí)分配、死鎖、棧溢出等一系列新的坑。
今天,我們就從工程實(shí)踐的本質(zhì)出發(fā),把這個(gè)問(wèn)題講透:RTOS 的核心價(jià)值到底是什么?到底什么場(chǎng)景、什么節(jié)點(diǎn),才是引入 RTOS 的最佳時(shí)機(jī)?又有哪些情況,根本沒(méi)必要上 RTOS?
在談 “什么時(shí)候用” 之前,我們必須先糾正一個(gè)最常見(jiàn)的誤區(qū),RTOS 的核心不是 “多任務(wù)”,而是 “確定性實(shí)時(shí)調(diào)度”。
這是它和裸機(jī)、和 Linux 這類通用操作系統(tǒng)最本質(zhì)的區(qū)別,也是我們判斷要不要用它的核心標(biāo)尺。
我們先拆解裸機(jī)的本質(zhì):絕大多數(shù)裸機(jī)程序,都是前后臺(tái)系統(tǒng),中斷服務(wù)程序是前臺(tái),處理異步事件;while (1) 超級(jí)循環(huán)是后臺(tái),輪詢處理所有業(yè)務(wù)邏輯。這套架構(gòu)的天生短板,就是執(zhí)行時(shí)延完全不可控。
后臺(tái)循環(huán)里的所有任務(wù),必須按順序執(zhí)行,哪怕后面有緊急的事件,也必須等前面的函數(shù)執(zhí)行完畢;哪怕你把關(guān)鍵邏輯放進(jìn)中斷,也會(huì)面臨 “長(zhǎng)中斷阻塞其他中斷、關(guān)中斷導(dǎo)致系統(tǒng)抖動(dòng)、中斷上下文無(wú)法執(zhí)行復(fù)雜邏輯” 的致命問(wèn)題。
而 RTOS ,正是為了解決這個(gè)核心痛點(diǎn)而生,它的核心能力,我們可以濃縮為 4 點(diǎn)。
這是 RTOS 的靈魂。內(nèi)核可以讓高優(yōu)先級(jí)任務(wù),立刻打斷正在執(zhí)行的低優(yōu)先級(jí)任務(wù),搶占 CPU 資源。這意味著,你的關(guān)鍵控制邏輯,響應(yīng)時(shí)延有了明確的上界,不會(huì)被其他非核心業(yè)務(wù)影響,完美滿足硬實(shí)時(shí)需求。
極簡(jiǎn)內(nèi)核,資源開(kāi)銷(xiāo)極低
很多人誤以為 “RTOS 占資源多,小 MCU 跑不了”,但事實(shí)是,主流 RTOS 的最小內(nèi)核,ROM 占用僅 1~3KB,RAM 占用僅幾百字節(jié),哪怕是 8 位 MCU、Cortex-M0 + 這類極簡(jiǎn)內(nèi)核的芯片,都能輕松跑起來(lái)。真正的資源開(kāi)銷(xiāo),從來(lái)不是內(nèi)核,而是任務(wù)棧、協(xié)議棧和業(yè)務(wù)組件。
信號(hào)量、消息隊(duì)列、事件組、互斥鎖…… 這些內(nèi)核原生的線程安全的通信同步機(jī)制,幫我們徹底解決了 “中斷與主循環(huán)數(shù)據(jù)交互、多模塊間同步、共享資源競(jìng)態(tài)” 的問(wèn)題,不用再自己造輪子,更不用踩 “標(biāo)志位亂跳、緩沖區(qū)覆蓋” 的裸機(jī)常見(jiàn)坑。
RTOS 天然支持按業(yè)務(wù)模塊拆分獨(dú)立任務(wù),每個(gè)任務(wù)有自己的上下文和執(zhí)行邏輯,模塊間僅通過(guò)標(biāo)準(zhǔn)化接口通信,耦合度極低。加新功能就加新任務(wù),不用重構(gòu)原有代碼,多人協(xié)作開(kāi)發(fā)、后期迭代維護(hù)的效率,會(huì)比裸機(jī)高出一個(gè)量級(jí)。很多工程師做選型的時(shí)候,全憑感覺(jué)和經(jīng)驗(yàn),拍腦袋就定了用不用 RTOS,結(jié)果項(xiàng)目做到一半才發(fā)現(xiàn)選錯(cuò)了,進(jìn)退兩難。在做決策之前,你必須先想清楚這 3 個(gè)問(wèn)題,才能做出最適合項(xiàng)目的選擇。問(wèn)題 1:你的系統(tǒng),要的是 “實(shí)時(shí)性”,還是 “并發(fā)”?
這是最核心的問(wèn)題,很多人都把這兩個(gè)概念搞混了。RTOS 的不可替代性,在于硬實(shí)時(shí)性,也就是 “響應(yīng)時(shí)延的確定性”,它能保證你的關(guān)鍵任務(wù),在規(guī)定的時(shí)間內(nèi)一定能得到執(zhí)行。如果你的系統(tǒng),只是需要 “同時(shí)做多件事”,但對(duì)時(shí)延沒(méi)有硬要求,比如只是同時(shí)采集傳感器、刷新屏幕、發(fā)串口數(shù)據(jù),哪怕延遲個(gè)幾百 ms,也不會(huì)影響系統(tǒng)功能,那裸機(jī)的狀態(tài)機(jī)、分時(shí)輪詢,完全可以滿足需求,不是必須上 RTOS。只有當(dāng)你的系統(tǒng),對(duì)任務(wù)的響應(yīng)時(shí)延、執(zhí)行周期有明確的硬要求,超時(shí)就會(huì)出問(wèn)題,RTOS 才是剛需。問(wèn)題 2:你的硬件資源,能不能扛住 RTOS 的全鏈路開(kāi)銷(xiāo)?
很多人只看 RTOS 內(nèi)核的開(kāi)銷(xiāo),覺(jué)得 “內(nèi)核只占幾 KB,我的 MCU 完全夠用”,但忽略了全鏈路的資源開(kāi)銷(xiāo)。RTOS 的真正資源占用,包括這幾個(gè)部分:內(nèi)核本身的 ROM、RAM 開(kāi)銷(xiāo);每個(gè)任務(wù)的獨(dú)立棧空間開(kāi)銷(xiāo)(比如 10 個(gè)任務(wù),每個(gè)棧 128 字節(jié),光棧空間就占了 1.25KB RAM);消息隊(duì)列、信號(hào)量、互斥鎖等內(nèi)核對(duì)象的 RAM 開(kāi)銷(xiāo);基于 RTOS 移植的協(xié)議棧、組件庫(kù)的資源開(kāi)銷(xiāo)。做選型的時(shí)候,必須把這些開(kāi)銷(xiāo)全部算進(jìn)去,給 MCU 的 ROM 和 RAM 留足余量。別選了個(gè) RAM 只有 2KB 的 MCU,結(jié)果光 RTOS 和任務(wù)棧就占滿了,業(yè)務(wù)代碼根本跑不起來(lái),最后只能換芯片,耽誤項(xiàng)目進(jìn)度。這里給一個(gè)通用的參考閾值,僅跑 RTOS 最小內(nèi)核:Cortex-M0 + 及以上,ROM≥8KB,RAM≥2KB;跑 RTOS + 常用組件(文件系統(tǒng)、GUI、協(xié)議棧):Cortex-M3 及以上,ROM≥32KB,RAM≥8KB。問(wèn)題 3:團(tuán)隊(duì)能不能 hold 住 RTOS 帶來(lái)的復(fù)雜度?
RTOS 不是 “銀彈”,它解決了裸機(jī)的問(wèn)題,也帶來(lái)了新的復(fù)雜度和風(fēng)險(xiǎn)。任務(wù)優(yōu)先級(jí)分配不當(dāng),會(huì)導(dǎo)致系統(tǒng)饑餓、低優(yōu)先級(jí)任務(wù)長(zhǎng)期得不到執(zhí)行;互斥鎖使用不當(dāng),會(huì)導(dǎo)致死鎖,整個(gè)系統(tǒng)卡死;沒(méi)有處理好優(yōu)先級(jí)反轉(zhuǎn),會(huì)導(dǎo)致硬實(shí)時(shí)任務(wù)時(shí)延超標(biāo);任務(wù)棧分配不足,會(huì)導(dǎo)致棧溢出,系統(tǒng)跑飛;多任務(wù)訪問(wèn)共享資源,沒(méi)有做好保護(hù),會(huì)出現(xiàn)競(jìng)態(tài)問(wèn)題,數(shù)據(jù)錯(cuò)亂……這些問(wèn)題,都需要團(tuán)隊(duì)有足夠的 RTOS 開(kāi)發(fā)經(jīng)驗(yàn)和調(diào)試能力,才能提前規(guī)避、快速定位。如果團(tuán)隊(duì)沒(méi)有相關(guān)的技術(shù)積累,就必須提前做好技術(shù)儲(chǔ)備,比如先做 demo 驗(yàn)證、組織技術(shù)培訓(xùn)、學(xué)習(xí)內(nèi)核原理和調(diào)試方法,別等到項(xiàng)目中期才踩坑,進(jìn)退兩難。講透了本質(zhì),我們就可以直接給出結(jié)論:當(dāng)你的項(xiàng)目出現(xiàn)以下任意一種場(chǎng)景,引入 RTOS 就是性價(jià)比最高、甚至是唯一可行的方案。場(chǎng)景 1:系統(tǒng)存在硬實(shí)時(shí)需求,對(duì)響應(yīng)時(shí)延有明確的上界
要求這是 RTOS 最不可替代的核心場(chǎng)景,也是裸機(jī)無(wú)論怎么優(yōu)化都無(wú)法突破的天生瓶頸。什么是硬實(shí)時(shí)?就是系統(tǒng)的關(guān)鍵任務(wù),必須在確定的時(shí)間內(nèi)完成響應(yīng)和執(zhí)行,一旦超時(shí),就會(huì)導(dǎo)致系統(tǒng)故障、財(cái)產(chǎn)損失甚至安全事故。舉幾個(gè)最常見(jiàn)的例子,工業(yè)控制場(chǎng)景,電機(jī) FOC 矢量控制,要求 100us 內(nèi)必須完成電流采樣、環(huán)路計(jì)算、PWM 輸出,錯(cuò)過(guò)一個(gè)周期就會(huì)導(dǎo)致電機(jī)失步、設(shè)備失控;汽車(chē)電子場(chǎng)景,車(chē)身穩(wěn)定控制、剎車(chē)輔助系統(tǒng),要求 ms 級(jí)甚至 us 級(jí)的響應(yīng)時(shí)延,超時(shí)直接關(guān)乎行車(chē)安全;通信場(chǎng)景,工業(yè)總線協(xié)議(CANopen、EtherCAT)、實(shí)時(shí)數(shù)據(jù)傳輸,必須在固定周期內(nèi)完成數(shù)據(jù)收發(fā)和解析,否則就會(huì)丟幀、總線出錯(cuò)。這種場(chǎng)景下,裸機(jī)完全無(wú)解。復(fù)雜的算法計(jì)算會(huì)拉長(zhǎng)中斷執(zhí)行時(shí)間,導(dǎo)致其他中斷被阻塞,關(guān)中斷時(shí)長(zhǎng)超標(biāo),系統(tǒng)穩(wěn)定性直接崩塌;你把它放進(jìn)主循環(huán)?主循環(huán)里一個(gè)串口打印、Flash 寫(xiě)操作,就可能帶來(lái)幾十 ms 的阻塞,直接錯(cuò)過(guò)控制周期。而 RTOS 的搶占式調(diào)度,完美解決這個(gè)問(wèn)題,把硬實(shí)時(shí)任務(wù)設(shè)為最高優(yōu)先級(jí),只要它的就緒條件滿足(比如定時(shí)周期到、中斷觸發(fā)),就能立刻搶占 CPU,無(wú)論低優(yōu)先級(jí)任務(wù)在執(zhí)行什么,都能保證關(guān)鍵任務(wù)的時(shí)延確定性。場(chǎng)景 2:業(yè)務(wù)邏輯復(fù)雜,多模塊并行,裸機(jī)狀態(tài)機(jī)已經(jīng)維護(hù)不動(dòng)了
這是我們?nèi)粘i_(kāi)發(fā)中最常遇到的場(chǎng)景,也是很多工程師從裸機(jī)轉(zhuǎn)向 RTOS 的核心原因。嵌入式項(xiàng)目的特點(diǎn),就是需求永遠(yuǎn)在變。一開(kāi)始,項(xiàng)目可能只是個(gè)簡(jiǎn)單的傳感器采集,幾十行裸機(jī)代碼就搞定了;但隨著需求迭代,你要加藍(lán)牙 / BLE 通信、OLED/LCD 人機(jī)交互、按鍵處理、數(shù)據(jù) Flash 存儲(chǔ)、低功耗管理、OTA 升級(jí)、云平臺(tái)對(duì)接……當(dāng)系統(tǒng)的并行模塊超過(guò) 3 個(gè),裸機(jī)的弊端就會(huì)徹底爆發(fā),主循環(huán)里塞滿了各個(gè)模塊的狀態(tài)機(jī),標(biāo)志位滿天飛,耦合度極高,改一個(gè)模塊的邏輯,可能影響其他所有模塊;各個(gè)模塊的執(zhí)行周期、耗時(shí)完全不同,很容易出現(xiàn) “一個(gè)模塊阻塞,整個(gè)系統(tǒng)卡頓” 的問(wèn)題,比如寫(xiě) Flash 導(dǎo)致按鍵響應(yīng)延遲、刷新屏幕導(dǎo)致傳感器采集丟數(shù);代碼可維護(hù)性極差,新人接手項(xiàng)目,光理清楚主循環(huán)的執(zhí)行邏輯、標(biāo)志位的含義,就要花一周時(shí)間,更別說(shuō)迭代開(kāi)發(fā)了。而 RTOS 的任務(wù)化設(shè)計(jì),就是這套亂局的最優(yōu)解。你可以把傳感器采集、通信協(xié)議、人機(jī)交互、存儲(chǔ)管理,每個(gè)模塊拆成一個(gè)獨(dú)立的任務(wù),每個(gè)任務(wù)有自己的執(zhí)行循環(huán)和優(yōu)先級(jí),模塊間通過(guò)消息隊(duì)列通信,邊界清晰,耦合度極低。加新功能,就新增一個(gè)任務(wù),幾乎不用改動(dòng)原有代碼;多人協(xié)作,每個(gè)人負(fù)責(zé)自己的任務(wù)模塊,不會(huì)出現(xiàn)代碼沖突、互相影響的問(wèn)題。場(chǎng)景 3:大量異步事件需要處理,中斷與應(yīng)用層的交互極其復(fù)雜
嵌入式系統(tǒng)的核心,就是處理各種異步事件,串口接收、CAN 總線數(shù)據(jù)、傳感器中斷、DMA 傳輸完成中斷、GPIO 外部中斷…… 事件越多,裸機(jī)的處理方式就越捉襟見(jiàn)肘。裸機(jī)處理異步事件的標(biāo)準(zhǔn)流程,是 “中斷里置標(biāo)志位,主循環(huán)里輪詢標(biāo)志位處理”。但當(dāng)事件源多了,問(wèn)題就來(lái)了,標(biāo)志位數(shù)量爆炸,管理難度指數(shù)級(jí)上升,很容易出現(xiàn)漏處理、重復(fù)處理的問(wèn)題;事件處理的優(yōu)先級(jí)無(wú)法控制,主循環(huán)里先輪詢誰(shuí),誰(shuí)就先處理,哪怕后輪詢的是緊急事件,也只能排隊(duì);中斷和主循環(huán)之間的數(shù)據(jù)傳遞,只能靠全局緩沖區(qū),沒(méi)有線程安全保障,很容易出現(xiàn)數(shù)據(jù)覆蓋、競(jìng)態(tài)問(wèn)題,排查起來(lái)極其困難;中斷服務(wù)程序里只能做極簡(jiǎn)操作,不能執(zhí)行耗時(shí)邏輯、不能調(diào)用非重入函數(shù),復(fù)雜的事件處理根本沒(méi)法在中斷里完成。RTOS 則給出了工業(yè)界驗(yàn)證了幾十年的標(biāo)準(zhǔn)解法,中斷服務(wù)程序只做最核心的觸發(fā)操作,所有業(yè)務(wù)處理全部放在任務(wù)上下文。比如 CAN 總線收到了緊急控制指令,ISR 里只需要做兩件事,把收到的數(shù)據(jù)放進(jìn)消息隊(duì)列,發(fā)送信號(hào)量喚醒對(duì)應(yīng)的高優(yōu)先級(jí)處理任務(wù),然后立刻退出中斷。后續(xù)的協(xié)議解析、邏輯執(zhí)行,全部在任務(wù)里完成。這套方案的優(yōu)勢(shì)極其明顯:中斷執(zhí)行時(shí)間極短,不會(huì)阻塞其他中斷,保證了系統(tǒng)的中斷響應(yīng)能力;不同事件的處理任務(wù),可以設(shè)置不同的優(yōu)先級(jí),緊急事件優(yōu)先處理,完全符合業(yè)務(wù)需求;消息隊(duì)列、信號(hào)量等 IPC 機(jī)制,原生保證線程安全,不用自己處理競(jìng)態(tài)問(wèn)題,數(shù)據(jù)傳遞穩(wěn)定可靠。場(chǎng)景 4:需要使用成熟的協(xié)議棧、組件庫(kù),而它們強(qiáng)依賴
RTOS現(xiàn)在的嵌入式開(kāi)發(fā),早已不是 “從零寫(xiě)所有代碼” 的時(shí)代了。成熟的協(xié)議棧、組件庫(kù),能幫我們節(jié)省 90% 的開(kāi)發(fā)時(shí)間,而這些工業(yè)級(jí)的組件,絕大多數(shù)都是基于 RTOS 設(shè)計(jì)和適配的。舉幾個(gè)最常見(jiàn)的例子,網(wǎng)絡(luò)相關(guān),TCP/IP 協(xié)議棧(LwIP)、MQTT/HTTP 物聯(lián)網(wǎng)協(xié)議、Wi-Fi 驅(qū)動(dòng)及協(xié)議棧;工業(yè)總線:Modbus 主從站、CANopen、Profinet、EtherCAT 協(xié)議棧;外設(shè)相關(guān),USB Host/Device 協(xié)議棧、SD 卡文件系統(tǒng)(FatFS);人機(jī)交互,LVGL、emWin 等 GUI 圖形庫(kù);通用組件,OTA 升級(jí)框架、加密安全組件、云平臺(tái)設(shè)備 SDK(阿里云、騰訊云、華為云)。這些組件,大多是多線程架構(gòu)設(shè)計(jì),強(qiáng)依賴 RTOS 的任務(wù)調(diào)度、延時(shí)管理、IPC 通信機(jī)制。如果你非要用裸機(jī)跑,只有兩個(gè)選擇,要么花大量的時(shí)間和精力,把多線程邏輯改成裸機(jī)狀態(tài)機(jī),費(fèi)時(shí)費(fèi)力,還很容易改出 bug,穩(wěn)定性完全沒(méi)法保障;要么只能用閹割版的組件,很多功能沒(méi)法用,性能大打折扣。而引入 RTOS,這些組件幾乎可以無(wú)縫移植,配好優(yōu)先級(jí)和內(nèi)存,就能直接跑起來(lái)。不僅大大縮短了開(kāi)發(fā)周期,還能直接用上工業(yè)級(jí)的成熟方案,比自己寫(xiě)的代碼穩(wěn)定得多。場(chǎng)景 5:低功耗需求與實(shí)時(shí)響應(yīng),需要同時(shí)兼顧
現(xiàn)在絕大多數(shù)電池供電的嵌入式設(shè)備,比如物聯(lián)網(wǎng)終端、穿戴設(shè)備、工業(yè)無(wú)線傳感器,都有一個(gè)核心需求,既要極致的低功耗,最大化電池續(xù)航,又要能快速響應(yīng)外部事件和定時(shí)任務(wù)。裸機(jī)做低功耗,通常是在主循環(huán)的末尾進(jìn)入睡眠模式,靠中斷喚醒。但這套方案,在多任務(wù)、多周期的場(chǎng)景下,幾乎是無(wú)解的,主循環(huán)里每個(gè)模塊的執(zhí)行時(shí)間不確定,沒(méi)法精準(zhǔn)控制睡眠時(shí)長(zhǎng),要么頻繁喚醒,功耗降不下來(lái);要么睡眠太久,錯(cuò)過(guò)定時(shí)任務(wù)的執(zhí)行周期;多個(gè)不同周期的任務(wù),比如 10ms 執(zhí)行一次的傳感器采集、1s 執(zhí)行一次的數(shù)據(jù)上報(bào)、1 分鐘執(zhí)行一次的狀態(tài)刷新,裸機(jī)很難精準(zhǔn)調(diào)度,只能按最短的周期喚醒,造成大量的無(wú)效喚醒,功耗浪費(fèi)嚴(yán)重;睡眠模式的進(jìn)出和業(yè)務(wù)邏輯強(qiáng)耦合,改一個(gè)模塊的執(zhí)行周期,就要重寫(xiě)整個(gè)低功耗邏輯。而 RTOS 原生的 Tickless 低功耗模式,完美解決了這個(gè)問(wèn)題。內(nèi)核會(huì)自動(dòng)統(tǒng)計(jì)所有任務(wù)的就緒時(shí)間,計(jì)算出系統(tǒng)可以睡眠的最大時(shí)長(zhǎng),直接進(jìn)入對(duì)應(yīng)深度的睡眠模式,直到最近的任務(wù)需要喚醒,或者外部中斷觸發(fā),才會(huì)退出睡眠。這套機(jī)制,既保證了所有任務(wù)的執(zhí)行周期精準(zhǔn)無(wú)誤,又最大化了系統(tǒng)的睡眠時(shí)長(zhǎng),把功耗降到了極致。同時(shí),外部中斷可以隨時(shí)喚醒系統(tǒng),喚醒后高優(yōu)先級(jí)任務(wù)立刻執(zhí)行,完全兼顧了低功耗和實(shí)時(shí)響應(yīng)。場(chǎng)景 6:團(tuán)隊(duì)多人協(xié)作開(kāi)發(fā),需要清晰的模塊邊界和開(kāi)發(fā)規(guī)范
現(xiàn)在的嵌入式項(xiàng)目,早已不是 “一個(gè)工程師包打天下” 的時(shí)代了。稍復(fù)雜的項(xiàng)目,都會(huì)有多人分工:有人寫(xiě)底層驅(qū)動(dòng),有人寫(xiě)硬件控制邏輯,有人寫(xiě)通信協(xié)議,有人寫(xiě)人機(jī)交互,有人寫(xiě)業(yè)務(wù)應(yīng)用。裸機(jī)開(kāi)發(fā),在多人協(xié)作的場(chǎng)景下,簡(jiǎn)直是災(zāi)難。所有代碼都塞在一個(gè)主循環(huán)里,模塊之間沒(méi)有清晰的邊界,全局變量滿天飛,很容易出現(xiàn)兩個(gè)人改了同一段代碼,出現(xiàn)嚴(yán)重的代碼沖突;一個(gè)人改了一個(gè)全局變量,導(dǎo)致另一個(gè)人的模塊出現(xiàn)莫名其妙的 bug;模塊之間互相調(diào)用,耦合度拉滿,一個(gè)模塊出問(wèn)題,整個(gè)系統(tǒng)都崩了。而 RTOS 的任務(wù)化架構(gòu),天然就給團(tuán)隊(duì)協(xié)作劃定了清晰的邊界。我們可以提前做架構(gòu)設(shè)計(jì),拆分好業(yè)務(wù)模塊,給每個(gè)模塊分配獨(dú)立的任務(wù),定義好模塊間的通信接口和數(shù)據(jù)格式。開(kāi)發(fā)人員只需要負(fù)責(zé)自己的任務(wù)模塊,只要接口不變,內(nèi)部邏輯怎么改,都不會(huì)影響其他模塊。不僅開(kāi)發(fā)效率大大提升,代碼的可測(cè)試性、可維護(hù)性也有了質(zhì)的飛躍。每個(gè)任務(wù)可以單獨(dú)做單元測(cè)試,出了問(wèn)題,也能快速定位到對(duì)應(yīng)的模塊和責(zé)任人,大大降低了調(diào)試和維護(hù)的成本。講完了必須上的場(chǎng)景,我們也要客觀地講清楚RTOS 不是萬(wàn)能的,更不是 “越用越高級(jí)”。在很多場(chǎng)景下,引入 RTOS 反而會(huì)畫(huà)蛇添足,增加不必要的復(fù)雜度和成本。場(chǎng)景 1:極簡(jiǎn)邏輯的單功能項(xiàng)目,硬件資源極度受限
如果你的項(xiàng)目,只是一個(gè)極簡(jiǎn)的單功能應(yīng)用,代碼量只有幾百行,邏輯固定,沒(méi)有多模塊并行,沒(méi)有實(shí)時(shí)性要求,比如LED 呼吸燈、繼電器延時(shí)控制、單傳感器閾值報(bào)警、簡(jiǎn)單的 IO 口檢測(cè)輸出。同時(shí),硬件選型也極度受限,比如用的是 8 位 MCU,ROM 只有幾 KB,RAM 只有幾百字節(jié),成本壓到了極致。這種場(chǎng)景,裸機(jī)幾行代碼就能完美搞定,引入 RTOS 反而會(huì)增加內(nèi)核開(kāi)銷(xiāo),占用本就緊張的硬件資源,還增加了代碼復(fù)雜度,完全是殺雞焉用牛刀。場(chǎng)景 2:對(duì)代碼量、執(zhí)行效率有極致要求,且邏輯長(zhǎng)期不變
有兩類項(xiàng)目,裸機(jī)的優(yōu)勢(shì)是 RTOS 無(wú)法替代的,一類是成本極度敏感的消費(fèi)類量產(chǎn)產(chǎn)品,MCU 的選型已經(jīng)壓到了極致,每 1KB 的 ROM、每 1 字節(jié)的 RAM,都和產(chǎn)品成本直接掛鉤。裸機(jī)的代碼量最小,沒(méi)有內(nèi)核調(diào)度的開(kāi)銷(xiāo),能最大化利用有限的硬件資源,把 BOM 成本壓到最低。另一類是專用的、邏輯固定的嵌入式設(shè)備,比如專用的電源管理芯片、信號(hào)解碼芯片、固定邏輯的工業(yè)控制器,產(chǎn)品一旦量產(chǎn),邏輯一輩子都不會(huì)改,需要的是極致的執(zhí)行效率和穩(wěn)定性。裸機(jī)沒(méi)有任務(wù)調(diào)度的開(kāi)銷(xiāo),執(zhí)行路徑完全可控,不會(huì)出現(xiàn)系統(tǒng)調(diào)度帶來(lái)的抖動(dòng),執(zhí)行效率和確定性反而比 RTOS 更高。場(chǎng)景 3:團(tuán)隊(duì)無(wú) RTOS 技術(shù)積累,項(xiàng)目周期極短,無(wú)容錯(cuò)空間
RTOS 雖然能解決很多裸機(jī)的痛點(diǎn),但它本身也帶來(lái)了新的技術(shù)門(mén)檻和坑點(diǎn),任務(wù)優(yōu)先級(jí)怎么分配才合理?怎么避免死鎖和優(yōu)先級(jí)反轉(zhuǎn)?怎么排查棧溢出?怎么保證共享資源的線程安全?這些問(wèn)題,沒(méi)有足夠的 RTOS 開(kāi)發(fā)經(jīng)驗(yàn),很容易踩坑,而且很多坑是隱性的,比如棧溢出、競(jìng)態(tài)問(wèn)題,可能測(cè)試的時(shí)候沒(méi)問(wèn)題,量產(chǎn)后大批量出問(wèn)題,造成災(zāi)難性的后果。如果你的團(tuán)隊(duì),所有人都只熟悉裸機(jī)開(kāi)發(fā),完全沒(méi)有 RTOS 的技術(shù)積累和項(xiàng)目經(jīng)驗(yàn),而項(xiàng)目周期又極短,要求 3 個(gè)月內(nèi)必須量產(chǎn)上線,沒(méi)有時(shí)間做技術(shù)預(yù)研和驗(yàn)證。這種場(chǎng)景,盲目上 RTOS,大概率會(huì)因?yàn)椴瓤訉?dǎo)致項(xiàng)目延期,甚至交付失敗。這種情況,要么提前安排技術(shù)預(yù)研,要么老老實(shí)實(shí)基于裸機(jī)做狀態(tài)機(jī)優(yōu)化,別為了 “技術(shù)升級(jí)” 而冒項(xiàng)目失敗的風(fēng)險(xiǎn)。說(shuō)到底,RTOS 從來(lái)不是衡量嵌入式工程師水平的標(biāo)尺,也不是項(xiàng)目 “高大上” 的標(biāo)志,它只是一個(gè)工具,一個(gè)解決嵌入式系統(tǒng) “實(shí)時(shí)性、并發(fā)性、可維護(hù)性” 痛點(diǎn)的工程方案。
什么時(shí)候該上 RTOS?答案很簡(jiǎn)單,當(dāng)你的項(xiàng)目需求,裸機(jī)已經(jīng)無(wú)法低成本、高可靠、高效率地滿足的時(shí)候,就是引入 RTOS 的最佳時(shí)機(jī)。
不要為了不用而不用,硬扛著寫(xiě) “標(biāo)志位地獄” 和 “超級(jí)狀態(tài)機(jī)”,把自己熬得心力交瘁;也不要為了用而用,盲目上系統(tǒng),帶來(lái)一堆不必要的復(fù)雜度和風(fēng)險(xiǎn)。
技術(shù)的本質(zhì),永遠(yuǎn)是解決問(wèn)題,而不是制造問(wèn)題。