1.代码及解析
我们先贴出代码,下面再进行解析原理
u8 KEY_Scan(u8 mode,u16 TIMES) { static u8 key_up=1; //按键松开标志 static u16 times; if(mode)key_up=1; //如果mode等于1,支持连按 if(key_up&&(KEY4==0||KEY8==0||KEY12==0||KEY16==0))//只要在key_up等于1时,其中一个按键被按下就可以进入执行代码 { times++; //记录进入低电平的时间 if(times>=TIMES)//抖动的时间已经过去 { 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;// 无按键按下 }
1.假设我们传入的参数mode为0,进入函数,第一次初始化时key_up为1,然后没有去执行“if(mode)key_up=1;”,此时若没有按键按下,则满足
“else if(KEY4==1&&KEY8==1&&KEY12==1&&KEY16==1)key_up=1;”,所以key_up还是等于1,返回值为0。
2.假设有按键按下,持续够一定的低电平时间了(抖动时间过去了),清零times,让key_up等于0,然后判断此时是哪个按键按下就返回对应的值。
3.返回对应的值之后,如果我们一直按着不放,第二次执行这个函数就会因为key_up在前一次函数执行中已经等于0,所以我们就算按着按键不放也进入不了
“if(key_up&&(KEY4==0||KEY8==0||KEY12==0||KEY16==0))”,那么一次按键动作只能有一次返回值为4、8、12或16的机会,其他时候都是返回0。如果我们按键松手了,那就满足
“else if(KEY4==1&&KEY8==1&&KEY12==1&&KEY16==1)key_up=1;”,这样key_up恢复为1了,下次按键动作又能够进入
“if(key_up&&(KEY4==0||KEY8==0||KEY12==0||KEY16==0))”从而可以返回对应的按键值。不支持连按模式就讲解完了。
4.参数mode为1时,总会执行“if(mode)key_up=1;”,所以按键按着不放函数的执行都会进入
“if(key_up&&(KEY4==0||KEY8==0||KEY12==0||KEY16==0))”,这样返回的按键值的机会比不支持连按时候还要多,
这就是mode等于1时呈现的支持连按功能。
原理解析就讲解完了,可以看到,该代码在不支持连按模式下是按下之后就执行返回值了的,而不是像以前一样要抬起按键之后才会执行返回值的语句,所以不管我们的按键手速是快是慢,程序都会在最快时间内去执行返回值的语句。
2.补充
我们不再使用“#define TIMES 1000”,因为有时“KEY_Scan()”在各种不同的循环体里扫描返回值,有些循环一次执行时间很快,有些却很慢,我们在第五章已经分析过这些情况了,所以TIMES的值需要随机应变。我们决定让TIMES作为按键程序的第二个参数,这样在某些循环体里如果循环一次的时间很快,我们调为“KEY_Scan(0,1000);”,循环一次的时间很慢就改为“KEY_Scan(0,300);”
3.测试代码
#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; //按键松开标志 static u16 times; if(mode)key_up=1; //如果mode等于1,支持连按 if(key_up&&(KEY4==0||KEY8==0||KEY12==0||KEY16==0))//只要在key_up等于1时,其中一个按键被按下就可以进入执行代码 { times++; //记录进入低电平的时间 if(times>=TIMES)//抖动的时间已经过去 { 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;// 无按键按下 } void KEY_Init() { P2=0X7F;//让P2.7输出低电平,其他输出高电平,这样就可以使能4个按键了 } void main() { u8 key; //用来读取按键动作的返回值 LED_Init();//初始化LED硬件模块 KEY_Init();//初始化按键模块 P0=0xFE; //先点亮LED2 while(1) { key=KEY_Scan(0,1000); //不支持连按模式,判断阈值为1000 if(key==4)LED2=!LED2; //执行功能代码 if(key==8)LED4=!LED4; //执行功能代码 if(key==12)LED6=!LED6;//执行功能代码 if(key==16)LED8=!LED8;//执行功能代码 } }
把“KEY_Scan(0,1000);”改为“KEY_Scan(1,1000);”就是支持连按了。
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程