声明:代码确实写的不好,用的都是最笨的方法实现功能,不喜勿喷
其实按键的检测主要是检测IO口的电平。下面看一下蓝桥杯板子上的按键的电路图:
这块开发板上是通过跳线帽来控制独立按键和矩阵按键的,用跳线帽将2和3连在一起就是独立按键,将2和1连在一起就是矩阵按键。
独立按键:
对于独立按键的控制相对来说比较简单,我们只需要读取 P30、P31、P32、P33四个IO口的电平状态就可以判断按键是否按下了。
对于这个板子来说只要判断这四个IO是不是低电平就可以判断按键是否按下了。
直接看一下代码:
void keyscan()
{
if(P30==0)
{
Delay6ms();
if(P30==0)
{
P00 = 0;
}
while(!P30);
}
else if(P31==0)
{
Delay6ms();
if(P31==0)
{
P01 = 0;
}
while(!P31);
}
else if(P32==0)
{
Delay6ms();
if(P32==0)
{
P02 = 0;
}
while(!P32);
}
else if(P33==0)
{
Delay6ms();
if(P33==0)
{
P03 = 0;
}
while(!P33);
}
}
void Delay6ms() //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
_nop_();
i = 65;
j = 136;
do
{
while (--j);
} while (--i);
}
一般来说对于按键的判断我们都是在按键按下之后把一些标志位置位或者直接去操控一下东西,比如点亮LED灯、数码管显示等。
对于按键的检测大部分情况下是要消除抖动的,在程序中Delay6ms()延时之后在次判断是否按下就是为了消除抖动。当然最后我们也是要进行松手检测的,这样可以防止程序发生一些不必要的错乱。
还有一种独立按键的检测方式,这种方式可以不用延时函数,而是用定时中断来定时扫描,下面看一下程序:
uchar KeySta[4] = {1,1,1,1};//独立按键的当前状态
void main()
{
uchar backup[4] = {1,1,1,1};//按键值备份,保存前一次的值
uchar cnt;
P2 = 0XA0;P0 = 0X00;//关闭蜂鸣器和继电器
P2 = 0X80;P0= 0XFF;//开启流水灯
P2=0XC0;P0=0XFF;//开启数码管片选端,选中所有数码管
P2=0XEF;P0=0XFF;//开启数码管段选端,关闭所有段
Timer0Init();
while(1)
{
if(KeySta[0] != backup[0]) //当前值与前一次值不相等说明此时按键有动作
{
if(backup[0] == 1) //如果前一次值为1说明当前是按下动作
{
cnt++;
Display1_2(cnt,cnt+1);
}
if(backup[0] == 0) //如果前一次值为0说明当前是弹起动作
{
}
backup[0] = KeySta[0];
}
if(KeySta[1] != backup[1])
{
if(backup[1] == 0)
{
Display4_5(4,5);
}
backup[1] = KeySta[1];
}
if(KeySta[2] != backup[2])
{
if(backup[2] == 0)
{
Display3_6(10,10);
}
backup[2] = KeySta[2];
}
if(KeySta[3] != backup[3])
{
if(backup[3] == 0)
{
Display7_8(7,8);
}
backup[3] = KeySta[3];
}
}
}
void Timer0Init(void) //2毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x9A; //设置定时初值
TH0 = 0xA9; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
EA = 1;
ET0 = 1;
}
void Timer0() interrupt 1
{
static unsigned char keybuf[4] = {0XFF,0XFF,0XFF,0XFF};//扫描缓冲区,保存一段时间内的扫描值
uchar i;
TL0 = 0x9A; //设置定时初值
TH0 = 0xA9; //设置定时初值
//将四个独立按键值移入缓冲区
keybuf[0] = (keybuf[0]<<1)| P30;
keybuf[1] = (keybuf[1]<<1)| P31;
keybuf[2] = (keybuf[2]<<1)| P32;
keybuf[3] = (keybuf[3]<<1)| P33;
for(i=0;i<4;i++)
{
if(keybuf[i] == 0x00)//连续八次扫描全为0,说明按键已经按下
{
KeySta[i] = 0;
}
else if(keybuf[i] == 0XFF)//连续八次扫描全为1,说明按键已经按下
{
KeySta[i] = 1;
}
}
}
矩阵按键:
矩阵按键相对来说比较麻烦一点,一般我们用的检测思路是对高四位的其中一位赋值零检测低四位,或者低低四位的其中一位赋值零检测高四位。
判断的依据和处理的方法和独立按键是一样的,下面来看一下代码:
void keysca16()
{
uchar temp;
//第一列按键
P3 = 0X7F;P42 = 1;P44=0;
temp = P3;
temp = temp&0X0F;
if(temp!=0X0F)
{
Delay6ms();
if(temp!=0X0F)
{
temp = P3;
switch(temp)
{
case 0X7E: P0=0XFE;break;
case 0X7D: P0=0XFD;break;
case 0X7B: P0=0XFB;break;
case 0X77: P0=0XF7;break;
}
while(temp!=0X0F)
{
temp = P3;
temp = temp&0X0F;
}
}
}
//第二列按键
P3 = 0XBF;P42 = 0;P44 = 1;
temp = P3;
temp = temp&0X0F;
if(temp!=0X0F)
{
Delay6ms();
if(temp!=0X0F)
{
temp = P3;
switch(temp)
{
case 0XBE: P0=0XEF;break;
case 0XBD: P0=0XDF;break;
case 0XBB: P0=0XBF;break;
case 0XB7: P0=0X7F;break;
}
while(temp!=0X0F)
{
temp = P3;
temp = temp&0X0F;
}
}
}
//第三列按键
P3 = 0XDF;P42 = 1;
temp = P3;
temp = temp&0X0F;
if(temp!=0X0F)
{
Delay6ms();
if(temp!=0X0F)
{
temp = P3;
switch(temp)
{
case 0XDE: P0=0XFF;break;
case 0XDD: P0=0X00;break;
case 0XDB: P0=0XAA;break;
case 0XD7: P0=0X55;break;
}
while(temp!=0X0F)
{
temp = P3;
temp = temp&0X0F;
}
}
}
//第四列按键
P3 = 0XEF;
temp = P3;
temp = temp&0X0F;
if(temp!=0X0F)
{
Delay6ms();
if(temp!=0X0F)
{
temp = P3;
switch(temp)
{
case 0XEE: P0=0X00;break;
case 0XED: P0=0XFF;break;
case 0XEB: P0=0X55;break;
case 0XE7: P0=0XAA;break;
}
while(temp!=0X0F)
{
temp = P3;
temp = temp&0X0F;
}
}
}
}
void Delay6ms() //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
_nop_();
i = 65;
j = 136;
do
{
while (--j);
} while (--i);
}