通常普通的按鍵掃描程序,網上一大堆,基於掃描延時防抖等簡單的操作,這裏要講的的遇到複雜的按鍵處理程序,
普通按鍵掃描:基於 一個按鍵的短按長按釋放
複雜的按鍵掃描:有組合按鍵,且按鍵也有長短按,以及釋放
現在如何實現一個按鍵掃描模塊去處理這種按鍵掃描程序呢?這裏用到按鍵狀態機爲基礎框架。對按鍵編碼能較好的實現複雜按鍵處理。
一、對按鍵進行編碼具體實現參考如下
//代表按鍵按下的電平 用來切換不同的電路 一般都如下
#define PRESS 0X00 //低電平表示按下
#define RELEASE 0X01 //搞電平表示未按下
//這裏有六個按鍵,借用六位
#define USER_KEY_ALL_MSK 0x003F
#define USER_KEY1_PORT P1
#define USER_KEY1_PIN BIT0
#define USER_KEY1 P10
#define USER_KEY1_MSK 0x0001
#define USER_KEY1_POS 0
#define USER_KEY2_PORT P1
#define USER_KEY2_PIN BIT1
#define USER_KEY2 P11
#define USER_KEY2_MSK 0x0002
#define USER_KEY2_POS 1
#define USER_KEY3_PORT P1
#define USER_KEY3_PIN BIT2
#define USER_KEY3 P12
#define USER_KEY3_MSK 0x0004
#define USER_KEY3_POS 2
#define USER_KEY4_PORT P1
#define USER_KEY4_PIN BIT3
#define USER_KEY4 P13
#define USER_KEY4_MSK 0x0008
#define USER_KEY4_POS 3
#define USER_KEY5_PORT P1
#define USER_KEY5_PIN BIT4
#define USER_KEY5 P14
#define USER_KEY5_MSK 0x0010
#define USER_KEY5_POS 4
#define USER_KEY6_PORT P4
#define USER_KEY6_PIN BIT2
#define USER_KEY6 P42
#define USER_KEY6_MSK 0x0020
#define USER_KEY6_POS 5
//狀態機,一個簡單的狀態,你可以設計更復雜,短按釋放,長按釋放,長按不釋放、、等各個狀態
typedef enum
{
KEY_NULL = 0,
KEY_PRESS,
KEY_LONG_PRESS,
KEY_RELEASE,
}Type_Key_Status;
二、定義實現上部分就可以對按鍵檢測編碼了,按鍵檢測,得到按鍵鍵值編碼。
由於沒有找到合適的辦法循環處理,讓代碼更簡潔,所以只能每一個按鍵都檢測一次。
uint16_t read_key(void)
{
uint16_t key_value =0;
if(USER_KEY1 == PRESS)
{
key_value |=(0x01<<USER_KEY1_POS);
}
else
{
key_value |=(0x00<<USER_KEY1_POS);
}
if(PRESS == USER_KEY2 )
{
key_value |=(0x01<<USER_KEY2_POS);
}
else
{
key_value |=(0x00<<USER_KEY2_POS);
}
if(PRESS ==USER_KEY3)
{
key_value |=(0x01<<USER_KEY3_POS);
}
else
{
key_value |=(0x00<<USER_KEY3_POS);
}
if(USER_KEY4 == PRESS)
{
key_value |=(0x01<<USER_KEY4_POS);
}
else
{
key_value |=(0x00<<USER_KEY4_POS);
}
if(USER_KEY5 == PRESS)
{
key_value |=(0x01<<USER_KEY5_POS);
}
else
{
key_value |=(0x00<<USER_KEY5_POS);
}
if(PRESS == USER_KEY6)
{
key_value |=(0x01<<USER_KEY6_POS);
}
else
{
key_value |=(0x00<<USER_KEY6_POS);
}
return key_value;
}
三、最後也是最重要的一步就是按鍵狀態掃描的實現。
// 定義一個全局的按鍵狀態
Type_Key_Status key_status = KEY_NULL;
void key_scan(void)
{
uint16_t old_key_value = 0,new_key_value =0;
switch(key_status)
{
case KEY_NULL:
old_key_value = read_key();
if(old_key_value == 0) //沒按鍵按下
{
return;
}
delay_ms(50);
new_key_value = read_key();
if(old_key_value == new_key_value)
{
old_key_value = new_key_value; //有鍵按下,狀態跳轉
key_short_press_callback(new_key_value) //回調按下處理函數
key_status = KEY_PRESS;
}else
{
key_status = KEY_NULL;
}
break;
case KEY_PRESS:
delay_ms(50);
new_key_value = read_key();
if(old_key_value == new_key_value)
{
old_key_value = new_key_value;
key_long_press_callback(new_key_value); //回調長按下處理
key_status = KEY_LONG_PRESS;
}else
{
key_short_release_callback(new_key_value); //回調短按釋放處理
key_status = KEY_RELEASE;
}
break;
case KEY_LONG_PRESS:
delay_ms(50);
new_key_value = read_key();
if(old_key_value == new_key_value)
{
old_key_value = new_key_value;
key_long_long_press_callback(new_key_value); //回調超長按下處理
key_status = KEY_RELEASE; //更具自定義功能狀態去跳轉
}else
{
key_long_release_callback(new_key_value); //回調長按釋放處理
key_status = KEY_RELEASE;
}
break;
case KEY_RELEASE:
release_key_handle();
key_status = KEY_NULL; //釋放回到正常檢測狀態
break;
}
};
四、最後就是在各個按鍵狀態的基礎上實現處理函數,這裏就可以對編碼的那就值進行解析,分別處理,對於按鍵釋放有組合也很好處理。
void key_short_press_handle(uint16_t key_value)
{
switch(key_value & USER_KEY_ALL_MSK)
{
//沒有組合鍵
case USER_KEY1_MSK:
break;
case USER_KEY2_MSK:
break;
case USER_KEY3_MSK:
break;
case USER_KEY4_MSK:
break;
case USER_KEY5_MSK:
break;
case USER_KEY6_MSK:
break;
//組合按鍵
case USER_KEY1_MSK|USER_KEY2_MSK : break;
...
}
}