當(dāng)前位置:首頁(yè) > 公眾號(hào)精選 > 嵌入式微處理器
[導(dǎo)讀][導(dǎo)讀] 為什么寫(xiě)本文?做公號(hào)兩月,遇到一些初學(xué)單片機(jī)的同學(xué),剛剛?cè)胧肿鰡纹瑱C(jī)開(kāi)發(fā),還沒(méi)有涉及到使用RTOS,且剛?cè)胧种苯由蟁TOS可能會(huì)有些難度,有的使用的相對(duì)較老單片機(jī)資源還有限,也不適合跑RTOS?;蛘呤褂肦TOS,在整體思路上比較迷茫,不知從何入手,

[導(dǎo)讀] 為什么寫(xiě)本文?做公號(hào)兩月,遇到一些初學(xué)單片機(jī)的同學(xué),剛剛?cè)胧肿鰡纹瑱C(jī)開(kāi)發(fā),還沒(méi)有涉及到使用RTOS,且剛?cè)胧种苯由蟁TOS可能會(huì)有些難度,有的使用的相對(duì)較老單片機(jī)資源還有限,也不適合跑RTOS?;蛘呤褂肦TOS,在整體思路上比較迷茫,不知從何入手,所以本文來(lái)聊聊我對(duì)單片機(jī)程序的整體框架設(shè)計(jì)的一些思路體會(huì)。

為啥要討論架構(gòu)

單片機(jī)系統(tǒng)開(kāi)發(fā)人員的目標(biāo)之一是在編程環(huán)境中創(chuàng)建固件,以實(shí)現(xiàn)低成本系統(tǒng)、軟件可靠性以及快速的開(kāi)發(fā)迭代時(shí)間。實(shí)現(xiàn)這種編程環(huán)境的最佳方法實(shí)踐是使用統(tǒng)一的固件架構(gòu)體系結(jié)構(gòu),該體系結(jié)構(gòu)在產(chǎn)品開(kāi)發(fā)過(guò)程中充當(dāng)框架并支持“固件模塊化”,或稱(chēng)為子系統(tǒng)。

如果不采用統(tǒng)一的設(shè)計(jì)架構(gòu),那么其業(yè)務(wù)需求耦合關(guān)系復(fù)雜,不采用先設(shè)計(jì)-后開(kāi)發(fā)的方法論,想到哪里寫(xiě)到哪里,則程序后期維護(hù)將變得異常艱辛,而引入潛在bug/缺陷的風(fēng)險(xiǎn)也將大大增加,且不具備多人協(xié)同開(kāi)發(fā)的可能。

可以結(jié)合固件模塊化、可測(cè)試性和兼容性的正確組合的設(shè)計(jì)體系架構(gòu)結(jié)構(gòu)應(yīng)用于任何固件開(kāi)發(fā)項(xiàng)目,以最大程度地提高代碼可復(fù)用性,加快固件調(diào)試速度并提高固件可移植性。

模塊化架構(gòu)設(shè)計(jì)?

模塊化編程將程序功能分解為固件模塊/子系統(tǒng),每個(gè)模塊執(zhí)行一個(gè)功能,并包含完成該功能所需的所有源代碼和變量。

模塊化/子系統(tǒng)化有助于協(xié)調(diào)團(tuán)隊(duì)中許多人的并行工作,管理項(xiàng)目各個(gè)部分之間的相互依賴(lài)關(guān)系,并使設(shè)計(jì)人員、系統(tǒng)集成人員能夠以可靠的方式組裝復(fù)雜的系統(tǒng)。具體來(lái)說(shuō),它可以幫助設(shè)計(jì)人員實(shí)現(xiàn)和管理復(fù)雜性。隨著應(yīng)用程序的大小和功能的增長(zhǎng),需要模塊化才能將它們分成單獨(dú)的部分(無(wú)論是作為“組件”,“模塊”還是“子系統(tǒng)”)。然后,每個(gè)這樣分離的部分就成為模塊化體系結(jié)構(gòu)的一個(gè)元素。這樣,可以使用定義明確的界面隔離和訪(fǎng)問(wèn)每個(gè)組件。此外,模塊化編程可提高固件的可讀性,同時(shí)簡(jiǎn)化固件的調(diào)試,測(cè)試和維護(hù)。

