什么是嵌入式系統?
嵌入式系統(Embedded system),是一種“完全嵌入受控器件內部,為特定應用而設計的專(zhuān)用計算機系統”,根據英國電氣工程師協(xié)會(huì )( U.K. Institution of Electrical Engineer)的定義,嵌入式系統為控制、監視或輔助設備、機器或用于工廠(chǎng)運作的設備。與個(gè)人計算機這樣的通用計算機系統不同,嵌入式系統通常執行的是帶有特定要求的預先定義的任務(wù)。由于嵌入式系統只針對一項特殊的任務(wù),設計人員能夠對它進(jìn)行優(yōu)化,減小尺寸降低成本。嵌入式系統通常進(jìn)行大量生產(chǎn),所以單個(gè)的成本節約,能夠隨著(zhù)產(chǎn)量進(jìn)行成百上千的放大。[1] 嵌入式系統是用來(lái)控制或者監視機器、裝置、工廠(chǎng)等大規模設備的系統。國內普遍認同的嵌入式系統定義為:以應用為中心,以計算機技術(shù)為基礎,軟硬件可裁剪,適應應用系統對功能、可靠性、成本、體積、功耗等嚴格要求的專(zhuān)用計算機系統。通常,嵌入式系統是一個(gè)控制程序存儲在ROM中的嵌入式處理器控制板。事實(shí)上,所有帶有數字接口的設備,如手表、微波爐、錄像機、汽車(chē)等,都使用嵌入式系統,有些嵌入式系統還包含操作系統,但大多數嵌入式系統都是由單個(gè)程序實(shí)現整個(gè)控制邏輯。嵌入式系統的核心是由一個(gè)或幾個(gè)預先編程好以用來(lái)執行少數幾項任務(wù)的微處理器或者單片機組成。與通用計算機能夠運行用戶(hù)選擇的軟件不同,嵌入式系統上的軟件通常是暫時(shí)不變的;所以經(jīng)常稱(chēng)為“固件”。
嵌入式系統的主要特點(diǎn):
?。?) 系統內核小
?。?) 專(zhuān)用性強
?。?) 系統精簡(jiǎn)
?。?) 高實(shí)時(shí)性
?。?)多任務(wù)的操作系統
?。?)專(zhuān)門(mén)的開(kāi)發(fā)工具和環(huán)境
那么使用嵌入式軟件遇到的難題有哪些?我們又該如何解決?
當今世界,放眼江湖,有電子的地方就有嵌入式軟件,有電子故障的地方,也就有嵌入式軟件設計缺陷的影子。我們今天就把軟件所容易犯的錯誤和規避的方法一一羅列,并給出應對之法。
嵌入式軟件的最大特點(diǎn)是以控制為主,軟硬結合的較多,功能性的操作較多,模塊相互間調用的較多,外部工作環(huán)境復雜容易受到干擾或干擾別的設備,且執行錯誤的后果不僅僅是數據錯誤而是有可能導致不可估量的災難,所以總結起來(lái),嵌入式軟件可靠性設計需注意的問(wèn)題有四個(gè)方面:
1、軟件接口
先說(shuō)軟件接口中容易出問(wèn)題的地方和編程人員容易犯的錯誤。
軟件接口調用一般會(huì )有數據的賦值,賦值變量的數據類(lèi)型可能會(huì )存在強制的數據轉換;需加以檢查。如果為了防范出問(wèn)題的話(huà),可以添加對數據范圍和數據類(lèi)型的檢查。
賦值數據的數量不對路,多了少了的都不好,會(huì )出現意外的賦值結果,不過(guò)還好,這項錯誤比較好檢查。
軟件編程中,會(huì )有對某一功能操作代碼的復用,比如對某個(gè)端口的數據檢查和控制,在整個(gè)程序中只會(huì )發(fā)生兩次,為了圖省事,可能就直接把該段代碼直接插入實(shí)際程序模塊中去了,這樣,在源程序代碼中,就出現了兩段完全相同,完成相同功能,只是服務(wù)于不同模塊的代碼,按道理來(lái)說(shuō),這樣設計其實(shí)也沒(méi)啥問(wèn)題,是的,你沒(méi)錯,但你的行為會(huì )使別人無(wú)意中犯錯。就像青年男女相處,女孩子純粹是想和男孩子充分享受溫馨的氣氛和心情,并不想更深入的發(fā)生什么,但女孩子邀請男生去的是她的家,在家里換上了家居的睡衣,窗戶(hù)緊閉,放著(zhù)的還是曖昧的音樂(lè ),然后無(wú)限哀怨地說(shuō)“我沒(méi)想到結果會(huì )是這樣的”,那怪得誰(shuí)來(lái)呢?在代碼方面,您的這種做法與貌似引誘男孩上鉤的少女無(wú)異。有人會(huì )說(shuō)了,我這樣寫(xiě)代碼怎么就算引誘呢?原因是程序可能會(huì )升級,您這幾行代碼在實(shí)際應用過(guò)程中也不能保證是盡善盡美的,發(fā)現不完善的地方后,勢必會(huì )修改,如果你還能想得起來(lái),可能不會(huì )遺漏,如果修改此代碼的是別的人,改了一個(gè)地方,別的地方?jīng)]改,是不是還留著(zhù)隱患?那如何做呢?方法不難,把這段功能單獨做成一個(gè)模塊即可,對此端口的讀取和控制賦值均由此獨立模塊完成,如果數據的正確性影響大的話(huà),還需要對端口數據的正確性進(jìn)行檢查和判斷。嵌入式軟件可靠性編程方法的四個(gè)目的是防錯、判錯、糾錯、容錯。對端口數據的判斷屬于判錯的內容,如果數據有錯的話(huà),糾錯和容錯的設計方法應該不用我深入講解了吧?
2、軟硬件接
硬件如男人,對外的執行都靠它來(lái)實(shí)現,一旦出現問(wèn)題,執行后的后果就不可控了,周***說(shuō)過(guò)“外交無(wú)小事”。但如何注意呢?
對讀進(jìn)來(lái)的硬件接口的數據要判斷其真偽;
對輸出的數據的執行效果要檢測;
對輸出的數據的可能后果要進(jìn)行預防性設計,數據輸出的過(guò)程,我們從設計上要做一個(gè)分析,分析的思路是一般容易局限在穩態(tài)過(guò)程,忽視了過(guò)渡過(guò)程。舉例說(shuō)明,比如我們控制一個(gè)支路的供電,從軟件控制來(lái)說(shuō),直接給繼電器一個(gè)啟動(dòng)信號,讓開(kāi)狀態(tài)的觸點(diǎn)閉合就可以了,非“關(guān)”即“開(kāi)”,是受控繼電器的兩個(gè)穩態(tài)狀態(tài),但事實(shí)上,在從開(kāi)到閉合的過(guò)程中,支路供電的電壓并不是一個(gè)簡(jiǎn)單0V—24V(24V為示例而已)的跳變狀態(tài),而是一個(gè)抖動(dòng),有沖擊信號的過(guò)程,這種情況在硬件上的防護是必不可少的,但在軟件上也不是可以事不關(guān)己、高高掛起的。
另外在邏輯上,宜將容易被干擾和容易產(chǎn)生的干擾控制動(dòng)作從時(shí)序上控制好,予以分開(kāi)隔離。比如,控制繼電器的過(guò)程是容易產(chǎn)生抖動(dòng)尖峰脈沖而干擾數據總線(xiàn)和控制信號總線(xiàn)的,這時(shí)候從控制上,不宜同時(shí)實(shí)施數據的發(fā)送和接收工作,不宜作出其他的控制動(dòng)作,惹不起咱躲得起,躲過(guò)這一陣干擾的時(shí)候總可以了吧?
3、軟件代碼
軟件的可靠性是隨著(zhù)時(shí)間的推移,可靠性逐漸增加的,這一點(diǎn)區別于電子可靠性、機械可靠性。電子可靠性服從指數分布,在整個(gè)生命周期內,其失效率為一個(gè)常數;機械可靠性因為磨損、腐蝕、運動(dòng)等因素的存在,隨時(shí)間推移可靠度會(huì )下降。因此也就有了軟件可靠性設計的一個(gè)特定規律和注意事項。
既然需要通過(guò)時(shí)間推移,通過(guò)不斷改進(jìn),軟件可靠性得到提升。那么軟件的可維護性就是一個(gè)大問(wèn)題了。這也是為什么軟件工程管理方面特別關(guān)注軟件文檔、注釋的原因了。但做這些要求的人只是人云亦云,并不理解如此做法的真正動(dòng)機。至于注釋如何去做、變量如何命名、軟件配置管理如何操作,這里面既有很常規的方法,也有一些我們司空見(jiàn)慣然而是錯誤的做法。信手舉上幾個(gè)值得注意的細節供參考。
變量定義時(shí)宜將變量類(lèi)型的變量名程中體現于其中;如AD_result_int、Cal_result_float等。這樣為的好檢查,防止數據類(lèi)型的強制轉換或強制賦值時(shí)出現數據類(lèi)型的錯誤;
注釋要充分;
代碼的布局風(fēng)格宜統一,便于閱讀查找;
不可出現非受控的default流程,所有數值和變量,不論是調用函數時(shí)賦予的、讀取接口讀進(jìn)來(lái)的、還是中間變量計算出來(lái)的,在應用前都宜作數據有效性的判斷,并對判定的所有可能結果均做受控的對應處理。
關(guān)于軟件可維護性編程方法方面的文章資料在網(wǎng)上是鋪天蓋地,不予贅述,綜合采用之即可。很多文章把軟件可維護性編程規范推薦做成企業(yè)的嵌入式軟件可靠性設計規范,實(shí)在是有點(diǎn)以偏概全,有失偏頗的,用一句娛樂(lè )圈的話(huà)來(lái)說(shuō),“愛(ài)情是生活的重要內容,但它不是生活的全部”,軟件可維護性編程方法亦然。
軟件代碼在執行中容易出現的下一個(gè)問(wèn)題是跑飛,程序指針受到干擾,跳轉到了一個(gè)非受控位置,執行了不該執行的代碼。如果執行了不該執行的代碼,如果在程序中加入了足夠的變量判斷、讀值判斷、狀態(tài)檢測判斷等,那倒還好了,后果也不會(huì )太嚴重,甚至最終還是可能自己跑回來(lái)的。但有一種跑飛是比較可怕的,一般我們在ROM中存放的程序目標代碼是1-3字節的指令,就是最多3條字段的目標碼組成了執行動(dòng)作,如果程序指針跑飛到了某個(gè)3字節指令的第2個(gè)字節上的時(shí)候,執行的后果是什么,可就真的沒(méi)人知道了,即使在程序上作了足夠的數據判錯、邏輯跳轉的防范措施,結果也不會(huì )好。而且ROM一般是不可能全部都被程序代碼填滿(mǎn)的,總有富余空間,富余空間中的默認內容是啥,這些默認字節是否也會(huì )導致一些操作呢?單片機中的默認空間是0FFH,DSP的我沒(méi)查過(guò),大家有興趣查一下,跳到這些字段里,也是容易出麻煩的。
好了,不再羅嗦,直接給出解決方法吧,就是每隔一段程序代碼或控制區域,就人為放置上幾個(gè)NOP指令,在NOP指令后放置一個(gè)長(cháng)跳轉的ERR處理程序。注意NOP最少放置3個(gè),這樣任何的跑飛最多只能占用2個(gè)NOP,第三個(gè)NOP一樣還是能把程序代碼揪回來(lái),揪回來(lái)后就執行ERR處理程序。
如果碰到安全性、可靠性等級要求比較高的程序,推薦的處理方法可以采用熱備份的處理方法,即用兩段代碼同時(shí)執行同一個(gè)功能,執行的結果進(jìn)行對比,如果一致則放行通過(guò),如果結果不一致,咋處理就看您的嘍。但是… …國人有的是辦法,為了圖省事,你領(lǐng)導不是要求我編熱備份程序嗎,那好,我就把原來(lái)的代碼復制一遍,重新插入到某個(gè)地方,您這和明朝時(shí)代馮保太監(還是嚴嵩、張居正阿?拿不準了,大家有興趣的翻看《明朝那些事兒》查閱下)玩的沒(méi)啥兩樣,自己寫(xiě)奏章,自己給自己審批奏章。既然是備份就是為了防止一個(gè)人出問(wèn)題,那最好的辦法自然是不同的人來(lái)編這段,如果原理計算方法上也不同,數據采集通道也不同,那就過(guò)年帶娶媳婦的,好上加好了。
安全性和可靠性的編程細節注意事項還有很多,窺一斑難見(jiàn)全豹呵,諸位仁兄一起努力鉆研了。
4、數據、變量
變量的定義是為的避免各種混淆,同一程序內數據和數據的混淆、不同人讀程序時(shí)對變量理解上出現的二義性、視覺(jué)效果上容易出現的錯誤(字母的“o”和數字的“0”,字母的“l(fā)”和數字的“1”)。這里要遵循一個(gè)“要么相同,要么迥異”的基本規則,這條規則在很多的領(lǐng)域都有應用,用的最絕的是朱元璋,對待貪官,要么不理你,自覺(jué)點(diǎn)您貪差不多了就收手吧,您自己不收手的話(huà),做的過(guò)了直接就殺,株連幾族,所以在明朝,朱元璋是殺人最多的皇帝;在結構的防呆性設計上,接插件的選型也是如此,如果一個(gè)乳白色和一個(gè)淺灰色的同類(lèi)接插件,最好的選擇是有很直觀(guān)的視覺(jué)差異或結構的差異,或者干脆就是相同的,相同須基于一個(gè)前提,互換性要好。
用顯意的符號來(lái)命名變量和語(yǔ)句標號。標識符的命名有明確含義,且是完整單詞或易理解的縮寫(xiě)。短單詞通過(guò)去掉“元音”形成縮寫(xiě);長(cháng)單詞取頭幾個(gè)字母形成縮寫(xiě);一些單詞有公認的縮寫(xiě)。如:
Temp — tmp;
Flag — flg;
Statistic — stat;
Increment — inc;
Message — msg。
特殊約定或縮寫(xiě),要有注釋說(shuō)明。在源文件開(kāi)始處,對使用的縮寫(xiě)或約定注釋說(shuō)明。自己特有的命名風(fēng)格,要自始至終保持一致。對于變量命名,禁止取單個(gè)字符(如i、j、k.。。);含義+變量類(lèi)型、數據類(lèi)型等,i、j、k作局部循環(huán)變量是允許的,但容易混淆的字母慎用。如int Liv_Width,L代表局部變量(Local)(g全局變量Global)、i代表數據類(lèi)型(Interger)、 v代表 變量(Variable)(c常量Const)、Width代表變量的含義,這種命名方式可防止局部變量與全局變量重名。
禁用易混淆的標識符(R1和Rl,DO和D0等)來(lái)表示不同的變量、文件名和語(yǔ)句標號。
除了編譯開(kāi)關(guān)/頭文件等特殊應用,避免使用_EXAMPLE_TEST_之類(lèi)以下劃線(xiàn)開(kāi)始和結尾的定義。
全局變量是戰略性資源,它決定了模塊和模塊間的耦合度,需在項目上提升到一個(gè)足夠高的高度,慎用全局變量,不得不用的時(shí)候,要單獨為每一個(gè)全局變量編寫(xiě)獨立的操作模塊或函數,在修改全局變量的時(shí)候,要檢查是否有別的函數在調用它并且需要此數值保持穩定。
對變量代表某個(gè)特定含義的時(shí)候,盡量不要僅僅用位來(lái)代表什么,比如用某變量的第零位代表某個(gè)狀態(tài)(0000 0001,其中僅用1代表某個(gè)內容,這樣01H、03H、05H… 會(huì )有很多個(gè)組合都能代表這個(gè)狀態(tài));位容易受干擾被修改,信息出現錯誤的幾率大很多。
也不要用00H、FFH等數據代表,就像我們面試一群人一樣,第一個(gè)被面試人和最后一個(gè)被面試人容易被記住,00H和FFH亦然,系統默認狀態(tài)是00和FF的時(shí)候較多,他們容易被復位或置位成這類(lèi)數值。推薦以四位的二進(jìn)制碼的某個(gè)中間值為狀態(tài)變量,如1001。
變量數據在應用之前宜作數據類(lèi)型和數值范圍的判斷;
數據在存儲過(guò)程中也容易出現問(wèn)題,EEPROM、RAM等都有過(guò)類(lèi)似的案例。數據出錯時(shí)避免不了的,解決的辦法是學(xué)花旗銀行等美國金融企業(yè),之所以在9.11后他們能很快恢復業(yè)務(wù),基本沒(méi)有數據方面的損失,原因何在?因為他們有異地容災數據備份系統,知里面有兩個(gè)關(guān)鍵詞,異地、備份。我們的信息也同樣,首先選擇存在不同的介質(zhì)中、或相同的介質(zhì)但迥異的存放環(huán)境和位置下,雙重備份的結局是兩邊不一致的時(shí)候,數據被懷疑并拒絕反映執行,但嵌入式軟件很多時(shí)候是要靠數據來(lái)推動(dòng)執行機構的,即使發(fā)現數據有問(wèn)題也不允許行政不作為,這種情況下,作為我們也很難辦,2個(gè)不同的數據,有明顯問(wèn)題的還好排除,都在有限范圍內可如何判定哈?這種時(shí)候沒(méi)辦法只好三備份,少數服從多數是唯一的選擇了。石頭剪刀布的方式不好用,葛優(yōu)的分歧終端機也不適用,就只好選擇這種最原始最有效的辦法了,唯一需要注意的是數據宜存放于三種不同的備份環(huán)境下,不然豈不成了你家哥倆兒,咋表決都占便宜阿。
以上僅就嵌入式軟件可靠性的關(guān)注方面分了幾大類(lèi),進(jìn)行了基本的描述,實(shí)際應用中,需要關(guān)注的點(diǎn)還有很多很多,如果是準備自行制定設計規范的話(huà),以上的思路應該也可以給與一些啟迪了。
評論
查看更多