人機界面最重要的就是按鍵了,覺得按鍵做的最好的就是手機的按鍵了,有長按、敵探、連發(fā)等功能。還有組合等。一個好的按鍵程序用書本上學的按鍵檢測方法已經(jīng)不能適應工程的需要了,為此人們設計出一種狀態(tài)機檢測按鍵的方法。
在一個系統(tǒng)中按鍵是隨機的,因此系統(tǒng)軟件對按鍵要一直循環(huán)查詢,由于按鍵檢測過程需要進行消抖處理,因此取狀態(tài)機的時間序列為10ms,這樣不僅可以跳過按鍵抖動的影響,同時也小于0.3-0.5秒的穩(wěn)定閉合期,不會將按鍵的操作過程丟失。
程序?qū)崿F(xiàn)方法,用定時器定時10ms,每隔10ms檢測一次按鍵,將一個按鍵的檢測過程分為幾個不同的狀態(tài),最簡單的分為 初使狀態(tài)-按鍵閉合確認狀態(tài)-按鍵釋放狀態(tài),如果要求按鍵實現(xiàn)的功能越多,狀態(tài)也就越多 ,比如還有常用的長按狀態(tài)。以下是一個狀態(tài)機按鍵程序,僅供參考。
程序基于AVR單片機,
key.h文件的一部分
#define KEY0_PORT PORTD
#define KEY0_DDR DDRD
#define KEY0_PIN PIND
#define KEY0 PD0
#define KEY1_PORT PORTD
#define KEY1_DDR DDRD
#define KEY1_PIN PIND
#define KEY1 PD1
#define KEY2_PORT PORTD
#define KEY2_DDR DDRD
#define KEY2_PIN PIND
#define KEY2 PD2
#define KEY3_PORT PORTD
#define KEY3_DDR DDRD
#define KEY3_PIN PIND
#define KEY3 PD3
#define KEY0_STATUS (BIT_STATUS(KEY0_PIN,KEY0))
#define KEY1_STATUS (BIT_STATUS(KEY1_PIN,KEY1))
#define KEY2_STATUS (BIT_STATUS(KEY2_PIN,KEY2))
#define KEY3_STATUS (BIT_STATUS(KEY3_PIN,KEY3))
#define KEY_SERIES_FLAG 200 //按鍵連發(fā)開始所需時間長度
#define KEY_SERIES_DELAY 5 //按鍵連發(fā)的時間間隔長度
//按鍵屬性
#define KEY_DOWN 0xA0
#define KEY_LONG 0xB0
#define KEY_LIAN 0xC0
#define KEY_UP 0xD0
#define KEY_LONG 0xB0
#define KEY_LIAN 0xC0
#define KEY_UP 0xD0
#define NO_KEY 0x00
#define KEY0_DOWN 0X01
#define KEY1_DOWN 0X02
#define KEY2_DOWN 0X03
#define KEY3_DOWN 0X04
#define KEY0_PRESS (KEY_DOWN|KEY0_DOWN)
#define KEY1_PRESS (KEY_DOWN|KEY1_DOWN)
#define KEY2_PRESS (KEY_DOWN|KEY2_DOWN)
#define KEY3_PRESS (KEY_DOWN|KEY3_DOWN)
key.c文件一部分
static uchar Get_Key(void)
{
if (KEY0_STATUS==0) return KEY0_DOWN;
if (KEY1_STATUS==0) return KEY1_DOWN;
if (KEY2_STATUS==0) return KEY2_DOWN;
if (KEY3_STATUS==0) return KEY3_DOWN;
return NO_KEY;
}
uchar Key_Scan(void)
{
static uchar Key_State = 0; //按鍵狀態(tài)
static uchar Key_Prev = 0; //上一次按鍵
static uchar Key_Delay = 0; //按鍵連發(fā)時間
static uchar Key_Series = FALSE; //標志連發(fā)開始
uchar Key_Press = NO_KEY; //按鍵值
uchar Key_Return = NO_KEY; //按鍵返回值
Key_Press = Get_Key();
switch (Key_State)
{
case 0://按鍵初始態(tài)00
if (Key_Press !=NO_KEY)//有按鍵按下
{
Key_State = 1;//轉(zhuǎn)到按鍵確認
Key_Prev = Key_Press;//保存按鍵狀態(tài)
}
break;
case 1://按鍵確認態(tài)01
if ( Key_Press ==Key_Prev )//確認和上次按鍵相同
{
Key_State = 2;//判斷按鍵長按
//返回按鍵按下鍵值,按鍵按下就響應,如果想彈起來再響應
//可以在彈起來后再返回按鍵值
Key_Return = KEY_DOWN | Key_Prev;
}
else//按鍵抬起,是抖動,不響應按鍵
{
Key_State = 0;
}
break;
case 2://按鍵釋放態(tài)10
if (Key_Press == NO_KEY )//按鍵釋放了
{
Key_State = 0;
Key_Delay = 0;
Key_Series = FALSE;
Key_Return = KEY_UP | Key_Prev; //返回按鍵抬起值
break;
}
if ( Key_Press ==Key_Prev )
{
Key_Delay++;
if ((Key_Series==TRUE) && (Key_Delay>KEY_SERIES_DELAY))
{
Key_Delay = 0;
Key_Return = KEY_LIAN | Key_Press; //返回連發(fā)的值
Key_Prev = Key_Press; //記住上次的按鍵.
break;
}
if (Key_Delay>KEY_SERIES_FLAG)
{
Key_Series = TRUE;
Key_Delay = 0;
Key_Return = KEY_LONG | Key_Prev; //返回長按后的值
break;
}
}
default :
break;
}
return Key_Return;
}
每10ms調(diào)用一次按鍵檢測,根據(jù)Key_Return的值來判斷按鍵的操作,用狀態(tài)機省去傳統(tǒng)按鍵的延時去抖,也不在在按鍵的死等待,對程序時間的利用有很大的幫助,根據(jù)按鍵返回的狀態(tài)值,事件可以在按鍵按下響應,也可以在按鍵彈起來響應,也可以實現(xiàn)連發(fā)、長按等功能。