蓝桥杯---16位矩阵键盘
在之前的两章中,我们接触的是独立按键。现在,我们可以了解一下16位矩阵按键。首先先看一下原理图:
首先,需要将条形帽跳至1 2端口,即表示为16位矩阵按键。15单片机的矩阵按键大致可以分为按行扫描和按列扫描。我们用按列扫描的方式,也就是从左边的一根线往下看,分别加到了P37,P36,P35和P34这四个I/O借口上,但我们要注意的是,此时我们用的是15的单片机,P37和P36口已经改变了,我们见一下转接板的图便知晓问题所在。
从图中可以看出,转接板的P0,P1,P2口都和原来一样,但是P3口有一点是不一样的,P36变成了P42,P37变成了P44.这一点在写程序的时候需要更改过来。我们先来想两排的按键,考虑到精准的问题,程序写的会复杂一些。首先,我们是按行扫描,比方说先是第一行按键,就要令P44=0,之后呢需要精准一下,就要将P42=0,以确保不会混乱。再然后,就是要判断哪个被按下了,就需要行列的协同作战才能达到的。还是以之前的为例子,就要写if((P30=0)&&(P44=0))就能精准判断哪个被按下了。下面我们贴这个程序:
//两排按键控制数码管
#include<stc15f2k60s2.h>
#define uchar unsigned char
#define uint unsigned int
uchar code tab[]={0xc0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0Xbf,0XFF};//ROM
void delayms(int ms);
void keyscan();
void main()
{
P2=0XA0;P0=0X00;P2=0X80;P0=0XFF; //板子初始化程序
P2=0XC0;P0=0X01;P2=0XFF;P0=0XFF; //数码管初始化程序
while(1)
{
keyscan();
}
}
void keyscan()
{
P44=0;P42=1;
if((P300)&&(P440))//用来判断哪一行和列被按下
{
delayms(5);
if(P30==0)
{
P0=tab[0];
}
while(!P30);
}
else if((P31==0)&&(P44==0))
{
delayms(5);
if(P31==0)
{
P0=tab[1];
}
while(!P31);
}
else if((P32==0)&&(P44==0))
{
delayms(5);
if(P32==0)
{
P0=tab[2];
}
while(!P32);
}
else if((P33==0)&&(P44==0))
{
delayms(5);
if(P33==0)
{
P0=tab[3];
}
while(!P33);
}
P42=0;P44=1;
if((P30==0)&&(P42==0))
{
delayms(5);
if(P30==0)
{
P0=tab[4];
}
while(!P30);
}
else if((P31==0)&&(P42==0))
{
delayms(5);
if(P31==0)
{
P0=tab[5];
}
while(!P31);
}
else if((P32==0)&&(P42==0))
{
delayms(5);
if(P32==0)
{
P0=tab[6];
}
while(!P32);
}
else if((P33==0)&&(P42==0))
{
delayms(5);
if(P33==0)
{
P0=tab[7];
}
while(!P33);
}
}
void delayms(int ms)
{
int i,j;
for(i=ms;i>0;i–)
for(j=845;j>0;j–);
}
其实,这样写是有点复杂的。可以有更简单的写法。我们将if语句换为switch语句,还需要引入一个变量temp,对P3口整体赋值。16位按键程序如下:
#include<stc15f2k60s2.h>
#define uchar unsigned char
#define uint unsigned int
uchar code tab[]={0xc0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0Xbf,0XFF};//ROM
void delayms(int ms);
void keyscan16();
void main()
{
P2=0XA0;P0=0X00;P2=0X80;P0=0XFF; //板子初始化程序
P2=0XC0;P0=0X01;P2=0XFF;P0=0XFF; //数码管初始化程序
while(1)
{
keyscan16();
}
}
void keyscan16()
{
uchar temp;
P44=0;P42=1;P3=0X7F;//0111 1111
temp=P3;
temp=temp&0X0F;//1111 1101 & 0000 1111 = 0000 1101
if(temp!=0x0f)//判断按键被按下了
{
delayms(5);//消抖
temp=P3;//整体赋值
temp=temp&0X0F;//判断是否真的被按下了
if(temp!=0x0f)
{
temp=P3;
switch(temp)
{
case 0x7e: P0=tab[0];break;//1111 1110 P37----p30
case 0x7d: P0=tab[1];break;//1111 1101
case 0x7b: P0=tab[2];break;
case 0x77: P0=tab[3];break;
}
while(temp!=0x0f)//等待松手
{
temp=P3;
temp=temp&0X0F;
}
}
}
P44=1;P42=0;P3=0XBF;//1011 1111
temp=P3;
temp=temp&0X0F;//1111 1101 & 0000 1111 = 0000 1101
if(temp!=0x0f)
{
delayms(5);
temp=P3;
temp=temp&0X0F;
if(temp!=0x0f)
{
temp=P3;
switch(temp)
{
case 0xBe: P0=tab[4];break;//1111 1110 P37----p30
case 0xBd: P0=tab[5];break;//1111 1101
case 0xBb: P0=tab[6];break;
case 0xB7: P0=tab[7];break;
}
while(temp!=0x0f)
{
temp=P3;
temp=temp&0X0F;
}
}
}
//跑串
P3=0XDF;P44=1;P42=1;//1101 1111
temp=P3;
temp=temp&0X0F;//1111 1101 & 0000 1111 = 0000 1101
if(temp!=0x0f)
{
delayms(5);
temp=P3;
temp=temp&0X0F;
if(temp!=0x0f)
{
temp=P3;
switch(temp)
{
case 0xDe: P0=tab[8];break;//1111 1110 P37----p30
case 0xDd: P0=tab[9];break;//1111 1101
case 0xDb: P0=tab[10];break;
case 0xD7: P0=tab[11];break;
}
while(temp!=0x0f)
{
temp=P3;
temp=temp&0X0F;
}
}
}
P3=0XEF;P44=1;P42=1;//1110 1111
temp=P3;
temp=temp&0X0F;
if(temp!=0x0f)
{
delayms(5);
temp=P3;
temp=temp&0X0F;
if(temp!=0x0f)
{
temp=P3;
switch(temp)
{
case 0xEe: P0=tab[0];break;
case 0xEd: P0=tab[2];break;
case 0xEb: P0=tab[4];break;
case 0xE7: P0=tab[6];break;
}
while(temp!=0x0f)
{
temp=P3;
temp=temp&0X0F;
}
}
}
}
void delayms(int ms)
{
int i,j;
for(i=ms;i>0;i–)
for(j=845;j>0;j–);
}
不要看程序这么长,其实核心程序也就那么几行:拿控制第一列按键来说,
P44=0;P42=1;P3=0X7F;//0111 1111
temp=P3;
temp=temp&0X0F;//1111 1101 & 0000 1111 = 0000 1101
if(temp!=0x0f)//判断按键被按下了
{
delayms(5);//消抖
temp=P3;//再次整体赋值
temp=temp&0X0F;//判断是否真的被按下了
if(temp!=0x0f)
{
temp=P3;
switch(temp)
{
case 0x7e: P0=tab[0];break;//1111 1110 P37----p30
case 0x7d: P0=tab[1];break;//1111 1101
case 0x7b: P0=tab[2];break;
case 0x77: P0=tab[3];break;
}
while(temp!=0x0f)//等待松手
{
temp=P3;
temp=temp&0X0F;
}
}
}
随后的三列需要注意的是,p44和p42不用后需要将其关闭,以防混乱。
还有另外一种写法:
其他的写法
#include<stc15f2k60s2.h>
#define uchar unsigned char
#define uint unsigned int
uchar code tab[]={0xc0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0Xbf,0XFF};//ROM
uchar num=0;
void delayms(int ms);
void keyscan16();
void main()
{
P2=0XA0;P0=0X00;P2=0X80;P0=0XFF; //板子初始化程序
P2=0XC0;P0=0X01;P2=0XFF;P0=0XFF; //数码管初始化程序
while(1)
{
keyscan16();
P0=tab[num];
}
}
void keyscan16()
{
uchar temp;
P44=0;P42=1;P3=0X7F;
temp=P3;
temp=temp&0X0F;//1111 1101 & 0000 1111 = 0000 1101
if(temp!=0x0f)
{
delayms(5);
temp=P3;
temp=temp&0X0F;
if(temp!=0x0f)
{
temp=P3;
switch(temp)
{
case 0x7e: num=0;break;//1111 1110 P37----p30
case 0x7d: num=1;break;//1111 1101
case 0x7b: num=2;break;
case 0x77: num=3;break;
}
while(temp!=0x0f)
{
temp=P3;
temp=temp&0X0F;
}
}
}
P44=1;P42=0;P3=0XBF;//1011 111
temp=P3;
temp=temp&0X0F;//1111 1101 & 0000 1111 = 0000 1101
if(temp!=0x0f)
{
delayms(5);
temp=P3;
temp=temp&0X0F;
if(temp!=0x0f)
{
temp=P3;
switch(temp)
{
case 0xBe: num=4;break;//1111 1110 P37----p30
case 0xBd: num=5;break;//1111 1101
case 0xBb: num=6;break;
case 0xB7: num=7;break;
}
while(temp!=0x0f)
{
temp=P3;
temp=temp&0X0F;
}
}
}
P3=0XDF;P44=1;P42=1;//1101 1111
temp=P3;
temp=temp&0X0F;//1111 1101 & 0000 1111 = 0000 1101
if(temp!=0x0f)
{
delayms(5);
temp=P3;
temp=temp&0X0F;
if(temp!=0x0f)
{
temp=P3;
switch(temp)
{
case 0xDe: num=8;break;//1111 1110 P37----p30
case 0xDd: num=9;break;//1111 1101
case 0xDb: num=10;break;
case 0xD7: num=11;break;
}
while(temp!=0x0f)
{
temp=P3;
temp=temp&0X0F;
}
}
}
P3=0XEF;P44=1;P42=1;//1101 1111
temp=P3;
temp=temp&0X0F;//1111 1101 & 0000 1111 = 0000 1101
if(temp!=0x0f)
{
delayms(5);
temp=P3;
temp=temp&0X0F;
if(temp!=0x0f)
{
temp=P3;
switch(temp)
{
case 0xEe: num=0;break;//1111 1110 P37----p30
case 0xEd: num=2;break;//1111 1101
case 0xEb: num=4;break;
case 0xE7:num=6;break;
}
while(temp!=0x0f)
{
temp=P3;
temp=temp&0X0F;
}
}
}
}
void delayms(int ms)
{
int i,j;
for(i=ms;i>0;i–)
for(j=845;j>0;j–);
}
其实也就是更直观了。