按键扫描消抖经典算法实现以及Proteus实例仿真对比
- unsigned char Trg;
- unsigned char Cont;
- void KeyRead( void )
- {
- unsigned char ReadData = P1^0xff; // 注解1
- Trg = ReadData & (ReadData ^ Cont); // 注解2
- Cont = ReadData; // 注解3
- }
复制代码- Trg(triger) 代表的是触发,Cont(continue)代表的是连续按下。
- 注解1:读P1的端口数据,取反,然后送到ReadData 临时变量里面保存起来。
- 注解2:用来计算触发变量的。一个位与操作,一个异或操作,我想学过C语言都应该懂吧?Trg为全局变量,其它程序可以直接引用。
- 注解3:用来计算连续变量。
- 上述实现算法不仅适用于端口以总线方式来读取判断,也同样适用于独立IO口信号的判断和处理,具体实现函数如下:
- unsigned char Trg;
- unsigned char Cont;
- void KeyRead( void )
- {
- unsigned char ReadData = P10^0x01; //
- Trg = ReadData & (ReadData ^ Cont); //
- Cont = ReadData; /
- }
复制代码
- 1. 没有按键的时候
- 没有按下时,IO口为高电平,就是P10为0x01,ReadData读端口并且和0x01进行取反,很显然,P10^0x01的值就是 0x00。
- Trg = ReadData & (ReadData ^ Cont); (初始状态下,Cont也是为0的)很简单的数学计算,因为ReadData为0,则它和任何数“相与”,结果也是为0。
- Cont = ReadData; 保存Cont 其实就是等于ReadData为0。
2. 第一次IO口按键按下的情况:- 端口没有触发时,IO口状态为0x01,ReadData读端口并且取反,很显然,就是 0x01 。
- Trg = ReadData & (ReadData ^ Cont); 因为这是第一次按下,所以Cont是上次的值,应为为0。那么这个式子的值也不难算,也就是 Trg = 0x01 & (0x01^0x00) = 0x01。
- Cont = ReadData = 0x01;
- ReadData = 0x01;
- Trg = 0x01;//Trg只会在这个时候对应位的值为1,其它时候都为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>
复制代码
3. IO口按键按着不松(长按键)的情况:- 端口数据为0xfe,ReadData读端口并且取反是 0x01 。
- Trg = ReadData & (ReadData ^ Cont); 因为这是连续按下,所以Cont是上次的值,应为为0x01。那么这个式子就变成了 Trg = 0x01 & (0x01^0x01) = 0x00
Cont = ReadData = 0x01;- ReadData = 0x01;
- Trg = 0x00;
- Cont = 0x01;
复制代码 因为现在按键是长按着,所以MCU会每个一定时间(20ms左右)不断的执行这个函数,那么下次执行的时候情况会是怎么样的呢?
- ReadData = 0x01;这个不会变,因为按键没有松开.
- Trg = ReadData & (ReadData ^ Cont) = 0x01 & (0x01 ^ 0x01) = 0 ,只要按键没有松开,这个Trg值永远为 0.
- Cont = 0x01;只要按键没有松开,这个值永远是0x0.
4. 按键松开的情况:端口数据为0xff,ReadData读端口并且取反是 0x00 。
- Trg = ReadData & (ReadData ^ Cont) = 0x00 & (0x00^0x01) = 0x00;
- Cont = ReadData = 0x00;
- ReadData = 0x00;
- Trg = 0x00;
- Cont = 0x00;
复制代码 回到了初始状态,也就是没有按键按下的状态.
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};
- //定义数码管显示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]; //开始运行显示0
- while(1) {
- KeyRead();
- if(Trg==1) {
- P0=segment[count];
- count++;
- if(count>=10) { //超过0~9,数码管显示回到0
- count=0;
- }
- }
- }
- }
- //void main() {//这是没有经过消抖处理的代码
- // P3=0XFF;
- // P0=segment[0]; //开始运行显示0
- // while(1) {
- //
- // if(KeyValue==0) {
- // P0=segment[count];
- // count++;
- // if(count>=10) { //超过0~9,数码管显示回到0
- // count=0;
- // }
- // }
- // }
- //}
复制代码 - 这种算法摒弃了使用延时的常规做法。
- 仿真文件和程序建附件
全部资料51hei附件下载:
按键扫描消抖算法实现.zip
(61.47 KB, 下载次数: 33)
|