按鍵掃描消抖經(jīng)典算法實(shí)現(xiàn)以及Proteus實(shí)例仿真對(duì)比
- unsigned char Trg;
- unsigned char Cont;
- void KeyRead( void )
- {
- unsigned char ReadData = P1^0xff; // 注解1
- Trg = ReadData & (ReadData ^ Cont); // 注解2
- Cont = ReadData; // 注解3
- }
復(fù)制代碼- Trg(triger) 代表的是觸發(fā),Cont(continue)代表的是連續(xù)按下。
- 注解1:讀P1的端口數(shù)據(jù),取反,然后送到ReadData 臨時(shí)變量里面保存起來。
- 注解2:用來計(jì)算觸發(fā)變量的。一個(gè)位與操作,一個(gè)異或操作,我想學(xué)過C語言都應(yīng)該懂吧?Trg為全局變量,其它程序可以直接引用。
- 注解3:用來計(jì)算連續(xù)變量。
- 上述實(shí)現(xiàn)算法不僅適用于端口以總線方式來讀取判斷,也同樣適用于獨(dú)立IO口信號(hào)的判斷和處理,具體實(shí)現(xiàn)函數(shù)如下:
- unsigned char Trg;
- unsigned char Cont;
- void KeyRead( void )
- {
- unsigned char ReadData = P10^0x01; //
- Trg = ReadData & (ReadData ^ Cont); //
- Cont = ReadData; /
- }
復(fù)制代碼
- 1. 沒有按鍵的時(shí)候
- 沒有按下時(shí),IO口為高電平,就是P10為0x01,ReadData讀端口并且和0x01進(jìn)行取反,很顯然,P10^0x01的值就是 0x00。
- Trg = ReadData & (ReadData ^ Cont); (初始狀態(tài)下,Cont也是為0的)很簡(jiǎn)單的數(shù)學(xué)計(jì)算,因?yàn)镽eadData為0,則它和任何數(shù)“相與”,結(jié)果也是為0。
- Cont = ReadData; 保存Cont 其實(shí)就是等于ReadData為0。
2. 第一次IO口按鍵按下的情況:- 端口沒有觸發(fā)時(shí),IO口狀態(tài)為0x01,ReadData讀端口并且取反,很顯然,就是 0x01 。
- Trg = ReadData & (ReadData ^ Cont); 因?yàn)檫@是第一次按下,所以Cont是上次的值,應(yīng)為為0。那么這個(gè)式子的值也不難算,也就是 Trg = 0x01 & (0x01^0x00) = 0x01。
- Cont = ReadData = 0x01;
- ReadData = 0x01;
- Trg = 0x01;//Trg只會(huì)在這個(gè)時(shí)候?qū)?yīng)位的值為1,其它時(shí)候都為0
- Cont = 0x01;<span style="background-color: rgb(255, 255, 255); color: rgb(79, 79, 79); font-family: "PingFang SC", "Microsoft YaHei", SimHei, Arial, SimSun; font-weight: normal;"></span>
復(fù)制代碼
3. IO口按鍵按著不松(長(zhǎng)按鍵)的情況:- 端口數(shù)據(jù)為0xfe,ReadData讀端口并且取反是 0x01 。
- Trg = ReadData & (ReadData ^ Cont); 因?yàn)檫@是連續(xù)按下,所以Cont是上次的值,應(yīng)為為0x01。那么這個(gè)式子就變成了 Trg = 0x01 & (0x01^0x01) = 0x00
Cont = ReadData = 0x01;- ReadData = 0x01;
- Trg = 0x00;
- Cont = 0x01;
復(fù)制代碼 因?yàn)楝F(xiàn)在按鍵是長(zhǎng)按著,所以MCU會(huì)每個(gè)一定時(shí)間(20ms左右)不斷的執(zhí)行這個(gè)函數(shù),那么下次執(zhí)行的時(shí)候情況會(huì)是怎么樣的呢?
- ReadData = 0x01;這個(gè)不會(huì)變,因?yàn)榘存I沒有松開.
- Trg = ReadData & (ReadData ^ Cont) = 0x01 & (0x01 ^ 0x01) = 0 ,只要按鍵沒有松開,這個(gè)Trg值永遠(yuǎn)為 0.
- Cont = 0x01;只要按鍵沒有松開,這個(gè)值永遠(yuǎn)是0x0.
4. 按鍵松開的情況:端口數(shù)據(jù)為0xff,ReadData讀端口并且取反是 0x00 。
- Trg = ReadData & (ReadData ^ Cont) = 0x00 & (0x00^0x01) = 0x00;
- Cont = ReadData = 0x00;
- ReadData = 0x00;
- Trg = 0x00;
- Cont = 0x00;
復(fù)制代碼 回到了初始狀態(tài),也就是沒有按鍵按下的狀態(tài).
Proteus仿真
- 代碼:
- #include <REGX52.H>
- #include <intrins.h>
- sbit KeyValue=P3^7;
- unsigned char code segment[]= {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
- //定義數(shù)碼管顯示0~9
- unsigned char Trg;
- unsigned char Cont;
- static char count=1;
- void KeyRead( void )
- {
- unsigned char ReadData = KeyValue^0x01; // 注解1
- Trg = ReadData & (ReadData ^ Cont); // 注解2
- Cont = ReadData; // 注解3
-
- }
- void main() {
- P3=0XFF;
- P0=segment[0]; //開始運(yùn)行顯示0
- while(1) {
- KeyRead();
- if(Trg==1) {
- P0=segment[count];
- count++;
- if(count>=10) { //超過0~9,數(shù)碼管顯示回到0
- count=0;
- }
- }
- }
- }
- //void main() {//這是沒有經(jīng)過消抖處理的代碼
- // P3=0XFF;
- // P0=segment[0]; //開始運(yùn)行顯示0
- // while(1) {
- //
- // if(KeyValue==0) {
- // P0=segment[count];
- // count++;
- // if(count>=10) { //超過0~9,數(shù)碼管顯示回到0
- // count=0;
- // }
- // }
- // }
- //}
復(fù)制代碼 - 這種算法摒棄了使用延時(shí)的常規(guī)做法。
- 仿真文件和程序建附件
全部資料51hei附件下載:
按鍵掃描消抖算法實(shí)現(xiàn).zip
(61.47 KB, 下載次數(shù): 33)
2021-9-10 13:49 上傳
點(diǎn)擊文件名下載附件
按鍵掃描消抖算法
|