實現原理:令其中某一行或某一列爲0(等同於獨立鍵盤的接地),判斷對應的位置的列或行是否爲0,從而確定是哪一個按鍵被按下。(注意跳線帽位置的更改)
學習時使用的平臺爲CT107S,原理圖如下:
其與競賽用的官方平臺CT107D不同在於WR、RD對應的引腳不同,CT107D原理圖如下:(CT107D電路是爲52單片機所設計,需使用IAP15F2K60S轉接板,經轉接板後WR,RD也爲P42,P44,也即程序仍使用的P42,P44,而並非如下圖的直接使用P36,P37,本人在此曾有迷惑)
轉接板原理圖參考如下:
矩陣鍵盤第一列按鍵控制L1~L4點亮
#include<STC15F2K60S2.H>
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<STC15F2K60S2.H>
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<STC15F2K60S2.H>
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<STC15F2K60S2.H>
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轉接板,則無需更改。