基于STC15单片机的智能密码锁(矩阵按键输入)设计

本文介绍了智能门锁的设计,包括其安全性和便利性,以及如何利用LCD1602显示、RTC芯片(如PCF8583)实现实时时间显示、矩阵按键进行密码输入、步进电机模拟开锁和关锁等功能。文章详细阐述了各个组件的工作原理和代码实现,包括按键扫描、密码验证和错误处理机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、项目背景

二、功能需求

 三、功能组成

四、总结


一、项目背景

        智能门锁是一种基于现代智能化技术,与传统门锁进行比较的创新型的电子门锁产品。传统门锁通常采用钥匙旋转来开启门锁,但传统门锁存在钥匙遗失、易被复制等问题,特别是具有主动性质的人员如不法分子,可以通过主动窃取、复制钥匙等手段,轻松翻越传统门锁,进入家庭、企事业单位或其他场所,造成不必要的经济和社会损失。智能门锁则通过密码、指纹、身份验证等技术,提供更加安全、便捷、舒适的门锁体验,实现智能门锁物联网系统。

        智能门锁结合了多个技术:如无线通信技术、计算机技术、集成电路技术和自动控制技术等。同时在保证安全性的前提下,实现开锁过程的智能和自动化。

        智能门锁是现代化、智能化、人性化、网络化、绿色化、安全性齐备的新型门锁产品,得到越来越多人的青睐和使用。

二、功能需求

智能门锁的核心功能是使用数字密码进行解锁,另外还加入密码修改功能以及对密码错误次数过多的报警和禁止操作功能。

在功能上需要有欢迎界面,主界面的时间显示,以及在按键按下时可以自由切换界面,主要有界面一为输入密码界面,界面二为更改密码界面。 

 三、功能组成

        在功能实现过程中需要用到LCD1602来显示,首先我们需要对LCD1602进行初始化,其次呢,还要用到LCD1602的显示功能,在智能锁的开机界面我们想让它来显示我们设置字符串,首先就要用到字符串显示函数

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]);
	}
}

通过这个函数,我们就可以在LCD屏的指定位置开始显示我们指定的字符串,同时考虑到,在我们输入密码的过程中,密码是通过在屏幕上一个一个显示,所以我们还需要一个可以在指定位置来显示单个字符的函数

void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
	LCD_SetCursor(Line,Column);
	LCD_WriteData(Char);
}

此外LCD1602还为我们预留了8个可以存放自定义字符的地址,我们可以通过取模软件来自定义自己想要显示的字符,那我们要如何来显示呢,这时就要用到下面这个函数了

/**
  * @brief	在指定位置显示自定义字符
*   @param	X 列0~15; Y 行 0~1; Num 字符存储位置0~7;*LCD_Cust 自定义字模表
  * @retval	
  */
void LCD_Show_Customer(unsigned char X,unsigned char Y,unsigned char Num,unsigned char *LCD_Cust)//
{
	unsigned char i;
	unsigned char Com = Num;
	X&=0X0F;
	Y&=0X01;
	if(Y)
	{
		X=X+0X40;
	}
	X=X+0X80;
	Com=Com<<3;
	Com=Com+0X40;
	for(i=0;i<8;i++) 
	{
		LCD_WriteCommand(Com);
		Com++;
		LCD_WriteData(LCD_Cust[i]);
	}
	LCD_WriteCommand(X);
	LCD_WriteData(Num);
}

在第一节我们知道,在上电后,我们不仅想让它只有欢迎界面,还希望它可以在我们没有操作的时候显示当前时间,年月日时分秒等等,为了时间的准确性,我们就需要用到时钟芯片,既RTC芯片(Real-Time Clock Chip),RTC芯片可以提供实时时钟功能,多用于需要记录时间信息的场合,如计时器、闹钟、烤箱等等。常用的RTC芯片有DS1302、DS3231、PCF8583等,此次我们使用PCF8583,对PCF8583进行配置后,我们就要让我们设定的时间可以显示在LCD屏幕上,通过前面的两个函数,我们就可以轻松实现这个功能

