
[導讀] 為什么寫本文?做公號兩月,遇到一些初學單片機的同學,剛剛入手做單片機開發,還沒有涉及到使用RTOS,且剛入手直接上RTOS可能會有些難度,有的使用的相對較老單片機資源還有限,也不適合跑RTOS。
或者使用RTOS,在整體思路上比較迷茫,不知從何入手,所以本文來聊聊我對單片機程序的整體框架設計的一些思路體會。
單片機系統開發人員的目標之一是在編程環境中創建固件,以實現低成本系統、軟件可靠性以及快速的開發迭代時間。
實現這種編程環境的最佳方法實踐是使用統一的固件架構體系結構,該體系結構在產品開發過程中充當框架并支持“固件模塊化”,或稱為子系統。
如果不采用統一的設計架構,那么其業務需求耦合關系復雜,不采用先設計-后開發的方法論,想到哪里寫到哪里,則程序后期維護將變得異常艱辛,而引入潛在bug/缺陷的風險也將大大增加,且不具備多人協同開發的可能。
可以結合固件模塊化、可測試性和兼容性的正確組合的設計體系架構結構應用于任何固件開發項目,以最大程度地提高代碼可復用性,加快固件調試速度并提高固件可移植性。
模塊化編程將程序功能分解為固件模塊/子系統,每個模塊執行一個功能,并包含完成該功能所需的所有源代碼和變量。

模塊化/子系統化有助于協調團隊中許多人的并行工作,管理項目各個部分之間的相互依賴關系,并使設計人員、系統集成人員能夠以可靠的方式組裝復雜的系統。具體來說,它可以幫助設計人員實現和管理復雜性。
隨著應用程序的大小和功能的增長,需要模塊化才能將它們分成單獨的部分(無論是作為“組件”,“模塊”還是“子系統”)。
然后,每個這樣分離的部分就成為模塊化體系結構的一個元素。這樣,可以使用定義明確的界面隔離和訪問每個組件。此外,模塊化編程可提高固件的可讀性,同時簡化固件的調試,測試和維護。
即便是一個人獨立開發一個項目,這樣做依然在代碼的調試、可讀性、可移植性方面是最佳實踐的整體策略。如果代碼設計良好,則在其他項目可以輕松應用。而且模塊經過上一項目的測試驗證,在新的項目中再次應用其缺陷風險將大幅降低。所以每做一個項目,以這種策略不斷積累模塊"輪子"組件,隨著經驗的增長,積累的“輪子”就越來越多,也越來越好。
所以其優點是顯而易見的,否則每做一個項目,都從輪子造起,開發時間長不說,開發水平也得不到提高,重復性工作也很枯燥。
比如前文中談到的非易失存儲管理子系統,如設計良好,就變成一個可靠的可移植的輪子。這段話請深入理解,并拿走不謝!
固件開發中模塊化編程的基本概念是創建固件模塊。從概念上講,模塊代表關注點分離。在計算機科學中,關注點分離是將計算機程序分解為功能很少重疊的獨特功能的過程。關注點是程序的任何關注點或功能,并且與功能或行為同義。
關注點分離的發展傳統上是通過模塊化和封裝來實現的,其實也就是解耦思想。
固件模塊可以分為幾種類型:
實施估計模塊化設計的一些規則:
需要注意的是,模塊化設計會引入一些調用開銷,也可能增加固件尺寸大小。在實際實現時,折中考量。不要過度模塊化,所以建議采用高內聚、低耦合的實現策略。
在前面文章中有談到過的呼吸機PB560的設計,看過其代碼,本打算解讀一下其代碼設計,但讀下來發現,其設計過度模塊化了,沒有實現高內聚的思想。其源代碼很多源文件僅僅實現了一個函數,而不是把一類問題集中抽象實現,后來就放棄了其代碼解讀。
做工程開發,一定是需求驅動的。第一件事需要對需求有比較清晰的認知,然后才能設計一個比較合理的框架。我們需要實現什么?大致總體設計過程策略我的基本采用如下圖所示思路(我比較喜歡繪圖,圖會讓人比較直觀)

問自己第一個問題是:這個項目要實現什么主要功能?這個來自哪里?如果是實際產品開發,則可能來自市場的需求,如果是自己的DIY項目,也一定會YY出一個大致的想法?總之不管源自何方,需求總要先梳理清楚。那么需求一般意義上包含哪些呢?
結合固件模塊原理以及相關指導原則,那么將相關性高的需求,抽象實現在一系列的模塊中,在由這一系列模塊配合實現某個相關性高的業務需求,再進一步這些模塊就變成一個子系統。多個子系統在main.c的調度下,協調完成產品的整體功能。
對于某些不使用RTOS的應用而言,可以使用如下的框架進行:
void main(void)
{
/*各模塊初始化*/
init_module_1();
init_module_2();
....
while(1)
{
/*實現一個定時調度策略*/
if(timer50ms)
{
timer50ms = 0;
app_module_1();
}
if(timer100ms)
{
timer100ms = 0;
app_module_2();
}
/*異步請求處理,如中斷后臺處理*/
if(flag1)
{
communication_handler();
}
.....
}
}
對于基于RTOS的集成實現舉例:
void task1(void)
{
/*處理子系統相關的初始化*/
init_task1();
while(1)
{
/*應用相關調用*/
task1_mainbody();
....
}
}
....
void taskn(void)
{
/*處理子系統相關的初始化*/
init_taskn();
while(1)
{
/*應用相關調用*/
taskn_mainbody();
....
}
}
void main(void)
{
/*一些基本硬件相關初始化,比如IO,時鐘,OS tick定時器等*/
init_hal();
......
/*一些基本RTOS初始化*/
init_os();
/*任務創建*/
os_creat("task1",task1,棧設置,優先級,...);
......
os_creat("taskn",taskn,棧設置,優先級,...);
/*啟動OS調度器,交由OS調度管理應用任務*/
os_start();
}
具體不同的RTOS,其函數名各有不同,但大致思路一般都差不多。
本文從為什么需要模塊化設計整體架構,到這樣做的好處,以及具體做的一些指導原則,再到實際中如何實現,怎么做到高內聚低耦合,提供了一些個人工作中的體會以及思路。
同時對于裸機程序整體框架、基于RTOS的集成框架做了兩個demo,基本能解決大部分的框架思路問題。將前文中的一些個人推崇的原則,在加粗總結下:
極力建議采用先設計-后開發的模式,比較忌諱逐步debug,想到哪里寫到哪里。當然對于新手學習而言,后一種模式,可以逐步漸進迭代,也可以比較快的增長經驗。當然如何取舍,全憑個人意愿。
相信您如深入閱讀,細細體會,應該從設計思想上得到些領悟,有所提高。如果能幫助到您,則我心甚慰,也不枉辛苦碼了這么多字。當然如果覺得文章有價值,也麻煩幫忙點在看,或者轉發分享。讓更多朋友能看到,當然對于單片機開發大神而言,文中觀點則顯得頗為粗淺了。


1.國產嵌入式操作系統,你最看好哪一個?
2.楊福宇專欄|溫州特斯拉失控案EDR數據的深度解讀
3.【視頻上線】嵌入式實時操作系統學習之道
4.學習STM32單片機,繞不開的串口
5.RISC-V產業的現狀與未來~
6.當MCU死機了,先把硬件抓過來~

免責聲明:本文系網絡轉載,版權歸原作者所有。如涉及作品版權問題,請與我們聯系,我們將根據您提供的版權證明材料確認版權并支付稿酬或者刪除內容。