創龍首頁 >關于創龍 > 新聞資訊 > 行業新聞

聯系我們

Contact Us

公司總機:020-8998-6280

技術熱線:020-3893-9734

技術郵箱:support@tronlong.com

銷售郵箱:sales@tronlong.com

經驗之談:嵌入式如何進行架構設計?

2022/04/12

【閱讀這篇文章,你能了解到什么】


1. 從事嵌入式開發12年的我,對架構設計的理解;


2. 對嵌入式系統中的架構設計要刻意訓練;


3. 嵌入式系統開發過程中的一些小技巧;


4. 一個用于智能家居項目的Demo,可以直接編譯、執行;


【我對架構設計的理解】


1.架構設計概念的認識


    相信看這篇文章的同學,大部分都是從事嵌入式開發的,大家也肯定有這么一個印象:在招聘網站上的一些架構設計的崗位,都是針對 Web 方向的,卻很少看到招聘嵌入式崗位的系統架構師的崗位。


   我的理解是大概有下面2個原因:


(1) Web開發:百家爭鳴,沒有統一的標準和老大



    這些年得益于移動互聯網的發展,前、后端開發崗位的需求量大增,而且各種框架層出不窮。


    如何利用這些框架來為用戶提供高性能的服務并沒有一個統一的標準,于是百家爭鳴,相應的設計師崗位也就層出不窮。

(2) 嵌入式開發:Linux 舍我其誰


    在嵌入式系統的開發中,在操作系統的選擇上幾乎沒有太大的余地,大部分是 ARM+Linux 組合。


    在 Linux 操作系統層面:那些大神們已經把內核和驅動層設計的很完美了,很少需要開發人員做大量的修改。


    在應用程序層面:開發人員如果沒有什么追求,只為了實現規格書中定義的功能即可。


    而老板呢,也只是重視產品功能是否能正常實現,至于什么可移植、可擴展、執行效率等等,不會想到這個層面。


    即使產品需要更新換代,讓開發人員重新實現即可,反正只需要功能OK就行。


2.嵌入式系統的架構設計重要性


    說一個小故事。


    有一位同事為客戶寫一個單片機產品的程序,后來同事離職后把代碼移交給我。


    這個產品有一個小功能需要修改一下,恰巧那會我正在處理另外一個項目,于是在征得老板許可的情況下把源代碼發給客戶,請他們自己修改。


    因為拿到了源代碼,客戶肯定很開心啊,因為只要吃透了代碼,其他類似的設備都可以自己開發了。


    過了一段時間,我問客戶:上次那個產品的功能修改怎么樣了?


    他說:還沒搞定呢,上次你給的代碼我丟了,會把人看死的,現在正從頭重新寫代碼呢。    

    故事是真實的。


    代碼都是字符組成的,有些代碼看起來賞心悅目,有些代碼看起來懷疑人生。

    沒有架構設計進行指導的代碼,有這些缺點:


(1) 代碼不能復用,移植很麻煩。


(2) 當需求發生改動時,不能快速調整代碼。


(3) 對于已有的代碼:不敢改、不想改,牽一發而動全身。


(4) 調試bug很頭疼。

  
    相反的,如果架構設計的好,對各方面都有好處:


    對于項目來說:


(1) 項目周期可控


(2) 代碼可讀性好


(3) 功能可擴展


(4) 修改單一模塊不會影響其他功能


(5) 并行開發


(6) 單元測試方便

    

對于開發人員來說


(1) 節省開發時間


(2) 全局視角,提高開發大型項目的能力


(3) debug輕松、快速 

【如何進行架構設計】


1.設計文檔


    只要進入編程領域,大家都知道要高內聚、低耦合,分模塊、分層設計。


    但是具體需要怎么做?


    如何在規定好的項目周期內把事情做好,而且讓自己沒那么累?


    如何為自己后期的維護做好鋪墊?


    。。。


    這些問題可能在項目初期的時候,都規劃的比較好。


    但是在執行過程中,就會越來越偷懶,越來越偏離預定義的方向。






    我的建議是:


    無論項目的大小,無論項目周期的長短,一定要有設計文檔,設計文檔的詳細程度就需要根據項目的實際情況進行靈活把握了。


    在設計文檔中,就要把架構方面的設計體現出來。在實現的過程中,嚴格按照文檔中的要求來做。


