五、用矩阵键盘实现密码锁

您所在的位置:网站首页 按键式6位密码门锁怎么破解 五、用矩阵键盘实现密码锁

五、用矩阵键盘实现密码锁

2024-07-11 20:19| 来源: 网络整理| 查看: 265

矩阵键盘

独立键盘与单片机进行连接时,每一个按键都需要单片机的一个I/O口,若某单片机系统较多按键,如果用独立按键便会占用较多的I/O口资源。为了尽可能节省I/O口线,引入矩阵键盘。

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

image-20221103204438277

以巫妖王单片机上的4×4矩阵键盘为例,讲解矩阵键盘的原理和检测方法,其原理图如上图所示。将16个按键排成4行4列,第一行将每个按键的一端连接在一起构成行线,第一列将每个按键的另一端连接在一起构成列线,这样一共有4行4列共八根线,我们将这八根线连接到单片机的8个I/O口上,通过程序扫描键盘就可检测16个键。用这种办法我们也可以实现3行3列9个键,5行5列25个键等。

无论是独立键盘还是矩阵键盘,单片机检测其是否被按下的依据都是一样的,也就是检测与该键对应的I/O口是否为低电平。独立键盘有一端固定为低电平,单片机写程序检测时比较方便,但是矩阵键盘两端都与单片机I/O口相连,因此在检测时需要人为通过单片机的I/O口送出低电平。

下面着重介绍一下扫描的概念:

数码管扫描(输出扫描)

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

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

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

以按行扫描为例:

当P1.4-P1.7口赋值为1101时,此时先看P17所在的行,无论S1、S2、S3和S4谁按下,两端都是高电平,同理P15和P14同样如此,而P16所在的行因为P1.6口赋值为0,只要在此基础检测P1.0-P1.3口电平情况就可以判断究竟是S5、S6、S7还是S8被按下。具体的说,当P1.4-P1.7口赋值为1101时,如果P1.0-P1.3口赋值为:1110(P1 .3为0),则S5被按下,其他同理,并以此类推即可。

在写代码前,再介绍C51子函数带返回值的写法

//格式 类型 函数名(形参) { 函数体; return 数据; } 例如: int getSum(int num1,int num2) { int sum = num1 + num2; return sum; } //参数是 函数接收外面传进来的 //返回值 是函数从里面扔出去的 模块化代码

各模块具体代码如下

主函数main()

#include #include "Delay.h" #include "LCD1602.h" #include "MaxtrixKey.h" unsigned char KeyNum; //定义变量 接一下返回值 void main() { LCD_Init(); LCD_ShowString(1,1,"Hello World!"); while(1) { KeyNum=MaxtrixKey(); if(KeyNum) { LCD_ShowNum(2,1,KeyNum,2); } } } /* 为什么需要加上if(KeyNum)进行判断,这是因为如果不加的话有一下一种情况: 当你没有按下键时,开始执行KeyNum=MaxtrixKey()语句,即KeyNum通过调用MaxtrixKey函数获取键值,此时KeyNum获取的值为0(不按下键,MaxtrixKey函数内的值就是初始化的值0) 然后开始执行LCD_ShowNum函数,这样1602上就会显示00 当你按下某个键,不松手,会卡在执行KeyNum=MaxtrixKey()语,显示0 显示的键值和显示0 间隔的时间太短 以至于人眼无法识别 */

MaxtrixKey.h

#ifndef__MAXTRIXKRY_H__ #define__MAXTRIXKRY_H__ unsigned char MaxtrixKey(); #endif

MaxtrixKey.c

#include #include "Delay.h" /** * @brief 矩阵键盘读取按键键码 * @param 无 * @retval KeyNumer 按下按键的键码值 如果按下不放,程序会停留在此函数,松手一瞬间,返回按键码,没有按键时,返回0 */ unsigned char MaxtrixKey() { 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; }

LCD1602.h定义如下

#ifndef __LCD1602_H__ #define __LCD1602_H__ //用户调用函数: void LCD_Init(); void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char); void LCD_ShowString(unsigned char Line,unsigned char Column,char *String); void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length); void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length); void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length); void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length); #endif

LCD1602.c定义如下

