|
之前的電子鐘程序中,用的按鍵消抖處理方法是10ms的延時,這種方法效率比較低
所以現在利用狀態(tài)機原理重寫一下,效率很高啊
4個獨立按鍵中用到3個,
keys5用于切換對時分秒等狀態(tài),keys2是減小數值,keys3是增加數值
同時可以判斷按鍵的"短按,長按,連發(fā)"等功能
小于2秒視為短按,
大于2秒視為長按,
在長按狀態(tài)下每0.2秒自動連發(fā)一次, 這樣對時的時候就不用按N次了
程序分很多個文件 ,Keil uVision4 打包
- #include "keyScan.h"
- #include <reg52.h>
- /*按鍵初始化,若io沒有復用的話可以省略此步驟
- void KeyInit(void)
- {
- keyS2 = 1 ;
- keyS3 = 1 ;
- keyS4 = 1 ;
- keyS5 = 1 ;
- //即P3|=0xf0;
- }*/
- static u8 getKey(void) //獲取P3口值
- {
- if(key_down == keyS2)
- {
- return KEYS2_VALUE ;
- }
- if(key_down == keyS3 )
- {
- return KEYS3_VALUE ;
- }
- if(key_down == keyS4 )
- {
- return KEYS4_VALUE ;
- }
-
- if(key_down == keyS5 )
- {
- return KEYS5_VALUE ;
- }
- return key_up ; //0xf0 沒有任何按鍵
- }
- //函數每10ms被調用一次,而我們彈性按鍵過程時一般都20ms以上
- //所以每次按鍵至少調用本函數2次
- u8 read_key(u8* pKeyValue)
- {
- static u8 s_u8keyState=0; //未按,普通短按,長按,連發(fā)等狀態(tài)
- static u16 s_u16keyTimeCounts=0; //在計時狀態(tài)的計數器
- static u8 s_u8LastKey = key_up ; //保存按鍵釋放時的P3口數據
- u8 keyTemp=0; //鍵對應io口的電平
- s8 key_return=0; //函數返回值
- keyTemp=key_up & getKey(); //提取所有的key對應的io口
- switch(s_u8keyState) //這里檢測到的是先前的狀態(tài)
- {
- case state_keyUp: //如果先前是初始態(tài),即無動作
- {
- if(key_up!=keyTemp) //如果鍵被按下
- {
- s_u8keyState=state_keyDown; //更新鍵的狀態(tài),普通被按下
- }
- }
- break;
-
- case state_keyDown: //如果先前是被按著的
- {
- if(key_up!=keyTemp) //如果現在還被按著
- {
- s_u8keyState=state_keyTime; //轉換到計時態(tài)
- s_u16keyTimeCounts=0;
- s_u8LastKey = keyTemp; //保存鍵值
- }
- else
- {
- s_u8keyState=state_keyUp; //鍵沒被按著,回初始態(tài),說明是干擾
- }
- }
- break;
-
- case state_keyTime: //如果先前已經轉換到計時態(tài)(值為3)
- { //如果真的是手動按鍵,必然進入本代碼塊,并且會多次進入
- if(key_up==keyTemp) //如果未按鍵
- {
- s_u8keyState=state_keyUp;
- key_return=return_keyPressed; //返回1,一次完整的普通按鍵
- //程序進入這個語句塊,說明已經有2次以上10ms的中斷,等于已經消抖
- //那么此時檢測到按鍵被釋放,說明是一次普通短按
- }
- else //在計時態(tài),檢測到鍵還被按著
- {
- if(++s_u16keyTimeCounts>key_longTimes) //時間達到2秒
- {
- s_u8keyState=state_keyLong; //進入長按狀態(tài)
- s_u16keyTimeCounts=0; //計數器清空,便于進入連發(fā)重新計數
- key_return=return_keyLong; //返回state_keyLong
- }
- //代碼中,在2秒內如果我們一直按著key的話,返回值只會是0,不會識別為短按或長按的
- }
- }
- break;
-
- case state_keyLong: //在長按狀態(tài)檢測連發(fā) ,每0.2秒發(fā)一次
- {
- if(key_up==keyTemp)
- {
- s_u8keyState=state_keyUp;
- }
- else //按鍵時間超過2秒時
- {
- if(++s_u16keyTimeCounts>key_autoTimes)//10*20=200ms
- {
- s_u16keyTimeCounts=0;
- key_return=return_keyAuto; //每0.2秒返回值的第2位置位(1<<2)
- }//連發(fā)的時候,肯定也伴隨著長按
- }
- key_return |= return_keyLong; //0x02是肯定的,0x04|0x02是可能的
- }
- break;
-
- default:
- break;
- }
- *pKeyValue = s_u8LastKey ; //返回鍵值
- return key_return;
- }
復制代碼
|
|