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