嵌入式架構有多重要?
要做到嵌入式應用的代碼邏輯清晰,
且避免重復的造輪子,
沒有好的應用架構怎么行?
如果沒有好的架構,
移植將會是一件很痛苦的事情。
如果沒有好的架構,
復用是最大的難題,
沒法更大限度的復用原有的代碼。
如果沒有好的架構,
一旦驅動改了,
所有的地方都要改,
費時費力且很容易出錯。
如果沒有好的架構,
應用層中穿插著硬件驅動層的代碼,
看著會是一片混亂,
邏輯不清,
代碼維護起來會很困難。
01
嵌入式系統(tǒng)的基本架構
硬件架構
軟件架構
大多數(shù)人參與的是 嵌入式軟件設計 ,更多的是接觸的是上層軟件系統(tǒng)部分,可以分為兩大類型嵌入式軟件應用工程師以及嵌入式驅動工程師。
前者主要負責 linux APP 設計,負責應用層業(yè)務開發(fā),主要具備如下幾個專業(yè)技能:
2.熟悉多線程管理、進程間通信、文件IO操作
3.了解基本的shell編程
4.熟悉數(shù)據(jù)庫操作
5.了解QT或者Android
后者負責驅動開發(fā),更加涉及底層。
2.熟悉Linux驅動模型
3.熟悉ARM架構
4.熟悉基本的電路原理
02
嵌入式程序設計思路
如果功能模塊變動了,只需升級功能功能模塊,其他的模塊不受影響,應用層也不受影響。
休息一下,推薦一篇文章《怎樣混好嵌入式/MCU/ARM/DSP這一行?》
03
一個引以為戒的實例
一、錯誤的示范
版本一的架構設計
2.1系統(tǒng)體系結構
系統(tǒng)分為兩層:硬件驅動層、應用層。
2.1.1硬件驅動層
硬件驅動層包含板載硬件資源正常運行所需的所有驅動程序。
1)MCU初始化
2)I2C數(shù)據(jù)存取
3)SPI數(shù)據(jù)讀取
4)加速度計初始化
5)藍牙模塊啟動
6)BC95模塊啟動
7)485通訊模塊啟動
2.2.2應用層
1)Mcu運行模式切換
2)震動及傾斜
3)數(shù)據(jù)解析
4)開/關鎖
5)數(shù)據(jù)發(fā)送
6)歷史數(shù)據(jù)保存
版本二的架構設計
1.對架構的理解還不是很清晰,既然是做架構設計,那就應該從整體來看,而不是僅僅只是局限于一個模塊,或者功能里面。
2.還是每個層次的理解也還不是很清晰,比如講MCU的初始化,歸于硬件驅動層里面。MCU的初始化,嚴格意義上來說,是屬于流程的一部分了,而不是驅動。比如電腦的開啟啟動,把這個歸于硬件的驅動里面,肯定是屬于牛頭不對馬嘴的。
3.還有就是各個模塊的啟動,也是不能屬于硬件驅動層的,也都是業(yè)務流程的一部分了,都不應該屬于驅動層的一部分。
4.還有就是總線數(shù)據(jù)的讀寫,雖然驅動的作用也就是讀寫,但是數(shù)據(jù)總線的讀寫不能寫成硬件驅動。
5.應用層的系統(tǒng)參數(shù)初始化,也還是屬于流程。
6.數(shù)據(jù)的解析和數(shù)據(jù)的發(fā)生,都是屬于通信功能里面的,不應該單獨獨立出來,屬于單個的應用。
1.應用的代碼邏輯清晰,且避免重復造輪子。
2.如果沒有好的架構,移植將會是一件很痛苦的事情,因此一個好的架構設計,方便軟件的移植。
3.最大限度地復用。
4.高內(nèi)聚低耦合。
(2)設計思路
如何把硬件的驅動和一個功能封裝成一個個的模塊,然后可以像小朋友搭積木一個,一個個模塊可以快速的拼接起來,組成一個個不同的模型。
我們的嵌入式架構思路也是來源于此,即功能模塊化設計、分層設計。
這個設計和WEB開發(fā)的MVC模式類似,都是注重分層設計。
模塊化設計:將收集到的需求,進行歸類,總結和分析,將這些需求概括為一個個單獨的功能,每一個功能,做成一個單獨的功能模塊。
分層設計一句話不好直接表達,其主要體現(xiàn)在一下幾方面:
1.功能模塊對外調(diào)用的模塊封裝成一個個API,將底層驅動做個API以供功能模塊調(diào)用。(各個功能模塊可以獨立編譯(如通信模塊純ANSI C,可在任意平臺復用),或者調(diào)用驅動層接口(日志庫模塊調(diào)用了驅動讀寫Flash),總而言之,言而總之,封裝出各個功能獨立的可復用的功能模塊。)
2.API分為驅動層API和應用層API,而不是所有程序都調(diào)用驅動層API。(整個應用中都調(diào)用驅動層API會導致應用中驅動調(diào)用隨處可見,無法移植和最大限度的復用)
總體分 硬件驅動層-->功能模塊層-->業(yè)務邏輯層-->應用層
總體結構示意框圖:
1.層與層之間不能跨層調(diào)用。
2.模塊與模塊各自獨立,無依賴關系。
3.模塊提供統(tǒng)一的接口供上層調(diào)用,模塊的內(nèi)外接口分明。
4.模塊的功能只能增,不能改。
5.各個功能模塊層也還可以進行繼續(xù)分層,比如接口層、驅動層、硬件層。
(3)模塊層次說明
硬件驅動層包含板載硬件資源正常運行所需的所有驅動程序并提供API給功能模塊調(diào)用。
功能模塊層包括實現(xiàn)具體功能的函數(shù),通過調(diào)用驅動層API實現(xiàn)相應功能,同時提供可調(diào)用的API給業(yè)務邏輯層。
業(yè)務邏輯層包括產(chǎn)品整體功能的各個業(yè)務流程,通過調(diào)用功能模塊層的API實現(xiàn)。
應用層將各個業(yè)務邏輯進行整合調(diào)用,完成整個產(chǎn)品的功能。
(4)優(yōu)勢
如果驅動變動了,或者換不同平臺,只需更改驅動層,應用層不受影響。
如果功能模塊變動了,只需升級相應的功能模塊,其他的模塊不受影響,應用層也不受影響。
按照這種邏輯設計好之后,主要的工作就是在業(yè)務邏輯層。應用層則為程序的總體流程和框架,主要調(diào)用業(yè)務邏輯層實現(xiàn)不同的功能。
04
給嵌入式代碼也來個分層
一、遇到的問題
代碼結構也會有缺陷:
(1)開發(fā)效率低:每次使用片內(nèi)的某一資源(例如定時器等),筆者都要去查詢CC2430中文手冊,比較eggache~
正是由于以上問題,筆者決定暫停了該系列博文的續(xù)寫,抽出時間來思考一下解決辦法。
二、由網(wǎng)站分層引起的思考
筆者在學習嵌入式編程之前,曾有過 ASP.NET 網(wǎng)站開發(fā)經(jīng)驗,對其分層理論也有所實踐,下面簡單提一下:
一般的有一定復雜度的網(wǎng)站可分為以下三層:
總之,分層以后,大大提高了代碼的復用性與擴展性。
那么在嵌入式開發(fā)中,能否也利用分層的思想,來提高開發(fā)效率,增強其可維護性與可擴展性呢?下面,是一些筆者思考后的淺見。
三、嵌入式項目也來分個層
當然不能照搬ASP.NET 的具體分層思想,具體問題得具體分析嘛~
首先,嵌入式開發(fā)的核心就是芯片,它提供固定的片內(nèi)資源共開發(fā)者使用。而且它具有一個很重要的特點就是,不隨項目的需求變動而變動。所以應將其作為最底層,為上層提供基礎支持。我們將其命名為 硬件抽象層(Hardware Abstract Layer)。
芯片有了當然還不夠,通常我們會在片外擴展一些功能模塊來滿足具體的項目需求,例如:傳感器、鍵盤、LCD屏等。這一層的特點是,隨項目的變動而以模塊為單位動態(tài)增減。這一層的運作需要芯片內(nèi)部資源的支持,所以應處于硬件抽象層之上,并為上層調(diào)用。我們將其命名為 功能模塊層(Functional Module Layer)。
OK,現(xiàn)在原材料都準備齊了:芯片+擴展模塊,接下來就要開始真正的加工了:我們需要靈活調(diào)用之前兩層所提供的接口,實現(xiàn)具體的項目需求。我們將其命名為應用程序層(Application Layer)。
圖文:
(1)硬件抽象層(HAL)
實現(xiàn)對片內(nèi)資源 (如定時器、ADC、中斷、I/O等) 的通用配置,隱藏具體的SFR操作細節(jié),為上層提供簡單清晰的調(diào)用接口。
嵌入式開發(fā)的核心就是芯片,它提供固定的片內(nèi)資源(常用的有I/O,ISR,TIMER等,稍微好點的還有ADC,SPI等硬件資源,不需要芯片外圍ADC采集芯片或模擬SPI)共開發(fā)者使用。而且它具有一個很重要的特點就是,不隨項目的新增需求變動而變動。所以應將其作為最底層,為上層提供基礎支持。
(2)硬件驅動層(HDL)
嵌入式開發(fā)基本都會使用片外資源,如AT24C02,W25Q128等常見的外圍EEPROM芯片,需要SPI通信(硬件SPI或I/O模擬的SPI)發(fā)送相應指令驅動該芯片,實現(xiàn)該芯片能正常工作。因此驅動這部分的API函數(shù)實現(xiàn)程序即為硬件驅動層。即使換了MCU,也只需將調(diào)用過硬件抽象層的API函數(shù)替換即可。
(3)功能模塊層(FML)
通過調(diào)用 HAL,實現(xiàn)項目中所涉及到的各片外功能模塊,隱藏具體的模塊操作細節(jié),并為上層提供簡單清晰的調(diào)用接口。
硬件抽象層和驅動層主要就是為功能模塊層提供的,實現(xiàn)該項目需要的功能,比如KEY、LED和EEPROM等功能,其中LEY、LED基本調(diào)用硬件抽象層的API函數(shù)(更復雜的可能通過片外芯片獲取/控制等,因此可能也需要使用硬件驅動層),EEPROM調(diào)用硬件驅動層的API函數(shù),即使EEPROM芯片更換(AT24C02或W25Q128等),也不影響EEPROM之前編寫含的功能代碼程序(前提是AT24C02,W25Q128提供的API函數(shù)提供的是統(tǒng)一標準)。
(4)應用程序層(APL)
通過調(diào)用 HAL 與 FML,實現(xiàn)最終的應用功能。
負責的就是功能模塊的使用和之間的邏輯關系處理等等,比如用戶交互界面應用程序可能需要KEY、LED、LCD等。
四、硬件抽象層和硬件驅動層的主要區(qū)別
硬件抽象層使用的芯片內(nèi)本身的資源(芯片手冊都有介紹),而硬件驅動層使用的是芯片本身不存在的資源,而且需要編寫相應代碼才能實現(xiàn)的資源。
比如正點原子STM32中CAN使用的TJA1050芯片,CAN屬于STM32的片內(nèi)資源,TJA1050屬于片外資源,但由于TJA1050不需要額外的代碼就能通過STM32中CAN本身提供API函數(shù)正常 工作;因此可以認為TJA1050不屬于硬件驅動層,而若使用TJA1041,則需要編寫額外代碼才能使正常工作才能使STM32中CAN本身提供API函數(shù)正常工作,因此可以將TJA1041歸為硬件驅動層。
若不要分這么細,可以將硬件抽象層和硬件驅動層統(tǒng)一歸為硬件抽象層。
五、功能模塊層和硬件抽象層、硬件驅動層的主要區(qū)別
功能模塊層是按照項目需求提取出來的功能,需要硬件抽象層和硬件驅動層的硬件支持才能實現(xiàn),功能模塊層根據(jù)項目的功能需求改變而改變,而硬件抽象層和硬件驅動層則是項目需求書中的功耗等硬件相關的需求變動而改變,當然,若子功能的增加而硬件不支持,則也需更換硬件驅動。
比如項目中的數(shù)據(jù)儲存功能,硬件支持有AT24C02、W25Q128和芯片本身的FLASH,都可以支持數(shù)據(jù)儲存功能,即使后期因為功耗或節(jié)約成本等問題,硬件的更換也不影響數(shù)據(jù)儲存功能的實現(xiàn)(前提規(guī)劃好標準規(guī)范的API函數(shù)定義)且避免了重寫該功能代碼所帶來的各種問題,保證了該功能的穩(wěn)定性。
分層結構示意圖
免責聲明:本文內(nèi)容由21ic獲得授權后發(fā)布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!