嵌入式系統開發過程常被比喻為拼圖,一個個相互契合的組件形成完整系統。有時,你可能會強行將不匹配的組件拼在一起,但結果卻與預期的圖像不符。我們應該拋棄將開發最終結果視為單一版本程式碼的想法,嵌入式系統的開發更像是隨著時間變化的拼圖,涵蓋了概念、原型設計、硬體啟動、除錯、測試、發佈、維護等階段,並且會不斷重複這些過程。
在嵌入式系統中,彈性設計不僅是讓程式碼能夠解決當下的問題,更重要的是確保系統在整個生命週期中能夠靈活應對變化。我們的目標是保持足夠的彈性,在有限的資源下滿足產品需求,並應對嵌入式系統中固有的其他問題。
為了提升系統的靈活性,我們可以從軟體設計中借鑒一些優秀的設計原則。
系統拆分需要經驗,但有一個簡單的準則:考慮哪些部分可以獨立變動。
在嵌入式系統中,這往往可以通過物理硬體來幫助識別。舉例來說,如果一個感測器 X 透過通訊通道 Y 進行數據傳輸,那麼感測器和通道可以視為兩個獨立的子系統,也是程式碼模組化的良好候選對象。
一旦我們將系統拆解成獨立的物件或模組,就可以針對每個模組進行測試。越早發現並修正錯誤,成本越低,對所有人都有利。因此,不要等待別人為你發現問題,測試和品質控制應該是你開發過程中的一部分。
寫程式時,應考慮如何測試它。為系統編寫測試程式不僅能提高程式品質,還可以作為文件,讓其他人更容易理解你的程式。此外,這會讓人覺得你是一個高水準的開發者。
另一個減少錯誤的方式是對程式碼進行適當的註解(comment)。然而,記錄程式碼時,要掌握適當的細節層次。例如:
i++; // 增加索引值
這類註解毫無意義,因為它無法提供額外的資訊。
註解的目標是為未來的自己或其他開發者提供清晰的上下文。假設你在一年後再次看到這段程式碼,已經忘記了當時的解決方案,註解應該幫助你重新理解這段程式碼的用意。註解應該描述程式碼的意圖(intent),而非操作過程。
在資源受限的系統中,提早最佳化的誘惑是很大的。然而,你應該抵制這種衝動。首先實作出功能,確保其正常運行並經過測試,然後再針對需要的部分進行優化。
時間和資源有限,因此應優先關注主要的資源消耗者。優化一個很少執行的函數並無多大價值,如果另一個常執行的函數占用了大量處理時間,那麼這才應該是優化的重點。儘管在嵌入式系統中,某些程度的最佳化是不可避免的,但必須在了解資源使用狀況後再進行調整。
如著名的電腦科學家 Donald Knuth 所言:「過早最佳化是萬惡之源。」大多數情況下,我們應該專注於解決大部分問題,而非沉迷於微小的效率提升,這樣可以避免將精力浪費在不必要的細節上。
We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. —Donald Knuth
仔細理解這句話時,可以從以下幾個角度進行分析:
在開發初期,你可能並不完全了解系統的性能瓶頸在哪裡。如果在這時過早對某些部分進行優化,很可能會浪費大量時間,最終發現優化的地方其實對整體性能影響不大。而這樣的優化可能會讓程式碼變得更複雜、難以理解,甚至引入新的錯誤。
Knuth的建議是先讓系統運行起來,專注於實現功能並確保其正確性。當系統的主要功能完成後,再回頭優化那些真正需要優化的部分。這樣可以避免因過度關注效能導致的資源浪費,並確保系統具備穩定性和可維護性。
Knuth強調不要在小的效能優化上浪費太多時間,應該將精力集中在那些真正需要解決的問題上。在資源有限的情況下,開發者應該優先完成能夠產生最大效益的工作,而非陷入微小的效能改進中。
優化應該基於分析和數據支撐,專注於系統的真正瓶頸部分。例如,先完成所有功能,進行性能測試,然後根據結果來決定哪部分需要優化。這種方法可以有效避免無謂的「小優化」而導致系統混亂和不可預測的行為。
在開發一個智慧農業系統時,團隊將土壤濕度感測器、溫度感測器和無線通訊模組拆分成獨立的模組。這些模組之間通過定義良好的接口進行通信。當需要升級無線通訊模組時,其他感測器模組並未受到影響,團隊僅需專注於通訊模組的調整,節省了大量開發和測試時間。
另一個例子是在汽車電子系統中,團隊將引擎控制、溫度監控和安全系統分別作為獨立的模組進行開發。這使得當引擎控制系統需要調整時,安全系統和溫度監控系統仍然能保持穩定運行,降低了系統崩潰的風險。
這些原則和實例展示了嵌入式系統開發的挑戰和應對策略,有效應用這些設計原則能夠大幅提升系統的靈活性和可靠性。