新型的按鍵掃描程序,僅三行程序
因?yàn)橛辛诉@個(gè)支持,那么按鍵處理就變得很爽了,下面看應(yīng)用:
應(yīng)用一:一次觸發(fā)的按鍵處理
假設(shè)PB0為蜂鳴器按鍵,按一下,蜂鳴器beep的響一聲。這個(gè)很簡(jiǎn)單,但是大家以前是怎么做的呢?對(duì)比一下看誰(shuí)的方便?
#define KEY_BEEP 0x01
void KeyProc(void)
{
if (Trg & KEY_BEEP) // 如果按下的是KEY_BEEP
{
Beep(); // 執(zhí)行蜂鳴器處理函數(shù)
}
}
怎么樣?夠和諧不?記得前面解釋說(shuō)Trg的精粹是什么?精粹就是只會(huì)出現(xiàn)一次。所以你按下按鍵的話(huà),Trg & KEY_BEEP 為“真”的情況只會(huì)出現(xiàn)一次,所以處理起來(lái)非常的方便,蜂鳴器也不會(huì)沒(méi)事亂叫,hoho~~~
或者你會(huì)認(rèn)為這個(gè)處理簡(jiǎn)單,沒(méi)有問(wèn)題,我們繼續(xù)。
應(yīng)用2:長(zhǎng)按鍵的處理
項(xiàng)目中經(jīng)常會(huì)遇到一些要求,例如:一個(gè)按鍵如果短按一下執(zhí)行功能A,如果長(zhǎng)按2秒不放的話(huà)會(huì)執(zhí)行功能B,又或者是要求3秒按著不放,計(jì)數(shù)連加什么什么的功能,很實(shí)際。不知道大家以前是怎么做的呢?我承認(rèn)以前做的很郁悶。
但是看我們這里怎么處理吧,或許你會(huì)大吃一驚,原來(lái)程序可以這么簡(jiǎn)單
這里具個(gè)簡(jiǎn)單例子,為了只是說(shuō)明原理,PB0是模式按鍵,短按則切換模式,PB1就是加,如果長(zhǎng)按的話(huà)則連加(玩過(guò)電子表吧?沒(méi)錯(cuò),就是那個(gè)!)
#define KEY_MODE 0x01 // 模式按鍵
#define KEY_PLUS 0x02 // 加
void KeyProc(void)
{
if (Trg & KEY_MODE) // 如果按下的是KEY_MODE,而且你常按這按鍵也沒(méi)有用,
{ //它是不會(huì)執(zhí)行第二次的哦 , 必須先松開(kāi)再按下
Mode++; // 模式寄存器加1,當(dāng)然,這里只是演示,你可以執(zhí)行你想
// 執(zhí)行的任何代碼
}
if (Cont & KEY_PLUS) // 如果“加”按鍵被按著不放
{
cnt_plus++; // 計(jì)時(shí)
if (cnt_plus > 100) // 20ms*100 = 2S 如果時(shí)間到
{
Func(); // 你需要的執(zhí)行的程序
}
}
}
不知道各位感覺(jué)如何?我覺(jué)得還是挺簡(jiǎn)單的完成了任務(wù),當(dāng)然,作為演示用代碼。
應(yīng)用3:點(diǎn)觸型按鍵和開(kāi)關(guān)型按鍵的混合使用
點(diǎn)觸形按鍵估計(jì)用的最多,特別是單片機(jī)。開(kāi)關(guān)型其實(shí)也很常見(jiàn),例如家里的電燈,那些按下就不松開(kāi),除非關(guān)。這是兩種按鍵形式的處理原理也沒(méi)啥特別,但是你有沒(méi)有想過(guò),如果一個(gè)系統(tǒng)里面這兩種按鍵是怎么處理的?我想起了我以前的處理,分開(kāi)兩個(gè)非常類(lèi)似的處理程序,現(xiàn)在看起來(lái)真的是笨的不行了,但是也沒(méi)有辦法啊,結(jié)構(gòu)決定了程序。不過(guò)現(xiàn)在好了,用上面介紹的辦法,很輕松就可以搞定。
原理么?可能你也會(huì)想到,對(duì)于點(diǎn)觸開(kāi)關(guān),按照上面的辦法處理一次按下和長(zhǎng)按,對(duì)于開(kāi)關(guān)型,我們只需要處理Cont就OK了,為什么?很簡(jiǎn)單嘛,把它當(dāng)成是一個(gè)長(zhǎng)按鍵,這樣就找到了共同點(diǎn),屏蔽了所有的細(xì)節(jié)。程序就不給了,完全就是應(yīng)用2的內(nèi)容,在這里提為了就是說(shuō)明原理~~
好了,這個(gè)好用的按鍵處理算是說(shuō)完了??赡軙?huì)有朋友會(huì)問(wèn),為什么不說(shuō)延時(shí)消抖問(wèn)題?哈哈,被看穿了。果然不能偷懶。下面談?wù)勥@個(gè)問(wèn)題,順便也就非常簡(jiǎn)單的談?wù)勎易约河脮r(shí)間片輪辦法,以及是如何消抖的。
延時(shí)消抖的辦法是非常傳統(tǒng),也就是 第一次判斷有按鍵,延時(shí)一定的時(shí)間(一般習(xí)慣是20ms)再讀端口,如果兩次讀到的數(shù)據(jù)一樣,說(shuō)明了是真正的按鍵,而不是抖動(dòng),則進(jìn)入按鍵處理程序。
當(dāng)然,不要跟我說(shuō)你delay(20)那樣去死循環(huán)去,真是那樣的話(huà),我衷心的建議你先放下手上所有的東西,好好的去了解一下操作系統(tǒng)的分時(shí)工作原理,大概知道思想就可以,不需要詳細(xì)看原理,否則你永遠(yuǎn)逃不出“菜鳥(niǎo)”這個(gè)圈子。當(dāng)然我也是菜鳥(niǎo)。我的意思是,真正的單片機(jī)入門(mén),是從學(xué)會(huì)處理多任務(wù)開(kāi)始的,這個(gè)也是學(xué)校程序跟公司程序的最大差別。當(dāng)然,本文不是專(zhuān)門(mén)說(shuō)這個(gè)的,所以也不獻(xiàn)丑了。
我的主程序架構(gòu)是這樣的:
volatile unsigned char Intrcnt;
void InterruptHandle() // 中斷服務(wù)程序
{
Intrcnt++; // 1ms 中斷1次,可變
}
void main(void)
{
SysInit();
while(1) // 每20ms 執(zhí)行一次大循環(huán)
{
KeyRead(); // 將每個(gè)子程序都掃描一遍
KeyProc();
Func1();
Funt2();
…
…
while(1)
{
if (Intrcnt>20) // 一直在等,直到20ms時(shí)間到
{
Intrcnt="0";
break; // 返回主循環(huán)
}
}
}
}
貌似扯遠(yuǎn)了,回到我們剛才的問(wèn)題,也就是怎么做按鍵消抖處理。我們將讀按鍵的程序放在了主循環(huán),也就是說(shuō),每20ms我們會(huì)執(zhí)行一次KeyRead()函數(shù)來(lái)得到新的Trg 和 Cont 值。好了,下面是我的消抖部分:很簡(jiǎn)單
基本架構(gòu)如上,我自己比較喜歡的,一直在用。當(dāng)然,和這個(gè)配合,每個(gè)子程序必須執(zhí)行時(shí)間不長(zhǎng),更加不能死循環(huán),一般采用有限狀態(tài)機(jī)的辦法來(lái)實(shí)現(xiàn),具體參考其它資料咯。
懂得基本原理之后,至于怎么用就大家慢慢思考了,我想也難不到聰明的工程師們。例如還有一些處理,
怎么判斷按鍵釋放?很簡(jiǎn)單,Trg 和Cont都為0 則肯定已經(jīng)釋放了。
評(píng)論