即便是一個(gè)人獨(dú)立開(kāi)發(fā)一個(gè)項(xiàng)目,這樣做依然在代碼的調(diào)試、可讀性、可移植性方面是最佳實(shí)踐的整體策略。如果代碼設(shè)計(jì)良好,則在其他項(xiàng)目可以輕松應(yīng)用。而且模塊經(jīng)過(guò)上一項(xiàng)目的測(cè)試驗(yàn)證,在新的項(xiàng)目中再次應(yīng)用其缺陷風(fēng)險(xiǎn)將大幅降低。所以每做一個(gè)項(xiàng)目,以這種策略不斷積累模塊"輪子"組件,隨著經(jīng)驗(yàn)的增長(zhǎng),積累的“輪子”就越來(lái)越多,也越來(lái)越好。所以其優(yōu)點(diǎn)是顯而易見(jiàn)的,否則每做一個(gè)項(xiàng)目,都從輪子造起,開(kāi)發(fā)時(shí)間長(zhǎng)不說(shuō),開(kāi)發(fā)水平也得不到提高,重復(fù)性工作也很枯燥。比如前文中談到的非易失存儲(chǔ)管理子系統(tǒng),如設(shè)計(jì)良好,就變成一個(gè)可靠的可移植的輪子。這段話(huà)請(qǐng)深入理解,并拿走不謝!


固件模塊原理

固件開(kāi)發(fā)中模塊化編程的基本概念是創(chuàng)建固件模塊。從概念上講,模塊代表關(guān)注點(diǎn)分離。在計(jì)算機(jī)科學(xué)中,關(guān)注點(diǎn)分離是將計(jì)算機(jī)程序分解為功能很少重疊的獨(dú)特功能的過(guò)程。關(guān)注點(diǎn)是程序的任何關(guān)注點(diǎn)或功能,并且與功能或行為同義。關(guān)注點(diǎn)分離的發(fā)展傳統(tǒng)上是通過(guò)模塊化和封裝來(lái)實(shí)現(xiàn)的,其實(shí)也就是解耦思想。

固件模塊可以分為幾種類(lèi)型:

  • 與很多上層用戶(hù)模塊都有關(guān)的代碼被實(shí)現(xiàn)為單獨(dú)的固件模塊。常見(jiàn)的如底層硬件相關(guān)的抽象實(shí)現(xiàn)。例如,hal_adc.c 是ADC用戶(hù)模塊的固件模塊,而hal_timer.c是Timer用戶(hù)模塊的固件模塊。
  • 用于特定純軟件算法的代碼被實(shí)現(xiàn)為單獨(dú)的固件模塊。 例如,alg_filter.c是執(zhí)行軟件過(guò)濾器(例如中值過(guò)濾器,均值過(guò)濾器或加權(quán)均值過(guò)濾器、IIR/FIR濾波)的固件模塊。
  • 特定應(yīng)用程序的代碼實(shí)現(xiàn)為單獨(dú)的固件模塊。 例如,app_battery.c是電池充電器應(yīng)用程序的固件模塊。特定工具的代碼實(shí)現(xiàn)為單獨(dú)的固件模塊。例如,debug_print.c是用于實(shí)現(xiàn)日志打印功能的固件模塊。
  • ......

實(shí)施估計(jì)模塊化設(shè)計(jì)的一些規(guī)則:

  • 所有與模塊相關(guān)的功能都應(yīng)集成到單個(gè)源文件中,這是 高內(nèi)聚的體現(xiàn)。
  • 模塊對(duì)外提供一個(gè)頭文件,該文件聲明了該模塊的所有資源(硬件依賴(lài)/宏/常量/變量/函數(shù))。盡量用struct將緊密相關(guān)的變量進(jìn)行集總封裝。
  • 在源文件中包括自檢代碼部分,以實(shí)現(xiàn)該模塊模塊的所有自檢功能。
  • 固件模塊的接口應(yīng)經(jīng)過(guò)精心設(shè)計(jì)和定義。
  • 由于固件取決于硬件,因此需要在源文件頭中明確提及硬件的相關(guān)性。比如利用宏將硬件依賴(lài)轉(zhuǎn)定義,或者利用函數(shù)將基本操作進(jìn)行封裝。則在新的架構(gòu)體系,僅僅需要移植這部分實(shí)現(xiàn)即可使用。
  • 通常,固件模塊可供其他團(tuán)隊(duì)成員在其他項(xiàng)目中使用??赡苌婕暗焦芾砀?,缺陷修復(fù)、所有者應(yīng)維護(hù)模塊。源文件頭應(yīng)包含“作者”和“版本”信息。
  • 固件在某種程度上取決于編譯器。源文件頭中應(yīng)聲明基于什么開(kāi)發(fā)環(huán)境進(jìn)行過(guò)驗(yàn)證,以指定編譯器或與IDE相關(guān)的信息。

