狀態機思路在程序設計中的應用

狀態機思路在單片機程序設計中的應用編程

狀態機的概念
狀態機是軟件編程中的一個重要概念。比這個概念更重要的是對它的靈活應用。在一個思路清晰並且高效的程序中,必然有狀態機的身影浮現。設計


好比說一個按鍵命令解析程序,就能夠被看作狀態機:原本在A狀態下,觸發一個按鍵後切換到了B狀態;再觸發另外一個鍵後切換到C狀態,或者返回到A狀態。這就是最簡單的按鍵狀態機例子。實際的按鍵解析程序會比這更復雜些,但這不影響咱們對狀態機的認識。指針


進一步看,擊鍵動做自己也能夠看作一個狀態機。一個細小的擊鍵動做包含了:釋放、抖動、閉合、抖動和從新釋放等狀態。進程


一樣,一個串行通訊的時序(無論它是遵循何種協議,標準串口也好、I2C也好;也無論它是有線的、仍是紅外的、無線的)也均可以看作由一系列有限的狀態構成。事件


顯示掃描程序也是狀態機;通訊命令解析程序也是狀態機;甚至連繼電器的吸合/釋放控制、發光管(LED)的亮/滅控制又未嘗不是個狀態機。程序設計


當咱們打開思路,把狀態機做爲一種思想導入到程序中去時,就會找到解決問題的一條有效的捷徑。有時候用狀態機的思惟去思考程序該幹什麼,比用控制流程的思惟去思考,可能會更有效。這樣一來狀態機便有了更實際的功用。變量


程序其實就是狀態機。軟件


也許你還不理解上面這句話。請想一想看,計算機的大廈不就是創建在「0」和「1」兩個基本狀態的地基之上麼?程序

狀態機的要素
狀態機可概括爲4個要素,即現態、條件、動做、次態。這樣的概括,主要是出於對狀態機的內在因果關係的考慮。「現態」和「條件」是因,「動做」和「次態」是果。詳解以下:方法


①現態:是指當前所處的狀態。


②條件:又稱爲「事件」。當一個條件被知足,將會觸發一個動做,或者執行一次狀態的遷移。


③動做:條件知足後執行的動做。動做執行完畢後,能夠遷移到新的狀態,也能夠仍舊保持原狀態。動做不是必需的,當條件知足後,也能夠不執行任何動做,直接遷移到新狀態。


④次態:條件知足後要遷往的新狀態。「次態」是相對於「現態」而言的,「次態」一旦被激活,就轉變成新的「現態」了。


若是咱們進一步概括,把「現態」和「次態」統一塊兒來,而把「動做」忽略(降格處理),則只剩下兩個最關鍵的要素,即:狀態、遷移條件。


狀態機的表示方法有許多種,咱們能夠用文字、圖形或表格的形式來表示一個狀態機。


純粹用文字描述是很低效的,因此就不介紹了。接下來先介紹圖形的方式。

狀態遷移圖(STD)
狀態遷移圖(STD),是一種描述系統的狀態、以及相互轉化關係的圖形方式。狀態遷移圖的畫法有許多種,不過通常都大同小異。咱們結合一個例子來講明一下它的畫法,如圖1所示。

圖1 狀態遷移圖


①狀態框:用方框表示狀態,包括所謂的「現態」和「次態」。

②條件及遷移箭頭:用箭頭表示狀態遷移的方向,並在該箭頭上標註觸發條件。


③節點圓圈:當多個箭頭指向一個狀態時,能夠用節點符號(小圓圈)鏈接彙總。


④動做框:用橢圓框表示。


⑤附加條件判斷框:用六角菱形框表示。


狀態遷移圖和咱們常見的流程圖相比有着本質的區別,具體體現爲:在流程圖中,箭頭表明了程序PC指針的跳轉;而在狀態遷移圖中,箭頭表明的是狀態的改變。


咱們會發現,這種狀態遷移圖比普通程序流程圖更簡練、直觀、易懂。這正是咱們須要達到的目的。

狀態遷移表
除了狀態遷移圖,咱們還能夠用表格的形式來表示狀態之間的關係。這種表通常稱爲狀態遷移表。


表1就是前面介紹的那張狀態遷移圖的另外一種描述形式。

表1 狀態遷移表


①採用表格方式來描述狀態機,優勢是可容納更多的文字信息。例如,咱們不但能夠在狀態遷移表中描述狀態的遷移關係,還能夠把每一個狀態的特徵描述也包含在內。


②若是表格內容較多,過於臃腫不利於閱讀,咱們也能夠將狀態遷移表進行拆分。通過拆分後的表格根據其具體內容,表格名稱也有所變化。