void LCD_Display_Main(unsigned char Lock_Flag)
{
	unsigned char time_ge,time_shi;
	get_time();
	if(Lock_Flag == 0)
	{
		Lock(0);
	}
	else
	{
		Lock(1);
	}
	time_ge=time_buf1[1]%10;
	time_shi=time_buf1[1]/10;
	LCD_ShowChar(1,2,'2');
	LCD_ShowChar(1,3,'0');
	LCD_ShowChar(1,5,time_shi+'0');
	LCD_ShowChar(1,6,time_ge+'0');

	time_ge=time_buf1[2]%10;
	time_shi=time_buf1[2]/10;
	LCD_ShowChar(1,8,time_shi+'0');
	LCD_ShowChar(1,9,time_ge+'0');

	time_ge=time_buf1[3]%10;
	time_shi=time_buf1[3]/10;
	LCD_ShowChar(1,11,time_shi+'0');
	LCD_ShowChar(1,12,time_ge+'0');

	time_ge=time_buf1[4]%10;
	time_shi=time_buf1[4]/10;
	LCD_ShowChar(2,4,time_shi+'0');
	LCD_ShowChar(2,5,time_ge+'0');

	time_ge=time_buf1[5]%10;
	time_shi=time_buf1[5]/10;
	LCD_ShowChar(2,7,time_shi+'0');
	LCD_ShowChar(2,8,time_ge+'0');

	time_ge=time_buf1[6]%10;
	time_shi=time_buf1[6]/10;
	LCD_ShowChar(2,10,time_shi+'0');
	LCD_ShowChar(2,11,time_ge+'0');
	


	LCD_ShowChar(1,14,time_buf1[7]+'0');
	

	
	LCD_Show_Customer(3,0,2,table3);
	LCD_Show_Customer(6,0,2,table3);
	LCD_Show_Customer(9,0,2,table3);
	
	LCD_Show_Customer(5,1,3,table4);
	LCD_Show_Customer(8,1,3,table4);
	

在前面我们提到密码的输入需要通过矩阵按键来进行输入,这就要用到我们对按键扫描的知识了,话不多说直接放代码

unsigned char Matrixkey()
{
	unsigned char KeyNumber=0;
	P2M1&=0X00;P2M0|=0X00;
	P4M1&=0X00;P4M0|=0X00;
	P5M1&=0X00;P5M0|=0X00;
	P44=1;P45=1;P46=1;P47=1;P26=1;P27=1;P52=1;P53=1;
	P44=0;
	if(P52==0){Delay(20);while(P52==0);Delay(20);KeyNumber=1;}
	if(P53==0){Delay(20);while(P53==0);Delay(20);KeyNumber=2;}
	if(P26==0){Delay(20);while(P26==0);Delay(20);KeyNumber=3;}
	if(P27==0){Delay(20);while(P27==0);Delay(20);KeyNumber=4;}
	P44=1;P45=1;P46=1;P47=1;P26=1;P27=1;P52=1;P53=1;
	P45=0;
	if(P52==0){Delay(20);while(P52==0);Delay(20);KeyNumber=5;}
	if(P53==0){Delay(20);while(P53==0);Delay(20);KeyNumber=6;}
	if(P26==0){Delay(20);while(P26==0);Delay(20);KeyNumber=7;}
	if(P27==0){Delay(20);while(P27==0);Delay(20);KeyNumber=8;}
	P44=1;P45=1;P46=1;P47=1;P26=1;P27=1;P52=1;P53=1;
	P46=0;
	if(P52==0){Delay(20);while(P52==0);Delay(20);KeyNumber=9;}
	if(P53==0){Delay(20);while(P53==0);Delay(20);KeyNumber=10;}
	if(P26==0){Delay(20);while(P26==0);Delay(20);KeyNumber=11;}
	if(P27==0){Delay(20);while(P27==0);Delay(20);KeyNumber=12;}
	P44=1;P45=1;P46=1;P47=1;P26=1;P27=1;P52=1;P53=1;
	P47=0;
	if(P52==0){Delay(20);while(P52==0);Delay(20);KeyNumber=13;}
	if(P53==0){Delay(20);while(P53==0);Delay(20);KeyNumber=14;}
	if(P26==0){Delay(20);while(P26==0);Delay(20);KeyNumber=15;}
	if(P27==0){Delay(20);while(P27==0);Delay(20);KeyNumber=16;}
	return KeyNumber;
}

关于矩阵键盘的详细内容可以参考以前的文章哦~

PS:在矩阵按键那一节有详细介绍和实现原理~

到这里我们已经基本完成了对外设的配置,但是我们怎么来模拟开锁和关锁呢,可能大家已经想到可以使用舵机等等,这次呢我们就使用步进电机的正转和反转来模拟关锁和开锁,要想使用步进电机,首先就要对步进电机进行配置,我们可以使用单四拍


void Motor_Drive41(uchar X,uint Speed)
{
  if(X==1)  
	{
		DD=0;CC=0;BB=0;AA=1;	
    Delay(Speed);  

		DD=0;CC=0;BB=1;AA=0;	
    Delay(Speed);  

		DD=0;CC=1;BB=0;AA=0;	
    Delay(Speed);  

		DD=1;CC=0;BB=0;AA=0;	
    Delay(Speed); 
  }
	else       
	{
		DD=1;CC=0;BB=0;AA=0;	
    Delay(Speed);  

		DD=0;CC=1;BB=0;AA=0;	
    Delay(Speed);  

		DD=0;CC=0;BB=1;AA=0;	
    Delay(Speed); 

		DD=0;CC=0;BB=0;AA=1;	
    Delay(Speed);  
  }	
}

电机既然要启动,我们就需要把电机关闭,要怎么实现呢

void MotorStop(void)
{
   DD=0;CC=0;BB=0;AA=0;
}

是的,就是这么简单。

终于到这里我们完成了对外设的配置,下一步就要来编写我们的主函数

/*
1、	输入密码和更改密码后的确认按键(返回键值为13)
2、	输入密码和更改密码时的删除按键(返回键值为14)
3、	关锁键(返回键值为15)且只能在开锁状态下使用
4、	对矩阵按键扫描进行了优化(可避免因按键抖动造成的键值连续返回)
5、	按键按下蜂鸣器提醒
6、	开机音乐
7、	密码错误三次锁定三秒且蜂鸣器长鸣
8、	对功能进行了优化(关锁状态下不能进入密码更改界面,只能在开锁状态下才能进入密码更改界面,且开锁状态        
    下不能再次进入密码输入界面)
9、 按键16(返回键值16)切换界面,选择输入密码还是更改密码

  */
#include <STC15F2K60S2.H>
#include "LCD1602.h"
#include "Delay.h"
#include "Matrixkey.h"
#include "stepmotor.h"
#include "PCF8563.h"
#include "Start.h"
#include <string.h>

第一步我们需要对我们的基础功能进行介绍,并引入我们需要的函数头文件。

unsigned char Page_Flag;
unsigned char Lock_Flag;
unsigned char OK_Flag;
unsigned char Error_Num;
unsigned char PassWord[] = "000000"; 
unsigned char PassW_Set[] = "123456";

定义我们需要的全局变量。

    LCD_Init();
	time_init();
	Start_up();
	Music();
	Delay(1000);
	Delete();

对开机界面进行初始化,接下来就可以进入我们循环体中咯~

Number = Matrixkey();
		if(Number == 13)
		{
			Buzzer(200);
			OK_Flag = 1;
		}
		if(Number == 15)
		{
			Buzzer(200);
			if(Lock_Flag != 0)
			{
				Lock_Flag = 0;
				while(StepGround--)
							{
								Motor_Drive41(0,5);
							}
						MotorStop();
						StepGround = 100;
			}	
		}
		if(Number == 16) 
		{
			Buzzer(200);
			Delete();
			Page_Flag++;	
			if((Lock_Flag == 1) && (Page_Flag == 1))
			{
				Page_Flag = 2;
			}
			if(Page_Flag == 3)Page_Flag = 0;
		}

第一步要对我们各个按键的功能逐一实现,在实现过程中我们可以借助不同的标志位来实现我们想要实现的功能

if(Page_Flag == 0) //显示主页面万年历
		{
			LCD_Display_Main(Lock_Flag);
		}
		if(Page_Flag == 1)	//密码输入显示
		{
			LCD_ShowString(1,1,"PassWord:");
			if(Number == 14)//删除操作
			{
					Buzzer(200);
					LCD_ShowString(2,count,"                ");
					count--;
				}
			if( (Number >= 1) && (Number <= 9) && (count < 6))
			{
				Buzzer(200);
				PassWord[count] = Number + 0x30;
				LCD_ShowChar(2,count + 1,PassWord[count]);
				Delay(500);
				LCD_ShowChar(2,count + 1,'*');
				count++;
				if(count == 6)
				{
					if(OK_Flag == 1)
					{
					count = 0;
					OK_Flag = 0;					
					if(strcmp(PassWord,PassW_Set)==0)//密码比对
					{
						while(StepGround--)
							{
								Motor_Drive41(1,5);
							}
							MotorStop();
							StepGround = 100;
							Delete();
							LCD_ShowString(1,1,"PassWord:");
							LCD_ShowString(2,1,"Success");
							Delay(2000);
							Page_Flag = 0;
							Lock_Flag = 1;
							Delete();
					}
					else
					{
						Delete();
						LCD_ShowString(1,1,"PassWord:");
						LCD_ShowString(2,1,"Fail");
						Error_Num++;
						Delay(1000);
						Delete();
						Page_Flag = 0;
					}
				}				
			}
		}
	}
		if((Page_Flag == 2) && (Lock_Flag == 0))Page_Flag = 0;//关锁不能更改密码
		if((Page_Flag == 2) && (Lock_Flag == 1))//开锁更改密码
		{
			LCD_ShowString(1,1,"NewPassWord:");
			if(Number == 14)//删除操作
			{
					Buzzer(200);
					LCD_ShowString(2,count,"                ");
					count--;
				}
			if( (Number >= 1) && (Number <= 9) && (count < 6))//密码更改
			{
				Buzzer(200);
				PassW_Set[count] = Number + 0x30;
				LCD_ShowChar(2,count + 1,PassW_Set[count]);
				Delay(500);
				LCD_ShowChar(2,count + 1,'*');
				count++;
				if(count == 6)
				{
					if(OK_Flag == 1)
					{
						count = 0;
						OK_Flag = 0;
						Delete();
						LCD_ShowString(1,1,"NewPassWord:");
						LCD_ShowString(2,1,"SetSuccess");
						Delay(1000);
						Delete();
						Page_Flag = 0;
					}		
				}
			}
		}
		if(Error_Num == 3)//密码错误3次提醒
		{
			Error_Num = 0;
			Delete();
			LCD_ShowString(1,3,"PlaseWait 3s");
			Buzzer(6000);
			Delete();
		}

四、总结

可能大家发现介绍里面有开机音乐这一项功能,我们可以通过该变蜂鸣器声调来模拟音乐,如下

void Music()
{
		unsigned char x = 200;
		unsigned int count = 500;
		P3M1 = 0x00;
		P3M0 = 0x00;
		while(1)
		{
			count += 100;
			while(x--)
			{
				buzzer = ~buzzer;
				Delay_M(count);
			}
			x = 200;
			if(count == 1200)break;
		}
		
}

PS:该蜂鸣器为无源蜂鸣器。

最后:此次设计没有设计密码进行掉电不丢失的功能,掉电后密码就会回到设置的初始密码,感兴趣的可以查阅资料怎样将密码存入EEPROM

  1. EEPROM 存储器
    EEPROM 是一种可擦写可编程非易失性存储器件,可以在掉电后保持数据不丢失。单片机的程序可以通过操作 EEPROM 存储器来保持需要保存的数据,如设置参数、校准数据等。当单片机重新上电时,可以通过读取 EEPROM 存储器中的数据来恢复之前的设置。

 最后附上主函数代码


#include <STC15F2K60S2.H>
#include "LCD1602.h"
#include "Delay.h"
#include "Matrixkey.h"
#include "stepmotor.h"
#include "PCF8563.h"
#include "Start.h"
#include <string.h>

unsigned char Page_Flag;
unsigned char Lock_Flag;
unsigned char OK_Flag;
unsigned char Error_Num;
unsigned char PassWord[] = "000000"; 
unsigned char PassW_Set[] = "123456";
void main()
{
	unsigned char Number;
	unsigned char count = 0;
	unsigned int StepGround = 100;
	LCD_Init();
	time_init();
	Start_up();
	Music();
	Delay(1000);
	Delete();
	while(1)
	{
		Number = Matrixkey();
		if(Number == 13)
		{
			Buzzer(200);
			OK_Flag = 1;
		}
		if(Number == 15)
		{
			Buzzer(200);
			if(Lock_Flag != 0)
			{
				Lock_Flag = 0;
				while(StepGround--)
							{
								Motor_Drive41(0,5);
							}
						MotorStop();
						StepGround = 100;
			}	
		}
		if(Number == 16) 
		{
			Buzzer(200);
			Delete();
			Page_Flag++;	
			if((Lock_Flag == 1) && (Page_Flag == 1))
			{
				Page_Flag = 2;
			}
			if(Page_Flag == 3)Page_Flag = 0;
		}
		if(Page_Flag == 0) //ʱ¼äÏÔʾ
		{
			LCD_Display_Main(Lock_Flag);
		}
		if(Page_Flag == 1)	
		{
			LCD_ShowString(1,1,"PassWord:");
			if(Number == 14)
			{
					Buzzer(200);
					LCD_ShowString(2,count,"                ");
					count--;
				}
			if( (Number >= 1) && (Number <= 9) && (count < 6))
			{
				Buzzer(200);
				PassWord[count] = Number + 0x30;
				LCD_ShowChar(2,count + 1,PassWord[count]);
				Delay(500);
				LCD_ShowChar(2,count + 1,'*');
				count++;
				if(count == 6)
				{
					if(OK_Flag == 1)
					{
					count = 0;
					OK_Flag = 0;					
					if(strcmp(PassWord,PassW_Set)==0)
					{
						while(StepGround--)
							{
								Motor_Drive41(1,5);
							}
							MotorStop();
							StepGround = 100;
							Delete();
							LCD_ShowString(1,1,"PassWord:");
							LCD_ShowString(2,1,"Success");
							Delay(2000);
							Page_Flag = 0;
							Lock_Flag = 1;
							Delete();
					}
					else
					{
						Delete();
						LCD_ShowString(1,1,"PassWord:");
						LCD_ShowString(2,1,"Fail");
						Error_Num++;
						Delay(1000);
						Delete();
						Page_Flag = 0;
					}
				}				
			}
		}
	}
		if((Page_Flag == 2) && (Lock_Flag == 0))Page_Flag = 0;
		if((Page_Flag == 2) && (Lock_Flag == 1))
		{
			LCD_ShowString(1,1,"NewPassWord:");
			if(Number == 14)
			{
					Buzzer(200);
					LCD_ShowString(2,count,"                ");
					count--;
				}
			if( (Number >= 1) && (Number <= 9) && (count < 6))
			{
				Buzzer(200);
				PassW_Set[count] = Number + 0x30;
				LCD_ShowChar(2,count + 1,PassW_Set[count]);
				Delay(500);
				LCD_ShowChar(2,count + 1,'*');
				count++;
				if(count == 6)
				{
					if(OK_Flag == 1)
					{
						count = 0;
						OK_Flag = 0;
						Delete();
						LCD_ShowString(1,1,"NewPassWord:");
						LCD_ShowString(2,1,"SetSuccess");
						Delay(1000);
						Delete();
						Page_Flag = 0;
					}		
				}
			}
		}
		if(Error_Num == 3)
		{
			Error_Num = 0;
			Delete();
			LCD_ShowString(1,3,"PlaseWait 3s");
			Buzzer(6000);
			Delete();
		}
	}
}

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

FightingLod

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

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

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

打赏作者

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

抵扣说明:

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

余额充值