51单片机按键检测--独立按键与矩阵键盘

按键可以说是51单片机项目开发的一个重要组件了,它是作为51单片机IO口输入的一种重要方式。我们可以通过按键控制单片机执行相应的程序,得到我们想要得效果。51单片机的按键输入主要有两种,一种是独立按键,每个按键对应一个IO口,通过循环或者中断去检测,这种方法常用于按键个数较少得时候。如果按键的个数较多,每个按键都分配一个IO口,会占用大量的资源,所以就有了矩阵键盘。矩阵键盘是通过单片机扫描键盘的每行每列,通过行和列唯一确定按键的编号,下面对这两种方法进行介绍。
1 独立按键
Proteus仿真电路图
在这里插入图片描述
途中按键通过P1.0P1.3输入,四个LED灯连接P.0P2.3,不同按键按下,对应不同的LED灯亮,程序如下:

#include <reg51.h>

unsigned char num;

void main()
{
	TMOD=0x01;
	TH0 = (65536-917)/256;	//1000/1.09	
	TL0 = (65536-917)%256;;		
	EA=1;
	ET0=1;
	TR0=1;
	P1=0xff;
	P2=0x00;
	while(1){
		if(num==20){
			num=0;
			switch(P1){
				case ~0x01:
					P2=~0x01;
					break;
				case ~0x02:
					P2=~0x02;
					break;
				case ~0x04:
					P2=~0x04;
					break;
				case ~0x08:
					P2=~0x08;
					break;
				defult:
				break;
		}
	}
}
	}

void Timer0() interrupt 1
{
  TH0 = (65536-917)/256;		
	TL0 = (65536-917)%256;	
	num++;
}

采用的是定时器0中断的形式,定时器0每1ms产生一次中断,num加一,再while循环中判断num=20时候,也就是计时20ms,读取P1的状态,通过判断P1的值判断是那个按键按下,点亮对应的LED灯。效果图如下:
在这里插入图片描述
独立按键很简单,想必大家有比我这更好的例子(比如加上消抖),今天的重点时矩阵键盘。
2 矩阵键盘检测
Proteus仿真电路图
在这里插入图片描述

这里将16个按键按照4*4排列,矩阵键盘的每一行分别连接P3.0P3.3;矩阵键盘的每一列连接P3.4P3.7。扫描的原理大致是这样的:先将P30置零,其余都为1(P3-0xfe),然后读取P3口的状态,如果P3!=0xfe了(这里主要是高四位会变化,第四位不变),说明有按键按下了,而且一定是第一行中的某个按键。然后就去判断P3口的状态,如果第一个按键按下(左上角),那应该是P3.4=0,刚才P3.0=0,那么P3口的状态就是P3=0xee,以此类推,第一行第二个,第三个,第四个按键按下,对应P3=0xde, P3=0xbe, P3=0x7e。这样就可以判断是哪个按键按下了,如果P3=0xfe,就说明第一行没有按键按下,那么同样的方法,令P3=0xfd,判断第二行是否有按键按下,依次给每一行置零(P3=0xfb,P3=0xf7),读取列的状态,判断是哪个按键按下,如果都没有,说明没有按键按下。
C51代码:

#include <reg51.h>
void Delay10ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 18;
	j = 235;
	do
	{
		while (--j);
	} while (--i);
}
void key_scan()
{
	unsigned char temp;
	P3=0xfe;
	temp=P3;
	temp&=0xf0;
	if(temp!=0xf0)
	{
		delay10ms();
		temp=P3;
		temp&=0xf0;
		if(temp!=0xf0)
		{
			temp=P3;
			switch(temp)
			{
				case 0xee:
					P2=0x00;
				break;
				case 0xde:
					P2=0x01;
				break;
				case 0xbe:
					P2=0x02;
				break;
				case 0x7e:
					P2=0x03;
				break;
			}
			while(temp!=0xf0)
			{
				temp=P3;
				temp&=0xf0;
			}
		}
	}
	
	P3=0xfd;
	temp=P3;
	temp&=0xf0;
	if(temp!=0xf0)
	{
		delay10ms();
		temp=P3;
		temp&=0xf0;
		if(temp!=0xf0)
		{
			temp=P3;
			switch(temp)
			{
				case 0xed:
					P2=0x04;
				break;
				case 0xdd:
					P2=0x05;
				break;
				case 0xbd:
					P2=0x06;
				break;
				case 0x7d:
					P2=0x07;
				break;
			}
			while(temp!=0xf0)
			{
				temp=P3;
				temp&=0xf0;
			}
		}
	}
	
	
	P3=0xfb;
	temp=P3;
	temp&=0xf0;
	if(temp!=0xf0)
	{
		delay10ms();
		temp=P3;
		temp&=0xf0;
		if(temp!=0xf0)
		{
			temp=P3;
			switch(temp)
			{
				case 0xeb:
					P2=0x08;
				break;
				case 0xdb:
					P2=0x09;
				break;
				case 0xbb:
					P2=0x0a;
				break;
				case 0x7b:
					P2=0x0b;
				break;
			}
			while(temp!=0xf0)
			{
				temp=P3;
				temp&=0xf0;
			}
		}
	}
	
	
	
	P3=0xf7;
	temp=P3;
	temp&=0xf0;
	if(temp!=0xf0)
	{
		delay10ms();
		temp=P3;
		temp&=0xf0;
		if(temp!=0xf0)
		{
			temp=P3;
			switch(temp)
			{
				case 0xe7:
					P2=0x0c;
				break;
				case 0xd7:
					P2=0x0d;
				break;
				case 0xb7:
					P2=0x0e;
				break;
				case 0x77:
					P2=0x0f;
				break;
			}
			while(temp!=0xf0)
			{
				temp=P3;
				temp&=0xf0;
			}
		}
	}
	
	
}

