陳曉麗
(珠海格力電器股份有限公司 廣東珠海 519070)
在單片機控制系統(tǒng)中,按鍵是最常用的輸入設(shè)備,是人-機接口中非常重要的組成部分,家用電器或其它消費性電子產(chǎn)品中就經(jīng)常使用按鍵來實現(xiàn)功能控制或選擇、配置信息參數(shù)等。隨著產(chǎn)品功能越來越豐富,按鍵的作用越來越多樣化,同一個按鍵被賦予了多種功能(即一鍵多功能),比如:短按一個按鍵是功能模式切換,而長按這一個按鍵又可以是關(guān)機的功能,這使得按鍵的檢測和處理更加復雜,也更加重要。本文講述了一種按鍵的多種狀態(tài)判斷方法和相應(yīng)的按鍵消抖處理方法。
按鍵都是以開關(guān)狀態(tài)來輸入數(shù)據(jù)的。根據(jù)硬件電路上對按鍵檢測的不同來區(qū)分,可以將按鍵檢測電路分為兩種類型,一類是I/O掃描式按鍵電路,另一類是AD采樣式按鍵電路。這兩種電路在按鍵檢測原理上存在區(qū)別,I/O掃描式按鍵檢測是根據(jù)I/O的高低電平來判斷是否有鍵按下,而AD采樣式按鍵檢測是根據(jù)I/O的AD采樣值范圍來判斷是否有鍵按下。雖然兩類按鍵的檢測方法不同,但是按鍵的處理方法是一樣的,包括狀態(tài)判斷處理和消抖處理。
為了實現(xiàn)一個按鍵有多種功能,可以根據(jù)操作按鍵的不同狀態(tài)來進行處理,這就需要判斷出按鍵的各種狀態(tài)。按鍵的狀態(tài)有多種類型,包括短按、長按、連按、短按釋放、長按釋放等。
這里介紹一種程序上判斷按鍵多種狀態(tài)的方法。
程序代碼如下:
#define NO_KEY 0xFF //按鍵沒有按下
#define TASK_KEY_LONG 0x20//按鍵長按
#define TASK_KEY_HOLD 0x40//按鍵連按
#define TASK_KEY_SHORT_UP 0x80//按鍵短按后釋放
#define TASK_KEY_LONG_UP 0x60//按鍵長按后釋放
#define KEY_SCAN_TIMES 3 //短按鍵的次數(shù)
#define KEY_LONG_TIMES 150 //長按鍵的次數(shù)
#define KEY_HOLD_TIMES 35 //連按鍵的次數(shù)
void KeyScan(void)
{
static unsigned char keyCounter; //用于區(qū)分短按、長按、連按等
static unsigned char keyValue; //按鍵穩(wěn)定狀態(tài)值
unsigned char keyTmp; //當前按鍵狀態(tài)
unsigned char key_return = NO_KEY;
static bool long_key; //按鍵長按標志
keyTmp = KeyDetect(); //獲取當前的按鍵
狀態(tài),keyTmp的每一位對應(yīng)一個按鍵狀態(tài),0表
示按鍵按下
if (keyTmp == NO_KEY) //釋放按鍵或者
按鍵沒有按下
{
if (long_key == 1)
{
key_return = keyValue | TASK_KEY_
LONG_UP; //長按后釋放按鍵
}
else if ((keyCounter < KEY_LONG_
TIMES ) && (keyCounter > KEY_SCAN_
TIMES))
{
key_return = keyValue | TASK_KEY_
SHORT_UP; //短按后釋放按鍵
}
keyValue = NO_KEY;
long_key = 0;
keyCounter = 0;
}
else if ((keyTmp != keyValue))
{
keyValue = keyTmp;
keyCounter = 0;
long_key = 0;
}
else
{
keyCounter++;
if (keyCounter == KEY_SCAN_TIMES)
{
key_return = keyValue; //短按
}
else if (keyCounter == KEY_LONG_
TIMES )
{
if (long_key == FALSE)
{
long_key = TRUE;
key_return = keyValue | TASK_KEY_LONG; //長按
}
}
else if (keyCounter == (KEY_LONG_TIMES + KEY_HOLD_TIMES) )
{
key_return = keyValue | TASK_KEY_HOLD; //連按
keyCounter = KEY_LONG_TIMES;
}
}
if ( key_return != NO_KEY)
{
PutMsg(key_return); //產(chǎn)生有按鍵的消息
}
}
函數(shù)KeyScan()的原理:在定時器的5ms中斷處理中調(diào)用這個函數(shù),通過按鍵掃描函數(shù)KeyDetect()獲取按鍵狀態(tài)keyTmp,它的每一位對應(yīng)一個按鍵狀態(tài),0表示按鍵按下,1表示按鍵沒有按下。當keyTmp為0xFF時,表示沒有任何按鍵按下;keyCounter用于累計按鍵按下的時間,短按時間為3×5ms=15ms,也就是說當檢測按鍵按下的時間超過15ms,就會發(fā)出一個短按的消息。同理,長按時間為150×5ms=750ms,連按消息是在長按后35×5=175ms后發(fā)出的,如果按鍵一直按著,就會每過175ms發(fā)出一個連按消息了;而短按釋放的消息就要求按鍵短按和按鍵釋放兩個條件都先后滿足,長按釋放的消息也如此。當有按鍵按下時,這個函數(shù)會產(chǎn)生一個按鍵消息key_return,它是按鍵類型keyValue同按鍵狀態(tài)(包括短按、長按、連按、短按釋放、長按釋放)進行或運算的結(jié)果。這樣處理的優(yōu)點:不管有多少個按鍵,每個按鍵都可以產(chǎn)生出這5類狀態(tài)的消息,按鍵數(shù)量有增加或刪減時,都不用更改代碼,方便維護。
常用的按鍵為機械彈性按鍵,也稱輕觸開關(guān)。機械按鍵由于觸點的彈性及電壓突跳等原因,在觸點閉合和斷開的瞬間會出現(xiàn)抖動。一個按鍵在閉合時不會馬上穩(wěn)定地接通,同樣,在斷開時也不會一下子斷開,在閉合和斷開的瞬間均伴隨有一連串的抖動,如圖1所示。
抖動時間的長短由按鍵的機械特性來決定,一般為5~10ms。這種抖動對人來說是感覺不到的,但對單片機來說,則是完全可以感知的,因為單片機的處理速度在微秒級。按鍵穩(wěn)定閉合時間的長短則由操作人員的按鍵動作決定的,一般為幾百個毫秒至數(shù)秒。如果不對按鍵消除抖動則會引起程序處理的誤操作。為了避免這種抖動現(xiàn)象,需進行按鍵消抖處理。
按鍵消抖有“硬件消抖”和“軟件消抖”兩種方式。簡單的硬件消抖是在按鍵接入單片機的引腳位置并入一個小電容,利用電容的充放電原理來實現(xiàn)消除因抖動所產(chǎn)生的毛刺。簡單的軟件消抖就是用加固定軟件延時的方法來去除抖動,具體方法就是在有按鍵按下時,利用軟件延時一段時間后再次檢測按鍵是否按下,實際上是避開了按鍵按下時的抖動時間。
這種硬件上并電容或軟件上延時的處理方式比較簡單,而且確實也起到了一定的消抖作用。但是在實際的生產(chǎn)使用過程中,按鍵千差萬別,不同廠家的物料也參差不齊,各種按鍵操作時產(chǎn)生的抖動時間不會是一致的。這樣就會出現(xiàn)一些問題了,電容過小或延時過短,可能會有按鍵誤動作的問題;而電容過大或延時過長,會有按鍵操作后反應(yīng)遲鈍的問題。下面介紹一種新的消抖處理方法,抖動時間的長或短,對按鍵的操作效果沒有任何影響。
程序代碼如下:
#define KEY_SHAKE_TIMES 8 //按鍵防抖的掃描次數(shù)
static unsigned char Count; //用于累計按鍵狀態(tài)穩(wěn)定的次數(shù)
static unsigned char keyStatus; //前次按鍵狀態(tài)
if(keyTmp != keyStatus) //當前按鍵狀態(tài)是否與前次按鍵狀態(tài)相同
{
keyStatus = keyTmp;
Count = 0;
return;
}
else
{
if (Count < 8)
{
Count++;
return;
}
}
只要在前面介紹的函數(shù)KeyScan()中獲取keyTmp值后增加這段代碼就可以了。它的原理:每次掃描中都將當前按鍵狀態(tài)keyTmp與前次按鍵狀態(tài)keyStatus進行比較,如果比較的兩次狀態(tài)不同,表示按鍵處于抖動中,會將用于累計按鍵狀態(tài)穩(wěn)定次數(shù)的變量Count清零,只有當連續(xù)8次比較的狀態(tài)都相同時,才認為狀態(tài)穩(wěn)定了,即沒有抖動了。這包括了按鍵按下時的抖動處理和按鍵釋放的抖動處理。其中Count設(shè)為8次,每5ms調(diào)用一次,這就是40ms,它的設(shè)定,與抖動時間長短無關(guān),只要大于抖動周期就可以了。這種處理方法的優(yōu)點在于:它與抖動過程的時間長短無關(guān),而且處理代碼簡單,不用區(qū)分按下抖動或釋放抖動。
本文介紹的這種單片機按鍵狀態(tài)檢測和消抖處理方法,與一般的按鍵檢測方法相比,能檢測更多類型的的按鍵狀態(tài),按鍵數(shù)量有增加或刪減時,也不用更改代碼,適用范圍廣,且代碼簡單,方便維護。采用的按鍵消抖方法也有很大的改進,與抖動過程的時間長短無關(guān),不用區(qū)分按下抖動或釋放抖動。
[1]譚浩強 C程序設(shè)計 清華大學出版社
[2]劉天時,劉賞,付春 一種單片機鍵盤電路設(shè)計與消抖處理 計算機與網(wǎng)絡(luò)2012年 第10期
[3]李運兵 微控制器中按鍵處理技巧及應(yīng)用 計算機應(yīng)用系統(tǒng) 2010年第2期