目录
(1)源代码(摘自战舰程序)
#include <REG51.H>
#define key_up 1
#define key_right 2
#define key_left 3
#define key_down 4
#define U8 unsigned char
sbit key0=P1^0;
sbit key1=P1^1 ;
sbit key2=P1^2 ;
sbit key3=P1^3 ;
bit key_state;
sbit LED0=P2^1;
sbit LED1=P2^2;
void delay(unsigned char z) //延时0.n ms
{
U8 a,b;
for(a=0;a<z;a++)
for(b=0;b<110;b++);
}
U8 key_scan(U8 mode) //mode==1 连续按键 mode==0 不支持连续按键
{
static key_state =1;
if(mode) key_state=1;
if(key_state&&(key0==0||key1==0||key2==0||key3==0))
{
delay(100);
key_state=0;
if(key0==0) return key_up;
else if (key1==0) return key_right;
else if (key2==0) return key_left;
else if (key3==0) return key_down;
}else if(key0==1&&key1==1&&key2==1&&key3==1) key_state=1;
return 0;
}
void main (void )
{
U8 key_return;
while(1)
{
key_return=key_scan(0);
if(key_return)
{
switch(key_return)
{
case key_up: LED0=!LED0; break;
case key_left: LED0=!LED0; break;
case key_down: LED1=!LED1; break;
case key_right: LED1=!LED1; break;
}
}else delay(100);
}
}
(2)代码解释
上面是按键扫描程序,通过mode 来修改按键是否可以长按
static key_state =1;
1,短按下KEY0时,每按一次,数字加1
2,当按下KEY0不放时,数字每隔10ms加1
static key_state 这句话是程序初始化的时候,只执行一次赋值,在每次执行该key_scan()时候,key_state 类似于全局变量能够保存上次的值,这样(和全局变量的区别)限定了key_state 使用只能在该函数内使用。
有按键按下的时候key_state是0,当函数再次进入按键扫描函数的时候(此时按键还是按下的),key_state的值为零。key_state&&(key0==0||key1==0||key2==0||key3==0 这条语句进去不去, key0==1&&key1==1&&key2==1&&key3==1 这个判断也进不去, 所以他会返回一个return 0 。表示没有按键按下。
这样就表示了按键只有按下一次,就是只有一个返回值返回。这样比起原先用的while(key==0){;} 这种语句相比,在动态扫描的时候不会让扫描出现错误。
当mode为一的时候每次进入扫描函数都会给key_state进行赋值为一,这样就像当于在一直按下某个键的时候,每隔delay(100) 的时候,按键执行一次,比如这个按键是加一的话,这样长按就是delay(100)个时间的加一,实现了这个功能。
(3)改进代码
在实际中,delay(100),会使得CPU停止在这个状态10ms,会对其它操作产生影响(如按键按下时,刚好需要通讯,则通讯会有10ms延迟)。可改用时间轮询法,采用时基改进程序。