基於狀態機的按鍵程式

2021-06-26 04:48:25 字數 2842 閱讀 9326

基於狀態機的按鍵程式

一般的按鍵輸入軟體介面程式非常簡單,在程式中一旦檢測到按鍵輸入口為低電平(有時可能為高),便採用軟體延時的方法來進行消抖,然後再次檢測按鍵輸入,如果再次確認為低電平則表示有按鍵按下,轉入執行按鍵處理程式。如果延時後檢測的電平為高電平則放棄本次按鍵檢測,重新開始一次按鍵檢測過程。在簡單的系統中這種方法比較可以用,但是在複雜的系統實時性要求較高的系統中這種方法的cpu利用率比較低,造成資源的浪費。另外,由於在不同的產品系統中對按鍵功能的定義和使用方式也會不同,而且是多變的,加上在測試和按鍵處理的同時,mcu還要同時處理其他的任務(如顯示、計算、計時等),因此編寫鍵盤和按鍵介面的處理程式需要掌握有效的分析方法,具備較高的軟體設計能力和程式編寫的技巧。而採用狀態機的方法是一種比較好的方法。

何為狀態機

關於狀態機的乙個極度確切的描述是它是乙個有向圖形,由一組節點和一組相應的轉移函式組成,狀態機通過響應一系列事件而「執行」。每個事件都在屬於「當前」節點的轉移函式的控制範圍內,其中函式的範圍是節點的乙個子集。函式返回「下乙個」(也許是同乙個)節點。這些節點中至少有乙個必須是終態。當到達終態,狀態機停止。

狀態機是一種概念性機器,它能採取某種操作來響應乙個外部事件。具體採取的操作不僅能取決於接收到的事件,還能取決於各個事件的相對發生順序。之所以能做到這一點,是因為機器能跟蹤乙個內部狀態,它會在收到事件後進行更新。為乙個事件而響應的行動不僅取決於事件本身,還取決於機器的內部狀態。另外,採取 的行動還會決定並更新機器的狀態。這樣一來,任何邏輯都可建模成一系列事件/狀態組合。

狀態機是軟體程式設計中的乙個重要概念。比如在乙個按鍵命令解析程式中,就可以看做狀態機,其過程如下:本來在a狀態下,觸發乙個按鍵後切換到b,再觸發另乙個鍵後就切換到c狀態,或者返回a狀態。這是最簡單的例子。其他的很多的程式都可以當做狀態機來處理。

狀態機可歸納為4個要素,即現態、條件、動作、次態。這樣的歸納,主要是出於對狀態機內在因果關係的考慮。「現態」和「條件」是因,「動作」和「次態」是果。詳細如下:

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

條件:又稱為「事件」。當乙個條件滿足,將會觸發乙個動作,或者執行一次狀態的遷移。

動作:條件滿足後執行動作。動作執行完畢後,可以遷移到新的狀態,也可以仍舊保持原狀態。動作不是必需的,當條件滿足後,也可以不執行任何動作,直接遷移到新狀態。

次態:條件滿足後要遷往的新狀態。「次態」是相對於「現態」而言的,「次態」一旦被啟用,就轉變為新的「現態」了。

按鍵的狀態機實現

乙個按鍵從鍵按下到鬆開的過程如下如所示。從圖中可以看出,按鍵的按下和鬆開的過程都有抖動的干擾問題,因此要將它們消除。

可將將按鍵抽象為4個狀態:

(1)    未按下,假定為s0

(2)    確認有鍵按下,假定為s1

(3)    鍵穩定按下狀態,假定為s2

(4)    鍵釋放狀態,假定為s3。

(有時也可以抽象為3個狀態s0,s1,s3)。

在乙個系統中按鍵的操作是隨機的,因此系統軟體中要對按鍵進行迴圈查詢。在按鍵檢測過程中需要進行消抖處理,消抖的延時處理一般要10ms或20ms,因此取狀態機的時間序列為10或20ms,這樣不僅可以跳過按鍵消抖的影響,同事也遠小於按鍵0.3-0.5s的穩定閉合其,不會將按鍵過程丟失。

