51单片机从零开始入门教程 第六章(矩阵键盘篇)

本文介绍了矩阵键盘的工作原理,包括按行和按列扫描方式,并详细展示了如何在开发板上实现矩阵按键读取和在液晶屏上显示键码,以及矩阵键盘在密码锁中的应用。

参考教程:[6-1] 矩阵键盘_哔哩哔哩_bilibili

一、概述

1、矩阵键盘的作用

        当键盘中的按键数量较多时,为了减少对MCU I/O口资源的占用,通常将按键排列成矩阵形式,MCU逐行或逐列地“扫描”矩阵每行或每列的电平状态,就可以读出任何位置按键的状态

2、两种扫描方式

(1)数码管扫描(输出扫描):

        这种扫描方式在第四章中有介绍,流程为“显示第1位→显示第2位→显示第3位→……”,快速循环这个过程,最终实现所有数码管同时显示不同数字的效果

(2)矩阵键盘扫描(输入扫描):

        数码管扫描是轮流控制不同位的输出,矩阵键盘扫描则是轮流读取不同行(或列)的输入,流程为“读取第1行(或列)→读取第2行(或列)→读取第3行(或列)→……”,快速循环这个过程,最终实现同时检测所有按键状态的效果

二、开发板原理图中的矩阵按键模块

1、矩阵按键的组成

        矩阵按键模块中有16个按键,它们按照4×4的方式排列,与它们相连接的是P1寄存器对应的8个I/O口,其中P10-13对应矩阵按键模块的每一列,P14-17对应矩阵按键的每一行

2、矩阵键盘的扫描方式

(1)按行扫描:

①如果扫描第一行,那么先将P17(第一行对应的I/O引脚)配置为低电平,P16、P15、P14配置为高电平,然后检测P10-13,其中哪一个输入I/O是低电平,那么该I/O对应列的第一行那个按键就是处于被按下的状态。

②如果扫描第二行,那么先将P16(第二行对应的I/O引脚)配置为低电平,P17、P15、P14配置为高电平,然后检测P10-13,其中哪一个输入I/O是低电平,那么该I/O对应列的第二行那个按键就是处于被按下的状态。

③第三行、第四行的扫描是类似的,这里不再赘述。

(2)按列扫描:

①如果扫描第一列,那么先将P13(第一列对应的I/O引脚)配置为低电平,P12、P11、P10配置为高电平,然后检测P14-17,其中哪一个输入I/O是低电平,那么该I/O对应行的第一列那个按键就是处于被按下的状态。

②如果扫描第二列,那么先将P12(第二列对应的I/O引脚)配置为低电平,P13、P11、P10配置为高电平,然后检测P14-17,其中哪一个输入I/O是低电平,那么该I/O对应行的第二列那个按键就是处于被按下的状态。

③第三列、第四列的扫描是类似的,这里不再赘述。

(3)对于本教程使用的开发板,建议采用按列扫描,若使用按行扫描,P15的电平会忽高忽低,可能影响蜂鸣器,从而造成异常现象,当然,这个具体取决于开发板的原理图,并不是所有开发板都有此异常现象。

​​​​​​​

三、矩阵键盘应用实验

1、在液晶屏上显示被按下的矩阵按键序号实验

(1)项目包含的文件:其中Delay.c、Delay.h、LCD1602.c及LCD1602.h全部沿用上一例的代码,这里不再给出,INTRINS.H及REGX52.H在系统include目录中,不需要自己编写。

(2)将源文件及头文件添加到项目中,然后进行编译。

①MatrixKey.c文件:

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

/**
  * @brief  矩阵键盘读取按键键码
  * @param  无
  * @retval KeyNumber 按下按键的键码值
		   如果按键按下不放,程序会停留在该函数中,松手后才会返回键码值
		   没有按键按下,函数返回0
  */