③好比,咱們能夠把狀態特徵和遷移關係分開列表。被單獨拆分出來的描述狀態特徵的表格,也能夠稱爲「狀態真值表」。這其中比較常見的就是把每一個狀態的顯示內容單獨列表。這種描述每一個狀態顯示內容的表稱之爲「顯示真值表」。一樣,咱們把單獨表述基於按鍵的狀態遷移表稱爲「按鍵功能真值表」。另外,若是每個狀態包含的信息量過多,咱們也能夠把每一個狀態單獨列表。


④因而可知,狀態遷移表做爲狀態遷移圖的有益補充,它的表現形式是靈活的。


⑤狀態遷移表優勢是信息涵蓋面大,缺點是視覺上不夠直觀,所以它並不能取代狀態遷移圖。比較理想的是將圖形和表格結合應用。用圖形展示宏觀,用表格說明細節。兩者互爲參照,相得益彰。

用狀態機思路實現一個時鐘程序
接下來,我將就狀態機的應用,結合流程圖、狀態遷移圖和狀態遷移,舉一個實際例子。下面這張圖是一個時鐘程序的狀態遷移圖,如圖2所示。

圖2 時鐘程序狀態遷移圖


把這張圖稍作概括,就能夠獲得它的另外一種表現形式——狀態遷移表,如表2所示。

表2 時鐘程序狀態遷移表

狀態機應用的注意事項
基於狀態機的程序調度機制,其應用的難點並不在於對狀態機概念的理解,而在於對系統工做狀態的合理劃分。


初學者每每會把某個「程序動做」看成是一種「狀態」來處理。我稱之爲「僞態」。那麼如何區分「動做」和「狀態」。本匠人的心得是看兩者的本質:「動做」是不穩定的,即便沒有條件的觸發,「動做」一旦執行完畢就結束了;而「狀態」是相對穩定的,若是沒有外部條件的觸發,一個狀態會一直持續下去。


初學者的另外一種比較致命的錯誤,就是在狀態劃分時漏掉一些狀態。我稱之爲「漏態」。


「僞態」和「漏態」這兩種錯誤的存在,將會致使程序結構的渙散。所以要特別當心避免。

更復雜的狀態機
前面介紹的是一種簡單的狀態結構。它只有一級,而且只有一維,如圖3所示。

圖3  線性狀態機結構


若是有必要,咱們能夠創建更復雜的狀態機模型。


1 多級狀態結構
狀態機能夠是多級的。在分層的多級狀態機系統裏面,一個「父狀態」下能夠劃分多個「子狀態」,這些子狀態共同擁有上級父狀態的某些共性,同時又各自擁有本身的一些個性。


在某些狀態下,還能夠進一步劃分子狀態。好比,咱們能夠把前面的時鐘例子修改以下:
把全部和時鐘功能有關的狀態,合併成1個一級狀態。在這個狀態下,又能夠劃分出3個二級子狀態,分別爲顯示時間、設置小時、設置分鐘;


一樣,咱們也能夠把全部和鬧鐘功能有關的狀態,合併成1個一級狀態。在這個狀態下,再劃分出4個二級子狀態,分別爲顯示鬧鐘、設置「時」、設置「分」、設置鳴叫時間。


咱們須要用另外一個狀態變量(寄存器)來表示這些子狀態。


子狀態下面固然還能夠有更低一級的孫狀態(子子孫孫無窮盡也),從而將整個狀態體系變成了樹狀多級狀態結構,如圖4所示。

圖4 樹狀多級狀態結構


2 多維狀態結構
狀態結構也能夠是多維的。從不一樣的角度對系統進行狀態的劃分,這些狀態的某些特性是交叉的。好比,在按照按鍵和顯示劃分狀態的同時,又按照系統的工做進程作出另外一種狀態劃分。這兩種狀態劃分同時存在,相互交叉,從而構成了二維的狀態結構空間。


舉一個這方面的例子,如:空調遙控器,如圖5所示。

圖5 多維狀態機結構


一樣,咱們也能夠構建三維、四維甚至更多維的狀態結構。每一維的狀態都須要用一個狀態變量(寄存器)來表示。


不管多級狀態結構和多維狀態結構看上去多麼迷人,匠人的忠告是:咱們依然要儘量地簡化狀態結構,能用單級、單維的結構,就不要給本身找事,去玩那噩夢般的複雜結構。


簡單的纔是最有效的。

結束語 對狀態機的理解須要一個由淺入深的過程。這個過程應該是與實踐應用和具體案例思考相結合的。當一種良好的思路成爲設計的習慣,它就能給設計者帶來回報。願這篇手記裏介紹的基於狀態機的編程思路能給新手們帶來一些啓迪,幫助你們找到「程序設計」的感受。

相關文章
相關標籤/搜索