取乎其上,得乎其中;取乎其中,得乎其下。


2. 程序文件的物理模型


(1) 分層設計


    業務層


    功能模塊層


    驅動層


(2) 分模塊設計


    根據功能來劃分模塊


    模塊之間通過API接口函數進行數據交互


    設計靈活的API接口函數 


3. 進程與線程的選擇


    在嵌入式系統中,實現產品的功能,可以通過多個進程相互配合來完成,也可以用多線程來實現,這個選擇沒有固定的標準,視項目的具體情況而定。


    我一般的做法是:


    如果產品功能不復雜,盡量用多線程來實現;


    如果產品設計到的功能比較多,那么就把強相關的模塊放到獨立的進程中。


(1) 使用進程


    各模塊獨立編譯,不會相互影響。


    出現類似 SegmentFault 問題,很容易定位到肇事者。


    方便分布式部署。


    代碼安全:除了整合人員,其他人只需要 clone 自己負責的模塊代碼,沒有權限、也不需要訪問別人的代碼。


    但是:需要考慮到進程之間的通信問題,比如:IPC調用、socket通信、總線。(我一般都會采用在本地系統內使用一條MQTT總線來掛接所有的通訊模塊)


(2) 使用線程


    創建線程成本低。


    線程之間共享全局變量(換個角度,這也是一種缺點)。


    模塊之間調用方便,因為函數地址直接可見。 


4. API設計


    可以把一個模塊看成是黑盒,給定一個輸入,就會返回確定的結果,或者執行確定的功能,


    模塊之間只需要定義好這個API接口函數就行。


    至于模塊內部是如何實現的,大家各顯其能。



    另外,如果你是API設計人員,一定要注意要讓調用者用起來很舒服。就像你遞一把剪刀給別人,一定是把手給對方。


    另外一個經驗,在項目設計初期,盡量不要把API的函數設計的太死板,容易給自己下套。


    例如:


(1) 可以設計帶有 char *的變量,使用json格式的字符串,來傳遞任意長度和類型的數據。


(2) 可以設計帶有 void *的變量,用來傳遞任意數據類型的地址,這個功能在很多項目中被使用的出神入化,比如:很早之前高通手機的BREW平臺,智能家居中的 ZWave平臺。 


5. 文件目錄的設計

    這部分容易理解,職責不同的文件要存放到相應的目錄中:頭文件、庫文件、可執行文件、相關文檔。如果這部分組織的不夠好,當你把項目移交給其他同事時,肯定會被其他人在心中默念一千遍:F-U-C-K Y-O-U!


6.編譯腳本的設計(構建工具)


        當我們接到一個嵌入式項目時,在確定方案之后,程序運行的平臺都是確定的,大部分情況就是嵌入式Linux,或者是一些變體。


在開發階段,我見過有些開發人員每調試一個功能點,就把代碼交叉編譯后放,然后通過NFS遠程掛載,或者scp遠程拷貝,在真實設備上執行。我看著都比較累


    其實完全可以在編譯腳本中為不同的平臺編譯一個版本。


    比如:使用Ubuntu系統來開發產品時,只要x86平臺可以模擬產品功能,就直接編譯x86版本。

    當所有的功能點在x86平臺上測試OK了, 再統一放到真實的嵌入式系統中進行聯調,這樣做能節省很多時間。


【Demo說明】


1.簡介


    這個Demo是從一個智能家居項目中抽取出來的,只是體現了各功能模塊的設計,函數內部沒有實現任何功能,僅僅是用來展示設計的過程。


    在 Ubuntu16.04 系統下,可以直接編譯執行。


3.系統架構圖


4.目錄結構


    Makefile: 編譯腳本


    application: 業務層


    module: 功能模塊層


    driver: 硬件驅動層 


5. 執行序列演示


    圖中橙色的箭頭,表示從云端發來一個控制指令。


    業務層接收到指令后,解析指令,發送給 Control 模塊。


    Control 模塊再次解析具體的指令,發送給 ZigBee 設備,同時記錄到日志中。

創龍官方微信公眾號

Copyright © 2013~2025 廣州創龍電子科技有限公司 All Rights Reserved  | 粵ICP備15055271號