unsigned char MatrixKey()
{
	unsigned char KeyNumber = 0;  //用该变量记录被按下的按键
	
	P1 = 0xFF;   //按列扫描,首先扫描第一列
	P1_3 = 0;    //P1_3对应第一列,置为低电平,其它三位置为高电平
	
	if(P1_7 == 0)
	{
		Delay(20);  //按键消抖
		while(P1_7 == 0);
		Delay(20);
		KeyNumber = 1;  //第一列第一行
	}
	if(P1_6 == 0)
	{
		Delay(20);  //按键消抖
		while(P1_6 == 0);
		Delay(20);
		KeyNumber = 5;  //第一列第二行
	}
	if(P1_5 == 0)
	{
		Delay(20);  //按键消抖
		while(P1_5 == 0);
		Delay(20);
		KeyNumber = 9;  //第一列第三行
	}
	if(P1_4 == 0)
	{
		Delay(20);  //按键消抖
		while(P1_4 == 0);
		Delay(20);
		KeyNumber = 13;  //第一列第四行
	}
	
	P1 = 0xFF;   //接着扫描第二列
	P1_2 = 0;    //P1_2对应第二列,置为低电平,其它三位置为高电平
	
	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 = 0;    //P1_1对应第三列,置为低电平,其它三位置为高电平
	
	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_0 = 0;    //P1_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

③main.c文件:

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

unsigned char KeyNum = 0;

void main()
{
	LCD_Init();  //初始化
	while(1)
	{
		KeyNum = MatrixKey();
		if(KeyNum)  //如果有按键按下
		{
			LCD_ShowNum(1,1,KeyNum,2);  //屏幕显示按下的按键序号
		}
	}
}

(3)将生成的.hex文件下载到开发板中,按下矩阵按键,屏幕上会显示按键对应的键码值。

2、矩阵键盘密码锁实验

(1)项目包含的文件:其中MatrixKey.c、MatrixKey.h、Delay.c、Delay.h、LCD1602.c及LCD1602.h全部沿用上一例的代码,这里不再给出,INTRINS.H及REGX52.H在系统include目录中,不需要自己编写。

(2)将源文件及头文件添加到项目中,在main.c文件中输入以下代码,然后进行编译。

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

unsigned char KeyNum = 0;
unsigned int Password;  //4位密码(32位,4个字节)
unsigned char Count = 0;  //记录已输入密码位数

void main()
{
	LCD_Init();  //初始化
	LCD_ShowString(1,1,"Password:");
	LCD_ShowNum(2,1,Password,4);
	while(1)
	{
		KeyNum = MatrixKey();
		if(KeyNum)  //如果有按键按下
		{
			if(KeyNum <= 10)  //如果s1-s10按键按下,输入密码
			{
				if(Count < 4)
				{
					Password *= 10;  //把上一位密码左移(给下一位密码腾出位置)
					Password += KeyNum % 10;  //获取输入的1位密码
				}
				Count++;
			}
			if(KeyNum == 11)  //s11作为确认键
			{
				if(Password == 2345)
				{
					LCD_ShowString(1,14,"OK");  //密码正确显示OK
					Delay(5000);  //停留5秒
					Password = 0;  //密码清零
					Count = 0;  //计数清零
					LCD_ShowNum(2,1,Password,4);  //更新显示
					LCD_ShowString(1,14,"   ");
				}
				else
				{
					LCD_ShowString(1,14,"ERR");  //密码错误显示ERR
					Delay(5000);  //停留5秒
					Password = 0;  //密码清零
					Count = 0;  //计数清零
					LCD_ShowNum(2,1,Password,4);  //更新显示
					LCD_ShowString(1,14,"   ");
				}
			}
			if(KeyNum == 12)  //s12作为手动清空输入键
			{
				Password = 0;  //密码清零
				Count = 0;  //计数清零
				LCD_ShowNum(2,1,Password,4);  //更新显示
			}
			LCD_ShowNum(2,1,Password,4);  //显示当前输入的密码
		}
	}
}

(3)将生成的.hex文件下载到开发板中进行测试。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zevalin爱灰灰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值