毫無疑問,單片機的萬能語言就是狀態機,在嵌入式單片機編程中狀態機c語言編程,也是我們常用的方法。
在此之前,我曾分享過兩種狀態機的實現方法,有些朋友說有點難度,我想再補充一些基礎實現方法以及思路,一步一步走,鏈接放在這里了!
本文將從最基礎入門的方法幫助大家了解狀態機,從我常用的2種狀態機編寫方式為大家慢慢展開。
/case的方法來實現要點
用/case的結構配合一個狀態變量,通過修改狀態變量的值來切換狀態。
代碼如下
1//代碼參考網絡
2
3//!?定義狀態名稱與狀態值之間的關系
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????????????//!?這里添加狀態機初始化代碼
16????????????…
17????????????s_chFSMState?=?FSM_STATE_A;//!
18????????????break;
19????????case?FSM_STATE_A:
20????????????//!?這里添加狀態機A進入下一狀態的檢測代碼
21????????????if?(<某某條件>)?{
22????????????????//!?這里做一些進入下一狀態時要做的準備工作
23????????????????s_chFSMState?=?FSM_STATE_B;//!
24????????????}
25????????????break;
26????????case?FSM_STATE_B:
27????????????//!?這里添加狀態機A進入下一狀態的檢測代碼
28????????????if?(<某某條件>)?{
29????????????????//!?這里做一些進入下一狀態時要做的準備工作
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?????????????//!?這里添加狀態機復位相關的代碼
42?????????????…
43?????????????chFSMState?=?FSM_START;//!
44?????????????//!?返回false表示狀態機已經不需要繼續運行了
45?????????????return?false;???????????????????????????????????????????????????????????????
46??????}
47
48??????//!?返回true表示狀態機正在運行
49??????return?true;?????????????????????????????????????????????????????????????????????????????????
50}
小結
從代碼可知,這種狀態機就是一路走到黑,沒有讓多個狀態同時處于激活狀態,也就是說在同一時刻,只能處于一種狀態之下。
無疑,實際中有很多這樣的應用,比如簡單的燈的開關,當然也有很多情況是多種狀態并存的,比如天氣的狀態就可以分為晴天、陰天、風雨雷電等等,可以同時處于多個狀態。
通用的if/else來了要點
用if else…else if結構的組合來描述狀態流程圖。
范例
1//代碼參考網絡
2//!?首先將布爾量的狀態標志壓縮在一個字節里面以節省內存開支
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????????//!?這里放置狀態機初始化的代碼
31????????…
32???????FSM_STATE_A?=?true;???????//!
33????}
34
35????if?(FSM_STATE_A)?{???????//!
36????????//!?這里放置狀態A的代碼或者
37????????…
38????????//!?這里放置某些條件以開啟別的狀態
39????????if?(<某些條件>)?{
40????????????//!?這里做一些“進入”下一個狀態之前的準備工作
41????????????FSM_STATE_B?=?true;?????//!
42????????????FSM_STATE_A?=?false;???//!
43????????}
44????}
45
46????if?(FSM_STATE_B)?{???????//!
47????????…
48????????//!?這里檢測某些條件
49????????if?(<某些條件>)?{
50????????????//!?這里做一些“開啟”某個狀態的準備工作
51????????????FSM_STATE_C?=?true;????//!
52????????????FSM_STATE_D?=?true;????//!
53????????????…
54????????}?else?if?(<某些條件>)?{
55????????????//!?滿足某些條件以后關閉當前狀態
56????????????FSM_STATE_B?=?false;
57????????}
58????}
59????…
60????if?(FSM_STATE_F)?{?????????????//!
61????????if?(!fsm_example_a(<實參列表>))?{//!
62????????????//!子狀態機運行完成,進入下一狀態
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}
小結
從范例可知狀態機c語言編程,這種狀態機雖然看起來比較費腦子,但是在應用當中非常靈活,通過布爾變量的開啟和關閉,你可以自由的控制某些狀態的開啟。
并且同一時刻可能有多個狀態是激活的,這種結構幾乎可以翻譯任何流程圖。
所有的函數都可以看作是狀態機要點
所有的函數都可以看作是狀態機,如果函數有返回值,且這個返回值能表征至少兩種以上不同的狀態,那么這些返回值就可以被用作指示當前狀態機的運行情況。
在我們實際編程中,我們也需要有這樣的思維,比如函數之間的引用,參數傳遞,這些都可以當作一個狀態,那么我們編碼的過程中,就能夠根據狀態運行進行相應的模塊化。
范例
我們經常會用到的枚舉類型,來寫測試用例,以判斷程序具體執行到函數體的哪一塊了
1enum
2{
3??test1=0,
4??test2,
5??test3,
6??test4,
7??...
8}
9
10//舉個簡單的例子,根據返回值判斷函數運行到哪里,來判斷邏輯走向
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}
小結
狀態機可以說是一個萬能的計算機語言表述方式,應用很廣泛,是裸機條件下多任務的廉價實現方案。
狀態機總結
在帶有操作系統的情況下也是如此,我們了解了狀態機的本質,能夠運用得當的話,對我們的模塊化編程,代碼的整理是很有幫助的。
推薦閱讀:
嵌入式編程專輯 Linux 學習專輯