来电了! 电工总算烦了,没想到会这么快,多亏阿福,外面真是只能凑合,还是自个儿宿舍舒服,明天开焊!
总图
最小系统&数码管
与门实现键盘中断触发
译码器实现矩阵键盘的扩展
扩展的矩阵键盘
程序代码:
#include
#include
#define uchar unsigned char //宏定义
#define uint unsigned int
code uchar table[]={0x3f,0x06,0x5b,//数码管显示的数值
0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,
0x77,0x7c,0x39,0x5e,0x79,0x71};
code uchar key_tab[32]={ //此数组为键盘编码 加号前为按前j的值即扫描值,加号后卫按键按下后P0取高位的值
0xf0+0xe0,0xf0+0xd0,0xf0+0xb0,0xf0+0x70, // 0,,,3,
0xf1+0xe0,0xf1+0xd0,0xf1+0xb0,0xf1+0x70, // 4,,,7,
0xf2+0xe0,0xf2+0xd0,0xf2+0xb0,0xf2+0x70, // 8,,,11,
0xf3+0xe0,0xf3+0xd0,0xf3+0xb0,0xf3+0x70, // 12,,,15,
0xf4+0xe0,0xf4+0xd0,0xf4+0xb0,0xf4+0x70, // 16,,,19,
0xf5+0xe0,0xf5+0xd0,0xf5+0xb5,0xf5+0x70, // 20,,,23,
0xf6+0xe0,0xf6+0xd0,0xf6+0xb0,0xf6+0x70, // 24,,,27,
0xf7+0xe0,0xf7+0xd0,0xf7+0xb0,0xf8+0x70, // 28,,,31,
}; // c,d,e,f,
uchar l_key=0x00; //定义变量,存放键值
uchar l_keyold=0xff; //作为按键放开否的凭证
uchar flag,flag1;//flag为了使最初不显示数字,flag1
void readkey(); //扫描键盘,获取键值
void display(uchar *lp); //显示子函数
void delay1(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}void delay(); //延时子函数
void main()
{
EA=1; //打开总中断
EX0=1; //打开外部中断
P0=0x0f; //键值高位为高电平,低位为低电平
while(1)
{
display(&l_key); //调用显示子函数
}
}
void key_scan() interrupt 0//外部中断,的优先级最高
{
EX0=0; //在读键盘时,关闭外部中断,防止干扰带来的多次中断
TMOD=0xf1; //设置定时器为工作方式 ,定时器零为方式1,16位定时器模式
TH0=0x2e; //设置初值,为毫秒,
TL0=0x00;
ET0=1; //开启定时器中断
TR0=1; //启动定时器计数
flag=1;
flag1++;
}
void time0() interrupt 1 //定时器的中断函数
{
TR0=0; //关闭定时器
readkey(); //定时ms后产生中断,调用此函数,读取键值
}
void readkey() //扫描键盘子函数
{
uchar i,j,key; //定义局部变量
j=0xf0; //设定初值
key=0xff;
for(i=0;i<8;i++) // 逐行扫描键盘
{
P0=j;
if((P0&0xf0)!=0xf0) //有按键按下,高位不可能全为
{
key=P0&0xf0; //读取P0口的值,退出循环,否则循环下次
break;
}
j++; //此函数的功能是:左移循环
}
if(key==0xff) //如果读取不到P0口的值,如干扰,则返回
{
l_keyold=0xff;
P0=0x0f; // 恢复P0口的值,等待按键按下,很重要,否则一直为低电平,无法触发中断
EX0=1; //在返回前,打开外部中断
return;
}
if(l_keyold==key) // 检查按键放开否,如果相等表明没有放开
{
TH0=0x2e; //设置初值
TL0=0x00;
TR0=1; //继续启动定时器,检查按键放开否
return;
}
TH0=0x2e;
TL0=0;
TR0=1; //启动定时器
l_keyold=key; //获取键值,作为放开否的凭证
key+=j;
for(i=0;i<32;i++) //查表获得相应的进制值存放到l_key中
{
if(key==key_tab[i])
{
l_key=i;
break;
}
}
//程序运行到此,就表明有键值存放到l_key中,主程序
//就可以检测键盘值并作相应的处理
}
void display(uchar *lp) //显示子函数
{
uchar i,temp,j;
P2=0; //P2口为输出值
P1=0xff;
if(*lp<16)
P1=0xfd;
else
P1=0xfe; //点亮第二个数码管
temp=flag1;
j=*lp;
if(flag==1)
{
if(j>15)
j-=16;
for(i=0;i<=j;i++)
{
if(flag1>temp)
break;
P2=table[i]; //查表获得相应的要显示的数字的数码段
delay(); //延时
delay1(500);
P2=0; //清零,准备显示下一个数值
}
}
}
void delay() //延时子函数
{
_nop_();_nop_();_nop_();_nop_();_nop_();
}