幸运微笑

微笑一下,世界就会变得不一样

2018年9月20日

LUCKY>

【金沙滩51单片机开发板】独立按键

和以前一样,我们用的是金沙滩的51单片机来做的实验

首先,我们需要知道的原理图


矩阵按键部分

QQ截图20180920190131.jpg

单片机部分

QQ截图20180920190227.jpg

实现的效果

1537442081493.gif

下面是源代码和解释

#include<reg52.h>

/*接口引脚定义*/
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;

sbit KeyIn1 = P2^4;
sbit KeyOut1 = P2^3;

sbit LED2 = P0^2;

/*延时函数,这样写在函数里会便于管理*/
void delay10(void)
{
	unsigned char i,c;
	for(c = 10;c>0;c--)
		for(i = 0;i<110;i++);
}

void main()
{
	/*打开74H138译码机*/
	ADDR0 = 0;
	ADDR1 = 1;
	ADDR2 = 1;
	ADDR3 = 1;
	ENLED = 0;

	/*初始化按键,
	需要把keyout设置为低电平,keyin设置为高电平才可以,具体见下文分解,
	这里简单解释下,单片机准双向IO口做为输入口时是只有自己是高电平时才能准确读取外部状态*/
	KeyIn1 = 1;
	KeyOut1 = 0;

	/*默认LED2是关闭的*/
	LED2 = 1;

	while(1)
	{
		/*一直在判断按键是否被按下,如果KeyIn1是低电平,说明按键被按下了*/
		if(KeyIn1 == 0)
		{
			/*确认按键被按下
			因为硬件的原因,可能同学们没有按下按键,只是被碰到了一下也可能导致
			程序误判为按下按键了,解决方法有两种,一种是从硬件上改进,使不会产生这种
			错误,还有就是软件判断这种情况,我们可以通过等待一段时间,碰一下的通电时间
			可能非常短,10ms这样,而按下去了至少都是要100ms才能抬起,大家可以试下
			你非常快速的按下按键,测量这段时间,是大于100ms的,所以我们可以通过软件
			等待一段时间再去判断是不是真的被按下了*/
			delay10();

			if(KeyIn1 == 0)/*到这里就是已经确认被按下了,在if下写动作*/
			{
				LED2 = ~LED2;  /*灯取反一下就好,如果按下之前是0,取反为1熄灭,同样
				按下之前如果是1,按下就变成0了,点亮*/

				while(KeyIn1 == 0);/*单片机的速度很快,也许本次按下还没抬起
				单片机就做完以上动作了,为了不产生长按成为连续按下的效果,
				这里等抬起后再判断是否再被按下*/
				
				/*这里重新初始化一下,有的同学反映不能按第二次,这里保证每次抬起后电位一致*/
				KeyIn1 = 1;
				KeyOut1 = 0;
			}
		}	
	}
}

解释:为什么输入检测口一定要高电平才能准确检测到外部电压,输出口要低电平?

常用的按键电路有两种,独立按键和矩阵按键,独立按键比较简单,它们各自与独立的输入线相连接,独立按键原理如下图所示。

QQ截图20180920192117.jpg

        4条输入线接到单片机的IO口上,当按键K1按下时,+5V通过电阻R1然后再通过按键K1最终进入GND形成一条通路,这条线路的全部电压都加到了R1这个电阻上了,因此KeyIn1这个引脚是低电平。当松开按键后,这条电路断开,就不会有电流通过,那么KeyIn1+5V就是连起来的,同+5V是一个高电平。我们就可以通过KeyIn1这个IO口的高低电平来判断是否有按键按下。这个电路中原理我们知道了,但是在我们的单片机IO口内部,也出存在一个上拉电阻。我们的按键是接到了P2口上,P2口默认是准双向IO口的,我们简单了解一下这个准双向IO口的电路,单片机准双向IO口如图下所示。 

QQ截图20180920192135.jpg

        这里说明一下,我们现在大多数单片机的IO口都是用MOS管而不是三极管的,但是在这里用三极管的原理和MOS极管是一样的,因此在这里用三极管替代MOS管来进行原理解释,三极管我们比较熟悉,有助于理解。 上图方框内的电路都是指单片机内部的部分,方框外的就是开发板上外接的上拉电阻和按键,不过金沙滩的开发板上按键这部分没有外接的上拉电阻,不影响使用。 当我们要读取外部按键信号的时候,单片机必须先给控制输入引脚的特殊功能寄存器写“1”,也就是高电平,这样我们才能正确读取到外部按键信号,下面我们来分析一下为什么。

        当单片机内部输出是高电平时,经过一个反向器变成低电平,NPN三极管不会被导通,那么从单片机IO口内部来看,由于上拉电阻R的存在,所以内部检测到的是一个高电平。当外部没有按键按下把电平拉低的话,VCC也是+5V,它们之间虽然有两个电阻,但是没有电压差,就不会有电流,线上所有的位置都是高电平,这个时候我们就可以通过IO口正常读取到按键的状态了。 当内部输出是个低电平,经过一个反相器变成高电平,NPN三极管导通,那么单片机的内部IO口就是个低电平,这个时候,外部虽然也有上拉电阻的存在,但是内外两个电阻是并联关系,不管按键是否按下,从单片机IO口内部来看到的状态都是低电平,我们就不能正常读取到准确的按键状态了。 

        其实个人感觉电流和水流很类似可以把电流当水流理解,内部和外部,只要有一边是低电位,那么电流就会顺流而下, 由于只有上拉电阻,下边没有电阻分压,直接到GND上了,所以不管另外一边是高还是低,IO口的电平肯定就是低电平了。 从上面的分析就可以得出一个结论,这种具有上拉的准双向IO口,如果要正常读取到外部信号的状态,必须首先得保证自己内部输出的是 1,如果内部输出 0,则无论外部信号是 1 还是 0,这个引脚读进来的都是 0

        到这里,再结合上面金沙滩矩阵按键部分的原理图,就应该知道为什么keyout要输出一个低电平了吧?目的就是提供一个接地引脚哦。

        所以大家在写程序的时候不要忘记这一点。

        大家有兴趣的可以写个每个按键对应一个灯,比如按K1就第1个灯亮,再按K1就第一个灯熄灭……按Kn就第n个灯亮,再按Kn就第n个灯熄灭(n<4)。写好后记得上传到下方评论区哦!

c02d8acc7b899e5143c622a34ea7d933c9950d11.jpg

来一发吐槽