我是老溫,一名熱愛學(xué)習(xí)的嵌入式工程師
關(guān)注我,一起變得更加優(yōu)秀!
狀態(tài)機(jī)的實(shí)現(xiàn)無非就是三個(gè)要素:狀態(tài)、事件、響應(yīng)。轉(zhuǎn)換成具體的行為,其實(shí)就三句話:
發(fā)生了什么事?現(xiàn)在系統(tǒng)處在什么狀態(tài)?在這樣的狀態(tài)下發(fā)生了這樣的事,系統(tǒng)要干什么?用C語言實(shí)現(xiàn)狀態(tài)機(jī),主要有三種方法:switch—case 法、表格驅(qū)動(dòng)法、函數(shù)指針法。下面給大家詳細(xì)介紹一下。01
switch—case 法狀態(tài)用 switch—case 組織起來, 將事件也用switch—case 組織起來, 然后讓其中一個(gè) switch—case 整體插入到另一個(gè) switch—case 的每一個(gè) case 項(xiàng)中 。
「程序清單 List4 :」
switch(StateVal)
{
case S0:
switch(EvntID)
{
case E1:
action_S0_E1(); /*S0 狀態(tài)下 E1 事件的響應(yīng)*/
StateVal = new state value;/*狀態(tài)遷移,不遷移則沒有此行*/
break;
case E2:
action_S0_E2(); /*S0 狀態(tài)下 E2 事件的響應(yīng)*/
StateVal = new state value;
break;
......
case Em:
action_S0_Em(); /*S0 狀態(tài)下 Em 事件的響應(yīng)*/
StateVal = new state value;
break;
default:
break;
}
break;
case S1:
......
break;
......
case Sn:
......
break;
default:
break;
}
上面的偽代碼示例只是通用的情況,實(shí)際應(yīng)用遠(yuǎn)沒有這么復(fù)雜。雖然一個(gè)系統(tǒng)中事件可能有很多種,但在實(shí)際應(yīng)用中,許多事件可能對(duì)某個(gè)狀態(tài)是沒有意義的。
例如在程序清單 List4中,如果 E2、······ Em 對(duì)處在 S0 狀態(tài)下的系統(tǒng)沒有意義,那么在 S0 的 case 下有關(guān)事件E2、······ Em 的代碼根本沒有必要寫,狀態(tài) S0 只需要考慮事件 E1 的處理就行了。
既然是兩個(gè) switch—case 之間的嵌套, 那么就有一個(gè)誰嵌套誰的問題, 所以說 switch—case法有兩種寫法:狀態(tài)嵌套事件和事件嵌套狀態(tài)。這兩種寫法都可以, 各有利弊, 至于到底選用哪種方式就留給設(shè)計(jì)人員根據(jù)具體情況自行決斷吧。
關(guān)于 switch—case 法還有最后一點(diǎn)要說明, 因?yàn)?switch—case 的原理是從上到下挨個(gè)比較,越靠后,查找耗費(fèi)的時(shí)間就越長,所以要注意狀態(tài)和事件在各自的 switch 語句中的安排順序,不推薦程序清單 List4 那樣按順序號(hào)排布的方式。出現(xiàn)頻率高或者實(shí)時(shí)性要求高的狀態(tài)和事件的位置應(yīng)該盡量靠前。
02
表格驅(qū)動(dòng)法如果說** switch—case 法是線性的**,那么表格驅(qū)動(dòng)法則是平面的。表格驅(qū)動(dòng)法的實(shí)質(zhì)就是將狀態(tài)和事件之間的關(guān)系固化到一張二維表格里, 把事件當(dāng)做縱軸,把狀態(tài)當(dāng)做橫軸,交點(diǎn)[Sn , Em]則是系統(tǒng)在 Sn 狀態(tài)下對(duì)事件 Em 的響應(yīng) 。 |