独立按键与矩阵按键

一、按键介绍

轻触按键:相当于是一种机械开关,按下时开关接通,松开时开关断开,实现原理是通过轻触按键内部的金属弹片受力弹动来实现接通和断开

c79df9e00ac84af38a2d0e233189c6bf.png

819bf9aa63224fc9aeebe651901b5968.png

轻触按键的内部结构介绍

我们可以很清楚地看到下图的按键内部是由两个触点和一个金属弹片组成的,两个触点与按键左端相连,中间的金属弹片与按键右端相连。当我们按下按键的时候按键内部的金属弹片就会被压扁,与两左端两触点接触,这样就实现了开关的接通。当我们松手的时候,金属弹片恢复原状,不再与两触点接触,这样开关就断开了。

7460d0341c8c4baeb1bbea2990ad05dd.png

按键的抖动

机械开关触点的断开、闭合时由于弹性作用,不会立马稳定的断开与接通,而是会产生一个轻微的抖动c1c9c79a57494d6f8e89058796ad6a31.png

 

消除抖动

按键消抖有两种方式,一种是硬件消抖,另一种是软件消抖。为了使电路更加简单同时也节约成本,通常采用软件消抖。

根据按键抖动的波形图,我们只需要在按键按下的时候给程序一个延迟,延迟掉这段抖动的时间即可。

二、独立按键

独立按键在51单片机中的位置

cccb94a28bc3446196804347776750da.png

独立按键原理图

35c25a2ec1564a95a2039e2282e2c72f.png

根据独立按键原理图可知

P3_4口控制key17, P3_5口控制key18......以此类推。

331dae0c28d34f6eadb072a3daac31c6.png

 

三、矩阵按键

在某一个系统设计中,如果需要使用很多的按键时,做成独立按键会大量占用 IO 口,因此我们引入了矩阵按键的设计。

e709adb88f514e4595bd23ccaf954aeb.png

矩阵按键原理图

b18357cae67d4f76901740b990c898db.png

根据矩阵按键原理图可知两个io口一起控制一个矩阵按键,并且八个io口就控制了16个按键,大大节约了io口资源。

例如:P3_4和P3_1口控制key5

当key5按下时,P3^4和P3^1口会因为接地而被拉低成低电平

 

b5fe3e0b04ad45c391a53d944ab79fab.png

 

四、抬手检测

为了防止多次检测按键或区分是按下触发程序还是抬手触发程序,我们需设计一个检测抬手的程序。

我们设计一个while循环,当按键没松手时就会一直执行这个空循环

如按键io口为P3^7

例:while(P3^7==0);

但是这个检测方式有延迟

 


按键控制流水灯和跑马灯

视频效果

独立按键控制流水灯、跑马灯

 

代码

#include <REGX52.H>

unsigned char n,m,i=2;

sbit k1=P3^4;
sbit k2=P3^5;

void Delay1ms(unsigned char xms)		//@12.000MHz 延时函数
{
	unsigned char i, j;

	i = 12;
	j = 169;
	while(xms--)
	{
	do
	{
		while (--j);
	} while (--i);
	}
}

void water_lamp(),race_lamp();         //声明water_lamp和race_lamp函数


void main()
{
	n=0,m=0;
	while(1)
	{
		if(i%2==0)
		{
			water_lamp();
		}
		else
		{
			race_lamp();
		}
		if(k1==0)
		{
			Delay1ms(5);
			while(k1==0);
			i++;
		}
		if(k2==0)
		{
			Delay1ms(5);
			while(k2==0);
			if(++n>13) n=0;
			if(++m>13) m=0;
		}
	}
}

void water_lamp()
{
	  if(n==0) P1=0XFE;
		if(n==1) P1=0XFC;
		if(n==2) P1=0XF8;
		if(n==3) P1=0XF0;
		if(n==4) P1=0XE0;
		if(n==5) P1=0XC0;
		if(n==6) P1=0X80;
		if(n==7) P1=0X7F;
		
		if(n==8) P1=0X3F;
		if(n==9) P1=0X1F;
		if(n==10) P1=0X0F;
		if(n==11) P1=0X07;
		if(n==12) P1=0X03;
		if(n==13) P1=0X01;
}

void race_lamp()
{
		if(n==0) P1=0XFE;
		if(n==1) P1=0XFD;
		if(n==2) P1=0XFB;
		if(n==3) P1=0XF7;
		if(n==4) P1=0XEF;
		if(n==5) P1=0XDF;
		if(n==6) P1=0XBF;
		if(n==7) P1=0X7F;
		
		if(n==8) P1=0XBF;
		if(n==9) P1=0XDF;
		if(n==10) P1=0XEF;
		if(n==11) P1=0XF7;
		if(n==12) P1=0XFB;
		if(n==13) P1=0XFD;
}



五、状态机思想的抬手检测

从上面的视频中,我们可以很明显看到按键有时候的反应不是那么灵敏,这就是利用while循环检测松手的bug,这个时候单片机的cpu一直卡在while循环里面,导致程序卡顿,这个时候我们可以利用另一种写法—状态机写法。

我们可以设置两种状态,0是按键按下状态,1是按键抬起状态。首先我们定义一个按键标志位key_flag,如果key_flag=0就是有按键按下的状态,key_flag=1就是按键抬起状态。同时当有不同按键按下的时候,则返回不同的值

代码

unsigned char key_flag;

if((P3_1==0 || P3_2==0 || P3_3==0) && key_flag==0)
{
      if(P3_1==0)     return 1;     //如果按键1按下则返回1

      if(P3_2==0)     return2;     //如果按键2按下则返回2

      if(P3_3==0)     return3;     //如果按键3按下则返回3

     key_flag=1;     //检测位置1,防止多次检测

}

if((P3_1==1 && P3_2==1 && P3_3==1) && key_flag==1)
{
     key_flag=0;     //重新置标志位为0,方便进入下次按键检测
}

最后在主函数中接收返回值,判断到底是哪个按键按下。

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值