1.還需消抖
可以看到我們?cè)诘?講和第7講的按鍵不支持連按代碼中,死循環(huán)都有“delay_ms(2);”,因?yàn)榇蠖鄶?shù)時(shí)候主循環(huán)都要做很多事,所以我們認(rèn)為這2ms的延時(shí)是很多復(fù)雜程序要執(zhí)行所消耗的時(shí)間,而正是因?yàn)檫@個(gè)延時(shí)函數(shù)的存在把按鍵的物理抖動(dòng)給濾掉了,誤導(dǎo)了我們以為這樣的不支持連按代碼是合格的。如果我們還是用這種寫法去實(shí)現(xiàn)不支持連按功能,那么請(qǐng)把下面的代碼下載進(jìn)開發(fā)板通過快按和慢按K4,觀察數(shù)碼管的顯示。
2.缺陷代碼
#include <reg52.h> sbit ADDR2 = P1^2; sbit ADDR1 = P1^1; sbit ADDR0 = P1^0; sbit ENLED = P1^4; sbit ADDR3 = P1^3; sbit LED2 = P0^0; sbit KEY4 = P2^7; unsigned char code LedChar[16]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E};//數(shù)碼管狀態(tài)值初始化 unsigned char LedBuff[6]={0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; unsigned char cnt=0;//可以在SEG_task()和main()中使用的全局變量 void SEG_task()//數(shù)碼管顯示函數(shù) { static unsigned char i=0; LedBuff[0]= LedChar[cnt%10]; if(cnt>=10) LedBuff[1]= LedChar[(cnt/10)%10]; //cnt沒到達(dá)10之前不更新LedBuff[1]的初始值 if(cnt>=100)LedBuff[2]= LedChar[(cnt/100)%10];//cnt沒到達(dá)100之前不更新LedBuff[2]的初始值 if(cnt==0){ LedBuff[1]=0xFF;LedBuff[2]=0XFF; }//cnt到達(dá)255之后再加1就溢出變?yōu)?了,這時(shí)候要再次熄滅這兩個(gè)數(shù)碼管 P0=0xFF; switch(i) { case 0: ADDR2 = 0;ADDR1 = 0;ADDR0 = 0;P0=LedBuff[0];i++;break; case 1: ADDR2 = 0;ADDR1 = 0;ADDR0 = 1;P0=LedBuff[1];i++;break; case 2: ADDR2 = 0;ADDR1 = 1;ADDR0 = 0;P0=LedBuff[2];i=0;break; } } void main() { unsigned char key_up=1;//定義記錄按鍵狀態(tài)值的變量,初始值為1避免程序一開始就進(jìn)入了“if(key_up==0)” unsigned int times=0; //用來記錄進(jìn)入過按鍵判斷語句的次數(shù) ADDR3 = 1;//使能三八譯碼器 ENLED = 0;// ADDR2 = 1;//************************** ADDR1 = 1;//讓三八譯碼器的IO6輸出低電平 ADDR0 = 0;//************************** P2 = 0xF7;//讓K4能具備有被拉低的條件先 while(1) { SEG_task();//數(shù)碼管顯示任務(wù) //按鍵功能部分 if(key_up==0) { if(KEY4==1)//按鍵已彈起 { cnt++; //執(zhí)行功能代碼 } } key_up=KEY4; //如果不松手,key_up就會(huì)等于0 } }
我們多按幾次,會(huì)發(fā)現(xiàn)有時(shí)抬起之后cnt就被加2了,也就是在一次按鍵的動(dòng)作里“cnt++;”被執(zhí)行了兩次,這是因?yàn)椤癝EG_task();”的執(zhí)行時(shí)間太短沒有濾掉按鍵的抖動(dòng),大家再次對(duì)照下圖自己分析
3.改善
有了“支持連按”的代碼思路,實(shí)現(xiàn)消抖還是很容易的,我們同樣用上times記錄按鍵IO端口進(jìn)入低電平的時(shí)間,只要times大于500證明抖動(dòng)的時(shí)間已經(jīng)過去,此時(shí)再判斷按鍵是否抬起就可以決定該不該執(zhí)行功能代碼了。
把按鍵功能代碼部分改為如下代碼即可完善出最終的不支持連按模式的代碼
//按鍵功能部分 if(key_up==0) { times++; if(times>=500&&KEY4==1)//低電平持續(xù)夠一定的時(shí)間了,證明抖動(dòng)時(shí)間已經(jīng)過去了,如果現(xiàn)在按鍵已經(jīng)抬起就執(zhí)行功能代碼 { times=0; cnt++;//執(zhí)行功能代碼 } } key_up=KEY4; //如果不松手,key_up就會(huì)等于0
筆者用串口測(cè)試過按下抬起的動(dòng)作無論多快,這個(gè)times一般都在500以上(串口后面再學(xué)),如果我們一直按著不放,times就會(huì)一直累加,如果累加到溢出之后,times又從0開始累加,當(dāng)times小于500的時(shí)候剛好松手,這樣是無法執(zhí)行功能代碼的,
因?yàn)椴粷M足“times>=500”的判斷,所以只要大家不刻意去做這樣長按不放的動(dòng)作,這種情況很少發(fā)生,就算發(fā)生,概率也只有500/65536=0.0076,我們的代碼還算是很實(shí)用的。
C語言網(wǎng)提供由在職研發(fā)工程師或ACM藍(lán)橋杯競賽優(yōu)秀選手錄制的視頻教程,并配有習(xí)題和答疑,點(diǎn)擊了解:
一點(diǎn)編程也不會(huì)寫的:零基礎(chǔ)C語言學(xué)練課程
解決困擾你多年的C語言疑難雜癥特性的C語言進(jìn)階課程
從零到寫出一個(gè)爬蟲的Python編程課程
只會(huì)語法寫不出代碼?手把手帶你寫100個(gè)編程真題的編程百練課程
信息學(xué)奧賽或C++選手的 必學(xué)C++課程
藍(lán)橋杯ACM、信息學(xué)奧賽的必學(xué)課程:算法競賽課入門課程
手把手講解近五年真題的藍(lán)橋杯輔導(dǎo)課程