矩阵键盘

矩阵键盘一般和之前学的LCD1602液晶屏一起控制,建议先看一下之前的博客学习一下液晶屏的使用。

当然矩阵键盘也可以和数码管和LED等一起操作,但是数码管需要扫描,很费CPU,LED又不能直观的看到键盘的操作。用LCD1602来学习矩阵键盘比较合适。

简介

在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排成矩阵形。

采用逐行或逐列扫描,就可以读出任意位置按键的状态。

解释一下

image.png

从原理图中我们可以看到,独立按键每个按键要使用一个I/O口,而矩阵键盘只用了8个I/O口。

假如矩阵键盘用独立按键的控制方式,四行四列需要16个I/O口。但是采用了扫描的控制方式后,我们只用了4+4=8个I/O口。

扫描的原理:

我们之前了解过数码管的扫描,叫做输出扫描。从第一位依此往下扫描到最后一位,然后快速循环,最终实现所有数码管同时显示。优点是解决了多位数码管不能在同一时间显示不同数字的情况,缺点是很费CPU。这里比较难理解,可以看看之前分析动态数码管的博客

矩阵键盘的扫描叫做输入扫描。单片机读取每一行(列)的状态,然后快速循环,最终实现所有按键同时检测的效果。

扫描也是显示器的一种显示方式,里面也有很多学问,感兴趣的朋友们可以去学习一下

原理

现在说一下矩阵键盘的使用原理。

大家想象一下,假如把矩阵键盘的第一行,全部接地(即P17赋值为0),那么是不是第一行就变成了一组独立按键呢?这个时候我们判断一下P10~P3是否位0,就能看出哪个按键按下了。(如果按键按下,说明和P17短路了,对应的管脚口肯定就是是0了)

image.png

那么扫描第一行的方式就是:P17赋值为0,P16~P14赋值为1,判断P10~P13哪个为零,对应的按键就按下了。比如这个时候我们检测到P11为零, 说明S3按键按下了。

以此类推,扫描第二行的方式就是:P16赋值为0,P17,P15,P14赋值为1,判断P10~P13哪个为零。……这种方法叫做逐行扫描。

同理,我们也可以用逐列扫描,先依次给P10~ P13低电平,依次判断P14~P17的电平,来判断哪个按键被按下了。

弱上拉(强下拉)模式

再来了解一下弱上拉模式:具有较弱的拉高电平或电位的能力,虽然弱,但是能够实现电平改变。

说人话,比如扫描第一行按键,P17赋值0,我们以前说过,单片机上电后每个I/O都是高电平,我们按下S1,P13和P17短接,我们的单片机是弱上拉模式,拉高电平能力有限,所以P13口的电平才能够被拉低。P13就变成了低电平。假如这是一个强上拉模式的单片机,那么即使P17被赋低电平,按下S1,P13的电平也不能够被拉低,因为单片机上电后的电平被强上拉了。

内部原理

image.png

画个草图,单片机内部是这样的,上电后,VCC和单片机读取电平的部分连接,这样I/O口就会输出高电平,同时单片机读取到高电平。

施密特触发器是数电里的一个知识点,是一种正反馈比较器,内部有高电阻。当外部接地后,强电流会趋向于往电阻较低的方向流,相当于节点和触发器那一部分断开了,这样单片机就读取不到电平了。

如果大家的数电模电底子比较扎实,应该很容易理解这个意思。当然没有看明白的朋友也不必担心,这些都是了解性内容,大概知道一下就行

除了弱上拉模式,单片机还有推挽输出(没有上拉电阻,高电平直接接VCC,低电平直接接GND)、高阻输入(既没有上拉,也没有下拉)、开漏输出……这些模式是嵌入式和开关电源的知识点,我们的管脚口是可以自由配置。现在不用理解太深,以后会再提。

大家可以在我们STC89C52的手册上查看一下

image.png

写代码

新建工程

同时去以前我们写过的工程里,把LCD1602的驱动和Delay的模块复制并添加进来。

image.png

image.png

编译好之后,我们会发现下面有一下关于函数定义的报错,其实影响不大,如果觉得碍眼可以关掉。

image.png

添加模块MatrixKey

image.png

生成.h的模板

我们在左侧的工具栏点击Functions就可以看到我们在各个文件内定义的函数了。

image.png

同样,点击books就可以看到一些官方给的参考资料。

点击Templates能够看到官方给的模板,点击就可以直接生成这些模板。

image.png

当然我们也可以自己配置模板,右键选择“Cofigure Templates”,来修改自己的配置。

