1.代码及解析
我们先贴出代码,下面再进行解析原理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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.测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | #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、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程