小灰的51单片机学习之渐入佳境(4)(如何操作一个按键,以及矩阵按键工作原理)

写在之前

其实小灰在写这篇文章之前,看了许多前辈的讲解,想借鉴点什么,他们说的当然是极好的,对于原理讲解的很细致。但是我仍然觉得对于一个初学者来说,理解还是有一定的难度,于是小灰写下了这篇文章,可能在某些原理上阐述的不够仔细,但是我所希望是大家能够先初步理解这个是什么,等到后面再深入理解这些东西。废话少说,我们先开始。

按键是怎么工作的?

对于按键,我相信大家并不陌生,比如说我们电脑键盘上的按键就是一种按键。其实按键的原理都是差不多的,我们先去看一个按键的模样吧!
在这里插入图片描述
大概一个按键就是这个样子啦,我们可以看到,当这个按键没有被按下的时候,我们的P3.4引脚链接的是GND,通过之前的学习我们能知道,GND的电压都是0,所以是低电平,我们可以视为P3.4引脚的状态被GND拉到低电平了,所以现在P3.4口是低电平。
当按键按下了之后,因为按键是连起来的,所以按键那一块是连通的,也就是这个样子
在这里插入图片描述
连起来了,我们很容易就会发现,GND那边被短路了,这样P3.4引脚接的就是高电平VCC了。
这样有没有发现一个问题,就是按键按下之前和按下之后P3.4引脚是两个状态,这就是我们按键的意义所在。我们可以把按键按下去的这个动作视为一个信号,当我按下去之后,P3.4引脚被拉成高电平了,这就是信号的表现形式。而我们可以在程序里面判断P3.4引脚的一个状况,从而判断按键是否按下了,有没有觉得很有趣呢?纸上谈兵是没有用的啦,接下来我们看一个小程序,就是当我这个按键按下去的时候,会让LED亮,没有按下则LED不亮。

#include <reg52.h>

sbit key = P3^4;  //这是我们假定的两个io口分别连接按键和LED
sbit LED = P1^0;  //需要自己根据自己手上的开发板的不同进行修改,sbit则是进行位定义

void main()
{
   LED = 1; //先让LED默认为灭
   while(1) //让程序一直循环下去
   {
      if(key == 1) //如果按键没有按下
      {
         LED = 1; //LED为灭
      }
      else if(key == 0) //如果按键按下之后
      {
         LED = 0; //LED为亮
      }
   }
}

有没有感觉很神奇呀,利用一个按键就能控制LED的亮灭,学到这里,你有没有更深层次的理解单片机是什么呢,我觉得包括我在内可能大部分人都知道单片机是个啥,知道他能干些啥,但是吧不知道如何表达,我觉得就是这种感觉,你可能感觉单片机是一个什么东西,但是不怎么能表达出来,那我们就继续加油继续学习!

独立按键消抖