按照如下操作,来添加一个模板吧!

image.png

#ifndef __|_H__
#define 



#endif

第一行的 “|“ 意思是生成模板后光标的位置。

MatrixKey文件

根据自己学到的内容,写如下代码

//MatrixKey.c
#include <REGX52.H>//我们用到了管脚口,所以需要导入这个头文件,它里面
//定义了各个管教口的地址
#include "Delay.H"//我们用到了延时函数,所以需要导入这个头文件

unsigned char Matrixkey()
{
	//我们用逐列扫描
	unsigned char KeyNumber = 0;
	//第一列
	P1 = 0xFF;//给P1的所有管脚口置1
	P1_3 = 0;
	if(P1_7==0) 
	{
		Delay(20);//消抖
		While(P1_7==0);//检测松手
		Delay(20);//消抖
		KeyNumber = 1;//赋值S1 
	}
	if(P1_6==0) 
	{
		Delay(20);//消抖
		While(P1_7==0);//检测松手
		Delay(20);//消抖
		KeyNumber = 5;//赋值S1 
	}
	if(P1_5==0) 
	{
		Delay(20);//消抖
		While(P1_7==0);//检测松手
		Delay(20);//消抖
		KeyNumber = 9;//赋值S1 
	}
	if(P1_4==0) 
	{
		Delay(20);//消抖
		While(P1_7==0);//检测松手
		Delay(20);//消抖
		KeyNumber = 13;//赋值S1 
	}
	//第二列
	P1 = 0xFF;//给P1的所有管脚口置1
	P1_2 = 0;
	if(P1_7==0) {Delay(20);While(P1_7==0);Delay(20);KeyNumber = 2; }
	if(P1_6==0) {Delay(20);While(P1_6==0);Delay(20);KeyNumber = 6; }
	if(P1_5==0) {Delay(20);While(P1_5==0);Delay(20);KeyNumber = 10; }
	if(P1_4==0) {Delay(20);While(P1_4==0);Delay(20);KeyNumber = 14; }
	//第三列
	P1 = 0xFF;//给P1的所有管脚口置1
	P1_1 = 0;
	if(P1_7==0) {Delay(20);While(P1_7==0);Delay(20);KeyNumber = 3; }
	if(P1_6==0) {Delay(20);While(P1_6==0);Delay(20);KeyNumber = 7; }
	if(P1_5==0) {Delay(20);While(P1_5==0);Delay(20);KeyNumber = 11; }
	if(P1_4==0) {Delay(20);While(P1_4==0);Delay(20);KeyNumber = 15; }
	//第四列
	P1 = 0xFF;//给P1的所有管脚口置1
	P1_0 = 0;
	if(P1_7==0) {Delay(20);While(P1_7==0);Delay(20);KeyNumber = 4; }
	if(P1_6==0) {Delay(20);While(P1_6==0);Delay(20);KeyNumber = 8; }
	if(P1_5==0) {Delay(20);While(P1_5==0);Delay(20);KeyNumber = 12; }
	if(P1_4==0) {Delay(20);While(P1_4==0);Delay(20);KeyNumber = 16; }
	return KeyNumber;
}

以上是我们比较容易判断的代码,当然我们也可以看一看单片机给的例程,学习一下矩阵键盘的代码,不过那种代码的逻辑比较复杂,不太好理解。

头文件如下:

//MatrixKey.h
#ifndef __MatrixKey_H__
#define __MatrixKey_H__

unsigned char Matrixkey();

#endif

主函数的内容:

#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"

unsigned char KeyNum;//定义变量来保存矩阵键盘函数的返回值

void main()
{
	LCD_Init();//这行代码必须写,不然后面怎么写我们的显示平也用不了
	LCD_ShowString(1,1,"HelloWorld!");
	while(1)
	{
		KeyNum = MatrixKey();
		if(KeyNum)	
		{
			LCD_ShowNum(2,1,KeyNum,2);
		}
	}
}

烧录程序就能看到,按下按键,显示屏第一行显示Hello world,第二行显示按下的键码值。

试着自己写注释

创建一个模板,名字叫做:@brief,brief是内容说明,param是参数说明,retval是返回值说明。有了这个模板,我们以后模块化编程的时候就更方便写注释方便自己和别人阅览。

image.png

/**
  * @brief	|
  * @param
  * @retval
*/

给我们的工程加上这段注释,那么MatrixKey.c文件前面就会有这么一段话

image.png

转自:https://blog.csdn.net/Destiny_Di/article/details/126924265