9.矩阵键盘的使用

实现原理:令其中某一行或某一列为0(等同于独立键盘的接地),判断对应的位置的列或行是否为0,从而确定是哪一个按键被按下。(注意跳线帽位置的更改)
学习时使用的平台为CT107S,原理图如下:
9.矩阵键盘的使用_第1张图片
其与竞赛用的官方平台CT107D不同在于WR、RD对应的引脚不同,CT107D原理图如下:(CT107D电路是为52单片机所设计,需使用IAP15F2K60S转接板,经转接板后WR,RD也为P42,P44,也即程序仍使用的P42,P44,而并非如下图的直接使用P36,P37,本人在此曾有迷惑)
9.矩阵键盘的使用_第2张图片
转接板原理图参考如下:
9.矩阵键盘的使用_第3张图片
矩阵键盘第一列按键控制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转接板,则无需更改。

你可能感兴趣的:(蓝桥杯IAP15F系列单片机)