編寫嵌入式軟件代碼的10個技巧

代碼維護是應用程序開發的重要方面,而爲了縮短上市時間,通常會忽略代碼維護。對於某些應用程序,這可能不會造成重大問題,因爲這些應用程序的壽命很短,或者已部署該應用程序,並且再也不會碰它。

但是,嵌入式系統應用程序的使用壽命可能長達數十年,這意味着一些早期的錯誤可能會在以後導致可觀的成本。

在開發可能具有長壽命的嵌入式應用程序時,在設計和實現上都必須考慮維護。以下技巧絕不會構成一個完整列表,但是它們解決了一些常見問題,這些問題可能會使您的應用程序維護者有理由詛咒您的名字,並且不要忘記您可能是其中之一!

提示1:避免使用匯編代碼

當然,在低端PIC上您別無選擇,而在高端ARM上您可能不需要它,但是在這兩種極端之間,有很多平臺使用匯編代碼來實現以下目的:提高性能並減少代碼大小。但是,問題在於,簡單地選擇使用匯編代碼可能會使您的項目脫軌,並使您陷入困境。

儘管彙編代碼允許您直接訪問機器的功能,但由於難以理解程序中正在發生的事情,因此可以輕易地忽略性能優勢。正是出於這個原因,構思了高級語言,例如C和Java。

由於調試高級語言的安全功能非常容易,因此請在調試時將每條彙編代碼都視爲可疑的。如果必須使用匯編,請在發表評論時儘量保持謹慎。在C或Java中,註釋可以使代碼混亂,但是將註釋組合在一起可以節省大量時間和挫敗感。

您可以選擇註釋彙編塊,但請確保每個塊中的指令不超過5或6條。理想情況下,應該在註釋中直接用僞代碼拼寫所使用的算法(請參閱提示8)。

提示2:避免註釋蠕變

這是一個通用的編程提示,但是在長壽命應用程序中變得尤爲重要的提示“管理您的註釋與它們記錄的代碼的關聯。隨着代碼的更新,註釋的遷移非常容易,並且結果很難理解。以下示例說明了隨着時間的推移,註釋蠕變的發生有多麼容易:

//此函數將兩個數字相加並返回結果 #if __DEBUG voidprintNumber(int num){ printf(“ Output:%dn”,num);

} #萬一

//此函數將兩個數字相乘並返回結果 整數乘(整數,整數b){

返回a * b; }

