51 单片机[6]:矩阵键盘及密码锁

一、认识矩阵键盘

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

img

扫描的概念

数码管扫描(输出扫描)
原理:显示第1位→显示第2位→显示第3位→……,然后快速循环这个过程,最终实现所有数码管同时显示的效果

矩阵键盘扫描(输入扫描)
原理:读取第1行(列)→读取第2行(列) →读取第3行(列) → ……,然后快速循环这个过程,最终实现所有按键同时检测的效果

以上两种扫描方式的共性:节省I/O口

单片机的I/O口是弱上拉、强下拉

img

当引脚输出为1时,驱动能力很弱,允许外部装置将其拉低。当引脚输出为低时,它的驱动能力很强,可吸收相当大的电流

二、简单的矩阵键盘实现

目标 :按下按键后,LCD屏显示键码。

把上节的Delay.c、Delay.h和LCD1602.c、LCD1602.h复制到项目中。

新建一个MatrixKey.c文件和MatrixKey.h

  1. 点击templates,在空白处右键,点击configure templates

img

  1. 点击新建图标,输入#ifndef,在Text中输入模板内容,点击OK

img

注意,要在下划线中间打一个竖杠,这样在点击模板后,光标会出现在该位置。

  1. 在MatrixKey.h文件中编辑,双击#ifndef,可以看到

img

在光标处输入MATRIXKEY

完整的MatrixKey.h文件内容为:

#ifndef __MATRIXKEY__H__
#define __MATRIXKEY__H__

unsigned char MatrixKey();

#endif
  1. 矩阵键盘的输入扫描要先确定列,再确定行。完整的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;//扫描第一列
	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;//扫描第二列
	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;//扫描第三列
	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;//扫描第四列
	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;
}
  1. main.c文件:
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"

unsigned char KeyNum;

void main()
{
	LCD_Init();//上电初始化
	LCD_ShowString(1, 1, "MatrixKey");
	while(1)
	{
		KeyNum=MatrixKey();
		if(KeyNum)
		{
			LCD_ShowNum(2, 1, KeyNum, 2);
		}
	}
}

三、矩阵键盘密码锁

目标:S1 ~ S9为数字1 ~ 9,S10为0,S11为确认,S12为取消。

把刚刚的简单项目复制一份,在旧项目的基础上进行过更改。

  1. 先实现一位数字输出。main.c文件如下:
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"

unsigned char KeyNum;
unsigned int Passward;

void main()
{
	LCD_Init();//上电初始化
	LCD_ShowString(1, 1, "Passward:");
	while(1)
	{
		KeyNum=MatrixKey();
		if(KeyNum)
		{
			if(KeyNum<=10)  //是否按下S1~S10
			{
				Passward = KeyNum%10;  //获取一位密码
			}
			LCD_ShowNum(2, 1, Passward, 2);
		}
	}
}

按下S1,LCD显示01,按下S2,LCD显示02……按下S10,LCD显示00.

  1. 实现输入一串数字
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"

unsigned char KeyNum;
unsigned int Passward;

void main()
{
	LCD_Init();//上电初始化
	LCD_ShowString(1, 1, "Passward:");
	while(1)
	{
		KeyNum=MatrixKey();
		if(KeyNum)
		{
			if(KeyNum<=10)  //是否按下S1~S10
			{
				Passward *= 10;         //密码左移一位
				Passward += KeyNum%10;  //获取一位密码
			}
			LCD_ShowNum(2, 1, Passward, 4);
		}
	}
}

这个程序好像可以实现密码输入。按下S1,显示0001,按下S3,显示0013。但是当数字很大超出数据范围时,密码就出现错误了,显示的数字就不按按下的按键显示了。

所以就需要计次。定义一个变量Count

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

unsigned char KeyNum;
unsigned int Passward, Count;

void main()
{
	LCD_Init();//上电初始化
	LCD_ShowString(1, 1, "Passward:");
	while(1)
	{
		KeyNum=MatrixKey();
		if(KeyNum)
		{
			if(KeyNum<=10)  //是否按下S1~S10
			{
				if(Count<4)
				{
					Passward *= 10;         //密码左移一位
					Passward += KeyNum%10;  //获取一位密码
				}
				Count++;
			}
			LCD_ShowNum(2, 1, Passward, 4);
		}
	}
}
  1. 验证密码,若正确则OK,否则ERR
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"

unsigned char KeyNum;
unsigned int Passward, Count;

void main()
{
	LCD_Init();//上电初始化
	LCD_ShowString(1, 1, "Passward:");
	while(1)
	{
		KeyNum=MatrixKey();
		if(KeyNum)
		{
			if(KeyNum<=10)  //是否按下S1~S10
			{
				if(Count<4)  //次数判断
				{
					Passward *= 10;         //密码左移一位
					Passward += KeyNum%10;  //获取一位密码
					Count++;  //计次加一
				}
				LCD_ShowNum(2, 1, Passward, 4);
			}
			if(KeyNum == 11)  //是否按下S11确认
			{
				if(Passward == 4399)
				{
					LCD_ShowString(1, 14, "OK");
				}
				else
				{
					LCD_ShowString(1, 14, "ERR");
				}
			}
		}
	}
}

再加上清零和更新显示

			if(KeyNum == 11)  //是否按下S11确认
			{
				if(Passward == 4399)
				{
					LCD_ShowString(1, 14, "OK ");
					Passward = 0;  //密码清零
					Count = 0;     //计次清零
					LCD_ShowNum(2, 1, Passward, 4);  //更新显示
				}
				else
				{
					LCD_ShowString(1, 14, "ERR");
					Passward = 0;  //密码清零
					Count = 0;     //计次清零
					LCD_ShowNum(2, 1, Passward, 4);  //更新显示
				}
			}
  1. 按下取消,清零
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"

unsigned char KeyNum;
unsigned int Passward, Count;

void main()
{
	LCD_Init();//上电初始化
	LCD_ShowString(1, 1, "Passward:");
	while(1)
	{
		KeyNum=MatrixKey();
		if(KeyNum)
		{
			if(KeyNum<=10)  //是否按下S1~S10
			{
				if(Count<4)  //次数判断
				{
					Passward *= 10;         //密码左移一位
					Passward += KeyNum%10;  //获取一位密码
					Count++;  //计次加一
				}
				LCD_ShowNum(2, 1, Passward, 4);
			}
			if(KeyNum == 11)  //是否按下S11确认
			{
				if(Passward == 4399)
				{
					LCD_ShowString(1, 14, "OK ");
					Passward = 0;  //密码清零
					Count = 0;     //计次清零
					LCD_ShowNum(2, 1, Passward, 4);  //更新显示
				}
				else
				{
					LCD_ShowString(1, 14, "ERR");
					Passward = 0;  //密码清零
					Count = 0;     //计次清零
					LCD_ShowNum(2, 1, Passward, 4);  //更新显示
				}
			}
			if(KeyNum == 12)  //是否按下S12取消
			{
				Passward = 0;  //密码清零
				Count = 0;     //计次清零
				LCD_ShowNum(2, 1, Passward, 4);  //更新显示
			}
		}
	}
}
  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值