嵌入式軟件架構(gòu)設(shè)計-事件型狀態(tài)機
掃描二維碼
隨時隨地手機看文章
前言
前面介紹了有限狀態(tài)機(FSM)和分層狀態(tài)機(HSM),這一篇介紹的主要是事件型狀態(tài)機(ESM)。
一種在嵌入式系統(tǒng)中廣泛應(yīng)用的設(shè)計方法,用于管理和控制系統(tǒng)的狀態(tài)轉(zhuǎn)換。它將狀態(tài)的切換與外部事件的發(fā)生聯(lián)系起來,使系統(tǒng)能夠更靈活地響應(yīng)不同的條件和輸入。
介紹
事件驅(qū)動型狀態(tài)機將系統(tǒng)劃分為一組狀態(tài),每個狀態(tài)表示系統(tǒng)在特定條件下的行為。狀態(tài)之間的轉(zhuǎn)換是由外部事件的發(fā)生觸發(fā)的,而不是由內(nèi)部條件或方法調(diào)用直接控制。
主要組成部分
-
狀態(tài)(States):系統(tǒng)在不同條件下可能處于的狀態(tài)。每個狀態(tài)表示一種特定的行為或狀態(tài)。
-
事件(Events):觸發(fā)狀態(tài)轉(zhuǎn)換的外部事件,可以是傳感器數(shù)據(jù)的變化、用戶輸入、定時器中斷等。
-
狀態(tài)轉(zhuǎn)換(Transitions):定義狀態(tài)之間的轉(zhuǎn)換規(guī)則,指明從一個狀態(tài)切換到另一個狀態(tài)需要哪個事件的觸發(fā)。
-
事件處理程序(Event Handlers):每個狀態(tài)可以關(guān)聯(lián)一個或多個事件處理程序,用于處理狀態(tài)轉(zhuǎn)換時觸發(fā)的事件。事件處理程序定義了狀態(tài)之間的行為。
工作原理
事件驅(qū)動型狀態(tài)機的工作原理如下:
-
初始化:系統(tǒng)初始化時處于初始狀態(tài)。
-
事件監(jiān)測:系統(tǒng)不斷監(jiān)測外部事件的發(fā)生。
-
事件匹配:當(dāng)某個外部事件發(fā)生時,狀態(tài)機檢查當(dāng)前狀態(tài)的狀態(tài)轉(zhuǎn)換表,找到與該事件匹配的狀態(tài)轉(zhuǎn)換。
-
狀態(tài)轉(zhuǎn)換:如果找到匹配的狀態(tài)轉(zhuǎn)換,系統(tǒng)執(zhí)行狀態(tài)轉(zhuǎn)換,并調(diào)用關(guān)聯(lián)的事件處理程序。這可能導(dǎo)致系統(tǒng)從當(dāng)前狀態(tài)切換到另一個狀態(tài)。
-
等待事件:一旦事件處理程序執(zhí)行完畢,系統(tǒng)會等待下一個外部事件的發(fā)生。
區(qū)別
基于事件驅(qū)動的狀態(tài)機和普通狀態(tài)機都是用于管理和控制系統(tǒng)狀態(tài)轉(zhuǎn)換的方法,但它們在設(shè)計思想和實現(xiàn)方式上有一些區(qū)別。
普通狀態(tài)機
-
狀態(tài)切換方式:在普通狀態(tài)機中,狀態(tài)之間的轉(zhuǎn)換通常是基于內(nèi)部條件或者直接的方法調(diào)用。狀態(tài)轉(zhuǎn)換通常由狀態(tài)之間的關(guān)系和切換條件直接控制。
-
切換條件:普通狀態(tài)機的狀態(tài)切換通常由硬編碼的邏輯條件決定,這些條件可能包括輸入信號、定時器、內(nèi)部變量等。
-
狀態(tài)管理:普通狀態(tài)機需要維護(hù)一個狀態(tài)轉(zhuǎn)換表或者邏輯判斷來控制狀態(tài)的切換和行為。狀態(tài)之間的關(guān)系和切換條件可能會使代碼變得復(fù)雜,尤其在狀態(tài)較多或者狀態(tài)之間的關(guān)系較復(fù)雜時。
-
應(yīng)用場景:普通狀態(tài)機適用于狀態(tài)轉(zhuǎn)換較為簡單、固定的場景,適合用于描述一些基本的系統(tǒng)行為和流程。
事件型驅(qū)狀態(tài)機
-
狀態(tài)切換方式:基于事件驅(qū)動的狀態(tài)機依賴于外部事件的發(fā)生來觸發(fā)狀態(tài)的轉(zhuǎn)換。狀態(tài)之間的轉(zhuǎn)換是由事件觸發(fā)的,狀態(tài)機根據(jù)事件的發(fā)生來確定下一個狀態(tài)。
-
切換條件:在基于事件驅(qū)動的狀態(tài)機中,狀態(tài)的轉(zhuǎn)換不是直接由內(nèi)部邏輯條件決定,而是由外部事件的發(fā)生來觸發(fā)。狀態(tài)之間的關(guān)系和切換條件更加松散。
-
狀態(tài)管理:基于事件驅(qū)動的狀態(tài)機不需要維護(hù)復(fù)雜的狀態(tài)轉(zhuǎn)換表,而是在收到特定事件時,根據(jù)事件來觸發(fā)狀態(tài)的切換。這種方式使得狀態(tài)機的設(shè)計更加靈活和可擴展。
-
應(yīng)用場景:基于事件驅(qū)動的狀態(tài)機適用于復(fù)雜的狀態(tài)轉(zhuǎn)換和流程,特別是當(dāng)狀態(tài)之間的關(guān)系比較復(fù)雜,或者需要根據(jù)外部事件來靈活控制狀態(tài)轉(zhuǎn)換時,這種方法更加合適。
總體而言,基于事件驅(qū)動的狀態(tài)機相對于普通狀態(tài)機更具靈活性和擴展性,適用于復(fù)雜的嵌入式MCU應(yīng)用場景。它能夠更好地處理狀態(tài)之間的關(guān)系,以及根據(jù)外部事件來觸發(fā)狀態(tài)的轉(zhuǎn)換,從而提供更高效、靈活和可擴展的狀態(tài)管理和控制。
代碼實現(xiàn)
下面是一個基于事件驅(qū)動的狀態(tài)機框架的簡單示例代碼,用于說明其工作原理。
#include#include // 定義狀態(tài)枚舉 typedef enum { STATE_IDLE, STATE_RUNNING, STATE_PAUSED, STATE_STOPPED } State; // 定義事件枚舉 typedef enum { EVENT_START, EVENT_PAUSE, EVENT_RESUME, EVENT_STOP } Event; // 定義狀態(tài)轉(zhuǎn)換表 typedef struct { State current; // 當(dāng)前狀態(tài) Event event; // 事件 State next; // 事件觸發(fā)后的新狀態(tài) void (*action)(void); } Transition; // 狀態(tài)處理函數(shù) void handleIdle(void) { printf("System is idle.\n"); } void handleRunning(void) { printf("System is running.\n"); } void handlePaused(void) { printf("System is paused.\n"); } void handleStopped(void) { printf("System is stopped.\n"); } // 狀態(tài)轉(zhuǎn)換函數(shù) void stateTransition(State* currentState, Event event) { // 定義狀態(tài)轉(zhuǎn)換表 static Transition transitions[] = { {STATE_IDLE, EVENT_START, STATE_RUNNING, handleRunning}, {STATE_RUNNING, EVENT_PAUSE, STATE_PAUSED, handlePaused}, {STATE_PAUSED, EVENT_RESUME, STATE_RUNNING, handleRunning}, {STATE_RUNNING, EVENT_STOP, STATE_STOPPED, handleStopped}, {STATE_PAUSED, EVENT_STOP, STATE_STOPPED, handleStopped} }; int numTransitions = sizeof(transitions) / sizeof(transitions[0]); // 查找并執(zhí)行狀態(tài)轉(zhuǎn)換 for (int i = 0; i < numTransitions; i++) { if (transitions[i].current == *currentState && transitions[i].event == event) { printf("Transition: %d -> %d\n", *currentState, transitions[i].next); transitions[i].action(); *currentState = transitions[i].next; break; } } } int main() { State currentState = STATE_IDLE; // 模擬狀態(tài)轉(zhuǎn)換事件 stateTransition(¤tState, EVENT_START); stateTransition(¤tState, EVENT_PAUSE); stateTransition(¤tState, EVENT_RESUME); stateTransition(¤tState, EVENT_STOP); return 0; }
運行結(jié)果:
Transition: 0 -> 1 System is running. Transition: 1 -> 2 System is paused. Transition: 2 -> 1 System is running. Transition: 1 -> 3 System is stopped.





