STM32狀態(tài)機編程----什么是狀態(tài)機?
什么是狀態(tài),點擊此處領(lǐng)取相關(guān)資料
狀態(tài)是人或事物表現(xiàn)出來的形態(tài)。是指現(xiàn)實(或虛擬)事物處于生成、生存、發(fā)展、消亡時期或各轉(zhuǎn)化臨界點時的形態(tài)或事物態(tài)勢。
通過上面那句話,我們知道了狀態(tài)就是一個對象在不同情況下對應的各種形態(tài)
做產(chǎn)品的時候,如果我們?nèi)绻獙@個對象所有的形態(tài)進行描述,在一些對象復雜的邏輯狀態(tài)下,比較復雜的邏輯問題,普通的流程圖,或時序圖對于對象和狀態(tài)的解讀缺乏直觀的描述。
這個時候就需要狀態(tài)機來對對象的各個形態(tài)進行描述,將對象的全部工作方式,分成幾個場景,這些場景的工作方式不同,然后將這些場景通過數(shù)學模型表示出來
比方說一個小燈泡的開關(guān),就是一個最基本的小型狀態(tài)機
這里就是兩個狀態(tài):①打開開關(guān),燈泡亮,②關(guān)閉開關(guān),燈泡滅
對應的狀態(tài)機圖:
這就是最簡單的一個狀態(tài)機
狀態(tài)機方便的地方是,如果現(xiàn)在我們只有兩種狀態(tài),這兩個狀態(tài)在 打開開關(guān)/關(guān)閉開關(guān)兩個條件之間跳轉(zhuǎn),如果我們要加上一個新的條件,比方說我們設(shè)定了定時開關(guān)燈,多了一個跳轉(zhuǎn)條件,如果燈泡開了超過8個小時就自動關(guān)閉,除非再次做打開開關(guān),否則燈泡一致處于關(guān)閉狀態(tài),這個狀態(tài)圖如下:
是不是很方便
再舉個最簡單的例子。人有三個狀態(tài)健康,感冒,康復中。
觸發(fā)的條件有淋雨(t1),吃藥(t2),打針(t3),休息(t4)。
所以狀態(tài)機就是健康->(t4)->健康;健康->(t1)->感冒;感冒->(t3)->健康;感冒->(t2)->康復中;康復中->(t4)->健康,等等。就是這樣狀態(tài)在不同的條件下跳轉(zhuǎn)到自己或不同狀態(tài)的情況,就叫做狀態(tài)機。
狀態(tài)機要素
通過上面的舉例,我們可以講狀態(tài)機可歸納為4個要素,即現(xiàn)態(tài)、條件、動作、次態(tài)。這樣的歸納,主要是出于對狀態(tài)機的內(nèi)在因果關(guān)系的考慮。“現(xiàn)態(tài)”和“條件”是因,“動作”和“次態(tài)”是果。詳解如下:
- ①現(xiàn)態(tài):是指當前所處的狀態(tài)。
- ②條件:又稱為“事件”,當一個條件被滿足,將會觸發(fā)一個動作,或者執(zhí)行一次狀態(tài)的遷移。
- ③動作:條件滿足后執(zhí)行的動作。動作執(zhí)行完畢后,可以遷移到新的狀態(tài),也可以仍舊保持原狀態(tài)。動作不是必需的,當條件滿足后,也可以不執(zhí)行任何動作,直接遷移到新狀態(tài)。
- ④次態(tài):條件滿足后要遷往的新狀態(tài)。“次態(tài)”是相對于“現(xiàn)態(tài)”而言的,“次態(tài)”一旦被激活,就轉(zhuǎn)變成新的“現(xiàn)態(tài)”了。
狀態(tài)機是一種編程思路。是現(xiàn)實事物運行規(guī)則抽象而成的一個數(shù)學模型。
有限狀態(tài)機
有限狀態(tài)機簡稱就是狀態(tài)機,因為一般的狀態(tài)機的狀態(tài)都是離散和可舉的,即為有限,所以后面的介紹都不加有限二字**。狀態(tài)機表示有限個狀態(tài)以及在這些狀態(tài)之間的轉(zhuǎn)移和動作等行為的數(shù)學模型**。通俗的描述狀態(tài)機就是定義了一套狀態(tài)変更的流程:
狀態(tài)機包含一個狀態(tài)集合,定義當狀態(tài)機處于某一個狀態(tài)的時候它所能接收的事件以及可執(zhí)行的行為,執(zhí)行完成后,狀態(tài)機所處的狀態(tài)。
狀態(tài)遷移圖(STD)
- (1)狀態(tài)框:用方框表示狀態(tài),包括所謂的“現(xiàn)態(tài)”和“次態(tài)”;
- (2)條件及遷移箭頭:用箭頭表示狀態(tài)遷移的方向,并在該箭頭上標注觸發(fā)條件;
- (3)節(jié)點圓圈:當多個箭頭指向一個狀態(tài)時,可以用節(jié)點符號(小圓圈)連接匯總;
- (4)動作框:用橢圓框表示;
- (5)附加條件判斷框:用六角菱形框表示;
STM32中的狀態(tài)機
舉個簡單的例子:就按鍵處理來說,按鍵動作本身也可以看做一個狀態(tài)機。一個細小的擊鍵動作包含了:釋放、抖動、按下、抖動和重新釋放等狀態(tài)。 當我們打開思路,把狀態(tài)機作為一種思想導入到程序中去時,就會找到處理疑問的一條有效的捷徑。有時候用狀態(tài)機的思維去思考程序該干什么,比用控制流程的思維去思考,可能會更有效。這樣一來狀態(tài)機便有了更實際的功用。廢話不多說,實踐才是檢驗真理的唯一標準。
也許有人覺得狀態(tài)機把問題復雜化了,其實我們在編寫代碼的時候在無形之中已經(jīng)使用了狀態(tài)機的思想,比方說我們的if else 判斷
if else語句結(jié)構(gòu)狀態(tài)機
if 條件1 else if 條件2 else if 條件3 ... else 條件n
我們知道C語言的if else if語句是從第一條開始判斷的,如果符合條件的那一行永遠在后面幾行,那么就要每次多執(zhí)行很多次的if …而if是判斷語句,括號內(nèi)的判斷是要執(zhí)行運算的,即使是單周期指令的MCU,在進行乘除運算等都需要消耗多個時鐘周期,因此,每次多執(zhí)行1次判斷至少浪費一個時鐘周期甚至更多,因此,這樣子的狀態(tài)機無疑是效率低下的,系統(tǒng)軟件設(shè)計會很復雜。
switch case結(jié)構(gòu)狀態(tài)機
switch()。
case1:。
if(not反復執(zhí)行狀態(tài)1)。
進入1狀態(tài)前要做的準備。
進入1狀態(tài)的過程。
if(not反復執(zhí)行狀態(tài)1)。
離開狀態(tài)1的過程。
case2:。
...。
使用Switch case 相較于if else的好處就是可以清楚的看到所有的狀態(tài),然后代碼架構(gòu)更清楚點,但是實際的運行效率還是沒有提高
再說一下使用Switch編寫狀態(tài)機的兩種寫法
我們假設(shè)狀態(tài)機的狀態(tài)轉(zhuǎn)換由下表所示:
當處于State0時發(fā)生event0 則執(zhí)行action0并將狀態(tài)變成state1,當state1狀態(tài)下發(fā)生event2則執(zhí)行action6并將狀態(tài)變成state2。以此類推。
下面描述下實現(xiàn)上述狀態(tài)機的兩種不同的寫法:
1)豎著寫:在狀態(tài)中判斷事件,并執(zhí)行相應的操作,完成相應的狀態(tài)轉(zhuǎn)換。
2)橫著寫:在事件中根據(jù)當前的狀態(tài),執(zhí)行相應的操作,完成相應的狀態(tài)轉(zhuǎn)換。
//豎著寫 switch(cur_state)
{ case State0: if(event1)
{
action0;
cur_state = State1;
} else if(event2)
{
action4;
cur_state = State1;
} else if(event3)
{
action5;
cur_state = State2;
} break; case State1: if(event1)
{
action1;
cur_state = State2;
} else if(event3)
{
action6;
cur_state = State0;
} break; case State2: if(event1)
{
action3;
cur_state = State0;
} break; default:break;
}
//橫著寫 void event0func(void) { switch(cur_state)
{ case State0:
action0;
cur_state = State1; break; case State1:
action1;
cur_state = State2; break; case State2:
action1;
cur_state = State0; break; default:break;
}
} void event1func(void) { switch(cur_state)
{ case State0:
action4;
cur_state = State1; break; default:break;
}
} void event2func(void) { switch(cur_state)
{ case State0:
action5;
cur_state = State2; break; case State1:
action6;
cur_state = State0; break; default:break;
}
}
上述兩種寫法實現(xiàn)的功能完全相同,對比兩種寫法:
1)寫法1(豎著寫)使用了if -else if語句隱含了優(yōu)先級,破壞可事件間的原有關(guān)系(各個時間應該同優(yōu)先級)
2)寫法1(豎著寫)在結(jié)構(gòu)上是順序查詢方式(查詢事件),浪費大量的時間,而且時間不可估算。
寫法2(橫著寫)因為在某個時間點上狀態(tài)是唯一確定的,在時間處理函數(shù)中通過switch語句可直接定位到相同狀態(tài),執(zhí)行時間也可以估算。
3)寫法2(橫著寫)比較直觀,程序執(zhí)行效率較高。
總體來說:寫法2要優(yōu)于寫法1。
- 贊