1.代码及解析
我们先贴出代码,下面再进行解析原理
u8 KEY_Scan(u8 mode,u16 TIMES)
{
static u8 key_up=1;
static u16 times;
if (mode)key_up=1;
if (key_up&&(KEY4==0||KEY8==0||KEY12==0||KEY16==0))
{
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;
if (key_up&&(KEY4==0||KEY8==0||KEY12==0||KEY16==0))
{
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;
}
void main()
{
u8 key;
LED_Init();
KEY_Init();
P0=0xFE;
while (1)
{
key=KEY_Scan(0,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);”就是支持连按了。
|