void main()
{
	P2=0x00;
	while(1)
	{
		key_scan();
	}
}

Key_scan()是键盘扫描函数,主要分为四大部分,每个部分核心都是一样的,就是实现上述矩阵键盘扫描原理,下面拿出第一段介绍:

P3=0xfe;
	temp=P3;
	temp&=0xf0;
	if(temp!=0xf0)
	{
		delay10ms();
		temp=P3;
		temp&=0xf0;
		if(temp!=0xf0)
		{
			temp=P3;
			switch(temp)
			{
				case 0xee:
					P2=0x00;
				break;
				case 0xde:
					P2=0x01;
				break;
				case 0xbe:
					P2=0x02;
				break;
				case 0x7e:
					P2=0x03;
				break;
			}
			while(temp!=0xf0)
			{
				temp=P3;
				temp&=0xf0;
			}
		}
	}

首先P3=0xfe,再将P3赋值给temp,temp再与0xf0与运算,如果P3的高四位有0出现,那么temp一定不等于0xf0,但是这样还不能直接判断就是有按键按下了,可能是一些干扰,而且按键按下时候初期时不稳定的,不是一个理想的下降沿,所以需要消抖,其实就是延时10ms再次读取P3口状态,如果现在tmep依然不等于0xf0,那么可以判断有按键按下了,然后就可以吧p3幅值给temp,进而判断temp的状态了。
然后下面这段程序就是判断按键是否抬起,否则的话会一直在这个循环,无法执行其他程序:

while(temp!=0xf0)
			{
				temp=P3;
				temp&=0xf0;
			}

上述代码时通过while循环实现的,也可以中断实现:

#include <reg51.h>
unsigned char num;
void Delay10ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 18;
	j = 235;
	do
	{
		while (--j);
	} while (--i);
}
void key_scan()
{
	unsigned char temp;
	P3=0xfe;
	temp=P3;
	temp&=0xf0;
	if(temp!=0xf0)
	{
		delay10ms();
		temp=P3;
		temp&=0xf0;
		if(temp!=0xf0)
		{
			temp=P3;
			switch(temp)
			{
				case 0xee:
					P2=0x00;
				break;
				case 0xde:
					P2=0x01;
				break;
				case 0xbe:
					P2=0x02;
				break;
				case 0x7e:
					P2=0x03;
				break;
			}
			while(temp!=0xf0)
			{
				temp=P3;
				temp&=0xf0;
			}
		}
	}
	
	P3=0xfd;
	temp=P3;
	temp&=0xf0;
	if(temp!=0xf0)
	{
		delay10ms();
		temp=P3;
		temp&=0xf0;
		if(temp!=0xf0)
		{
			temp=P3;
			switch(temp)
			{
				case 0xed:
					P2=0x04;
				break;
				case 0xdd:
					P2=0x05;
				break;
				case 0xbd:
					P2=0x06;
				break;
				case 0x7d:
					P2=0x07;
				break;
			}
			while(temp!=0xf0)
			{
				temp=P3;
				temp&=0xf0;
			}
		}
	}
	
	
	P3=0xfb;
	temp=P3;
	temp&=0xf0;
	if(temp!=0xf0)
	{
		delay10ms();
		temp=P3;
		temp&=0xf0;
		if(temp!=0xf0)
		{
			temp=P3;
			switch(temp)
			{
				case 0xeb:
					P2=0x08;
				break;
				case 0xdb:
					P2=0x09;
				break;
				case 0xbb:
					P2=0x0a;
				break;
				case 0x7b:
					P2=0x0b;
				break;
			}
			while(temp!=0xf0)
			{
				temp=P3;
				temp&=0xf0;
			}
		}
	}
	
	
	
	P3=0xf7;
	temp=P3;
	temp&=0xf0;
	if(temp!=0xf0)
	{
		delay10ms();
		temp=P3;
		temp&=0xf0;
		if(temp!=0xf0)
		{
			temp=P3;
			switch(temp)
			{
				case 0xe7:
					P2=0x0c;
				break;
				case 0xd7:
					P2=0x0d;
				break;
				case 0xb7:
					P2=0x0e;
				break;
				case 0x77:
					P2=0x0f;
				break;
			}
			while(temp!=0xf0)
			{
				temp=P3;
				temp&=0xf0;
			}
		}
	}
	
	
}

void main()
{
	TMOD=0x01;
	TH0 = (65536-917)/256;	//1000/1.09	
	TL0 = (65536-917)%256;;		
	EA=1;
	ET0=1;
	TR0=1;
	P2=0x00;
	while(1)
	{
		if(num==2)
		{
			num=0;
		key_scan();
		}
	}
}
void Timer0() interrupt 1
{
  TH0 = (65536-917)/256;		
	TL0 = (65536-917)%256;	
	num++;
}

核心的内容都一样,就不多解

  • 3
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值