陳曉麗
(珠海格力電器股份有限公司 廣東珠海 519070)
在單片機控制系統中,按鍵是最常用的輸入設備,是人-機接口中非常重要的組成部分,家用電器或其它消費性電子產品中就經常使用按鍵來實現功能控制或選擇、配置信息參數等。隨著產品功能越來越豐富,按鍵的作用越來越多樣化,同一個按鍵被賦予了多種功能(即一鍵多功能),比如:短按一個按鍵是功能模式切換,而長按這一個按鍵又可以是關機的功能,這使得按鍵的檢測和處理更加復雜,也更加重要。本文講述了一種按鍵的多種狀態判斷方法和相應的按鍵消抖處理方法。
按鍵都是以開關狀態來輸入數據的。根據硬件電路上對按鍵檢測的不同來區分,可以將按鍵檢測電路分為兩種類型,一類是I/O掃描式按鍵電路,另一類是AD采樣式按鍵電路。這兩種電路在按鍵檢測原理上存在區別,I/O掃描式按鍵檢測是根據I/O的高低電平來判斷是否有鍵按下,而AD采樣式按鍵檢測是根據I/O的AD采樣值范圍來判斷是否有鍵按下。雖然兩類按鍵的檢測方法不同,但是按鍵的處理方法是一樣的,包括狀態判斷處理和消抖處理。
為了實現一個按鍵有多種功能,可以根據操作按鍵的不同狀態來進行處理,這就需要判斷出按鍵的各種狀態。按鍵的狀態有多種類型,包括短按、長按、連按、短按釋放、長按釋放等。
這里介紹一種程序上判斷按鍵多種狀態的方法。
程序代碼如下:
#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 //短按鍵的次數
#define KEY_LONG_TIMES 150 //長按鍵的次數
#define KEY_HOLD_TIMES 35 //連按鍵的次數
void KeyScan(void)
{
static unsigned char keyCounter; //用于區分短按、長按、連按等
static unsigned char keyValue; //按鍵穩定狀態值
unsigned char keyTmp; //當前按鍵狀態
unsigned char key_return = NO_KEY;
static bool long_key; //按鍵長按標志
keyTmp = KeyDetect(); //獲取當前的按鍵
狀態,keyTmp的每一位對應一個按鍵狀態,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); //產生有按鍵的消息
}
}
函數KeyScan()的原理:在定時器的5ms中斷處理中調用這個函數,通過按鍵掃描函數KeyDetect()獲取按鍵狀態keyTmp,它的每一位對應一個按鍵狀態,0表示按鍵按下,1表示按鍵沒有按下。當keyTmp為0xFF時,表示沒有任何按鍵按下;keyCounter用于累計按鍵按下的時間,短按時間為3×5ms=15ms,也就是說當檢測按鍵按下的時間超過15ms,就會發出一個短按的消息。同理,長按時間為150×5ms=750ms,連按消息是在長按后35×5=175ms后發出的,如果按鍵一直按著,就會每過175ms發出一個連按消息了;而短按釋放的消息就要求按鍵短按和按鍵釋放兩個條件都先后滿足,長按釋放的消息也如此。當有按鍵按下時,這個函數會產生一個按鍵消息key_return,它是按鍵類型keyValue同按鍵狀態(包括短按、長按、連按、短按釋放、長按釋放)進行或運算的結果。這樣處理的優點:不管有多少個按鍵,每個按鍵都可以產生出這5類狀態的消息,按鍵數量有增加或刪減時,都不用更改代碼,方便維護。

常用的按鍵為機械彈性按鍵,也稱輕觸開關。機械按鍵由于觸點的彈性及電壓突跳等原因,在觸點閉合和斷開的瞬間會出現抖動。一個按鍵在閉合時不會馬上穩定地接通,同樣,在斷開時也不會一下子斷開,在閉合和斷開的瞬間均伴隨有一連串的抖動,如圖1所示。
抖動時間的長短由按鍵的機械特性來決定,一般為5~10ms。這種抖動對人來說是感覺不到的,但對單片機來說,則是完全可以感知的,因為單片機的處理速度在微秒級。按鍵穩定閉合時間的長短則由操作人員的按鍵動作決定的,一般為幾百個毫秒至數秒。如果不對按鍵消除抖動則會引起程序處理的誤操作。為了避免這種抖動現象,需進行按鍵消抖處理。
按鍵消抖有“硬件消抖”和“軟件消抖”兩種方式。簡單的硬件消抖是在按鍵接入單片機的引腳位置并入一個小電容,利用電容的充放電原理來實現消除因抖動所產生的毛刺。簡單的軟件消抖就是用加固定軟件延時的方法來去除抖動,具體方法就是在有按鍵按下時,利用軟件延時一段時間后再次檢測按鍵是否按下,實際上是避開了按鍵按下時的抖動時間。
這種硬件上并電容或軟件上延時的處理方式比較簡單,而且確實也起到了一定的消抖作用。但是在實際的生產使用過程中,按鍵千差萬別,不同廠家的物料也參差不齊,各種按鍵操作時產生的抖動時間不會是一致的。這樣就會出現一些問題了,電容過小或延時過短,可能會有按鍵誤動作的問題;而電容過大或延時過長,會有按鍵操作后反應遲鈍的問題。下面介紹一種新的消抖處理方法,抖動時間的長或短,對按鍵的操作效果沒有任何影響。
程序代碼如下:
#define KEY_SHAKE_TIMES 8 //按鍵防抖的掃描次數
static unsigned char Count; //用于累計按鍵狀態穩定的次數
static unsigned char keyStatus; //前次按鍵狀態
if(keyTmp != keyStatus) //當前按鍵狀態是否與前次按鍵狀態相同
{
keyStatus = keyTmp;
Count = 0;
return;
}
else
{
if (Count < 8)
{
Count++;
return;
}
}
只要在前面介紹的函數KeyScan()中獲取keyTmp值后增加這段代碼就可以了。它的原理:每次掃描中都將當前按鍵狀態keyTmp與前次按鍵狀態keyStatus進行比較,如果比較的兩次狀態不同,表示按鍵處于抖動中,會將用于累計按鍵狀態穩定次數的變量Count清零,只有當連續8次比較的狀態都相同時,才認為狀態穩定了,即沒有抖動了。這包括了按鍵按下時的抖動處理和按鍵釋放的抖動處理。其中Count設為8次,每5ms調用一次,這就是40ms,它的設定,與抖動時間長短無關,只要大于抖動周期就可以了。這種處理方法的優點在于:它與抖動過程的時間長短無關,而且處理代碼簡單,不用區分按下抖動或釋放抖動。
本文介紹的這種單片機按鍵狀態檢測和消抖處理方法,與一般的按鍵檢測方法相比,能檢測更多類型的的按鍵狀態,按鍵數量有增加或刪減時,也不用更改代碼,適用范圍廣,且代碼簡單,方便維護。采用的按鍵消抖方法也有很大的改進,與抖動過程的時間長短無關,不用區分按下抖動或釋放抖動。
[1]譚浩強 C程序設計 清華大學出版社
[2]劉天時,劉賞,付春 一種單片機鍵盤電路設計與消抖處理 計算機與網絡2012年 第10期
[3]李運兵 微控制器中按鍵處理技巧及應用 計算機應用系統 2010年第2期