0 引言
一般的按鍵驅(qū)動(dòng)程序通常非常簡(jiǎn)單。在程序中一旦檢測(cè)到按鍵輸入口為低電平時(shí),,就采用軟件延時(shí)10 ms后再次檢測(cè)按鍵輸入口,。如果仍然是低電平則表示有按鍵按下,便轉(zhuǎn)入執(zhí)行按鍵處理程序,;否則,,當(dāng)按鍵輸入口為高電平,,就會(huì)放棄本次按鍵的檢測(cè),重新開(kāi)始一次按鍵檢測(cè)過(guò)程,。這種方式不僅由于采用了軟件延時(shí)而使得MCU的效率降低,,同時(shí)也不容易同系統(tǒng)中其他功能模塊協(xié)調(diào)工作,且系統(tǒng)的實(shí)時(shí)性也差,。本文把單個(gè)按鍵作為一個(gè)簡(jiǎn)單的系統(tǒng),,根據(jù)狀態(tài)機(jī)的原理對(duì)其動(dòng)作的操作和確認(rèn)的過(guò)程進(jìn)行分析,并用狀態(tài)圖表示出來(lái),,然后根據(jù)狀態(tài)圖編寫(xiě)出按鍵接口程序,。
1 基于狀態(tài)機(jī)的簡(jiǎn)單按鍵驅(qū)動(dòng)設(shè)計(jì)
在一個(gè)嵌入式系統(tǒng)中,按鍵的操作是隨機(jī)的,。為了提高CPU的工作效率,,在設(shè)計(jì)按鍵驅(qū)動(dòng)的時(shí)候,利用S3C2440的外部中斷來(lái)實(shí)現(xiàn)對(duì)按鍵的處理,。很明顯,,系統(tǒng)的輸入信號(hào)與按鍵連接的I/O口電平,“1”表示按鍵處于開(kāi)放狀態(tài),,“0”表示按鍵處于閉合狀態(tài),。而系統(tǒng)的輸出信號(hào)則表示檢測(cè)和確認(rèn)到一次按鍵的閉合操作,用“1”表示,。
圖1給出了一個(gè)簡(jiǎn)單按鍵狀態(tài)機(jī)的狀態(tài)轉(zhuǎn)換圖,。
在圖中,將1次按鍵完整的操作分解為3個(gè)狀態(tài),。其中,,狀態(tài)0為按鍵的初始狀態(tài),當(dāng)按鍵輸入為“1”時(shí),,表示按鍵處于開(kāi)放,,輸出“0”(I/0),下一狀態(tài)仍為狀態(tài)0,;當(dāng)按鍵輸入為“0”時(shí),,表示按鍵閉合,但輸出還是“0”(沒(méi)有經(jīng)過(guò)消抖,,不能確認(rèn)按鍵真正按下),,下一狀態(tài)進(jìn)入狀態(tài)1。
狀態(tài)1為按鍵閉合確認(rèn)狀態(tài),,它表示在10 ms前按鍵為閉合的,,因此當(dāng)再次檢測(cè)到按鍵輸入為“0”時(shí),可以確認(rèn)按鍵被按下了(經(jīng)過(guò)10 ms的消抖),;輸出“1”則表示確認(rèn)按鍵閉合(0/1),,下一狀態(tài)進(jìn)入狀態(tài)2,。而當(dāng)再次檢測(cè)到按鍵的輸入為“1”時(shí),表示按鍵可能處在抖動(dòng)干擾,;輸出為“0”(I/0),,下一狀態(tài)返回到狀態(tài)0。這樣,,利用狀態(tài)1,,實(shí)現(xiàn)了按鍵的消抖處理。狀態(tài)2為等待按鍵釋放狀態(tài),,因?yàn)橹挥械劝存I釋放后,,一次完整的按鍵操作過(guò)程才算完成。
對(duì)圖1的分析可知,,在一次按鍵操作的整個(gè)過(guò)程中,,按鍵的狀態(tài)是從狀態(tài)0→狀態(tài)1→狀態(tài)2,最后返回到狀態(tài)0的,,并且在整個(gè)過(guò)程中,,按鍵的輸出信號(hào)僅在狀態(tài)1時(shí)給出了唯一的一次確認(rèn)按鍵閉合的信號(hào)“1”,,其他狀態(tài)均輸出“0”,。因此,圖1狀態(tài)機(jī)所表示的按鍵系統(tǒng),,不僅克服了按鍵抖動(dòng)的問(wèn)題,,同時(shí)也確保在一次按鍵的整個(gè)過(guò)程中,系統(tǒng)只輸出一次按鍵閉合信號(hào)(“1”),。
2 具有連發(fā)功能的按鍵驅(qū)動(dòng)設(shè)計(jì)
上面介紹的是最簡(jiǎn)單的情況,,不管按鍵被按下的時(shí)間保持多長(zhǎng),在這個(gè)按鍵的整個(gè)過(guò)程中都只給出了一次確認(rèn)的輸出,。但是有些場(chǎng)合為了方便使用者,,根據(jù)使用者按按鍵的時(shí)間多少來(lái)確定是否按鍵“連發(fā)”。例如,,在設(shè)置時(shí)鐘時(shí),,按按鍵的時(shí)間較短時(shí),設(shè)置加1,;按按鍵時(shí)間較長(zhǎng)時(shí),,設(shè)置加10,這時(shí)就需要根據(jù)按按鍵的時(shí)間長(zhǎng)短來(lái)確定具體輸出,。圖2是將按鍵驅(qū)動(dòng)設(shè)計(jì)為具有連發(fā)功能狀態(tài)機(jī)的狀態(tài)轉(zhuǎn)換圖,。
當(dāng)按鍵按下后1 s內(nèi)釋放了,系統(tǒng)輸出為1,;當(dāng)按鍵按下后1 s沒(méi)有釋放,,那么以后每隔0.5 s,,輸出為2,直到按鍵釋放為止,。如果系統(tǒng)輸出1,,應(yīng)用程序?qū)⒆兞考?;如果系統(tǒng)輸出2,,應(yīng)用程序?qū)⒆兞考?0,。這樣按鍵驅(qū)動(dòng)就有了處理連發(fā)按鍵的功能了。
3 程序設(shè)計(jì)
由于篇幅所限,,下面只給出按鍵驅(qū)動(dòng)的關(guān)鍵程序,,按鍵中斷處理程序和時(shí)間處理函數(shù):
這里的定時(shí)函數(shù)使用了Linux的內(nèi)核定時(shí)器。使用內(nèi)核定時(shí)器可以方便地實(shí)現(xiàn)每個(gè)狀態(tài)的特定定時(shí)時(shí)間,,并且安全釋放CPU,,提高CPU的效率。程序的基本思路是,,首先按鍵被按下進(jìn)入按鍵中斷服務(wù)程序buttons_interrupt(),,在中斷服務(wù)程序里確定按鍵狀態(tài)是否為初始態(tài)。如果是,,則進(jìn)行kbd_timer初始化且使按鍵狀態(tài)轉(zhuǎn)為消抖狀態(tài),。當(dāng)kbd_timer定時(shí)到以后,按鍵檢測(cè)按鍵狀態(tài)是否仍處于按下時(shí)轉(zhuǎn)換狀態(tài)為按鍵確定狀態(tài),,如果不是則恢復(fù)初始態(tài),。當(dāng)定時(shí)器1 s到達(dá)后,判斷按鍵是否仍是按下,。如是則轉(zhuǎn)換為連發(fā)狀態(tài),,否則恢復(fù)初始態(tài)。當(dāng)0.5 s到達(dá)后,,重新判斷按鍵是否仍是按下,。如是,則繼續(xù)為連發(fā)狀態(tài),,輸出值加10,;如果按鍵抬起,則恢復(fù)初始態(tài),。
4 實(shí)驗(yàn)結(jié)果
該驅(qū)動(dòng)程序經(jīng)過(guò)gcc-arm-liunx-3.4.4編譯,,并在Micro2440SDK開(kāi)發(fā)板上運(yùn)行(開(kāi)發(fā)板上的系統(tǒng)版本為linux2.6.13),運(yùn)行結(jié)果如圖3所示,。
從運(yùn)行結(jié)果可以看出,,如果按下按鍵并在1 s抬起,輸出值每次只加1;如果按下按鍵超過(guò)1 s,,系統(tǒng)的輸出值每隔0.5s將加10,。說(shuō)明本驅(qū)動(dòng)運(yùn)行正常,且具有了連發(fā)功能,。
結(jié) 語(yǔ)
本文主要分析了按鍵有限狀態(tài)機(jī)的工作過(guò)程,,并利用Liunx內(nèi)核定時(shí)器實(shí)現(xiàn)了狀態(tài)機(jī)的狀態(tài)轉(zhuǎn)換時(shí)間間隔,最后給出了基于有限狀態(tài)機(jī)的具有連發(fā)功能Linux驅(qū)動(dòng)編寫(xiě)代碼,,實(shí)現(xiàn)了具有連發(fā)功能的按鍵驅(qū)動(dòng),,為基于有限狀態(tài)機(jī)的按鍵驅(qū)動(dòng)提供了一種解決思路。