揭毅
(德賽工業(yè)研究院,惠州 516000)
在MCU系統(tǒng)程序設計中,常常遇到測試工程師反映我們的按鍵反應不靈敏,或是系統(tǒng)對外部的信號響應慢,實時性差。如果不是程序模塊設計問題,那我們就要考慮系統(tǒng)程序設計上的實時性問題了。但是如果僅僅在系統(tǒng)程序設計上片面地考慮實時性問題,而忽略了任務均衡性問題,那么系統(tǒng)又可能出現(xiàn)有的模塊程序響應快、有的模塊程序反應慢的問題。為了解決這些問題,下面就我在車載娛樂系統(tǒng)程序設計工作中的經(jīng)驗與大家聊聊。
實時性很容易被多數(shù)人誤認為就是“快”的意思。其實,“快”只是實時性的一個特征,而且是相對的——是相對于任務需求而言的。
無論你的個人電腦是采用了何種“奔X”CPU,也無論該CPU的主頻是幾個G,只要你安裝的是XP操作系統(tǒng),那么它就是一個非實時系統(tǒng)。相反,一個8位的MCU,哪怕主頻只有4MHz,也可以構成一個實時系統(tǒng)。
實時或是非實時,與CPU的速度并無直接關系,而完全取決于操作系統(tǒng)或程序架構。眾所周知,操作系統(tǒng)(OS)主要包括三大組成部分:進程調(diào)度、內(nèi)存管理和文件系統(tǒng)。其中,進程調(diào)度決定了系統(tǒng)的實時性。
實時系統(tǒng)的本質(zhì)特征在于:所有任務的響應時間和執(zhí)行時間都是可以根據(jù)各任務的需求進行設計,并且事先就能被預知。在一個實時系統(tǒng)上,我們可以根據(jù)需求分析的結(jié)果,對各個任務進行合理的、滿足要求的“實時性”設計,使得最終完成的程序能夠按照預定規(guī)則運行,并達到各種實時性指標的要求?;谶@種定位,我認為在程序設計時,不頻繁使用“計算器”的工程師通常不會有“實時性”的概念,這種工程師設計出的系統(tǒng)也很難講是實時系統(tǒng),至少,實時性指標是不能足以保證的。至此,大家應該可以理解我為何經(jīng)常會問一些同事:你有無購買計算器?微軟的工程師編程時無需使用計算器——因為他們設計的是非實時系統(tǒng),但我們卻需要——因為我們設計的是實時系統(tǒng)。區(qū)別就在于此!
在單片機系統(tǒng)中,很多情況下是不使用OS的。實際上,在沒有OS的多任務系統(tǒng)中,進程調(diào)度的工作是由應用軟件工程師自身編制程序來實現(xiàn)的。那么,自身編制的進程調(diào)度系統(tǒng)是否一定就是實時系統(tǒng)呢?我的回答是:不一定!關鍵在于你如何設計進程調(diào)度程序和如何合理安排各種任務。
如果你設計出的系統(tǒng)是非實時的,而實際各個任務的需求又是實時的,那么,系統(tǒng)就一定會存在問題。特別是在“任務并發(fā)”時,程序一定會出問題,甚至出現(xiàn)一些稀奇古怪的現(xiàn)象。
我經(jīng)常聽到軟件部的兄弟抱怨:MCU的速度不夠快;內(nèi)存沖突;需要提高主頻等等。
實際上,大家可以測試一下我們目前系統(tǒng)程序中MCU的平均運行效率。我可以肯定地說,在我們目前的系統(tǒng)中,MCU的平均運行效率絕沒有超過60%,很可能為20%~30%,甚至在10%左右。由于MCU的主振蕩器一直在工作,它的ALU一刻也不會停止運行,那么,它在干什么呢?實際上,MCU在反復執(zhí)行著一個沒有任何實際任務的“死循環(huán)”,等待中斷和時隙的到來——在絕大部分時間,MCU被閑置。
工程師所抱怨的速度不夠,通常是指在任務并發(fā)時,發(fā)生消息丟失、內(nèi)存/堆棧溢出或任務執(zhí)行被延遲等現(xiàn)象。
通常,單片機系統(tǒng)是一個多任務系統(tǒng)。這里的多任務總是表現(xiàn)為“多功能”,而非“高性能”。否則,我們就不會選擇采用MCU,尤其是8位MCU——因為8位MCU的性能總是不會太高的。基于MCU的這種低性能,通常不會將其用于大流量信號的處理,而是只作控制用??刂祁愋盘柕奶幚聿煌诖罅髁啃盘柕奶幚?,它僅需占用極少的ALU資源。
對于上面講到的這種“忙的時候忙不過來,閑的時候閑得要命”的情況,就引出了“任務均衡”的問題。任務均衡性設計,是任何實時嵌入式系統(tǒng)設計的關鍵工作之一。
在與軟件工程師討論一些程序設計細節(jié)時,發(fā)現(xiàn)我們的工程師們總是追求“快”。其實,如果每個任務的處理都要“快”,而且是無量綱的“快”,那么任務均衡性問題也就無從談起了。進行任務均衡性設計的實質(zhì)是:讓真正需要快速處理的任務快起來,讓無需快速處理的任務慢下來,最終達到任務均衡的目的,從而提高MCU的使用效率。這里的“慢”就是為了“快”,沒有“慢”也就沒有“快”。
無論是處理“快”的任務,還是處理“慢”的任務,都需要滿足系統(tǒng)性能的要求,否則所實現(xiàn)的系統(tǒng)就是一個不合格的系統(tǒng),或是一個不健康的系統(tǒng)。因此,在需求分析和程序架構設計階段,對各個任務的時間指標作出恰當?shù)姆治龊秃侠淼亩x就顯得非常重要。下面我舉幾個例子來說明。
根據(jù)人的反應速度和操作特點,對于儀表類設備,按鍵的捕獲時間在30~50ms左右已經(jīng)足夠。如果一味地追求“快”,不僅浪費系統(tǒng)資源,而且還會對鍵抖性能要求過高。一般,我們會設計一個20ms的鍵掃描周期,用兩次鍵掃值進行按鍵消抖,那么鍵捕獲時間不會超過40 ms——你會發(fā)現(xiàn)此時的按鍵操作已經(jīng)很靈敏了。在任務比較繁重的系統(tǒng)中,我們還可以將鍵捕獲和鍵響應的處理節(jié)拍區(qū)分開來。通常,鍵響應時間只要能保持在100~200ms以內(nèi),已經(jīng)不會使人感受到慢,有時這種延遲反而會給人更舒適的感受。
但是,對于旋轉(zhuǎn)編碼器這類器件,雖然我們可以將其歸并為“鍵輸入”范疇,但是它的脈沖寬度是比較窄的(可能會到幾百個μs),建議采用中斷的方式加以捕捉。但是,必須充分注意的是,檢測速度快,并不意味著接收脈沖的速度也需要快;否則,在測試者高速旋轉(zhuǎn)編碼器時,會產(chǎn)生頻繁中斷,很可能會影響到其他任務的實時性。實際上,我們接收的旋轉(zhuǎn)脈沖是用于數(shù)值增減和顯示Level的,每100ms跳動一格已經(jīng)是“目不暇接”了。因此,每中斷一次時,最好能將該中斷關閉,然后再在100ms時隙中將該中斷打開。
我們都清楚,通信接收的響應速度都是要求很高的,通常都是用中斷來進行接收處理。但是,一個完整報文(幀)的解析就不需要處理得很快了,完全可以安排在一個相對空閑的時隙中進行處理,而無需在中斷服務程序中加以處理。中斷服務程序執(zhí)行時間的加長,將帶來整個系統(tǒng)性能的下降。
ACC——對“下升沿”的響應,要盡量地快(500μs以內(nèi)),最好使用優(yōu)先級最高的中斷。因為,它需要應用于快速Mute,否則易產(chǎn)生點火POP-NOISE。但是,對“上降沿”的響應,就無需那么快,500ms就已滿足要求。
Parking——只要求檢測高低電平,而無需檢測邊沿,100ms的掃描周期已經(jīng)足夠。
Illuminance——只要求檢測高低電平,而無需檢測邊沿。由于部分車輛采用了PWM調(diào)光,PWM的頻率也沒有統(tǒng)一標準,建議硬件上采用檢波電路,以減小對MCU資源的占用。在采用硬件檢波電路以后,軟件的檢測掃描周期為100ms就已足夠。
Tele-Mute——只要求檢測高低電平,而無需檢測邊沿。100ms的掃描檢測周期已經(jīng)足夠。
Reverse——同Tele-Mute。
下面介紹一種在無OS環(huán)境下,實現(xiàn)實時性和任務均衡性的設計方法。
首先介紹一下“時隙”的概念,時隙的英文叫法是“Time slot”,也就是“時間間隙”的意思。我們通常會選擇一個基本時隙去掃描并執(zhí)行任務,有些任務每個基本時隙都去掃描,有些任務則無需每個基本時隙都去掃描,而是若干個基本時隙再去掃描一次。用時隙去同步任務的執(zhí)行,用時隙的長短來區(qū)分任務的輕重緩急。
基本時隙用定時器中斷來產(chǎn)生,其他時隙用基本時隙的整數(shù)倍來產(chǎn)生,并盡量在中斷服務程序中實現(xiàn)。時隙定時器是最重要的系統(tǒng)定時器,不僅要保持它的準確性,還需盡量簡潔,使其保持最高效運行。
基本時隙的設計最為重要,它與其他各時隙的設計都須根據(jù)實際系統(tǒng)的要求來進行?;緯r隙的長度決定了任務的最快掃描周期,從實時性要求來講,很顯然是越短越好。但是,基本時隙的過短將會對整個軟件系統(tǒng)的架構和性能產(chǎn)生重大不利影響,限制系統(tǒng)整體性能的發(fā)揮。
基本時隙的選擇原則是,在滿足實時性要求的前提下,盡量長一些。對于個別需要更快響應速度的激勵,采用中斷的方式來響應。
這里已經(jīng)引發(fā)了程序架構設計中的一個矛盾,即:基本時隙盡量長,盡量少開中斷,中斷服務程序盡量短。其實,這完全符合技術的特點,需要全方位地綜合考慮。選擇不是唯一性的,但是,對一個具體的系統(tǒng),最佳方案可能只有一個。
以上是筆者對實時性和任務均衡性程序設計上的一些看法。基于以上方法來編寫MCU程序可以大大提高程序的運行效率和系統(tǒng)實時性,改善任務的均衡性,并減少程序異常運行等問題的發(fā)生。