STM32狀態機編程----什么是狀態機?

什么是狀態,點擊此處領取相關資料

狀態是人或事物表現出來的形態。是指現實(或虛擬)事物處于生成、生存、發展、消亡時期或各轉化臨界點時的形態或事物態勢。

通過上面那句話,我們知道了狀態就是一個對象在不同情況下對應的各種形態


做產品的時候,如果我們如果要對這個對象所有的形態進行描述,在一些對象復雜的邏輯狀態下,比較復雜的邏輯問題,普通的流程圖,或時序圖對于對象和狀態的解讀缺乏直觀的描述。

這個時候就需要狀態機來對對象的各個形態進行描述,將對象的全部工作方式,分成幾個場景,這些場景的工作方式不同,然后將這些場景通過數學模型表示出來


比方說一個小燈泡的開關,就是一個最基本的小型狀態機

這里就是兩個狀態:①打開開關,燈泡亮,②關閉開關,燈泡滅

對應的狀態機圖:

這就是最簡單的一個狀態機

狀態機方便的地方是,如果現在我們只有兩種狀態,這兩個狀態在 打開開關/關閉開關兩個條件之間跳轉,如果我們要加上一個新的條件,比方說我們設定了定時開關燈,多了一個跳轉條件,如果燈泡開了超過8個小時就自動關閉,除非再次做打開開關,否則燈泡一致處于關閉狀態,這個狀態圖如下:

是不是很方便

再舉個最簡單的例子。人有三個狀態健康,感冒,康復中
觸發的條件有
淋雨(t1),吃藥(t2),打針(t3),休息(t4)
所以狀態機就是
健康->(t4)->健康;健康->(t1)->感冒;感冒->(t3)->健康;感冒->(t2)->康復中;康復中->(t4)->健康,等等。就是這樣狀態在不同的條件下跳轉到自己或不同狀態的情況,就叫做狀態機。

狀態機要素

通過上面的舉例,我們可以講狀態機可歸納為4個要素,即現態、條件、動作、次態。這樣的歸納,主要是出于對狀態機的內在因果關系的考慮。“現態”和“條件”是因,“動作”和“次態”是果。詳解如下:

  • 現態:是指當前所處的狀態。
  • 條件:又稱為“事件”,當一個條件被滿足,將會觸發一個動作,或者執行一次狀態的遷移。
  • 動作:條件滿足后執行的動作。動作執行完畢后,可以遷移到新的狀態,也可以仍舊保持原狀態。動作不是必需的,當條件滿足后,也可以不執行任何動作,直接遷移到新狀態。
  • 次態:條件滿足后要遷往的新狀態。“次態”是相對于“現態”而言的,“次態”一旦被激活,就轉變成新的“現態”了。

狀態機是一種編程思路。是現實事物運行規則抽象而成的一個數學模型。

有限狀態機

有限狀態機簡稱就是狀態機,因為一般的狀態機的狀態都是離散和可舉的,即為有限,所以后面的介紹都不加有限二字**。狀態機表示有限個狀態以及在這些狀態之間的轉移和動作等行為的數學模型**。通俗的描述狀態機就是定義了一套狀態変更的流程:

狀態機包含一個狀態集合,定義當狀態機處于某一個狀態的時候它所能接收的事件以及可執行的行為,執行完成后,狀態機所處的狀態。

狀態遷移圖(STD)

  • (1)狀態框:用方框表示狀態,包括所謂的“現態”和“次態”;
  • (2)條件及遷移箭頭:用箭頭表示狀態遷移的方向,并在該箭頭上標注觸發條件;
  • (3)節點圓圈:當多個箭頭指向一個狀態時,可以用節點符號(小圓圈)連接匯總;
  • (4)動作框:用橢圓框表示;
  • (5)附加條件判斷框:用六角菱形框表示;

STM32中的狀態機

舉個簡單的例子:就按鍵處理來說,按鍵動作本身也可以看做一個狀態機。一個細小的擊鍵動作包含了:釋放、抖動、按下、抖動和重新釋放等狀態。  當我們打開思路,把狀態機作為一種思想導入到程序中去時,就會找到處理疑問的一條有效的捷徑。有時候用狀態機的思維去思考程序該干什么,比用控制流程的思維去思考,可能會更有效。這樣一來狀態機便有了更實際的功用。廢話不多說,實踐才是檢驗真理的唯一標準。

也許有人覺得狀態機把問題復雜化了,其實我們在編寫代碼的時候在無形之中已經使用了狀態機的思想,比方說我們的if else 判斷

if else語句結構狀態機

if 條件1 else if  條件2 else if   條件3 ... else 條件n 


我們知道C語言的if else if語句是從第一條開始判斷的,如果符合條件的那一行永遠在后面幾行,那么就要每次多執行很多次的if …而if是判斷語句,括號內的判斷是要執行運算的,即使是單周期指令的MCU,在進行乘除運算等都需要消耗多個時鐘周期,因此,每次多執行1次判斷至少浪費一個時鐘周期甚至更多,因此,這樣子的狀態機無疑是效率低下的,系統軟件設計會很復雜。

switch case結構狀態機

 switch()。

  case1:。

  if(not反復執行狀態1)。

  進入1狀態前要做的準備。

  進入1狀態的過程。

  if(not反復執行狀態1)。

  離開狀態1的過程。

  case2:。

  ...。 

使用Switch case 相較于if else的好處就是可以清楚的看到所有的狀態,然后代碼架構更清楚點,但是實際的運行效率還是沒有提高


再說一下使用Switch編寫狀態機的兩種寫法

我們假設狀態機的狀態轉換由下表所示:

當處于State0時發生event0 則執行action0并將狀態變成state1,當state1狀態下發生event2則執行action6并將狀態變成state2。以此類推。

下面描述下實現上述狀態機的兩種不同的寫法:
1)
豎著寫:在狀態中判斷事件,并執行相應的操作,完成相應的狀態轉換。
2)
橫著寫:在事件中根據當前的狀態,執行相應的操作,完成相應的狀態轉換。

//豎著寫 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;
    }
} 

上述兩種寫法實現的功能完全相同,對比兩種寫法:

1)寫法1(豎著寫)使用了if -else if語句隱含了優先級,破壞可事件間的原有關系(各個時間應該同優先級)
2)寫法1(豎著寫)在結構上是順序查詢方式(查詢事件),浪費大量的時間,而且時間不可估算。
寫法2(橫著寫)因為在某個時間點上狀態是唯一確定的,在時間處理函數中通過switch語句可直接定位到相同狀態,執行時間也可以估算。
3)寫法2(橫著寫)比較直觀,程序執行效率較高。
總體來說:寫法2要優于寫法1。

完整資料可進群免費領取!!!

the end

評論(0)