51单片机——矩阵键盘扫描(矩阵键盘1602显示及密码锁)

本文介绍了矩阵键盘的结构、工作原理以及51单片机I/O口的不同模式,包括逐行扫描和逐列扫描。通过编程示例展示了如何用矩阵键盘控制LCD1602显示数字,并实现了一个简单的密码锁功能。
摘要由CSDN通过智能技术生成

一、矩阵键盘介绍

1、独立按键和矩阵键盘实物图及其原理图

可以看到矩阵键盘是4*4的一个结构,而独立按键是2*4的结构

从原理图可以看到,二者按键数量虽然不同,但I/O口数量均为8个,这也就是矩阵键盘的优势所在,大大减少了外设对I/O口的使用

独立按键:4个按键为一小组,一端接GND(低电平),另外一端连接4个I/O口,也就是说,通过给予I/O口高低电平进行按键的扫描

矩阵键盘:低四位(接口1234)控制行,高四位(5678)控制列,也就是说整个按键就是一个坐标图,通过(行,列)/(列,行)坐标来进行扫描,从而判断哪个按键被按下。

2、两种扫描方式(逐行扫描、逐列扫描)

两组扫描方式其实原理都一样,区别就在于先扫描行还是先扫描列,如若先扫描行,那就是逐行扫描,反之则就是逐列扫描;

(1)逐行扫描

逐行扫描就是说先扫描第一行中的哪个按键按下了,如果没有再扫描第二行,看一下是不是第二行里的某个按键按下了,如果还没有找到按下的那个按键,那么就继续扫描第三行、第四行,知道找出哪个按键被按下了。

(2)逐列扫描

行列扫描就是说先扫描所有的行,确定是哪一行的按键被按下了,之后再扫描所有的列,找出哪一列有按键被按下了,这样只要扫描两次就可以确定出到底是哪个按键被按下了。

接下来科普一下:

二、传统51单片机I/O口的工作模式

描述:通过前面的输入输出的内容(LED控制与按键的使用),我们对控制I/O口有了一个基本的了解。如果需要输出高低电平,可以对该引脚进行写"1"或者"0";如果需要读取I/O的电平,直接判断该引脚是高电平或者低电平既可。

在程序上对P0 ~ P3的输入输出控制是一样的,但实际上它们内部结构是不一样的

1、开漏输出(双向I/O口)模式(P0)

         输出:可以输出低电平,不能输出高电平(如果需要输出高电平,则引脚端需要在外部接上                      拉电路,增强驱动能力)

         输入:高低电平均可

