1.代碼及解析
我們先貼出代碼,下面再進(jìn)行解析原理
u8 KEY_Scan(u8 mode,u16 TIMES) { static u8 key_up=1; //按鍵松開(kāi)標(biāo)志 static u16 times; if(mode)key_up=1; //如果mode等于1,支持連按 if(key_up&&(KEY4==0||KEY8==0||KEY12==0||KEY16==0))//只要在key_up等于1時(shí),其中一個(gè)按鍵被按下就可以進(jìn)入執(zhí)行代碼 { times++; //記錄進(jìn)入低電平的時(shí)間 if(times>=TIMES)//抖動(dòng)的時(shí)間已經(jīng)過(guò)去 { times=0; key_up=0; if(KEY4==0)return 4; else if(KEY8==0)return 8; else if(KEY12==0)return 12; else if(KEY16==0)return 16; } } else if(KEY4==1&&KEY8==1&&KEY12==1&&KEY16==1)key_up=1; return 0;// 無(wú)按鍵按下 }
1.假設(shè)我們傳入的參數(shù)mode為0,進(jìn)入函數(shù),第一次初始化時(shí)key_up為1,然后沒(méi)有去執(zhí)行“if(mode)key_up=1;”,此時(shí)若沒(méi)有按鍵按下,則滿足
“else if(KEY4==1&&KEY8==1&&KEY12==1&&KEY16==1)key_up=1;”,所以key_up還是等于1,返回值為0。
2.假設(shè)有按鍵按下,持續(xù)夠一定的低電平時(shí)間了(抖動(dòng)時(shí)間過(guò)去了),清零times,讓key_up等于0,然后判斷此時(shí)是哪個(gè)按鍵按下就返回對(duì)應(yīng)的值。
3.返回對(duì)應(yīng)的值之后,如果我們一直按著不放,第二次執(zhí)行這個(gè)函數(shù)就會(huì)因?yàn)閗ey_up在前一次函數(shù)執(zhí)行中已經(jīng)等于0,所以我們就算按著按鍵不放也進(jìn)入不了
“if(key_up&&(KEY4==0||KEY8==0||KEY12==0||KEY16==0))”,那么一次按鍵動(dòng)作只能有一次返回值為4、8、12或16的機(jī)會(huì),其他時(shí)候都是返回0。如果我們按鍵松手了,那就滿足
“else if(KEY4==1&&KEY8==1&&KEY12==1&&KEY16==1)key_up=1;”,這樣key_up恢復(fù)為1了,下次按鍵動(dòng)作又能夠進(jìn)入
“if(key_up&&(KEY4==0||KEY8==0||KEY12==0||KEY16==0))”從而可以返回對(duì)應(yīng)的按鍵值。不支持連按模式就講解完了。
4.參數(shù)mode為1時(shí),總會(huì)執(zhí)行“if(mode)key_up=1;”,所以按鍵按著不放函數(shù)的執(zhí)行都會(huì)進(jìn)入
“if(key_up&&(KEY4==0||KEY8==0||KEY12==0||KEY16==0))”,這樣返回的按鍵值的機(jī)會(huì)比不支持連按時(shí)候還要多,
這就是mode等于1時(shí)呈現(xiàn)的支持連按功能。
原理解析就講解完了,可以看到,該代碼在不支持連按模式下是按下之后就執(zhí)行返回值了的,而不是像以前一樣要抬起按鍵之后才會(huì)執(zhí)行返回值的語(yǔ)句,所以不管我們的按鍵手速是快是慢,程序都會(huì)在最快時(shí)間內(nèi)去執(zhí)行返回值的語(yǔ)句。
2.補(bǔ)充
我們不再使用“#define TIMES 1000”,因?yàn)橛袝r(shí)“KEY_Scan()”在各種不同的循環(huán)體里掃描返回值,有些循環(huán)一次執(zhí)行時(shí)間很快,有些卻很慢,我們?cè)诘谖逭乱呀?jīng)分析過(guò)這些情況了,所以TIMES的值需要隨機(jī)應(yīng)變。我們決定讓TIMES作為按鍵程序的第二個(gè)參數(shù),這樣在某些循環(huán)體里如果循環(huán)一次的時(shí)間很快,我們調(diào)為“KEY_Scan(0,1000);”,循環(huán)一次的時(shí)間很慢就改為“KEY_Scan(0,300);”
3.測(cè)試代碼
#include <reg52.h> #include <function.h> sbit KEY4 = P2^3; sbit KEY8 = P2^2; sbit KEY12 = P2^1; sbit KEY16 = P2^0; u8 KEY_Scan(u8 mode,u16 TIMES) { static u8 key_up=1; //按鍵松開(kāi)標(biāo)志 static u16 times; if(mode)key_up=1; //如果mode等于1,支持連按 if(key_up&&(KEY4==0||KEY8==0||KEY12==0||KEY16==0))//只要在key_up等于1時(shí),其中一個(gè)按鍵被按下就可以進(jìn)入執(zhí)行代碼 { times++; //記錄進(jìn)入低電平的時(shí)間 if(times>=TIMES)//抖動(dòng)的時(shí)間已經(jīng)過(guò)去 { times=0; key_up=0; if(KEY4==0)return 4; else if(KEY8==0)return 8; else if(KEY12==0)return 12; else if(KEY16==0)return 16; } } else if(KEY4==1&&KEY8==1&&KEY12==1&&KEY16==1)key_up=1; return 0;// 無(wú)按鍵按下 } void KEY_Init() { P2=0X7F;//讓P2.7輸出低電平,其他輸出高電平,這樣就可以使能4個(gè)按鍵了 } void main() { u8 key; //用來(lái)讀取按鍵動(dòng)作的返回值 LED_Init();//初始化LED硬件模塊 KEY_Init();//初始化按鍵模塊 P0=0xFE; //先點(diǎn)亮LED2 while(1) { key=KEY_Scan(0,1000); //不支持連按模式,判斷閾值為1000 if(key==4)LED2=!LED2; //執(zhí)行功能代碼 if(key==8)LED4=!LED4; //執(zhí)行功能代碼 if(key==12)LED6=!LED6;//執(zhí)行功能代碼 if(key==16)LED8=!LED8;//執(zhí)行功能代碼 } }
把“KEY_Scan(0,1000);”改為“KEY_Scan(1,1000);”就是支持連按了。
C語(yǔ)言網(wǎng)提供由在職研發(fā)工程師或ACM藍(lán)橋杯競(jìng)賽優(yōu)秀選手錄制的視頻教程,并配有習(xí)題和答疑,點(diǎn)擊了解:
一點(diǎn)編程也不會(huì)寫(xiě)的:零基礎(chǔ)C語(yǔ)言學(xué)練課程
解決困擾你多年的C語(yǔ)言疑難雜癥特性的C語(yǔ)言進(jìn)階課程
從零到寫(xiě)出一個(gè)爬蟲(chóng)的Python編程課程
只會(huì)語(yǔ)法寫(xiě)不出代碼?手把手帶你寫(xiě)100個(gè)編程真題的編程百練課程
信息學(xué)奧賽或C++選手的 必學(xué)C++課程
藍(lán)橋杯ACM、信息學(xué)奧賽的必學(xué)課程:算法競(jìng)賽課入門(mén)課程
手把手講解近五年真題的藍(lán)橋杯輔導(dǎo)課程