一種新型的按鍵程序
同時(shí),這里面用到了一些分層的思想,在單片機當中也是相當有用的,也是本文的另外一個(gè)重點(diǎn)。
對于老鳥(niǎo),我建議直接看那兩個(gè)表達式,然后自己想想就會(huì )懂的了,也不需要聽(tīng)我后面的自吹自擂了,我可沒(méi)有班門(mén)弄斧的意思,hoho~~但是對于新手,我建議將全文看完。因為這是實(shí)際項目中總結出來(lái)的經(jīng)驗,學(xué)校里面學(xué)不到的東西。
以下假設你懂C語(yǔ)言,因為純粹的C語(yǔ)言描述,所以和處理器平臺無(wú)關(guān),你可以在MCS-51,AVR,PIC,甚至是ARM平臺上面測試這個(gè)程序性能。當然,我自己也是在多個(gè)項目用過(guò),效果非常好的。
好了,工程人員的習慣,廢話(huà)就應該少說(shuō),開(kāi)始吧。以下我以AVR的MEGA8作為平臺講解,沒(méi)有其它原因,因為我手頭上只有AVR的板子而已沒(méi)有51的。用51也可以,只是芯片初始化部分不同,還有寄存器名字不同而已。
核心算法:
unsigned
unsigned
void
{
}
完了。有沒(méi)有一種不可思議的感覺(jué)?當然,沒(méi)有想懂之前會(huì )那樣,想懂之后就會(huì )驚嘆于這算法的精妙??!
下面是程序解釋?zhuān)?br />Trg(triger)
1:讀PORTB的端口數據,取反,然后送到ReadData
2:算法1,用來(lái)計算觸發(fā)變量的。一個(gè)位與操作,一個(gè)異或操作,我想學(xué)過(guò)C語(yǔ)言都應該懂吧?Trg為全局變量,其它程序可以直接引用。
3:算法2,用來(lái)計算連續變量。
看到這里,有種“知其然,不知其所以然”的感覺(jué)吧?代碼很簡(jiǎn)單,但是它到底是怎么樣實(shí)現我們的目的的呢?好,下面就讓我們繞開(kāi)云霧看青天吧。
我們最常用的按鍵接法如下:AVR是有內部上拉功能的,但是為了說(shuō)明問(wèn)題,我是特意用外部上拉電阻。那么,按鍵沒(méi)有按下的時(shí)候,讀端口數據為1,如果按鍵按下,那么端口讀到0。下面就看看具體幾種情況之下,這算法是怎么一回事。
(1)
端口為0xff,ReadData讀端口并且取反,很顯然,就是
Trg
Cont
結果就是:
ReadData
Trg
Cont
(2)
端口數據為0xfe,ReadData讀端口并且取反,很顯然,就是
Trg
Cont
結果就是:
ReadData
Trg
Cont
(3)
端口數據為0xfe,ReadData讀端口并且取反是
Trg
Cont
結果就是:
ReadData
Trg
Cont
因為現在按鍵是長(cháng)按著(zhù),所以MCU會(huì )每個(gè)一定時(shí)間(20ms左右)不斷的執行這個(gè)函數,那么下次執行的時(shí)候情況會(huì )是怎么樣的呢?
ReadData
Trg
Cont
(4)
端口數據為0xff,ReadData讀端口并且取反是
Trg
Cont
結果就是:
ReadData
Trg
Cont
很顯然,這個(gè)回到了初始狀態(tài),也就是沒(méi)有按鍵按下的狀態(tài)。
總結一下,不知道想懂了沒(méi)有?其實(shí)很簡(jiǎn)單,答案如下:
Trg
如果還是想不懂的話(huà),可以自己演算一下那兩個(gè)表達式,應該不難理解的。
因為有了這個(gè)支持,那么按鍵處理就變得很爽了,下面看應用:
應用一:一次觸發(fā)的按鍵處理
假設PB0為蜂鳴器按鍵,按一下,蜂鳴器beep的響一聲。這個(gè)很簡(jiǎn)單,但是大家以前是怎么做的呢?對比一下看誰(shuí)的方便?
#define
void
{
}
怎么樣?夠和諧不?記得前面解釋說(shuō)Trg的精粹是什么?精粹就是只會(huì )出現一次。所以你按下按鍵的話(huà),Trg
或者你會(huì )認為這個(gè)處理簡(jiǎn)單,沒(méi)有問(wèn)題,我們繼續。
應用2:長(cháng)按鍵的處理
項目中經(jīng)常會(huì )遇到一些要求,例如:一個(gè)按鍵如果短按一下執行功能A,如果長(cháng)按2秒不放的話(huà)會(huì )執行功能B,又或者是要求3秒按著(zhù)不放,計數連加什么什么的功能,很實(shí)際。不知道大家以前是怎么做的呢?我承認以前做的很郁悶。
但是看我們這里怎么處理吧,或許你會(huì )大吃一驚,原來(lái)程序可以這么簡(jiǎn)單
這里具個(gè)簡(jiǎn)單例子,為了只是說(shuō)明原理,PB0是模式按鍵,短按則切換模式,PB1就是加,如果長(cháng)按的話(huà)則連加(玩過(guò)電子表吧?沒(méi)錯,就是那個(gè)?。?br />#define
#define
void
{
}
不知道各位感覺(jué)如何?我覺(jué)得還是挺簡(jiǎn)單的完成了任務(wù),當然,作為演示用代碼。
應用3:點(diǎn)觸型按鍵和開(kāi)關(guān)型按鍵的混合使用
點(diǎn)觸形按鍵估計用的最多,特別是單片機。開(kāi)關(guān)型其實(shí)也很常見(jiàn),例如家里的電燈,那些按下就不松開(kāi),除非關(guān)。這是兩種按鍵形式的處理原理也沒(méi)啥特別,但是你有沒(méi)有想過(guò),如果一個(gè)系統里面這兩種按鍵是怎么處理的?我想起了我以前的處理,分開(kāi)兩個(gè)非常類(lèi)似的處理程序,現在看起來(lái)真的是笨的不行了,但是也沒(méi)有辦法啊,結構決定了程序。不過(guò)現在好了,用上面介紹的辦法,很輕松就可以搞定。
原理么?可能你也會(huì )想到,對于點(diǎn)觸開(kāi)關(guān),按照上面的辦法處理一次按下和長(cháng)按,對于開(kāi)關(guān)型,我們只需要處理Cont就OK了,為什么?很簡(jiǎn)單嘛,把它當成是一個(gè)長(cháng)按鍵,這樣就找到了共同點(diǎn),屏蔽了所有的細節。程序就不給了,完全就是應用2的內容,在這里提為了就是說(shuō)明原理~~
好了,這個(gè)好用的按鍵處理算是說(shuō)完了??赡軙?huì )有朋友會(huì )問(wèn),為什么不說(shuō)延時(shí)消抖問(wèn)題?哈哈,被看穿了。果然不能偷懶。下面談?wù)勥@個(gè)問(wèn)題,順便也就非常簡(jiǎn)單的談?wù)勎易约河脮r(shí)間片輪辦法,以及是如何消抖的。
延時(shí)消抖的辦法是非常傳統,也就是
當然,不要跟我說(shuō)你delay(20)那樣去死循環(huán)去,真是那樣的話(huà),我衷心的建議你先放下手上所有的東西,好好的去了解一下操作系統的分時(shí)工作原理,大概知道思想就可以,不需要詳細看原理,否則你永遠逃不出“菜鳥(niǎo)”這個(gè)圈子。當然我也是菜鳥(niǎo)。我的意思是,真正的單片機入門(mén),是從學(xué)會(huì )處理多任務(wù)開(kāi)始的,這個(gè)也是學(xué)校程序跟公司程序的最大差別。當然,本文不是專(zhuān)門(mén)說(shuō)這個(gè)的,所以也不獻丑了。
我的主程序架構是這樣的:
volatile
void
{
}
void
{
}
貌似扯遠了,回到我們剛才的問(wèn)題,也就是怎么做按鍵消抖處理。我們將讀按鍵的程序放在了主循環(huán),也就是說(shuō),每20ms我們會(huì )執行一次KeyRead()函數來(lái)得到新的Trg
基本架構如上,我自己比較喜歡的,一直在用。當然,和這個(gè)配合,每個(gè)子程序必須執行時(shí)間不長(cháng),更加不能死循環(huán),一般采用有限狀態(tài)機的辦法來(lái)實(shí)現,具體參考其它資料咯。
懂得基本原理之后,至于怎么用就大家慢慢思考了,我想也難不到聰明的工程師們。例如還有一些處理,
怎么判斷按鍵釋放?很簡(jiǎn)單,Trg
評論