实现原理:令其中某一行或某一列为0(等同于独立键盘的接地),判断对应的位置的列或行是否为0,从而确定是哪一个按键被按下。(注意跳线帽位置的更改)
学习时使用的平台为CT107S,原理图如下:
其与竞赛用的官方平台CT107D不同在于WR、RD对应的引脚不同,CT107D原理图如下:(CT107D电路是为52单片机所设计,需使用IAP15F2K60S转接板,经转接板后WR,RD也为P42,P44,也即程序仍使用的P42,P44,而并非如下图的直接使用P36,P37,本人在此曾有迷惑)
转接板原理图参考如下:
矩阵键盘第一列按键控制L1~L4点亮
#include
void KEY_Scan(void);
void Delayms(int ms);
void main(void)
{
P2=0XA0;P0=0X00;P2=0X80;P0=0XFF; //初始化程序
while(1)
{
KEY_Scan();
}
}
void KEY_Scan(void)
{
P44=0;
if(P30==0) //S7
{
Delayms(5);
if(P30==0)
{
P00=0; //L1亮
}
while(!P30);
}
else if(P31==0) //S6
{
Delayms(5);
if(P31==0)
{
P01=0; //L2亮
}
while(!P31);
}
else if(P32==0) //S5
{
Delayms(5);
if(P32==0)
{
P02=0; //L3亮
}
while(!P32);
}
else if(P33==0) //S4
{
Delayms(5);
if(P33==0)
{
P03=0; //L4亮
}
while(!P33);
}
}
void Delayms(int ms)
{
int i,j;
for(i=0;i<ms;i++)
for(j=845;j>0;j--);
}
矩阵键盘第一列按键控制L1-L4点亮,第二列控制L5~L8点亮
#include
void Delayms(int ms);
void KEY_Scan(void);
void main(void)
{
P2=0XA0;P0=0X00;P2=0X80;P0=0XFF; //初始化程序
while(1)
{
KEY_Scan();
}
}
void Delayms(int ms)
{
int i,j;
for(i=0;i<ms;i++)
for(j=845;j>0;j--);
}
void KEY_Scan(void)
{
P44=0;P42=1; //第一列
if((P30==0)&&(P44==0)) //S7
{
Delayms(5);
if(P30==0)
{
P00=0; //L1亮
}
while(!P30);
}
else if((P31==0)&&(P44==0)) //S6
{
Delayms(5);
if(P31==0)
{
P01=0; //L2亮
}
while(!P31);
}
else if((P32==0)&&(P44==0)) //S5
{
Delayms(5);
if(P32==0)
{
P02=0; //L3亮
}
while(!P32);
}
else if((P33==0)&&(P44==0)) //S4
{
Delayms(5);
if(P33==0)
{
P03=0; //L4亮
}
while(!P33);
}
P42=0;P44=1; //第二列
if((P30==0)&&(P42==0)) //S11
{
Delayms(5);
if(P30==0)
{
P04=0; //L5亮
}
while(!P30);
}
else if((P31==0)&&(P42==0)) //S10
{
Delayms(5);
if(P31==0)
{
P05=0; //L6亮
}
while(!P31);
}
else if((P32==0)&&(P42==0)) //S9
{
Delayms(5);
if(P32==0)
{
P06=0; //L7亮
}
while(!P32);
}
else if((P33==0)&&(P42==0)) //S8
{
Delayms(5);
if(P33==0)
{
P07=0; //L8亮
}
while(!P33);
}
}
矩阵键盘16按键控制数码管显示,按列扫描程序:
#include
unsigned char tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0X88,0X83,0XC6,0XA1,0X86,0X8E};
//定义一个数组,保存数码管显示所需的P0值,0~F
void Delayms(int ms);
void KEY_Scan16(void); //为了与独立按键函数相区别
void main(void)
{
P2=0XA0;P0=0X00;P2=0X80;P0=0XFF; //初始化程序
P2=0XC0;P0=0X01;P2=0XFF;P0=0XFF; //数码管初始化程序,打开第一个数码管
while(1)
{
KEY_Scan16();
}
}
void Delayms(int ms)
{
int i,j;
for(i=0;i<ms;i++)
for(j=845;j>0;j--);
}
void KEY_Scan16(void)
{
unsigned char temp;
//第一列 0111 1111
P44=0;P42=1;P3=0X7F; //此步骤个人认为相当于初始化矩阵键盘
//注意官方原理图上,P37,P38和P42,P44的关系,程序使用引脚为P44,P42,请参考转接板原理图
temp=P3;
temp=temp&0X0F; //如果不进行与运算,由于无法得知高四位的值,无法编写if程序
if(temp!=0X0F) //如果此时有按键被按下,temp将不再是0X0F
{
Delayms(5); //消抖
temp=P3;
temp=temp&0X0F; //与之前消抖所用不同,temp为变量,如果不进行重新扫描赋值,temp将不会发生变化,消抖不起作用
if(temp!=0X0F)
{
temp=P3;
switch(temp)
{
case 0X7E:P0=tab[1];break;//S7,1
case 0X7D:P0=tab[2];break;//S6,2
case 0X7B:P0=tab[3];break;//S5,3
case 0X77:P0=tab[4];break;//S4,4
}
}
while(temp!=0X0F)
{
temp=P3;
temp=temp&0X0F; //重新扫描判断按键状态,若赋值步骤,上一步进行完后恰好满足循环条件将一直死循环下去
}
}
//第二列 1011 1111
P44=1;P42=0;P3=0XBF;
temp=P3;
temp=temp&0X0F;
if(temp!=0X0F)
{
Delayms(5);
temp=P3;
temp=temp&0X0F;
if(temp!=0X0F)
{
temp=P3;
switch(temp)
{
case 0XBE:P0=tab[5];break;//S11,5
case 0XBD:P0=tab[6];break;//S10,6
case 0XBB:P0=tab[7];break;//S9,7
case 0XB7:P0=tab[8];break;//S8,8
}
}
while(temp!=0X0F)
{
temp=P3;
temp=temp&0X0F;
}
}
//第三列 1101 1111
P44=1;P42=1;P3=0XDF;
temp=P3;
temp=temp&0X0F;
if(temp!=0X0F)
{
Delayms(5);
temp=P3;
temp=temp&0X0F;
if(temp!=0X0F)
{
temp=P3;
switch(temp)
{
case 0XDE:P0=tab[9];break;//S15,9
case 0XDD:P0=tab[10];break;//S14,A
case 0XDB:P0=tab[11];break;//S13,b
case 0XD7:P0=tab[12];break;//S12,C
}
}
while(temp!=0X0F)
{
temp=P3;
temp=temp&0X0F;
}
}
//第四列 1110 1111
P44=1;P42=1;P3=0XEF;
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[13];break;//S19,d
case 0XED:P0=tab[14];break;//S18,E
case 0XEB:P0=tab[15];break;//S17,F
case 0XE7:P0=tab[0];break;//S16,0
}
}
while(temp!=0X0F)
{
temp=P3;
temp=temp&0X0F;
}
}
}
注:如果switch前没有temp=P3的重新赋值,所有的case里面高4位均为一致的0,可能出现此时P3按键值已发生变化但是用于判断的变量仍为原来的,从而造成误判
另一种简化写法:
#include
unsigned char tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0X88,0X83,0XC6,0XA1,0X86,0X8E};
unsigned char num;
void KEY_Scan16(void);
void Delayms(int ms);
void main(void)
{
P2=0XA0;P0=0X00;P2=0X80;P0=0XFF; //初始化程序
P2=0XC0;P0=0X01;P2=0XFF;P0=0XFF; //数码管初始化程序,打开第一个数码管
while(1)
{
KEY_Scan16();
P0=tab[num];
}
}
void Delayms(int ms)
{
int i,j;
for(i=0;i<ms;i++)
for(j=845;j>0;j--);
}
void KEY_Scan16(void)
{
unsigned char temp;
P44=0;P42=1;P3=0X7F; //第一列
temp=P3;
temp=temp&0X0F;
if(temp!=0X0F)
{
Delayms(5);
temp=P3;
temp=temp&0X0F;
if(temp!=0X0F)
{
temp=P3;
switch(temp)
{
case 0X7E:num=1;break;//S7,1
case 0X7D:num=2;break;//S6,2
case 0X7B:num=3;break;//S5,3
case 0X77:num=4;break;//S4,4
}
}
while(temp!=0X0F)
{
temp=P3;
temp=temp&0X0F;
}
}
P44=1;P42=0;P3=0XBF; //第二列
temp=P3;
temp=temp&0X0F;
if(temp!=0X0F)
{
Delayms(5);
temp=P3;
temp=temp&0X0F;
if(temp!=0X0F)
{
temp=P3;
switch(temp)
{
case 0XBE:num=5;break;//S11,5
case 0XBD:num=6;break;//S10,6
case 0XBB:num=7;break;//S9,7
case 0XB7:num=8;break;//S8,8
}
}
while(temp!=0X0F)
{
temp=P3;
temp=temp&0X0F;
}
}
P44=1;P42=1;P3=0XDF; //第三列
temp=P3;
temp=temp&0X0F;
if(temp!=0X0F)
{
Delayms(5);
temp=P3;
temp=temp&0X0F;
if(temp!=0X0F)
{
temp=P3;
switch(temp)
{
case 0XDE:num=9;break;//S13,9
case 0XDD:num=10;break;//S14,A
case 0XDB:num=11;break;//S13,b
case 0XD7:num=12;break;//S12,C
}
}
while(temp!=0X0F)
{
temp=P3;
temp=temp&0X0F;
}
}
P44=1;P42=1;P3=0XEF; //第四列
temp=P3;
temp=temp&0X0F;
if(temp!=0X0F)
{
Delayms(5);
temp=P3;
temp=temp&0X0F;
if(temp!=0X0F)
{
temp=P3;
switch(temp)
{
case 0XEE:num=13;break;//S19,d
case 0XED:num=14;break;//S18,E
case 0XEB:num=15;break;//S17,F
case 0XE7:num=0;break;//S16,0
}
}
while(temp!=0X0F)
{
temp=P3;
temp=temp&0X0F;
}
}
}
注:此程序运行后一个现象是数码管初始即显示0,因为定义num默认为0
如果CT107D使用的是STC8的转接板,则需将P42改为P43(STC8的WR引脚在P43),如果是CT107S使用STC8转接板,则无需更改。