你以为这就结束了???
想什么呢小老弟,hhh。你有没有发现一个问题,就是你在按下按键的时候可能LED不是很亮或者有时候LED在闪烁什么的,那是因为我们没有消抖,那消抖又是什么呢?
有事没事,百度百科,我们怀着鸡冻的心情又打开了百度百科
在这里插入图片描述
可能这句话有点专业,什么机械弹性开关,balabala的,我们用一种简单的语言来说吧,按键上面有一个按的一个区域,我们按下去之后可以自己弹回来,所以这就叫机械弹性开关。而按键按下之后会使本来不通的路导通,正是因为弹性开关的问题,会导致开关抖动,从而一下开一下关。如果你用按下按键,就容易发现,灯在闪。
在这里插入图片描述
现在我们发现了问题,那么怎么解决问题呢?
方案分为硬件消抖和软件消抖,别告诉我你现在还不知道什么是硬件,什么是软件!!!
硬件消抖的方案在这里就不介绍了,如果感兴趣的同学可以自己百度一下是怎么操作的,我在这里就和大家解释一下软件消抖是是怎么弄的。
大家可以根据上图来看得,在按键按下之前会抖动,按下之后会抖动,那我们怎么避开呢?我们一般采用延时的方式,即在第一次检测到按键按下之后,进行一个5ms-10ms的延时,如果按键还是按下的,那我们就执行相应的程序,比如说点一个灯。
下面是一个Visio的流程图,可以方便大家理解
在这里插入图片描述
为啥延时能解决按键抖动的问题呢?因为大家可以看到,我们一开始按下按键的时候是不稳定的,也就是前沿抖动,要过一会过后按键才会稳定在按下的那个状态,所以我们可以通过延时成功的避开按键抖动的那一部分,从而在一个稳定的状态下判定,已经按下。因为单片机的运行速度非常快,如果没有这个延时稳定的话,单片机就可能运行很多次这个判断按键按下,比如说你让
单片机按下按键之后,里面的一个变量加一,如果你能用显示屏显示出来的话你就可能看到,按键每次按下可能不止加一。我会在后面讲串口通信的时候让大家试一试这个问题,并让这个变量显示在电脑屏幕上。关说不练毫无意义,废话少说,上代码!

#include <reg52.h>

