毫無疑問,單片機的萬能語言就是狀態(tài)機,在嵌入式單片機編程中狀態(tài)機c語言編程,也是我們常用的方法。
在此之前,我曾分享過兩種狀態(tài)機的實現(xiàn)方法,有些朋友說有點難度,我想再補充一些基礎(chǔ)實現(xiàn)方法以及思路,一步一步走,鏈接放在這里了!
本文將從最基礎(chǔ)入門的方法幫助大家了解狀態(tài)機,從我常用的2種狀態(tài)機編寫方式為大家慢慢展開。
/case的方法來實現(xiàn)要點
用/case的結(jié)構(gòu)配合一個狀態(tài)變量,通過修改狀態(tài)變量的值來切換狀態(tài)。
代碼如下
1//代碼參考網(wǎng)絡(luò)
2
3//!?定義狀態(tài)名稱與狀態(tài)值之間的關(guān)系
4#define?FSM_START???????????????????????????????????0x00
5#define?FSM_STATE_A?????????????????????????????????0x01
6#define?FSM_STATE_B?????????????????????????????????0x02
7…
8#define?FSM_RESET???????????????????????????????????0xFF
9
10bool?fsm_example_A(?<形參列表>?)?{
11????static?uint8_t?s_chFSMState?=?FSM_START;//!
12?????????????????…
13????switch?(?s_chFSMState?)?{
14????????case?FSM_START:
15????????????//!?這里添加狀態(tài)機初始化代碼
16????????????…
17????????????s_chFSMState?=?FSM_STATE_A;//!
18????????????break;
19????????case?FSM_STATE_A:
20????????????//!?這里添加狀態(tài)機A進入下一狀態(tài)的檢測代碼
21????????????if?(<某某條件>)?{
22????????????????//!?這里做一些進入下一狀態(tài)時要做的準備工作
23????????????????s_chFSMState?=?FSM_STATE_B;//!
24????????????}
25????????????break;
26????????case?FSM_STATE_B:
27????????????//!?這里添加狀態(tài)機A進入下一狀態(tài)的檢測代碼
28????????????if?(<某某條件>)?{
29????????????????//!?這里做一些進入下一狀態(tài)時要做的準備工作
30????????????????????s_chFSMState?=?FSM_STATE_A;//!
31????????????}?else?if?(<某某條件>)?{
32????????????}?else?if?(<某某條件>)?{
33????????????????…
34????????????}?else?{
35????????????}
36????????????break;
37????????????…
38?????????case?FSM_STOP:
39?????????case?FSM_RESET:
40?????????default:
41?????????????//!?這里添加狀態(tài)機復(fù)位相關(guān)的代碼
42?????????????…
43?????????????chFSMState?=?FSM_START;//!
44?????????????//!?返回false表示狀態(tài)機已經(jīng)不需要繼續(xù)運行了
45?????????????return?false;???????????????????????????????????????????????????????????????
46??????}
47
48??????//!?返回true表示狀態(tài)機正在運行
49??????return?true;?????????????????????????????????????????????????????????????????????????????????
50}
小結(jié)
從代碼可知,這種狀態(tài)機就是一路走到黑,沒有讓多個狀態(tài)同時處于激活狀態(tài),也就是說在同一時刻,只能處于一種狀態(tài)之下。
無疑,實際中有很多這樣的應(yīng)用,比如簡單的燈的開關(guān),當然也有很多情況是多種狀態(tài)并存的,比如天氣的狀態(tài)就可以分為晴天、陰天、風雨雷電等等,可以同時處于多個狀態(tài)。
通用的if/else來了要點
用if else…else if結(jié)構(gòu)的組合來描述狀態(tài)流程圖。
范例
1//代碼參考網(wǎng)絡(luò)
2//!?首先將布爾量的狀態(tài)標志壓縮在一個字節(jié)里面以節(jié)省內(nèi)存開支
3typedef?union?{
4????uint8_t?????Value;
5????uint8_t?????Byte;???
6????struct?{
7????????unsigned?BIT0:1;
8????????unsigned?BIT1:1;
9????????unsigned?BIT2:1;
10????????unsigned?BIT3:1;
11????????unsigned?BIT4:1;
12????????unsigned?BIT5:1;
13????????unsigned?BIT6:1;
14????????unsigned?BIT7:1;
15????}Bits;
16}byte_t;
17
18#define?FSM_ACTION_FLAG?????????????s_tbState.Bits
19#define?FSM_STOP_ALL_ACTIONS()??????do?{s_tbState.Value?=?0;}while(0)
20#define?FSM_START???????????????????(0?==?s_tbState.Value)
21#define?FSM_STATE_A?????????????????FSM_ACTION_FLAG.BIT0
22#define?FSM_STATE_B?????????????????FSM_ACTION_FLAG.BIT1
23…
24#define?FSM_STATE_H?????????????????FSM_ACTION_FLAG.BIT7
25
26bool?fsm_example_B(?<形參列表>?)?{
27????static?byte_t?s_tbState?=?{0};//!
28
29????if?(FSM_START)?{?//!
30????????//!?這里放置狀態(tài)機初始化的代碼
31????????…
32???????FSM_STATE_A?=?true;???????//!
33????}
34
35????if?(FSM_STATE_A)?{???????//!
36????????//!?這里放置狀態(tài)A的代碼或者
37????????…
38????????//!?這里放置某些條件以開啟別的狀態(tài)
39????????if?(<某些條件>)?{
40????????????//!?這里做一些“進入”下一個狀態(tài)之前的準備工作
41????????????FSM_STATE_B?=?true;?????//!
42????????????FSM_STATE_A?=?false;???//!
43????????}
44????}
45
46????if?(FSM_STATE_B)?{???????//!
47????????…
48????????//!?這里檢測某些條件
49????????if?(<某些條件>)?{
50????????????//!?這里做一些“開啟”某個狀態(tài)的準備工作
51????????????FSM_STATE_C?=?true;????//!
52????????????FSM_STATE_D?=?true;????//!
53????????????…
54????????}?else?if?(<某些條件>)?{
55????????????//!?滿足某些條件以后關(guān)閉當前狀態(tài)
56????????????FSM_STATE_B?=?false;
57????????}
58????}
59????…
60????if?(FSM_STATE_F)?{?????????????//!
61????????if?(!fsm_example_a(<實參列表>))?{//!
62????????????//!子狀態(tài)機運行完成,進入下一狀態(tài)
63????????????…
64????????????FSM_STATE_F?=?false;??//!
65????????????FSM_STATE_x?=?true;??//!
66????????}
67????}
68
69????if?(FSM_STATE_H)?{?????//!
70????????//!
71????????…
72????????FSM_STOP_ALL_ACTIONS();??????//!
73????????return?false;???????????????//!
74????}
75
76????return?true;???????????????//!
77}
小結(jié)
從范例可知狀態(tài)機c語言編程,這種狀態(tài)機雖然看起來比較費腦子,但是在應(yīng)用當中非常靈活,通過布爾變量的開啟和關(guān)閉,你可以自由的控制某些狀態(tài)的開啟。
并且同一時刻可能有多個狀態(tài)是激活的,這種結(jié)構(gòu)幾乎可以翻譯任何流程圖。
所有的函數(shù)都可以看作是狀態(tài)機要點
所有的函數(shù)都可以看作是狀態(tài)機,如果函數(shù)有返回值,且這個返回值能表征至少兩種以上不同的狀態(tài),那么這些返回值就可以被用作指示當前狀態(tài)機的運行情況。
在我們實際編程中,我們也需要有這樣的思維,比如函數(shù)之間的引用,參數(shù)傳遞,這些都可以當作一個狀態(tài),那么我們編碼的過程中,就能夠根據(jù)狀態(tài)運行進行相應(yīng)的模塊化。
范例
我們經(jīng)常會用到的枚舉類型,來寫測試用例,以判斷程序具體執(zhí)行到函數(shù)體的哪一塊了
1enum
2{
3??test1=0,
4??test2,
5??test3,
6??test4,
7??...
8}
9
10//舉個簡單的例子,根據(jù)返回值判斷函數(shù)運行到哪里,來判斷邏輯走向
11int?testDemo()
12{
13????if?(FSM_STATE_A)?{?
14??????if?(<某些條件>)?{
15????????return?test1;
16??????}else{
17????????return?test2;
18??????}
19????}else{
20??????return?test3;
21????}
22????return?test4;
23}
小結(jié)
狀態(tài)機可以說是一個萬能的計算機語言表述方式,應(yīng)用很廣泛,是裸機條件下多任務(wù)的廉價實現(xiàn)方案。
狀態(tài)機總結(jié)
在帶有操作系統(tǒng)的情況下也是如此,我們了解了狀態(tài)機的本質(zhì),能夠運用得當?shù)脑挘瑢ξ覀兊哪K化編程,代碼的整理是很有幫助的。
推薦閱讀:
嵌入式編程專輯 Linux 學習專輯