int add(int a,intb){

#if __DEBUG //調試輸出 printNumber(a + b); #萬一 返回a + b; }

請注意,功能“添加”的註釋位於列表的頂部,而實際功能則位於下方。如果註釋和函數之間存在空格,則可能會超時發生。

可能的原因是在’add’及其註釋描述之間添加了printNumber函數。後來,有人看到有一個加法函數,並且在其上加上multiplenext似乎是合乎邏輯的”,註釋的蠕變導致代碼內的文檔脫節。要解決此問題,請嘗試將代碼保留在其文檔的功能內,或通過在註釋上方和下方插入行來使註釋塊非常明顯。

提示3:不要過早優化。

編程的主要缺點之一是過早的優化。但是,由於時間限制,草率的編碼或過分熱心的工程師,該規則在實踐中經常被打破。您編寫的任何程序都應儘可能簡單地開始,並且仍然提供所需的功能。“如果需要性能,請嘗試簡單地實現該程序,即使它與性能不匹配。

一旦測試並調試了完整的單元(它是大型系統的編程器或組件),然後回去進行優化。危險地優化代碼會導致維護噩夢,因爲優化後的代碼通常較難理解,並且您可能無法理解您需要的性能結果。理想情況下,使用探查器(例如與GCC一起使用的gprof或Intel的VTune)來查看瓶頸所在,並專注於這些領域-真正緩慢的事情可能會讓您感到驚訝。

提示4:ISR應該很簡單

出於性能和維護方面的考慮,中斷服務例程(ISR)應該儘可能簡單。作爲異步性質的ISR本質上比“常規”程序代碼更難調試,因此將其責任降到最低對於您的應用程序的總體可維護性很重要。嘗試將所有數據處理移出ISR並移至主程序中,然後ISR僅負責獲取數據(例如,從硬件中獲取)並將其放置在緩衝區中以備後用。可以使用一個簡單的標誌來向主程序發出信號,通知有要處理的數據。

提示5:將調試代碼保留在源文件中

在開發過程中,您可能會添加大量旨在調試“詳細輸出,聲明,LED閃爍等”的代碼。當項目結束時,可能很想刪除其中的這些部分。代碼以清理整個應用程序,尤其是在隨意添加調試代碼的情況下。

儘管清理應用程序是一個崇高的追求,但是刪除調試代碼會在以後產生問題。任何試圖維護該代碼的人都可能會複製原始開發中創建的許多步驟,“如果代碼已經存在,則維護變得非常容易。如果需要在生產版本中刪除代碼,請使用條件編譯或將調試代碼放在中央模塊或庫中,不要將其鏈接到生產版本中。應用程序的初始開發應包括編寫文檔和清理調試代碼的時間;花費的額外時間將是值得的。

技巧6:爲系統調用編寫包裝器

嘗試通過接口將低級I / O例程與高級程序邏輯分開,因爲通過單片開發可以使程序難以管理。將應用程序的所有功能放到幾個大功能中會使代碼難以理解,並且更難更新和調試。對於硬件接口尤其如此。您可能可以直接訪問硬件寄存器或I / O,甚至可以訪問平臺供應商提供的API,但是有很多動機來創建自己的“包裝程序”接口。

您通常無法控制硬件的功能,並且如果將來將來必須更改平臺,則在應用程序中使用特定於硬件的代碼(API或直接操作,這無關緊要)將使移植更加困難。

如果您創建自己的包裝器接口,就像創建爲硬件API定義的宏一樣簡單,則代碼可以是一致的,並且移植所需的所有更新都將位於集中位置。

提示7:僅分解功能

嵌入式應用程序將與PC應用程序不同,因爲許多功能將專用於您正在使用的硬件。不建議將功能單元儘可能地拆分爲最小–將單個作用域(功能)中的功能調用數保持在5或6以下,並使硬件的功能單元與軟件中的功能單元相對應。

進一步分解程序將創建調用圖的蜘蛛網,從而使調試和理解變得困難。

提示8:文檔

保留所有文檔以及代碼,理想情況下,還應保留硬件副本。在記錄應用程序時,請嘗試將盡可能多的設計和應用程序模型直接放入源代碼中。如果必須將其分開,則將其作爲巨大的註釋放入源文件中,並將其鏈接到程序中。

至少,如果您使用版本控制系統(例如CVS或Microsoft Source Safe),則將文檔與源代碼檢查到同一目錄中-如果不與源代碼一起放置,則丟失文檔確實很容易。

理想情況下,將所有文檔和源文件放在CD(或您選擇的便攜式存儲設備)上,將其與使用的硬件和開發工具一起密封在袋子中,然後將其放在安全的地方“您的後繼者將感謝您。

提示9:不要機靈!

類似於過早的優化,聰明的編碼會導致麻煩。由於C和C ++仍然是嵌入式世界中的主導語言,因此有很多方法可以解決一個問題。模板,繼承,goto,三元運算符(“?”),列表會不斷出現。

真正聰明的程序員可以提出使用這些工具解決問題的極其緊湊和優雅的方法。問題是通常只有程序員才能理解聰明的解決方案(以後可能會忘記它是如何工作的)。

唯一的解決方案是例如避免聰明,並儘量減少使用深奧的語言功能”,例如,不要依賴C語句中的短路評估,也不要使用三元運算符進行程序控制(使用if語句代替)。

提示10:將所有定義放在一個地方

如果您有很多常量定義或條件定義,請將它們放在中央位置。這可能是單個文件或源代碼目錄,但是如果將定義深埋在實現中,它會再次咬住您。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章