sbit key = P3^4;  //这是我们假定的两个io口分别连接按键和LED
sbit LED = P1^0;  //需要自己根据自己手上的开发板的不同进行修改,sbit则是进行位定义
void delay_ms(int z)	//一个简单的延时程序,不是很精准,这里不需要太精准,我们会在后面介绍精准的
{
	int i, j;
	for(i = 0; i < z; i++)
	{
		for(j = 0; j < 122; j++)
		{
			;
		}
	}
}
void main()
{
   LED = 1; //先让LED默认为灭
   while(1) //让程序一直循环下去
   {
      if(key == 0) //如果按键按下
      {
      	 delay_ms(7);	//延时7ms,5-10ms随便取一个吧
      	 if(key == 0) 	//再次判断,如果还是0就说明按键还是按下的
      	 {
			LED = !LED; //LED灯的状态翻转
		 }         
   }
}

这段代码的作用就是,每次按一下按键,led的状态就会翻转,从亮到灭,从灭到亮,这个还是很好玩的。
对于我们来说当然不满足于一个简单的按键!对于我们键盘来说也是一个个像这样的按键组成的,当然键盘对我们来说太过于复杂了,我们从简单的入手吧-------矩阵按键!

矩阵按键以及其工作原理

说到矩阵按键,小灰当年第一次接触的时候一直追问着学长,矩阵键盘为啥叫矩阵键盘啊,哈哈哈我相信你们可能也有这种疑问,为啥子他叫矩阵键盘啊,学长是这么和我说的,因为矩阵键盘排布像一个矩阵,所以他叫矩阵键盘,如此想来还有几分意思hhh。那么我们接下来就开始介绍矩阵键盘吧!
在这里插入图片描述
先放一张图吧,大家根据这张图可以看到矩阵键盘有16个按键,是4x4排布的样式,说道这里,爱思考的人估计就会想到一个问题了,我们之前的按键都是一个引脚对应一个IO口,然后判断那个IO口的状态从而判断按键是否按下,而这里的这个矩阵键盘只有8个引脚引出来显然是不符合4x4=16个按键的规格的,那这是为什么呢?
这要回到我们51单片机上来,大多数51芯片都只有32个引脚可以供我们使用,我们如果一个按键接一个io口,那就16个io用完了(不考虑用锁存器,io口的复用,看不懂没关系),只剩下16个,就很浪费资源。这种时候总有大神能站出来(手动滑稽),走我们去看看原理图上矩阵键盘长啥样子
在这里插入图片描述
是不是又懵圈了呢?哈哈哈没关系我们一点点来,大家从原理图能更清晰的看到矩阵按键的构造,并且有8个引脚引出来,我们可以进一步清晰的看到,以K1为例,他的俩端分别接的是P3.0口,和P3.4口,而在上面我们单个按键是一端接IO口,另一端接到vcc和gnd,按下之前io口连到gnd,是按下之后电平会被拉高,而这里则是按下之后P3.0和P3.4连起来。我相信聪明的同学已经想到办法了,那就是先把一个拉高然后把另外一个拉低,如果那个高电平也变低了那么就说明按键被按下了。
于此同时引出来的8个脚被分成两半,一半可以看做是行,一半可以看做为列,有没有觉得背后发凉!没错,就是我们的x轴和y轴,像一个平面直角坐标系一样。结合上面我们得把一个拉高一个拉低,所以我们先拉低高四位,也就是P3.4-P3.7,让他们都成为“0”,接下来我们再拉高低四位为“1”,举个栗子,我们按下K1之后,我们扫描IO口的状态我们会发现,本来低四位都是“1”,但是现在P3.0变成了高位,这时候我们就会知道,第一行有按键被按下,同理,假如我们是把高四位拉高,低四位拉低,我们又会知道是第一列有按键按下,对应(1,1)这个按键,我们就知道是K1啦!这样我们就能判断所有按键了,想一想,我们可以通过这个玩意做一个计算器,做一个密码锁,是不是有无限可能呢?代码来啦!

//因为小灰最近在忙电赛,和数学建模,没有空专门写一个按键的程序,翻到以前程序里的一个函数,希望大家见谅
uchar Key_scan()
{
	uchar x = 5, y = 5;         //这里我就是定义的一个x,和y作为一个x轴坐标,y轴坐标,5,5是不存在的
	P3 = 0xF0;          //P3,8位口,每一位放到一起就是一个8位的2进制码,转化到16进制就是这个,下面都是这个样子
	switch(P3)		//switch case结构判断
	{
	case 0xE0:  x = 1; break;
	case 0xD0: 	x = 2; break;
	case 0xB0:  x = 3; break;
	case 0x70:  x = 4; break;
	default:		x = 5; break;
	}
	P3 = 0x0F;              //ÐÐɨÃè
	switch(P3)
	{
	case 0x0E: y = 1; break;
	case 0x0D: y = 2; break;
	case 0x0B: y = 3; break;
	case 0x07: y = 4; break;
	default:   y = 5; break;
	}
	while(P3 != 0x0F);				//等待按键松开
	P3 = 0xff;	//P3口全部置1,恢复初始状态
	//下面我就没写了,这里可以作为你的判断内容,打个比方if里面判断到x=1,且y=1,你就知道是哪个按键按下,而5,都是不存在的
	//如果x或y有任何一个为5就说明矩阵按键没有按下
}

这样我们就会使用独立按键,和矩阵按键啦,是不是很简单呢?(我感觉屏幕面前的你可能十分想打我,不要着急,耐下心,你一定会搞懂的,我相信你!)
单独的一个按键感觉十分无聊,你可以写一个程序,比如说,按下哪个按键,LED以某种模式亮灯,就会发现很有趣,可能你还是觉得很无聊,emmm没关系,我们下节课说数码管,当你的输入得到反馈(数码管的显示)你就会觉得很有趣啦,其实真正的乐趣才刚刚开始呢!

写在最后

啊终于写完了这个按键,我前前后后大概写了有一个月吧,因为按键也是小灰掌握的比较薄弱的一块,又加上电赛,和期末,事情比较多,好吧,其实还是我懒hhh,下一篇是数码管,其实算是比较简单(kun nan)一个了(我是不会告诉你们我和我室友说了好久他都没懂这件事的),大家都加油鸭!我是小灰,一个努力用平实的语言写出困难内容的探索者!^ _ ^!

发布了15 篇原创文章 · 获赞 35 · 访问量 3405

猜你喜欢

转载自blog.csdn.net/weixin_44065323/article/details/90708041