#include //引脚配置: sbit LCD_RS=P2^6; sbit LCD_RW=P2^5; sbit LCD_EN=P2^7; #define LCD_DataPort P0 //函数定义: /** * @brief LCD1602延时函数,12MHz调用可延时1ms * @param 无 * @retval 无 */ void LCD_Delay() { unsigned char i, j; i = 2; j = 239; do { while (--j); } while (--i); } /** * @brief LCD1602写命令 * @param Command 要写入的命令 * @retval 无 */ void LCD_WriteCommand(unsigned char Command) { LCD_RS=0; LCD_RW=0; LCD_DataPort=Command; LCD_EN=1; LCD_Delay(); LCD_EN=0; LCD_Delay(); } /** * @brief LCD1602写数据 * @param Data 要写入的数据 * @retval 无 */ void LCD_WriteData(unsigned char Data) { LCD_RS=1; LCD_RW=0; LCD_DataPort=Data; LCD_EN=1; LCD_Delay(); LCD_EN=0; LCD_Delay(); } /** * @brief LCD1602设置光标位置 * @param Line 行位置,范围:1~2 * @param Column 列位置,范围:1~16 * @retval 无 */ void LCD_SetCursor(unsigned char Line,unsigned char Column) { if(Line==1) { LCD_WriteCommand(0x80|(Column-1)); } else if(Line==2) { LCD_WriteCommand(0x80|(Column-1+0x40)); } } /** * @brief LCD1602初始化函数 * @param 无 * @retval 无 */ void LCD_Init() { LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵 LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关 LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动 LCD_WriteCommand(0x01);//光标复位,清屏 } /** * @brief 在LCD1602指定位置上显示一个字符 * @param Line 行位置,范围:1~2 * @param Column 列位置,范围:1~16 * @param Char 要显示的字符 * @retval 无 */ void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char) { LCD_SetCursor(Line,Column); LCD_WriteData(Char); } /** * @brief 在LCD1602指定位置开始显示所给字符串 * @param Line 起始行位置,范围:1~2 * @param Column 起始列位置,范围:1~16 * @param String 要显示的字符串 * @retval 无 */ void LCD_ShowString(unsigned char Line,unsigned char Column,char *String) { unsigned char i; LCD_SetCursor(Line,Column); for(i=0;String[i]!='\0';i++) { LCD_WriteData(String[i]); } } /** * @brief 返回值=X的Y次方 */ int LCD_Pow(int X,int Y) { unsigned char i; int Result=1; for(i=0;i0;i--) { LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0'); } } /** * @brief 在LCD1602指定位置开始以有符号十进制显示所给数字 * @param Line 起始行位置,范围:1~2 * @param Column 起始列位置,范围:1~16 * @param Number 要显示的数字,范围:-32768~32767 * @param Length 要显示数字的长度,范围:1~5 * @retval 无 */ void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length) { unsigned char i; unsigned int Number1; LCD_SetCursor(Line,Column); if(Number>=0) { LCD_WriteData('+'); Number1=Number; } else { LCD_WriteData('-'); Number1=-Number; } for(i=Length;i>0;i--) { LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0'); } } /** * @brief 在LCD1602指定位置开始以十六进制显示所给数字 * @param Line 起始行位置,范围:1~2 * @param Column 起始列位置,范围:1~16 * @param Number 要显示的数字,范围:0~0xFFFF * @param Length 要显示数字的长度,范围:1~4 * @retval 无 */ void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length) { unsigned char i,SingleNumber; LCD_SetCursor(Line,Column); for(i=Length;i>0;i--) { SingleNumber=Number/LCD_Pow(16,i-1)%16; if(SingleNumber0;i--) { LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0'); } }

Delay.h

#ifndef __DELAY_H__ // #define __DELAY_H__ void Delay(unsigned int xms); #endif

Delay.c

void Delay(unsigned int xms) //@12.000MHz { while(xms--) { unsigned char i, j; i = 2; j = 239; do { while (--j); } while (--i); } } 密码锁

在上面的基础上模块化的代码上,只需要改动主函数mian()即可实现,因此,下面就只给出主函数密码

#include #include "Delay.h" #include "LCD1602.h" #include "MaxtrixKey.h" unsigned char KeyNum; //定义变量 接一下返回值 unsigned int PassWord,Count; //定义四位密码和计数器 void main() { LCD_Init(); LCD_ShowString(1,1,"PassWord:"); while(1) { KeyNum=MaxtrixKey(); if(KeyNum) { if(KeyNum


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3