狀態機——單片機的萬能語言(附代碼)

Python實戰社羣php

Java實戰社羣程序員

長按識別下方二維碼,按需求添加web

掃碼關注添加客服編程

進Python社羣▲微信

掃碼關注添加客服網絡

進Java社羣模塊化

做者丨李肖遙
函數

來源丨技術讓夢想更偉大測試

毫無疑問,單片機的萬能語言就是狀態機,在嵌入式單片機編程中,也是咱們經常使用的方法。ui

本文將從最基礎入門的方法幫助你們瞭解狀態機,從我經常使用的2種狀態機編寫方式爲你們慢慢展開。

switch/case的方法來實現

要點

用switch/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( <</span>形參列表> ) {
27    static byte_t s_tbState = {0};//!< 定義狀態變量
28
29    if (FSM_START) { //!< 起始狀態
30        //! 這裏放置狀態機初始化的代碼
31        …
32       FSM_STATE_A = true;       //!< 進入狀態B,start裝臺自動結束
33    }
34
35    if (FSM_STATE_A) {       //!< 一個典型的簡單狀態
36        //! 這裏放置狀態A的代碼或者
37        …
38        //! 這裏放置某些條件以開啓別的狀態
39        if (<</span>某些條件>) {
40            //! 這裏作一些「進入」下一個狀態以前的準備工做
41            FSM_STATE_B = true;     //!< 開啓下一個狀態
42            FSM_STATE_A = false;   //!< 結束當前狀態
43        }
44    }
45
46    if (FSM_STATE_B) {       //!< 一個典型的監視狀態
47        …
48        //! 這裏檢測某些條件
49        if (<</span>某些條件>) {
50            //! 這裏作一些「開啓」某個狀態的準備工做
51            FSM_STATE_C = true;    //!< 開啓某一個狀態而不結束當前狀態
52            FSM_STATE_D = true;    //!< 你固然能夠一次觸發多個狀態
53            …
54        } else if (<</span>某些條件>) {
55            //! 知足某些條件之後關閉當前狀態
56            FSM_STATE_B = false;
57        }
58    }
59    …
60    if (FSM_STATE_F) {             //!< 一個典型的子狀態機調用
61        if (!fsm_example_a(<實參列表>)) {//!< 等待子狀態機返回false
62            //!子狀態機運行完成,進入下一狀態
63            …
64            FSM_STATE_F = false;  //!< 結束當前狀態
65            FSM_STATE_x = true;  //!< 進入下一狀態x表明某個字母
66        }
67    }
68
69    if (FSM_STATE_H) {     //!< 一個典型的停止狀態
70        //!< 某些狀態機的操做,好比釋放某些資源
71        …
72        FSM_STOP_ALL_ACTIONS();      //!< 復位狀態機
73        return false;               //!< 返回false表示狀態機結束
74    }
75
76    return true;               //!< 返回true表示狀態機保持運行
77}

小結

從範例可知,這種狀態機雖然看起來比較費腦子,可是在應用當中很是靈活,經過布爾變量的開啓和關閉,你能夠自由的控制某些狀態的開啓。

而且同一時刻可能有多個狀態是激活的,這種結構幾乎能夠翻譯任何流程圖。

全部的函數均可以看做是狀態機

要點

全部的函數均可以看做是狀態機,若是函數有返回值,且這個返回值能表徵至少兩種以上不一樣的狀態,那麼這些返回值就能夠被用做指示當前狀態機的運行狀況。

在咱們實際編程中,咱們也須要有這樣的思惟,好比函數之間的引用,參數傳遞,這些均可以看成一個狀態,那麼咱們編碼的過程當中,就可以根據狀態運行進行相應的模塊化。

範例

咱們常常會用到的枚舉類型,來寫測試用例,以判斷程序具體執行到函數體的哪一塊了

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 (<</span>某些條件>) {
15        return test1;
16      }else{
17        return test2;
18      }
19    }else{
20      return test3;
21    }
22    return test4;
23}

小結

狀態機能夠說是一個萬能的計算機語言表述方式,應用很普遍,是裸機條件下多任務的廉價實現方案。

狀態機總結

在帶有操做系統的狀況下也是如此,咱們瞭解了狀態機的本質,可以運用得當的話,對咱們的模塊化編程,代碼的整理是頗有幫助的。

程序員專欄 掃碼關注填加客服 長按識別下方二維碼進羣


近期精彩內容推薦:  

 外包程序員入職螞蟻金服被質疑,網友:人生污點

 11 月全國程序員平均工資出爐

 棄用 Notepad++,還有 5 款更牛逼的選擇!

 福利!手把手教你Python爬取女神套圖


在看點這裏好文分享給更多人↓↓

相關文章
相關標籤/搜索