使用中断函数进行矩阵按键的扫描,在《手把手教你学51单片机》上面的代码修改了一下。感觉这个代码写的比较好。
#include
#define uchar unsigned char
sbit KEY_IN_1 = P4^4;
sbit KEY_IN_2 = P4^2;
sbit KEY_IN_3 = P3^5;
sbit KEY_IN_4 = P3^4;
sbit KEY_OUT_1 = P3^0;
sbit KEY_OUT_2 = P3^1;
sbit KEY_OUT_3 = P3^2;
sbit KEY_OUT_4 = P3^3;
uchar code LedChar[]={
0xc0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0Xbf,0XFF
};
uchar KeySta[4][4]={
{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}
};
void main()
{
uchar i,j;
uchar backup[4][4]={
{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}
};
P2=0xa0;//1010 0000,U9使能
P0=0x00;//关蜂鸣器和继电器
P2=0x80;//U6使能,关于LED的锁存器打开
P0=0xff;//关闭所有LED
P2=0xc0;//U8使能
P0=0xff;//com1-com8数码管位选
P2=0xff;//U7锁存器】使能,
P0=0xff;//段选
EA=1;//总使能开
TMOD=0x01;//十六位不可重装载模式,TH0,TL0全用
TH0=0xfc;//设定中断时间间隔
TL0=0x67;
ET0=1;//T0中断允许
TR0=1;//启动T0
//P0=LedChar[0];
while(1)
{
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
if(backup[i][j] != KeySta[i][j])//检测当前的按键状态与上一次按键状态 若满足条件说明有按下或弹起动作
{
if(backup !=0)//如果上一次是抬起状态 说明是按下动作发生了
{
P0=LedChar[i*4+j];
}
backup[i][j] = KeySta[i][j];//把当前值保存
}
}
}
}
}
void InterruptTime0() interrupt 1
{
uchar i;
static uchar keyout=0;
static uchar keybuf[4][4]={//缓冲 保存最近四次结果
{0xff,0xff,0xff,0xff},{0xff,0xff,0xff,0xff},
{0xff,0xff,0xff,0xff},{0xff,0xff,0xff,0xff}
};
TH0=0xfc;//重载
TL0=0x67;
keybuf[keyout][0] = (keybuf[keyout][0]<<1) | KEY_IN_1;
keybuf[keyout][1] = (keybuf[keyout][1]<<1) | KEY_IN_2;
keybuf[keyout][2] = (keybuf[keyout][2]<<1) | KEY_IN_3;
keybuf[keyout][3] = (keybuf[keyout][3]<<1) | KEY_IN_4;
for(i=0;i<4;i++)
{
if((keybuf[keyout][i] & 0x0f)==0x00)//单个按键连续四次为0确认按下状态
{
KeySta[keyout][i]=0;//刷新当前值
}
else if((keybuf[keyout][i]) & 0x0f ==0x0f)//四次为1 弹起状态
{
KeySta[keyout][i]=1;//刷新当前值
}
}
keyout++;//扫描换行/列
keyout&=0x03;
switch(keyout)
{
case 0:KEY_OUT_4 =1;KEY_OUT_1=0;break;
case 1:KEY_OUT_1 =1;KEY_OUT_2=0;break;
case 2:KEY_OUT_2 =1;KEY_OUT_3=0;break;
case 3:KEY_OUT_3 =1;KEY_OUT_4=0;break;
default:break;
}
}