作者 | Alicedodo
上一篇推文:咱們是時候改變一下嵌入式軟件開發思維方式了!提到了狀態機。在之前的推文中:干貨 | 嵌入式之狀態機編程。有簡單介紹了狀態機的示例。這次我們一起來學習C語言實現狀態機的三種方法解析。
狀態機的實現無非就是 3 個要素:狀態、事件、響應。轉換成具體的行為就 3 句話。
用 C 語言實現狀態機主要有 3 種方法:switch—case 法、表格驅動法、函數指針法。
狀態用 switch—case 組織起來, 將事件也用switch—case 組織起來, 然后讓其中一個 switch—case 整體插入到另一個 switch—case 的每一個 case 項中 。
「程序清單 List4 :」
switch(StateVal)
{
case S0:
switch(EvntID)
{
case E1:
action_S0_E1(); /*S0 狀態下 E1 事件的響應*/
StateVal = new state value;/*狀態遷移,不遷移則沒有此行*/
break;
case E2:
action_S0_E2(); /*S0 狀態下 E2 事件的響應*/
StateVal = new state value;
break;
......
case Em:
action_S0_Em(); /*S0 狀態下 Em 事件的響應*/
StateVal = new state value;
break;
default:
break;
}
break;
case S1:
......
break;
......
case Sn:
......
break;
default:
break;
}
上面的偽代碼示例只是通用的情況,實際應用遠沒有這么復雜。雖然一個系統中事件可能有很多種,但在實際應用中,許多事件可能對某個狀態是沒有意義的。
例如在程序清單 List4中,如果 E2、······ Em 對處在 S0 狀態下的系統沒有意義,那么在 S0 的 case 下有關事件E2、······ Em 的代碼根本沒有必要寫,狀態 S0 只需要考慮事件 E1 的處理就行了。
既然是兩個 switch—case 之間的嵌套, 那么就有一個誰嵌套誰的問題, 所以說 switch—case法有兩種寫法:狀態嵌套事件和事件嵌套狀態。這兩種寫法都可以, 各有利弊, 至于到底選用哪種方式就留給設計人員根據具體情況自行決斷吧。
關于 switch—case 法還有最后一點要說明, 因為 switch—case 的原理是從上到下挨個比較,越靠后,查找耗費的時間就越長,所以要注意狀態和事件在各自的 switch 語句中的安排順序,不推薦程序清單 List4 那樣按順序號排布的方式。出現頻率高或者實時性要求高的狀態和事件的位置應該盡量靠前。
如果說 switch—case 法是線性的,那么表格驅動法則是平面的。表格驅動法的實質就是將狀態和事件之間的關系固化到一張二維表格里, 把事件當做縱軸,把狀態當做橫軸,交點[Sn , Em]則是系統在 Sn 狀態下對事件 Em 的響應 。