需要注意的是,模塊化設(shè)計(jì)會(huì)引入一些調(diào)用開(kāi)銷(xiāo),也可能增加固件尺寸大小。在實(shí)際實(shí)現(xiàn)時(shí),折中考量。不要過(guò)度模塊化,所以建議采用高內(nèi)聚、低耦合的實(shí)現(xiàn)策略。在前面文章中有談到過(guò)的呼吸機(jī)PB560的設(shè)計(jì),看過(guò)其代碼,本打算解讀一下其代碼設(shè)計(jì),但讀下來(lái)發(fā)現(xiàn),其設(shè)計(jì)過(guò)度模塊化了,沒(méi)有實(shí)現(xiàn)高內(nèi)聚的思想。其源代碼很多源文件僅僅實(shí)現(xiàn)了一個(gè)函數(shù),而不是把一類(lèi)問(wèn)題集中抽象實(shí)現(xiàn),后來(lái)就放棄了其代碼解讀。

如何拆分模塊?

做工程開(kāi)發(fā),一定是需求驅(qū)動(dòng)的。第一件事需要對(duì)需求有比較清晰的認(rèn)知,然后才能設(shè)計(jì)一個(gè)比較合理的框架。我們需要實(shí)現(xiàn)什么?大致總體設(shè)計(jì)過(guò)程策略我的基本采用如下圖所示思路(我比較喜歡繪圖,圖會(huì)讓人比較直觀)

問(wèn)自己第一個(gè)問(wèn)題是:這個(gè)項(xiàng)目要實(shí)現(xiàn)什么主要功能?這個(gè)來(lái)自哪里?如果是實(shí)際產(chǎn)品開(kāi)發(fā),則可能來(lái)自市場(chǎng)的需求,如果是自己的DIY項(xiàng)目,也一定會(huì)YY出一個(gè)大致的想法?總之不管源自何方,需求總要先梳理清楚。那么需求一般意義上包含哪些呢?

  • 哪些是硬件IO接口需求,比如開(kāi)關(guān)量輸入,ADC采樣,I2C/SPI通信等等
  • 哪些是業(yè)務(wù)邏輯需求,比如要采集一個(gè)傳感器量數(shù)據(jù),控制一個(gè)加熱裝置,那么這是高內(nèi)聚的需求。
  • 哪些是算法相關(guān)的技術(shù)需求,比如產(chǎn)品中哪些信號(hào)需要濾波處理,哪些需要做頻域分析等等。
  • 是否有對(duì)外的通信協(xié)議需求。
  • 是否有業(yè)務(wù)數(shù)據(jù)需要?dú)v史存儲(chǔ),或者設(shè)備參數(shù)需要掉電保存
  • 是否需要有日志打印需求。
  • ........
  • 不一而足。

結(jié)合固件模塊原理以及相關(guān)指導(dǎo)原則,那么將相關(guān)性高的需求,抽象實(shí)現(xiàn)在一系列的模塊中,在由這一系列模塊配合實(shí)現(xiàn)某個(gè)相關(guān)性高的業(yè)務(wù)需求,再進(jìn)一步這些模塊就變成一個(gè)子系統(tǒng)。多個(gè)子系統(tǒng)在main.c的調(diào)度下,協(xié)調(diào)完成產(chǎn)品的整體功能。

如何集成調(diào)度

對(duì)于某些不使用RTOS的應(yīng)用而言,可以使用如下的框架進(jìn)行:

void main(void)
{
   /*各模塊初始化*/
   init_module_1();
   init_module_2();   
   ....
   while(1)
   {
       /*實(shí)現(xiàn)一個(gè)定時(shí)調(diào)度策略*/
       if(timer50ms)
       {
           timer50ms = 0;
           app_module_1();
       }
       if(timer100ms)
       {
           timer100ms = 0;
           app_module_2();
       }
       
       /*異步請(qǐng)求處理,如中斷后臺(tái)處理*/
       if(flag1)
       {
           communication_handler();
       }
       .....
   }
}

對(duì)于基于RTOS的集成實(shí)現(xiàn)舉例:

void task1(void)
{
    /*處理子系統(tǒng)相關(guān)的初始化*/
    init_task1();
    while(1)
    {
       /*應(yīng)用相關(guān)調(diào)用*/
       task1_mainbody();
       ....
    }
}
....
void taskn(void)
{
    /*處理子系統(tǒng)相關(guān)的初始化*/
    init_taskn();
    while(1)
    {
       /*應(yīng)用相關(guān)調(diào)用*/
       taskn_mainbody();
       ....
    }
}

