筆者在職場工作多年,維護過屎山級別的項目代碼,也參與過大大小小的軟件開發。我逐漸明白了寫代碼最重要的并不是炫技,而是讓其他維護這個項目的人能夠更快的上手去拓展項目的功能,以便能夠更好的傳承下去。
在實際的嵌入式應用開發過程中,我們常常能夠聽到軟件系統的分層設計,根據不同的產品軟件設計,它們可能擁有應用層、系統層、驅動層等等。在我看來,這些層的描述太大,但是它不得不存在;因為它能夠從宏觀上讓每個了解它的人知道它到底有什么東西,大部分情況下給人感覺是:哇,好牛逼!然后,就沒有然后了。
實際上,真正能夠體現設計的牛逼并不是簡單的描述幾個層就可以了,真正的設計,它至少擁有兩個面的維度,即數據平面、控制平面。當然,如果我們分得更細一點,它可以是數據平面、控制平面和管理平面。至于怎么定義每個平面的作用,早在1979年,就已經有一位叫做Trygve Reenskaug的大佬為我們設計好了所謂的MVC框架。直到如今,MVC框架廣泛應用于現代應用軟件設計中,也是嵌入式應用軟件設計中最常用的設計模式之一。那么,什么是MVC框架呢?
1、MVC框架
MVC框架,是軟件系統模塊化設計的一種方法,它給軟件系統劃分為三個大的部分,分別是Model(模型)、View(視圖)、Controller(控制器)。
Model模型
模型就是負責具體功能、業務邏輯實現的,它通常是一個產品內部的一些業務邏輯組成;例如,接下來我們要做的一個項目里有一個MQ-2傳感器,MQ-2傳感器的氣體檢測流程可以認為是一個模型。
View視圖
視圖就是負責展示、響應其它模塊處理結果的。例如,有一款設備擁有一個LCD屏幕,然后上面移植了一個GUI系統,它用于顯示當前MQ-2傳感器的數據,那么這個GUI系統就是一個視圖。當MQ-2傳感器檢測到的閾值超出我們所設定的閾值時,蜂鳴器或者LED報警了,那么蜂鳴器、LED也可以認為是一個視圖。當然,視圖不局限于以上這些內容,視圖也可以是IOT前端、也可以是一個Shell終端,甚至可以是一個進程或者線程。
Controller控制器
控制器就是用來接收用戶輸入的。通常,一個設備上可能有按鍵、觸摸屏、鼠標等輸入設備,那么當用戶控制輸入設備時,根據產品內部的業務邏輯,界面可能會發生跳轉(視圖),用戶看不到的另一面會啟動應用業務邏輯(模型),然后設備內部的業務邏輯處理完畢后,又會通知界面,例如彈窗或者僅僅是界面上控件數據更新(視圖)。
有了MVC架構以后,我們可以為我們接下來的項目做以下軟件模塊的劃分了,先預告一下,我們要做一個簡單的氣體檢測裝置,它會延用我們之前分享過的內容進一步規范化:
表驅動+狀態機法AD傳感器驅動檢測框架
讓傳感器數據更直觀之LCD曲線顯示
基于小熊派氣體傳感器MQ-2綜合實踐
Model
傳感器數據獲取、傳感器流程檢測。
View
LCD GUI(或者騰訊云、騰訊連連小程序)顯示,顯示傳感器數據、檢測狀態等
Controller
開發板上的按鍵、IOT終端下發命令(或騰訊連連小程序下發命令)
那么,這三個模塊怎么來通信呢?一般情況下,可以有兩種方式,一種是通過消息傳遞,另外一種是通過回調函數傳遞(類似事件回調觸發機制)。很顯然,我們的項目會考慮上RTOS,那么,通過消息隊列來傳輸數據就再好不過了!這樣的話,我們每個模塊之間的通信一旦設計好了,那么未來需要做的事情僅僅只需要關心:
消息發送端:數據怎么傳,要傳什么數據
接收消息端:數據怎么接,接完之后要做什么
解決了發送、接收數據的問題以后,第二步就是要設計傳感器的檢測流程了,它也是我們MVC架構中模型部分最重要的內容了,它是整個項目的核心業務。對于傳感器設備檢測來說,無非就是幾種分析狀態:
傳感器設備處于空閑狀態
傳感器設備處于校準狀態
傳感器設備處于檢測中狀態
傳感器設備處于獲取檢測結果狀態
從一種狀態切換到另一種狀態,那么一定是由某個事件觸發的,進而產生一定的動作,然后完成狀態的遷移,我們將這種稱為狀態機。在設計模式中,狀態機稱為狀態模式,狀態模式也是嵌入式軟件應用設計中最常用的模式。
2、狀態模式
狀態模式是設計模式中行為型模式的一種,它允許對象在內部狀態發生改變時改變它的行為。對于小白來說,狀態模式的概念講述是比較抽象的,那么,我可以舉一個接下來要做的氣體檢測儀項目來加深大家對狀態模式的理解,以下是這個項目的簡單的狀態遷移圖:
在狀態機的基本概念里,它的基本組成要素主要由現態、條件、動作、次態。我們能看到,檢測儀主要有四個狀態,分別是IDLE、CALI、DETECT、RESULT,每個狀態其實都是由相應的條件來進行觸發產生動作進而產生下一個狀態的。從以上的狀態遷移圖里,我們能很清晰地將每個狀態的遷移過程描述出來:
1.對于IDLE來說,主要有:
IDLE→START→CALI
解析:當檢測儀狀態為IDLE時,檢測儀的操作者需要發起一個START事件來讓檢測儀的狀態由IDLE進入到CALI狀態中。這樣的操作場景通常是檢測儀的操作者按下一個開始檢測的按鈕,檢測儀由空閑狀態轉為基準采集狀態,此時檢測儀可能會開啟各類傳感器,在此期間,各項傳感器指標需要與當前環境進行融合,使各項傳感器指標處于穩定狀態,這樣才有利于后續檢測結果精確。
2.對于CALI來說,主要有:
CALI→NEXT→DETECT CALI→STOP→IDLE
解析:當檢測儀狀態處于CALI時,如果此時條件滿足,則需要發起一個NEXT事件讓檢測儀狀態由CALI進入DETECT中。這個NEXT事件可以是CALI過程穩定后自動觸發的,也可以是由用戶手動觸發的,這個需要根據產品需求進行定義。如果此時條件不滿足則維持現態CALI,當檢測儀的操作者發起STOP事件時,通常是按下了某個返回或者退出的按鍵,則此時檢測的狀態由CALI遷移到了IDLE態。
3.對于DETECT來說,主要有:
DETECT→NEXT→RESULT DETECT→PREV→CALI DETECT→STOP→IDLE
解析:當檢測儀狀態處于DETECT時,此時內部會進行一系列的動作,那么它得有結果呀,結果就是由NEXT事件來產生的,這樣的應用場景通常是傳感器各項技術指標整合的檢測算法運算結果與檢測儀所設定的閾值進行比較后自行觸發的,最終將由DETECT狀態遷移到了RESULT。當然,如果當前處于DETECT狀態,而DETECT狀態的過程存在偏差,此時檢測儀操作者可以通過某個按鍵,觸發PERV事件,將DETECT狀態遷移到上個狀態CALI;當然,檢測儀操作者也可以直接選擇停止檢測,他只需要發起一個STOP事件(通常是一個返回按鍵)即可讓檢測儀的狀態由DETECT遷移到IDLE狀態。
4.對于RESULT來說,主要有:
RESULT→PREV→DETECT RESULT→STOP→IDLE
解析:當檢測儀狀態處于RESULT時,一般情況下檢測儀要么是通過聲光報警,要么是直接在LCD上進行展示,要么是都有。檢測儀的操作者可以繼續檢測,那么他只需要發起一個PREV事件就能讓檢測儀的狀態由RESULT遷移到DETECT,設備又能夠繼續進行檢測了,這就是所謂的快檢模式。當然,檢測儀操作者也可以發起一個STOP事件,讓檢測儀回到IDLE狀態。
對以上狀態遷移過程熟悉后,我們第二步要做的事情就是設計符合我們業務場景的枚舉以及結構體。首先是傳感器的狀態,有IDLE、CALI、DETECT、RESULT,用枚舉來體現就是:
//傳感器狀態 enumSensorState_t { IDLE=0, CALI, DETECT, RESULT };
每種狀態是由特定的事件進行觸發,那么傳感器的事件主要有:
//傳感器事件 enumSensorEvent_t { START=0, STOP, NEXT, };
有了狀態和事件之后,我們需要使用一個結構體來抽象從現態->事件->次態這個過程,那么我們可以這么來設計:
structSensorStateItem_t { enumSensorState_tCurState; enumSensorEvent_tEvent; enumSensorState_tNextSate; };
因此,我們能夠根據我們所描述的狀態規劃出一張表,而這張表就清晰的描述出現態->事件->次態的這幾個過程了:
structSensorStateItem_tSensorStateTable[]= { {IDLE,START,CALI},//IDLE->START->CALI {CALI,NEXT,DETECT},//CALI->NEXT->DETECT {CALI,STOP,IDLE},//CALI->STOP->IDLE {DETECT,NEXT,RESULT},//DETECT->NEXT->RESULT {DETECT,PREV,CALI},//DETECT->PREV->CALI {DETECT,STOP,IDLE},//DETECT->STOP->IDLE {RESULT,PREV,DETECT},//RESULT->PREV->DETECT {RESULT,STOP,IDLE},//RESULT->STOP->IDLE };
有了業務模型以后,接下來就是編寫代碼邏輯了!
-
傳感器
+關注
關注
2551文章
51134瀏覽量
753849 -
數據
+關注
關注
8文章
7048瀏覽量
89073 -
軟件
+關注
關注
69文章
4953瀏覽量
87546 -
框架
+關注
關注
0文章
403瀏覽量
17500
發布評論請先 登錄
相關推薦
評論