使用51单片机实现矩阵键盘密码锁的方法和步骤

目录

  • 实验目的
  • 实验现象
  • 硬件
  • 程序
  • 扫描函数
  • 主函数
  • 代码
  • main.c
  • matrixKeyboard.h
  • matrixKeyboard.c
  • Delay.h
  • Delay.c
  • 其他
  • 实验目的

    使用51单片机的矩阵键盘模块以及led1602显示屏,实现模拟密码锁。

    实验现象

    当程序烧录到单片机中后,led1602屏幕会显示文字。

    第一行会显示单词“PASSWORD”,第二行显示4个0,表示我们要写入的四位密码,每位默认为0。

    矩阵键盘前两行与第三行的前两个分别代表输入1-9与0,第三行第三个按钮表示删除,第三行第四个按钮表示确认。

    依次按下第一行的前三个按钮后,屏幕显示输入“0123”。

    按下确认键后,若输入的密码就是设置的密码(这里是0123),显示“SUCCESS”字样,如下图:

    反之,当输入的密码错误的时候,显示“FAIL”字样,并在5秒后回到输入密码界面,如下图:

    当按下删除键时,删除最近输入的值,例如当前输入内容是“1234”,那么在按下删除键后将显示“0123”,如下图:

    除了上述功能,当已经输入了四位数的时候,单片机将不再继续接受数据;当单片机数据为四个0的时候,按下删除键后单片机将不再继续删除数字。

    硬件

    本实验使用到4*4矩阵键盘,其内部结构图如下:

    我们可以将独立按键的原理应用到矩阵键盘上。当独立按键被按下后,若有一端接地,那么另一端也将被置于低电平。矩阵键盘同理,当键盘上某个按键被按下后,如果它有一端为低电平(相当于接地),那么另一端也会被置0。

    由此可见,想要找到被按下的那个按钮,如要对每个按钮进行如下操作:“先将按钮的一端置低电平,再监测按钮的另一端是否也为低电平。如果是,那么被按下的就是这个按钮”。

    由上图可知,矩阵键盘16个按钮用8根线串在一起,每一行的按钮或者每一列的按钮用一根线连在一起,大大降低了GPIO口占用。P10到P13分别将第四列到第一列的按钮绑在一起,P14到P17分别将第四行到第一行的按钮绑在一起。

    查找被按下的按钮时,可以按以下方式查找:

    1. 将P1口全部置高电平

    2. 将第i列的GPIO口置低电平(开始时i等于1,GPIO口就是P13)

    3. 依次检查第一行到第四行的GPIO口电平情况(P17到P14),有低电平的话就是这个按钮被按下

    4. 扫描完这一列,没有低电平,说明这一列没有被按下的,i+1后执行第二步

    5. 如果扫描四列都没有,说明没有按下的按钮。

    程序

    首先这个程序要在跑起来后,不断地对键盘进行扫描,如果扫描到了被按下的按钮,就执行对应的操作。

    因此应当有一个带有返回值的函数,这个函数用于返回被按下的按钮编号。主函数中循环执行这个函数,直到返回按钮的数值:

    unsigned short scan();//扫描键盘,有按钮被按下就返回编号,否则返回0
    
    int main(){
    	unsigned short res = 0;
    	while(1){
    		res = scan();
    		if(res != 0){
    			//扫描到被按下的按钮,执行对应操作
    		}
    	}
    }
    

    扫描函数

    上面的scan()函数就是执行扫描键盘的函数。在scan中,要实现对四列的扫描,要先初始化P1,再将要扫描的那一列的GPIO口置0,再看每一行的电平。

    由于要扫描四列,因此我写了四个函数,在scan中依次执行这四个函数,并返回数值。

    unsigned short scanColumn1();
    unsigned short scanColumn2();
    unsigned short scanColumn3();
    unsigned short scanColumn4();
    unsigned short scan(){
    	unsigned short res = 0;
    	res = scanColumn1();
    	if (res != 0) return res;
    	res = scanColumn2();
    	if (res != 0) return res;
    	res = scanColumn3();
    	if (res != 0) return res;
    	res = scanColumn4();
    	if (res != 0) return res;
    	return 0;
    }
    
    unsigned short scanColumn1(){
    	P1 = 0xff;//初始化P1口
    	P1_3 = 0;//第一列GPIO口置低电平
    	if (P1_7==0){//第一行有没有变成0
        	delay(20);//消抖
    		while(P1_7==0);
    		delay(20);
    		return 1;//返回按钮编号
    	}
    	else if (P1_6==0){//第二行有没有变成0
    	 	delay(20);
    		while(P1_6==0);
    		delay(20);
    		return 5;
    	}
    	else if (P1_5==0){//第三行有没有变成0
    	 	delay(20);
    		while(P1_5==0);
    		delay(20);
    		return 9;
    	}
    	else if (P1_4==0){//第四行有没有变成0
    	 	delay(20);
    		while(P1_4==0);
    		delay(20);
    		return 13;
    	}
    	return 0;
    }
    

    扫描第2-4列的函数与上面扫描第一行的大体相同,只是GPIO口与返回编号不一样而已。

    主函数

    上面写道当返回值不为0时,执行对应操作。现在返回值与操作的关系如下:

    返回值 操作
    0,13,14,15,16
    1 输入1
    2 输入2
    3 输入3
    4 输入4
    5 输入5
    6 输入6
    7 输入7
    8 输入8
    9 输入9
    10 输入0
    11 输入删除
    12 确认

    我们要使用一个初始值为0的变量表示当前输入的密码,当接收到输入0-9的指令时,将这个变量乘以10在加上0-9。

    例如最开始是0000,按下1后,0*10+1=1,led显示0001;当按下删除时,将这个变量除以10,由于c语言整形做除法舍去小数点,因此可实现删除最近输入的效果:1234,按下删除后1234/10=123,显示0123。

    除了要有一个变量表示密码,还要有一个初始值为0的变量表示已输入长度,每输入一位密码,这个变量值加1,当值为4时不再继续接受新的密码数字,当值为0是不支持删除操作。

    当按下12时,做一个简单的if-else判断,判断密码变量的值是否等于0-9999中的值(代码中设置),是的话打印SUCCESS,不是的话先打印FAIL,停滞几秒后程序打印刚刚输入的密码,等待重新输入。

    代码

    lcd1602显示屏的代码是我在b站找到的现成代码,不是我自己写的,就不放出了,只知道是在lcd1602显示屏上打印变量的值即可。

    main.c

    #include <REGX52.H>
    #include "LCD1602.h"
    #include "matrixKeyboard.h"
    #include "Delay.h"
    void main(){
    	unsigned short _code,_len,a;//code属于keil关键字,不可用code当变量名!
    	_code = 0;//密码变量
    	_len = 0;//长度变量
    	LCD_Init();
    	LCD_ShowString(1,1,"PASSSWORD");
    	LCD_ShowNum(2,1,_code,4);
    	while(1){
    		a = scan();//循环扫描,取编号
    		if (a>0&&a<=10){//按下输入0-9,且已输入密码长度小于4
    		if (_len<4){
    			if (a == 10) a = 0;
    			_len++;
    			_code = _code * 10+a;
    			LCD_ShowNum(2,1,_code,4);
    		}	
    		}
    		else if(a == 11){//按下删除且当前密码长度大于0
    		if (_len>0){
    			_len--;
    			_code = _code / 10;
    			LCD_ShowNum(2,1,_code,4);
    		}
    		}
    		else if(a == 12){//确认
    			if (_code == 123) LCD_ShowString(2,1,"SUCCESS");//密码正确,这里是123
    			else{//密码错误
    				LCD_ShowString(2,1,"FAIL");//错误信息,延时后打印刚刚输入的密码
    				delay(5000);
    				LCD_ShowString(2,1,"      ");
    				LCD_ShowNum(2,1,_code,4);
    			}
    		}
    	}
    }
    

    matrixKeyboard.h

    #ifndef __MATRIXKEYBOARD_H__
    #define __MATRIXKEYBOARD_H__
    #include <REGX52.H>
    #include "Delay.h"
    unsigned short scanColumn1();
    unsigned short scanColumn2();
    unsigned short scanColumn3();
    unsigned short scanColumn4();
    unsigned short scan();
    #endif
    

    matrixKeyboard.c

    #include "matrixKeyboard.h"
    unsigned short scanColumn1(){
    	 P1 = 0xff;//P1初始化
    	 P1_3 = 0;//相应列的GPIO置低电平
    	 if (P1_7==0){//看哪个是低电平
    	 	delay(20);
    		while(P1_7==0);
    		delay(20);
    		return 1;
    	 }
    	 else if (P1_6==0){
    	 	delay(20);
    		while(P1_6==0);
    		delay(20);
    		return 5;
    	 }
    	 else if (P1_5==0){
    	 	delay(20);
    		while(P1_5==0);
    		delay(20);
    		return 9;
    	 }
    	 else if (P1_4==0){
    	 	delay(20);
    		while(P1_4==0);
    		delay(20);
    		return 13;
    	 }
    	 return 0;
    }
    unsigned short scanColumn2(){
    	P1 = 0xff;
    	 P1_2 = 0;
    	 if (P1_7==0){
    	 	delay(20);
    		while(P1_7==0);
    		delay(20);
    		return 2;
    	 }
    	 else if (P1_6==0){
    	 	delay(20);
    		while(P1_6==0);
    		delay(20);
    		return 6;
    	 }
    	 else if (P1_5==0){
    	 	delay(20);
    		while(P1_5==0);
    		delay(20);
    		return 10;
    	 }
    	 else if (P1_4==0){
    	 	delay(20);
    		while(P1_4==0);
    		delay(20);
    		return 14;
    	 }
    	return 0;
    }
    unsigned short scanColumn3(){
    	P1 = 0xff;
    	 P1_1 = 0;
    	 if (P1_7==0){
    	 	delay(20);
    		while(P1_7==0);
    		delay(20);
    		return 3;
    	 }
    	 else if (P1_6==0){
    	 	delay(20);
    		while(P1_6==0);
    		delay(20);
    		return 7;
    	 }
    	 else if (P1_5==0){
    	 	delay(20);
    		while(P1_5==0);
    		delay(20);
    		return 11;
    	 }
    	 else if (P1_4==0){
    	 	delay(20);
    		while(P1_4==0);
    		delay(20);
    		return 15;
    	 }
    	 return 0;
    }
    unsigned short scanColumn4(){
    	P1 = 0xff;
    	 P1_0 = 0;
    	 if (P1_7==0){
    	 	delay(20);
    		while(P1_7==0);
    		delay(20);
    		return 4;
    	 }
    	 else if (P1_6==0){
    	 	delay(20);
    		while(P1_6==0);
    		delay(20);
    		return 8;
    	 }
    	 else if (P1_5==0){
    	 	delay(20);
    		while(P1_5==0);
    		delay(20);
    		return 12;
    	 }
    	 else if (P1_4==0){
    	 	delay(20);
    		while(P1_4==0);
    		delay(20);
    		return 16;
    	 }
    	 return 0;
    }
    unsigned short scan(){	
    	unsigned short res = 0;
    	res = scanColumn1();
    	if (res != 0) return res;
    	res = scanColumn2();
    	if (res != 0) return res;
    	res = scanColumn3();
    	if (res != 0) return res;
    	res = scanColumn4();
    	if (res != 0) return res;
    	return 0; 
    }
    

    Delay.h

    #ifndef __DELAY_H__
    #define __DELAY_H__
    #include "intrins.h"
    void delay(int ms);
    #endif
    

    Delay.c

    #include "Delay.h"
    void Delay(int ms)		//@11.0592MHz
    {
    	unsigned char i, j;
    	while(ms--){
    		_nop_();
    		i = 2;
    		j = 199;
    		do
    		{
    			while (--j);
    		} while (--i);
    	}
    
    }
    

    其他

    "code"属于keil关键字,不可取做变量名。

    物联沃分享整理
    物联沃-IOTWORD物联网 » 使用51单片机实现矩阵键盘密码锁的方法和步骤

    发表评论