劉 宸,黃世瑜
(四川職業(yè)技術(shù)學(xué)院,四川 遂寧 629000)
無論是獨立式按鍵還是矩陣式鍵盤,都需要使用按鍵。然而,機械式按鍵在按下和釋放時都存在一定時間的機械抖動,使得輸出電平不穩(wěn)定,從而導(dǎo)致程序錯誤動作。為了消除抖動帶來的不良影響,通常使用軟件消抖[1]。鍵盤識別過程中,軟件消抖的處理方法是本文主要的闡述對象。在獲取鍵位置碼、譯碼以及按鍵功能的過程中,每個步驟都有多種處理方法。本文在實現(xiàn)鍵盤識別的步驟中,將逐步介紹它們的特點及對應(yīng)的應(yīng)用場合,以尋求最優(yōu)的算法。這里,本文的程序代碼采用C430語言編寫。
首先,需要識別是否按下按鍵。與獨立式按鍵一樣,依靠識別與按鍵相連引腳的電平高低。其次,需要識別矩陣鍵盤中哪一位按鍵被按下,即要識別按鍵的位置碼。矩陣鍵盤結(jié)構(gòu)如圖1所示。
要獲取鍵盤中某個按鍵的位置碼,有反轉(zhuǎn)法和掃描法兩種方式。其中,掃描法是用行線作為輸出,列線作為輸入(交換行和列線的輸入、輸出方向亦可),行線逐行輸出低電平‘0’。若某行有鍵按下,列線則定會有低電平‘0’輸入;如果沒有按鍵,則列線輸入值全部為高電平‘1’。如果有鍵按下,由列線和行線讀取的坐標(biāo)位置就能確定相應(yīng)位置的按鍵有被按下[2]。
本文采用反轉(zhuǎn)法,即列線和行線交替輸入和輸出,分兩步獲得鍵盤中的位置碼,并且在多個按鍵同時被按下時,也能準(zhǔn)確識別出組合鍵。
反轉(zhuǎn)法實例程序段:
P3DIR=0X0F;//高4位輸入,低4位輸出
P3OUT=0XF0;//行,低4位輸出0
y=P3IN;//得列碼,如0xe0
P3DIR=0XF0;//高4位輸出,低4位輸入
P3OUT=0X0F;//列,高4位輸出0
x=P3IN;//得行碼,如0x0d
x=x+y;//合成位置碼,如0xed
圖1 矩陣鍵盤結(jié)構(gòu)
通過1.1的步驟獲得按鍵的行號和列號合成的位置碼,如0xed這樣的十六進(jìn)制數(shù)。但是,要轉(zhuǎn)換為有象征意義的鍵盤編號,還要進(jìn)行鍵盤譯碼。鍵盤的編號與鍵盤的位置碼沒有直接的運算關(guān)系,故采用查表法將位置碼轉(zhuǎn)變?yōu)閷?yīng)的鍵號。
譯碼程序段如下:
const char keytab[]={0x11,0x21,0x41,0x81,0x12,0x22,0x 42,0x82,0x14,0x24,0x44,0x84,0x18,0x28,0x48,0x88};//位置碼常量數(shù)組
...//將合成的位置碼key,用查表法與位置碼數(shù)組進(jìn)行逐一比對。
for(i=0;i<16;i++)
{if(key==keytab[i])
break;
}
由于鍵盤的邏輯布局按設(shè)計和功能要求不同,會導(dǎo)致每個按鍵的坐標(biāo)位置和鍵盤編號的對應(yīng)關(guān)系發(fā)生變化。如果每次都要重新尋找對應(yīng)關(guān)系來修改keytab[]數(shù)組,將會使程序不具有通用性,且浪費時間、效率低下。所以,可再通過一個翻譯數(shù)組,實現(xiàn)任意布局的鍵盤編號。
const char keynum[]=//翻譯數(shù)組,實現(xiàn)任意布局
{ 1,2,3,4,
5,6,7 ,8,
9,0,14 ,15,
10,11,12 ,13,16};
...//得到上一步驟的鍵號i(0~16)
return keynum[i];//返回值是將鍵號i通過翻譯數(shù)組翻譯后的值。
1.3.1 傳統(tǒng)方法
這里不討論硬件消抖,只討論軟件消抖。經(jīng)典鍵盤消抖程序采用延時再檢測的流程,首先查詢鍵盤是否有鍵按下,若無鍵按下,則不執(zhí)行功能。當(dāng)有鍵按下時,調(diào)用延時函數(shù)或者調(diào)用其他函數(shù),目的都是等待鍵盤電平抖動的時間過去后再次查詢。若此時仍然有鍵按下,說明確實有鍵可靠穩(wěn)定地按住,并去除了后沿抖動的可能[3]。然后,按照鍵盤上各按鍵的功能規(guī)劃執(zhí)行對應(yīng)的功能程序。最后,為了避免按住按鍵時的重復(fù)執(zhí)行功能,需要繼續(xù)循環(huán)檢測鍵盤,直到按鍵松開為止。
對應(yīng)的程序段如下:
display();//其他任務(wù)
key=inkey();//讀入鍵盤編碼
if(key<16)//有按鍵
{display();//延時消抖,并顯示
if(key==inkey())//兩次讀入鍵盤編碼相同
{
key_action(key);//執(zhí)行按鍵功能
while(key==inkey()){display();}//按住時等待松手
}
}
這段程序能夠較好地實現(xiàn)鍵盤消抖。如果系統(tǒng)的任務(wù)相對單一,使用這段程序可以完成任務(wù),但缺點是調(diào)用延時函數(shù)和等待松手循環(huán)查詢時,程序指針陷入有限循環(huán)中,無暇處理其他任務(wù),如讀取傳感器數(shù)據(jù)、輸出控制執(zhí)行部件等。雖然采用中斷系統(tǒng)可以處理這些實時任務(wù),由主程序調(diào)用鍵盤檢測的函數(shù),但這樣會導(dǎo)致在主程序無限循環(huán)中一直有鍵盤檢測的任務(wù),而系統(tǒng)則無法進(jìn)入低功耗模式。然而,在便攜式設(shè)備中不能進(jìn)入低功耗模式,將是無法想象的。當(dāng)然,可以把鍵盤檢測函數(shù)放在定時中斷服務(wù)函數(shù),由于中斷源的優(yōu)先順序問題,也會導(dǎo)致程序指針停留在此而無法執(zhí)行其他函數(shù)。
1.3.2 對電平計時的矩陣鍵盤檢測方法
從以上分析看出,傳統(tǒng)算法中執(zhí)行矩陣鍵盤檢測與其他任務(wù)的運行存在矛盾,有諸多弊端,而本文提出的對電平計時的矩陣鍵盤檢測方法可以解決這些問題。程序要求每隔幾毫秒讀取一次矩陣鍵盤的值,可以放在主函數(shù),最好放在定時中斷服務(wù)程序,目的是間隔抽樣檢測鍵盤輸入端口的電平。
程序流程圖如圖2所示,方法是間隔時間抽樣檢測,用一個計時值統(tǒng)計低電平保持的時間。首先讀取輸入端口數(shù)據(jù),判斷是否按鍵。當(dāng)有按鍵時,計時值+1;否則,計時值清零。若連續(xù)多次都檢測到低電平,計時值會累加,表示已經(jīng)度過鍵盤的抖動時間,可以穩(wěn)定可靠地按住按鍵。識別為短按時,需要低電平穩(wěn)定10 ms以上。若間隔時間為2 ms,則計時值需要10/2=5次。當(dāng)計時值累加到5時,滿足短按識別條件,就可以執(zhí)行對應(yīng)按鍵的功能。如果是長按還可實現(xiàn)連擊的效果,則當(dāng)計時值累加到500時,即低電平已經(jīng)穩(wěn)定2 ms×500=1 s,可視為長按有效。此時,將計時值回?fù)艿?00,并執(zhí)行相應(yīng)功能。如果繼續(xù)長按,計時值又從400累加到500時,又一次滿足長按條件,但周期只有2 ms×(500-400)=0.2 s,即長按1 s后每隔0.2 s就視為連擊一次,可以實現(xiàn)電視遙控器上的連加連減效果。返回鍵值的時間點只有5(短按)和500(長按),太小的是按鍵抖動時期,其他次數(shù)都不滿足按鍵條件,返回按鍵無效的鍵值。整個檢測按鍵的程序里沒有延時等待,因此程序指針不會停留在這里,轉(zhuǎn)而執(zhí)行其他任務(wù)。
圖2 對電平計時的矩陣鍵盤檢測方法
讀取按鍵值的程序段如下:
if(x!=0xFF)//x是合成的位置碼,若按下時x!=0xFF
{
cnt++;//統(tǒng)計低電平的時間
if(cnt==5)//連續(xù)檢測到5次低電平,表示抖動已經(jīng)過去,已進(jìn)入穩(wěn)定期5*2ms=10ms
{ key=x; }//20 ms時,給返回值,執(zhí)行功能
else if(cnt>500)//按住不松手 500×2 ms=1 s以上,長按,就連續(xù)執(zhí)行功能
{ cnt=400; key=x;}//從400增加到500,共100次的時間0.2 s
else key=0xff;//其他次數(shù)時,按了鍵,但沒達(dá)到條件
}
else {cnt=0; key=0xff;}//沒按鍵,抬手時,時間計數(shù)cnt清0
經(jīng)過上述步驟后,能讀取到穩(wěn)定可靠的鍵盤數(shù)據(jù)。按鍵的位置碼被翻譯數(shù)組翻譯后的鍵值是0~16。當(dāng)有按鍵時,鍵值是0~15;沒有按鍵或無效時,鍵值是16。按鍵的功能可根據(jù)鍵值分別對應(yīng)編寫。
void keyaction()
{ char key;
key=keyscan();//讀取鍵盤數(shù)據(jù)
if(key<16)//有按鍵,則執(zhí)行功能
{ if(key<10){n=key;}
switch(key)
{
case 10: if(n<15)n++;break;
case 11: if(n>0)n--;break;
case 12: if(n<15)n+=2; break;
case 13: if(n>0)n-=2; break;
}
P1OUT=table[n];//靜態(tài)顯示
}
}
此函數(shù)可放在主函數(shù)循環(huán)間隔調(diào)用,也可在定時中斷服務(wù)程序中定時調(diào)用。
while(1)
{ delay(2);//間隔2 ms讀取按鍵
keyaction();}//按鍵識別及執(zhí)行功能
測試通過搭建真實硬件電路和Proteus仿真的實驗驗證。實驗結(jié)果證明,本文提出的間隔抽樣統(tǒng)計低電平時間的矩陣鍵盤識別方法,能有效消除抖動帶來的影響,還能使程序指針不停留地執(zhí)行其他任務(wù)。該方法沒有依靠延時等待,不浪費系統(tǒng)時間,實現(xiàn)了任意布局,并區(qū)分出了短按和長按,具有優(yōu)越性。
為解決矩陣鍵盤識別傳統(tǒng)方法中鍵盤檢測與多任務(wù)實時運行存在的諸多問題,本文提出了一種抽樣檢測對電平計時的矩陣鍵盤識別方法。在不靠延時的前提下,既能夠可靠地消除抖動,又能夠保證程序順暢地運行其他任務(wù),并實現(xiàn)了鍵盤功能的任意布局,避免了鍵盤邏輯值的復(fù)雜計算和更改布局帶來的排序問題。同時,能嚴(yán)格區(qū)分短按和長按,稍作修改亦可識別雙擊。因此,這是一種通用性和效率更高的矩陣鍵盤識別方法。
參考文獻(xiàn):
[1] 劉 宸.兩種基于電平計時的按鍵檢測方法[J].四川職業(yè)技術(shù)學(xué)院學(xué)報,2017,27(4):151-153.
[2] 鄭玉章,徐愛鈞.嵌入式開發(fā)過程中按鍵檢測算法的改進(jìn)[J].單片機與嵌入式系統(tǒng)應(yīng)用,2014,14(8):73-75.
[3] 王海珍.按鍵檢測算法創(chuàng)新在嵌入式開發(fā)中的應(yīng)用[J].電子制作,2017(4):98,100.