假定鍵按下時埠電平為0,未按下時為1(或者相反)。通過狀態機實現按鍵檢測的過程如下:

首先,按鍵的初始態為s0,當檢測到輸入為1時,表示沒有鍵按下,保持s0。當按鍵輸入為0時,則有鍵按下,轉入狀態s1。

在s1狀態時,如果輸入的訊號為1,則表示剛才的按鍵操作為干擾,則狀態跳轉到s0;如果輸入訊號為0,則表示確實有鍵按下,此時可以讀取鍵狀態,產生相應的按鍵標誌或者將該事件存入訊息佇列。同時狀態機切換到s2狀態。

在s2狀態,如果輸入訊號為1,則沒有鍵按下,切換到s3;如果輸入訊號為0,則保持s2狀態,並進行計數。如果計數值超過一定的門限值,則可以認為該按鍵為長按鍵事件或者鍵一直按下狀態,如果未超過門限值,則認為是短按鍵事件,保持s2狀態。

在s3狀態,如果輸入訊號為高電平,則切換到s0.

上面就是採用狀態機進行按鍵檢測的過程。簡單程式如下:

enum key_states_e;  

void key_scan(void)

else

key_state = key_s1;

break;

case key_s2:

if(gpio_readinputdatabit(g_keys[0].port, g_keys[0].gpio)==1)else

key_state = key_s1;

break;

case key_s3:

if(gpio_readinputdatabit(g_keys[0].port, g_keys[0].gpio)==1)

} else

key_state = key_s4;

break;

case key_s4:

if(gpio_readinputdatabit(g_keys[0].port, g_keys[0].gpio)==1)

break;

default:

key_state = key_s1;

press = 0;

break;

}}

在定時器中,定時10ms,定時到後在中斷服務程式中呼叫上述函式,每次執行的間隔10ms,可以有效的消除消抖,提高cpu的利用率。

同時可以將狀態機應用於其他的程式中,乙個序列通訊的時序(不管它是遵循何種協議,標準串列埠也好、i2c也好;也不管它是有線的、還是紅外的、無線的)也都可以看做由一系列有限的狀態構成。顯示掃瞄程式也是狀態機;通訊命令解析程式也是狀態機;甚至連繼電器的吸合/釋放控制、發光管(led)的亮/滅控制又何嘗不是個狀態機。

基於狀態機的新型按鍵消抖掃瞄程式

一般的按鍵輸入軟體介面程式非常簡單,在程式中一旦檢測到按鍵輸入口為低電平 有時可能為高 便採用軟體延時的方法來進行消抖,然後再次檢測按鍵輸入,如果再次確認為低電平則表示有按鍵按下,轉入執行按鍵處理程式。如果延時後檢測的電平為高電平則放棄本次按鍵檢測,重新開始一次按鍵檢測過程。在簡單的系統中這種方法比...

狀態機按鍵消抖

一般的按鍵輸入軟體介面程式非常簡單,在程式中一旦檢測到按鍵輸入口為低電平 有時可能為高 便採用軟體延時的方法來進行消抖,然後再次檢測按鍵輸入,如果再次確認為低電平則表示有按鍵按下,轉入執行按鍵處理程式。如果延時後檢測的電平為高電平則放棄本次按鍵檢測,重新開始一次按鍵檢測過程。在簡單的系統中這種方法比...

按鍵的程式設計 狀態機1

現在的大學教育就是這樣。學無法致用。狀態機第一次見的時候是在數電裡面,那個時候是研究數位電路 比如鎖存器 用到的。不過由於是自學的,所以早就忘的一塌糊塗了。沒上完大學的人就是這樣啊。不過狀態機同樣在硬體的程式設計中得到廣泛使用。第一次見到狀態機的程式設計,就是在按鍵的程式設計中 馬潮老師的書 後來覺...