void main(void)
{
    /*一些基本硬件相關(guān)初始化,比如IO,時(shí)鐘,OS tick定時(shí)器等*/
    init_hal();
    ......
    
    /*一些基本RTOS初始化*/
    init_os();
    
    /*任務(wù)創(chuàng)建*/
    os_creat("task1",task1,棧設(shè)置,優(yōu)先級(jí),...);
    ......
    os_creat("taskn",taskn,棧設(shè)置,優(yōu)先級(jí),...);
    
    /*啟動(dòng)OS調(diào)度器,交由OS調(diào)度管理應(yīng)用任務(wù)*/
    os_start();
}

具體不同的RTOS,其函數(shù)名各有不同,但大致思路一般都差不多。

總結(jié)一下

本文從為什么需要模塊化設(shè)計(jì)整體架構(gòu),到這樣做的好處,以及具體做的一些指導(dǎo)原則,再到實(shí)際中如何實(shí)現(xiàn),怎么做到高內(nèi)聚低耦合,提供了一些個(gè)人工作中的體會(huì)以及思路。同時(shí)對(duì)于裸機(jī)程序整體框架、基于RTOS的集成框架做了兩個(gè)demo,基本能解決大部分的框架思路問(wèn)題。將前文中的一些個(gè)人推崇的原則,在加粗總結(jié)下:

  • 所有與模塊相關(guān)的功能都應(yīng)集成到單個(gè)源文件中,這是高內(nèi)聚的體現(xiàn)。
  • 模塊對(duì)外提供一個(gè)頭文件,該文件聲明了該模塊的所有資源(硬件依賴(lài)/宏/常量/變量/函數(shù))。盡量用struct將緊密相關(guān)的變量進(jìn)行集總封裝。
  • 在源文件中包括自檢代碼部分,以實(shí)現(xiàn)該模塊模塊的所有自檢功能。
  • 固件模塊的接口應(yīng)經(jīng)過(guò)精心設(shè)計(jì)和定義。
  • 由于固件取決于硬件,因此需要在源文件頭中明確提及硬件的相關(guān)性。比如利用宏將硬件依賴(lài)轉(zhuǎn)定義,或者利用函數(shù)將基本操作進(jìn)行封裝。則在新的架構(gòu)體系,僅僅需要移植這部分實(shí)現(xiàn)即可使用。
  • 通常,固件模塊可供其他團(tuán)隊(duì)成員在其他項(xiàng)目中使用??赡苌婕暗焦芾砀?,缺陷修復(fù)、所有者應(yīng)維護(hù)模塊。源文件頭應(yīng)包含“作者”和“版本”信息。
  • 固件在某種程度上取決于編譯器。源文件頭中應(yīng)聲明基于什么開(kāi)發(fā)環(huán)境進(jìn)行過(guò)驗(yàn)證,以指定編譯器或與IDE相關(guān)的信息。

極力建議采用先設(shè)計(jì)-后開(kāi)發(fā)的模式,比較忌諱逐步debug,想到哪里寫(xiě)到哪里。當(dāng)然對(duì)于新手學(xué)習(xí)而言,后一種模式,可以逐步漸進(jìn)迭代,也可以比較快的增長(zhǎng)經(jīng)驗(yàn)。當(dāng)然如何取舍,全憑個(gè)人意愿。

相信您如深入閱讀,細(xì)細(xì)體會(huì),應(yīng)該從設(shè)計(jì)思想上得到些領(lǐng)悟,有所提高。如果能幫助到您,則我心甚慰,也不枉辛苦碼了這么多字。當(dāng)然如果覺(jué)得文章有價(jià)值,也麻煩幫忙點(diǎn)在看,或者轉(zhuǎn)發(fā)分享。讓更多朋友能看到,當(dāng)然對(duì)于單片機(jī)開(kāi)發(fā)大神而言,文中觀點(diǎn)則顯得頗為粗淺了。至于贊賞,則隨心即可。


本文授權(quán)轉(zhuǎn)載自公眾號(hào)“嵌入式客?!?,作者逸珺

免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問(wèn)題,請(qǐng)聯(lián)系我們,謝謝!

嵌入式ARM

掃描二維碼,關(guān)注更多精彩內(nèi)容

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專(zhuān)欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車(chē)的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車(chē)技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車(chē)工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車(chē)。 SODA V工具的開(kāi)發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車(chē) 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶(hù)希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來(lái)越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開(kāi)幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱(chēng),數(shù)字世界的話(huà)語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱(chēng)"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