2、弱上拉模式(准双向I/O口)模式(P1 P2 P3)

         输出:高低电平均可(输出高电平时,驱动能力不强,也就是弱上拉,拉高电平的能力弱

         输入:高低电平均可

实际上所有的I/O都可以在引脚的外部接上拉电阻,增强I/O口的驱动能力,如下图所示为一个最小的单机最小系统原理图。

单片机内部上拉,则电流方向由单片机内部流向外部,称为拉电流

单片机外部上拉,则电流方向由外部流向单片机内部,称为灌电流

三、编程示例

1、LCD1602显示(实现按下哪个按键就显示相应的数字)

#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"

unsigned char KeyNum;

void main()
{
	 LCD_Init();                      //LCD初始化 
	 LCD_ShowString(1,1,"MatrixKey"); //LCD显示字符串
	while(1)
	{ 
		KeyNum = MatrixKey();         //获取矩阵键盘按键键码
	    if(KeyNum)
	  { 
	    LCD_ShowNum(2,1,KeyNum,2);    //输出显示键码
	  }
	}

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


unsigned char MatrixKey()
{
   unsigned char KeyNumber=0;
	
	
	P1 = 0xFF;  //全部行和列都给高电平
	P1_4 = 0;  //只有第一列给予低电平(可以认为只有第一列才进行工作)
		
	if(P1_0==0){Delay(10);while(P1_0==0);Delay(10);KeyNumber=1;} //如果第一行也给予0,那么 
就是第一行第一列的那个按键工作,也就是第一个按键01工作,也就是通过这种十字交叉的形式来确定哪个按键进行工作
	if(P1_1==0){Delay(10);while(P1_1==0);Delay(10);KeyNumber=5;}
	if(P1_2==0){Delay(10);while(P1_2==0);Delay(10);KeyNumber=9;}
	if(P1_3==0){Delay(10);while(P1_3==0);Delay(10);KeyNumber=13;}
	
  P1 = 0xFF;
  P1_5 = 0;
		
	if(P1_0==0){Delay(10);while(P1_0==0);Delay(10);KeyNumber=2;}
	if(P1_1==0){Delay(10);while(P1_1==0);Delay(10);KeyNumber=6;}
	if(P1_2==0){Delay(10);while(P1_2==0);Delay(10);KeyNumber=10;}
	if(P1_3==0){Delay(10);while(P1_3==0);Delay(10);KeyNumber=14;}
	
	P1 = 0xFF;
	P1_6 = 0;
	
	if(P1_0==0){Delay(10);while(P1_0==0);Delay(10);KeyNumber=3;}
	if(P1_1==0){Delay(10);while(P1_1==0);Delay(10);KeyNumber=7;}
	if(P1_2==0){Delay(10);while(P1_2==0);Delay(10);KeyNumber=11;}
	if(P1_3==0){Delay(10);while(P1_3==0);Delay(10);KeyNumber=15;}
		
	P1 = 0xFF;
	P1_7 = 0;
		
	if(P1_0==0){Delay(10);while(P1_0==0);Delay(10);KeyNumber=4;}
	if(P1_1==0){Delay(10);while(P1_1==0);Delay(10);KeyNumber=8;}
	if(P1_2==0){Delay(10);while(P1_2==0);Delay(10);KeyNumber=12;}
	if(P1_3==0){Delay(10);while(P1_3==0);Delay(10);KeyNumber=16;}
	
	return KeyNumber;

2、矩阵键盘密码锁

我们要实现:按键1-10作为数字1-9和0,密码设为四位,通过输入密码判断所输入密码是否正确,给出判断,按键11作为“密码确认”的执行,按键12作为“取消输入”的执行,也就是实现一个普通电子锁的功能。

有了以上的基础之后,我们直接在原本代码基础上进行修改:

第一个难点如何将按键10作为0的输出?-——通过对KeyNum取余,这样子输入1-9还是照常输出1-9,而按下按键10后,取余之后就会当作密码0进行使用,具体代码如下

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

unsigned char KeyNum;
unsigned int Password;  //重新定义一个名为password(密码)的变量

void main()
{
	 LCD_Init();
	 LCD_ShowString(1,1,"Password");   //将显示屏上的第一行字符串改为Password
	while(1)
	{ 
		KeyNum = MatrixKey();      
	    if(KeyNum)
	  { 
			if(KeyNum <= 10)   //如果按键按下且小于等于10
			{
					Password=KeyNum%10;  //就让KeyNum对10取余,再赋值给Password,这样子就能 
                                         //实现按下按键10当作0来使用,避免按键密码缺0的情况
			}
	    LCD_ShowNum(2,1,Password,2);    
	  }
	}

}

第二个难点输入端我们已经解决,那么如何能够让LCD1602从左到右依次显示我们所输入的四位数字?

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

unsigned char KeyNum;
unsigned int Password;

void main()
{
	 LCD_Init();
	 LCD_ShowString(1,1,"Password");
	while(1)
	{ 
		KeyNum = MatrixKey();
	    if(KeyNum)
	  { 
			if(KeyNum <= 10)
			{        
                    Password*=10; //密码左移一位,此时Password默认0,假如按下1,执行接下来的操作,Password此时为1,如果再按下2,再进行一次循环,此时password为10,再执行第二条程序,password便从12,以此类推,这样子就能得到输入的四位密码
					Password+=KeyNum%10;
			}
	    LCD_ShowNum(2,1,Password,4); //将LCD显示数字改为4位,其默认为0000,如果输入1就输出0001
	  }
	}

}

第三个难点:实现以上代码会发现,当我继续输入第五位数字时,第一位数字会被挤掉,怎么样控制输入密码者只能输入4位呢?————添加一个新的变量count再次进行判断,当它小于4时才能被录入

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

unsigned char KeyNum;
unsigned int Password,count;


void main()
{
	 LCD_Init();
	LCD_ShowString(1,1,"Password:");
	while(1)
	{ 
		KeyNum = MatrixKey();
	    if(KeyNum!=0)
	   { 
			if(KeyNum <= 10)
				{
					if(count < 4)
					{
					Password *= 10;
					Password += KeyNum%10;
					count ++;          //只能输入4位数字,超过就不被录入
					} 
                 }
         }
     }
}

第四步:实现“确定密码'按键功能

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

unsigned char KeyNum;
unsigned int Password,count;


void main()
{
	 LCD_Init();
	LCD_ShowString(1,1,"Password:");
	while(1)
	{ 
		KeyNum = MatrixKey();
	    if(KeyNum!=0)
	   { 
			if(KeyNum <= 10)
				{
					if(count < 4)
					{
					Password *= 10;
					Password += KeyNum%10;
					count ++;
					} 
					LCD_ShowNum(2,1,Password,4);
				}	
					if(KeyNum == 11)  //如果按下按键11,就确认密码,接下来进行密码验证
            {
							if(Password == 1125) //如果密码等于1125
                {
								  LCD_ShowString(1,12,"ture"); //显示正确
									Password = 0;              //为了能再次输入密码让其为0
									count = 0;                 //重新计数,再实行上面的操作
									LCD_ShowNum(2,1,Password,4);
								}else                
								   { LCD_ShowString(1,12,"Err"); //如不等于1125就显示错误
										 Password = 0;
									   count = 0;
										 LCD_ShowNum(2,1,Password,4);
									 }
						}

最后一步:实现”取消“功能

以下就是完整代码:

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

unsigned char KeyNum;
unsigned int Password,count;


void main()
{
	 LCD_Init();
	LCD_ShowString(1,1,"Password:");
	while(1)
	{ 
		KeyNum = MatrixKey();
	    if(KeyNum!=0)
	   { 
			if(KeyNum <= 10)
				{
					if(count < 4)
					{
					Password *= 10;
					Password += KeyNum%10;
					count ++;
					} 
					LCD_ShowNum(2,1,Password,4);
				}	
					if(KeyNum == 11)
            {
							if(Password == 1125)
                {
								  LCD_ShowString(1,12,"ture");
									Password = 0;
									count = 0;
									LCD_ShowNum(2,1,Password,4);
								}else
								   { LCD_ShowString(1,12,"Err");
										 Password = 0;
									   count = 0;
										 LCD_ShowNum(2,1,Password,4);
									 }
						}
			} if(KeyNum == 12)      //如果按下按键12
		     {
					Password = 0;   //密码归0,重新输入,实现“取消”功能
					count = 0;
					LCD_ShowNum(2,1,Password,4);
			   }
	 }
}

  • 42
    点赞
  • 70
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值