基于51单片机的密码锁设计

设计思路

电子密码锁设计,以AT89C51为主控,晶振电路和复位电路共同组成最小系统,使得单片机可以正常运行。矩阵按键作为输入模块,输入密码,LCD1602作为显示设备,显示输入的密码和提示语句,AT24C02作为EEPROM存储器,使用LED模拟“锁”,表示锁的开启和关闭状态。系统掉电后,密码数据不丢失,AT24C02保存输入的密码,在单片机上电后读取其保存的密码。

使用方法

1号按键开锁选项,9号按键修改密码。
矩阵键盘:

				 0      1      2       3
				 
				 4      5      6       7
				 
				 8      9    返回    确定
				 
				 $      $      $       $

接线

				 P1 -->矩阵键盘
				 P20--> EEPROM模块SDA
				 P21--> EEPROM模块SCL

系统框图

系统框图

硬件原理图

硬件原理图

程序源码

main.c

#include "reg52.h"		       //此文件中定义了单片机的一些特殊功能寄存器
#include "lcd.h"
#include "key.h"
#include "i2c.h"

#define u16 unsigned int 	  //对数据类型进行声明定义
#define u8 unsigned char

sbit AS=P2^2;               //继电器


u8 pw_num,Error_Num,PassWord_Length=6;
u8 PASSWORD[]={8,8,8,8,8,8,0,0,0,0};
u8 INPUT_PW_Tab[10];
u8 key_num,Step,Step5,Load_first_flag=0;

bit result_flag,Input_suc_flag;
bit List1=0;

void Step_0();
void Step_1();
void Step_2();
void Step_3();
void Step_4();
	  
void Step_5();
		void Step5_0();
	   void Step5_1();
	   void Step5_2();
	   void Step5_3();
	   void Step5_4();
	   void Step5_5();
void Step_6();

void CipherComparison();
void input_password(bit m);
void Read_Password();




void main()
{	
	u8 data1,a;
	//	ShowString(0x00," Pechin Science ");  
	//	At24c02Write(0,0);                                                //开机显示密码
	LcdWriteCom(0x01);  //清屏
	for(data1=0;data1<PassWord_Length+2;data1++)
	{
		a=At24c02Read(data1)+0x30;
	 	LcdWriteData(a);	
  	delay(1000);	
  }
	
	delay(1000);
	LcdInit();
	delay(1000);
	Step=0;
	Step5=0;
	Error_Num=0x00;
  Read_Password();

	while(1)
				{	
								key_num=KeyDown();                   //读取输入值

										switch(Step)
										{
												case 0:
												 {Step_0();break;}
												case 1:
												 {Step_1();break;}
												case 2:
												 {Step_2();break;}
												case 3:
												 {Step_3();break;}	
												case 4:
												 {Step_4();break;}	
												case 5:
												 {Step_5();break;}	
												case 6:
												 {Step_6();break;}	
												  
										}

				 }				
}


void Step_0()
{
					LcdInit();
					ShowString(0x00," Pechin Science ");                           //第一行显示Pechin Science 
	        ShowString(0x10,"    WELCOME!    ");                           // 第二行显示 WELCOME!  
	
					while(KeyDown()==0xff)Step=1;                                  //  有按键按下进入下一步  
	      
					
}

void Step_1()
{
		LcdWriteCom(0x01);                                           //清屏
	  ShowString(0x00,"Unlock");
		ShowString(0x0f,"<");	                                       //1602第一行显示unlock
	  ShowString(0x10,"Change Password");
		ShowString(0x1f," "); 	                                       // 1602第二行显示Change Password                                                                            	
	  Step=2;	                                                      //
}

void Step_2()
{

	if(key_num!=0x0b)  
		{
					if((key_num==0x01) ||( key_num==0x09))                    //1键或9键按下
					{
								List1=~List1;                           //Change Password
								if(List1==0)
									{                                                  
									ShowString(0x0f,"<");                           // Unlock            <
									ShowString(0x1f," ");	                          // Change Password  
								}
								else
								{
									ShowString(0x0f," ");                           // Unlock            
									ShowString(0x1f,"<");	                          // Change Password   <
								}
					}
		}
	else                                                           //确认键按下
	{
					if(List1==0){Step=3;}
					else        {Step=5;List1=0;}
	}
}

void Step_3()                                             //
{
								Step=4;
	              pw_num=0;
								LcdInit();
								ShowString(0x00,"Pass Word:  ");
                
						
}

void Step_4()                                                 
{
	   input_password(0);                                              //输入密码并以*显示
	   if(Input_suc_flag==1){Step=6;}                                  //密码输入完成进入下一步
      Input_suc_flag=0;                                              //清除密码输入完成标志
}

void Step_5()                                                        //修改密码
{
	switch(Step5)
	{
		
			case 0: {Step5_0();}  break;
			case 1: {Step5_1();}  break;
			case 2: {Step5_2();}  break;
			case 3: {Step5_3();}  break;
		  case 4: {Step5_4();}  break;
			case 5:	{Step5_5();}	break;

	}
}

void Step_6()
{
	CipherComparison();                                //密码比对
	if(result_flag==1)                                 //密码正确
		{
				LcdInit();
				ShowString(0x00,"    WELCOME!");
				AS=0;                                         //开继电器
				delay(60000);
				delay(60000);
				AS=1;	                                        //关继电器
		}
	else                                                //密码错误
		{
				LcdInit();
				ShowString(0x00,"Error 01!");
		}
		
		Step=0;
	

}



void Step5_0()                 
{
		LcdWriteCom(0x01);  //清屏
	  ShowString (0x00,"Input PassWord:");     //1602显示:输入密码
	  Step5=1;
	  pw_num=0;
}
void Step5_1()                
{
		input_password(0);                  //   输入密码并以*显示
		if(Input_suc_flag==1)               //密码输入完成
			{
							Step5=2;                  //
							Input_suc_flag=0;         //清除密码输入完成标志
			}
}
void Step5_2()                //
{
     CipherComparison();                //密码比对
	   Step5=3;
}
void Step5_3()                //
{
    if(result_flag==0)         //        密码错误
				{
							if(Error_Num<3)             //输出错误次数小于3
							{
								Error_Num++;
								LcdInit();
								ShowString (0x00,"Error 01");
								delay(20000);
								Step5=0;
							}
							else                          //密码错误次数大于3
							{
								Error_Num=0;
								Step=0;
							}
					
				}
		else						      					       //密码正确
				{
					LcdInit();
					ShowString (0x00,"New PassWord:");	
					pw_num=0;
					Step5=4;
				}
			
					
}
void Step5_4()
{
		input_password(1);     					       //输入密码并显示
		if(Input_suc_flag==1)                  //输入完成
			{ 
				Step5=5;
				Input_suc_flag=0;
				LcdWriteCom(0x01);  //清屏
	      ShowString (0x00,"      OK!");
			}
}
void Step5_5()
{
	unsigned char j;
	
	PassWord_Length=pw_num;                         //读取输入密码长度
	At24c02Write(0,Load_first_flag);        
  delay(100);	
	At24c02Write(1,PassWord_Length);                //保存 密码长度
	delay(100);
	for(j=0;j<PassWord_Length;j++)         
	{
		PASSWORD[j]=INPUT_PW_Tab[j];               		 //读取密码
		At24c02Write(j+2,INPUT_PW_Tab[j]);         		 //保存密码至EEPROM
		delay(100);
}
	Step5=0;
	Step=0;
}


void Read_Password()
{
	unsigned char j;

	Load_first_flag=At24c02Read(0x00);
//	if(Load_first_flag==0)         		 //初次运行  初始密码错误可以将此句打开重新编译下载
	{
	
		Load_first_flag=1;
		At24c02Write(0,0x01);
		delay(100);
		At24c02Write(1,0x06);           //写默认密码长度6至EEPROM
		delay(100);
		for(j=0;j<PassWord_Length;j++)
		{
			At24c02Write(j+2,8);              //写默认密码888888至EEPROM
			PASSWORD[j]=INPUT_PW_Tab[j];     //读密码
			delay(100);
		}
	}
	
	Load_first_flag=At24c02Read(0x00);
	PassWord_Length=At24c02Read(0x01);  //读取密码长度
	for(j=0;j<PassWord_Length;j++)       //读取密码
	{
		PASSWORD[j]=At24c02Read(j+2);
	}
	
}
void input_password(bit m)
{
	unsigned char j;
	if(key_num!=0x0b)                                      //ok键没有按下
		{
					if(key_num<0x0a)                               //1-9按下
					{
						INPUT_PW_Tab[pw_num]=key_num;                //保存至输入密码数组
						pw_num=pw_num+1;                              //密码长度+1
						
						 LcdWriteCom(0xc0);
						 for(j=0;j<pw_num;j++)
								{
												if(m==0) {LcdWriteData('*');	}                        //密码隐藏
												else     {LcdWriteData(INPUT_PW_Tab[j]+0x30);}         //显示密码
								}
											
					}
					if(key_num==0x0a)                              //返回键按下
					{
						if(pw_num!=0) {pw_num=pw_num-1;}
						else          {Step=0;}
						
							 
						// ShowString (0x00,"Pass Word:");  
                    LcdWriteCom(0xc0);						
										for(j=0;j<pw_num;j++)
											{
														if(m==0) {LcdWriteData('*');	}                   //密码隐藏
														else     {LcdWriteData(INPUT_PW_Tab[j]+0x30);}    //显示密码	
										   }
											LcdWriteData(' '); 
					}
		} 
	else                          //ok键按下
	  {
			if(pw_num==0)	  
					{
							Step=0;
						  LcdWriteCom(0x01);
						  ShowString (0x00,"Error 02!");
							delay(10000);
					}
		
			else{		
							Input_suc_flag=1; 
					}
					 //AS=0;			
		}                
}

void CipherComparison()
{ 
	u8 i,j=0;

	if(PassWord_Length==pw_num)                       //密码长度比对
	{
		for(i=0;i<PassWord_Length;i++)                  //密码比对
		{
			
				if(PASSWORD[i]!=INPUT_PW_Tab[i])
					{
						result_flag=0;break;                     //密码错误
					}
				else
					{
						result_flag=1;                          //密码正确
					}
					  INPUT_PW_Tab[i]=0XFF;                   //清除密码缓存数组
		}
	}
	else
	{result_flag=0;}
	
}

lcd.c

#include "lcd.h"

void Lcd1602_Delay1ms(uint c)   //误差 0us
{
    uchar a,b;
	for (; c>0; c--)
	{
		 for (b=199;b>0;b--)
		 {
		  	for(a=1;a>0;a--);
		 }      
	}
    	
}

#ifndef 	LCD1602_4PINS	 //当没有定义这个LCD1602_4PINS时
void LCD_WriteCmd(uchar com)	  //写入命令
{
	LCD1602_E = 0;     //使能
	LCD1602_RS = 0;	   //选择发送命令
	LCD1602_RW = 0;	   //选择写入
	
	LCD1602_DATAPINS = com;     //放入命令
	Lcd1602_Delay1ms(1);		//等待数据稳定

	LCD1602_E = 1;	          //写入时序
	Lcd1602_Delay1ms(5);	  //保持时间
	LCD1602_E = 0;
}
#else 
void LCD_WriteCmd(uchar com)	  //写入命令
{
	LCD1602_E = 0;	 //使能清零
	LCD1602_RS = 0;	 //选择写入命令
	LCD1602_RW = 0;	 //选择写入

	LCD1602_DATAPINS = com;	//由于4位的接线是接到P0口的高四位,所以传送高四位不用改
	Lcd1602_Delay1ms(1);

	LCD1602_E = 1;	 //写入时序
	Lcd1602_Delay1ms(5);
	LCD1602_E = 0;

//	Lcd1602_Delay1ms(1);
	LCD1602_DATAPINS = com << 4; //发送低四位
	Lcd1602_Delay1ms(1);

	LCD1602_E = 1;	 //写入时序
	Lcd1602_Delay1ms(5);
	LCD1602_E = 0;
}
#endif
//显示字符串
 void ShowString (unsigned char Coordinate,char *ptr)
 {

	  if(Coordinate<=0x0f)   //高四位为0,显示第一行
			{
				LcdWriteCom((Coordinate&0x0f)+0x80);
				while(*ptr!='\0')
				{
					LcdWriteData(*ptr);	
					ptr++;
				}
			}
		else                   //高四位为1,显示第2行
			{ 
				LcdWriteCom((Coordinate&0x0f)+0xc0);
				
				while(*ptr!='\0')
				{
					LcdWriteData(*ptr);	
					ptr++;
				}
			}
 }

//向LCD写入一个字节的数据		   
#ifndef 	LCD1602_4PINS		   
void LCD_WriteData(uchar dat)			//写入数据
{
	LCD1602_E = 0;	//使能清零
	LCD1602_RS = 1;	//选择输入数据
	LCD1602_RW = 0;	//选择写入

	LCD1602_DATAPINS = dat; //写入数据
	Lcd1602_Delay1ms(1);

	LCD1602_E = 1;   //写入时序
	Lcd1602_Delay1ms(5);   //保持时间
	LCD1602_E = 0;
}
#else
void LCD_WriteData(uchar dat)			//写入数据
{
	LCD1602_E = 0;	  //使能清零
	LCD1602_RS = 1;	  //选择写入数据
	LCD1602_RW = 0;	  //选择写入

	LCD1602_DATAPINS = dat;	//由于4位的接线是接到P0口的高四位,所以传送高四位不用改
	Lcd1602_Delay1ms(1);

	LCD1602_E = 1;	  //写入时序
	Lcd1602_Delay1ms(5);
	LCD1602_E = 0;

	LCD1602_DATAPINS = dat << 4; //写入低四位
	Lcd1602_Delay1ms(1);

	LCD1602_E = 1;	  //写入时序
	Lcd1602_Delay1ms(5);
	LCD1602_E = 0;
}
#endif


//初始化LCD屏		   
#ifndef		LCD1602_4PINS
void LcdInit()						  //LCD初始化子程序
{
 	LCD_WriteCmd(0x38);  //开显示
	LCD_WriteCmd(0x0c);  //开显示不显示光标
	LCD_WriteCmd(0x06);  //写一个指针加1
	LCD_WriteCmd(0x01);  //清屏
	LCD_WriteCmd(0x80);  //设置数据指针起点
}
#else
void LCD_Init()						  //LCD初始化子程序
{
	LCD_WriteCmd(0x32);	 //将8位总线转为4位总线
	LCD_WriteCmd(0x28);	 //在四位线下的初始化
	LCD_WriteCmd(0x0c);  //开显示不显示光标
	LCD_WriteCmd(0x06);  //写一个指针加1
	LCD_WriteCmd(0x01);  //清屏
	LCD_WriteCmd(0x80);  //设置数据指针起点
}
#endif



void LCD_Clear()
{
	LCD_WriteCmd(0x01);
	LCD_WriteCmd(0x80);	
}

//在任何位置显示字符串

void LCD_Dispstring(int x,int line,int *p)	  
{
	char i=0;
	if(line<1)	   //第一行显示
	{	
		while(*p!='\0')
		{
			if(i<16-x)
			{
				LCD_WriteCmd(0x80+i+x);	
			}
			else
			{
				LCD_WriteCmd(0x40+0x80+i+x-16);	
			}
			LCD_WriteData(*p);
			p++;
			i++;	
		}	
	}
	else		   //第2行显示
	{
		while(*p!='\0')
		{
			if(i<16-x)
			{
				LCD_WriteCmd(0x80+0x40+i+x);	
			}
			else
			{
				LCD_WriteCmd(0x80+i+x-16);	
			}
			LCD_WriteData(*p);
			p++;
			i++;	
		}	
	}		
}



lcd.h

#ifndef __LCD_H_
#define __LCD_H_

#define LCD1602_4PINS


#include<reg52.h>

#ifndef uchar
#define uchar unsigned char
#endif

#ifndef uint 
#define uint unsigned int
#endif


#define LCD1602_DATAPINS P0
sbit LCD1602_E=P2^7;
sbit LCD1602_RW=P2^5;
sbit LCD1602_RS=P2^6;


/*在51单片机12MHZ时钟下的延时函数*/
void Lcd1602_Delay1ms(uint c);   //误差 0us
/*LCD1602写入8位命令子函数*/
void LcdWriteCom(uchar com);
/*LCD1602写入8位数据子函数*/	
void LcdWriteData(uchar dat);
/*LCD1602初始化子程序*/		
void LcdInit();		
void Display_Standby();
void Display_str_Password();
void Display_result(bit rt);
void Display_Password(unsigned char i);
void ShowString (unsigned char Coordinate,char *ptr);

#endif

i2c.c

#include"i2c.h"

void Delay10us()
{
	unsigned char a,b;
	for(b=1;b>0;b--)
		for(a=2;a>0;a--);

}

void I2cStart()
{
	SDA=1;
	Delay10us();
	SCL=1;
	Delay10us();//建立时间是SDA保持时间>4.7us
	SDA=0;
	Delay10us();//保持时间是>4us
	SCL=0;			
	Delay10us();		
}

void I2cStop()
{
	SDA=0;
	Delay10us();
	SCL=1;
	Delay10us();//建立时间大于4.7us
	SDA=1;
	Delay10us();		
}

unsigned char I2cSendByte(unsigned char dat)
{
	unsigned char a=0,b=0;//最大255,一个机器周期为1us,最大延时255us。		
	for(a=0;a<8;a++)//要发送8位,从最高位开始
	{
		SDA=dat>>7;	 //起始信号之后SCL=0,所以可以直接改变SDA信号
		dat=dat<<1;
		Delay10us();
		SCL=1;
		Delay10us();//建立时间>4.7us
		SCL=0;
		Delay10us();//时间大于4us		
	}
	SDA=1;
	Delay10us();
	SCL=1;
	while(SDA)//等待应答,也就是等待从设备把SDA拉低
	{
		b++;
		if(b>200)	 //如果超过2000us没有应答发送失败,或者为非应答,表示接收结束
		{
			SCL=0;
			Delay10us();
			return 0;
		}
	}
	SCL=0;
	Delay10us();
 	return 1;		
}

unsigned char I2cReadByte()
{
	unsigned char a=0,dat=0;
	SDA=1;			//起始和发送一个字节之后SCL都是0
	Delay10us();
	for(a=0;a<8;a++)//接收8个字节
	{
		SCL=1;
		Delay10us();
		dat<<=1;
		dat|=SDA;
		Delay10us();
		SCL=0;
		Delay10us();
	}
	return dat;		
}


void At24c02Write(unsigned char addr,unsigned char dat)
{
	I2cStart();
	I2cSendByte(0xa0);//发送写器件地址
	I2cSendByte(addr);//发送要写入内存地址
	I2cSendByte(dat);	//发送数据
	I2cStop();
}

unsigned char At24c02Read(unsigned char addr) 
{
	unsigned char num;
	I2cStart();
	I2cSendByte(0xa0); //发送写器件地址
	I2cSendByte(addr); //发送要读取的地址
	I2cStart();
	I2cSendByte(0xa1); //发送读器件地址
	num=I2cReadByte(); //读取数据
	I2cStop();
	return num;	
}


i2c.h

#ifndef __I2C_H_
#define __I2C_H_

#include <reg52.h>

sbit SCL=P2^1;
sbit SDA=P2^0;

void I2cStart();
void I2cStop();
unsigned char I2cSendByte(unsigned char dat);
unsigned char I2cReadByte();
void At24c02Write(unsigned char addr,unsigned char dat);
unsigned char At24c02Read(unsigned char addr);

#endif

key.c

#include "key.h"

u8 KeyValue=0;



void delay(u16 i)
{
	while(i--);	
}


u8 KeyDown(void)
{
	char a=0;
	GPIO_KEY=0x0f;

	if(GPIO_KEY!=0x0f)//有按键按下
	{
		delay(1000);//延时10ms去抖
		if(GPIO_KEY!=0x0f)//有按键按下
		{	
			
			GPIO_KEY=0X0F;
			switch(GPIO_KEY)
			{
				case(0X07):	KeyValue=0;break;
				case(0X0b):	KeyValue=1;break;
				case(0X0d): KeyValue=2;break;
				case(0X0e):	KeyValue=3;break;
			}
			
			GPIO_KEY=0XF0;
			switch(GPIO_KEY)
			{
				case(0X70):	KeyValue=KeyValue;break;
				case(0Xb0):	KeyValue=KeyValue+4;break;
				case(0Xd0): KeyValue=KeyValue+8;break;
				case(0Xe0):	KeyValue=KeyValue+12;break;
			}
			while((a<50)&&(GPIO_KEY!=0xf0))	 
			{
				delay(1000);
				a++;
			}
			 
		}
	}
	else
	{
		KeyValue=0xff;  //无按键按下
	}
	
	return KeyValue;  //返回KeyValue
}

key.h

#ifndef _key_H
#define key_H

#include<reg52.h>

#ifndef u8
#define u8 unsigned char
#endif 
#ifndef u16
#define u16 unsigned int
#endif

#define GPIO_KEY P1

void delay(u16 i);
u8 KeyDown(void);
#endif

需要工程文件评论区留言

  • 36
    点赞
  • 362
    收藏
    觉得还不错? 一键收藏
  • 128
    评论
电子密码锁是一种智能化的锁具,它通过电子技术实现对门的开关控制,可以有效地提高房屋或办公室的安全性。在本篇文章中,我们将介绍如何基于51单片机设计一个简单的电子密码锁设计思路: 电子密码锁设计思路是通过51单片机控制密码输入与门的开关控制。设计需要采用矩阵键盘作为输入设备,将输入的密码与预设密码进行比较,如果相同,则控制门的开关。 硬件设计电子密码锁的硬件设计主要包括以下几个部分: 1. 51单片机控制模块:选择STC89C52RC单片机作为控制模块,具有较强的处理能力和稳定性。 2. 矩阵键盘输入模块:选择4x4的矩阵键盘,通过51单片机的IO口读取用户输入的密码。 3. 驱动电路模块:选择继电器作为驱动装置,通过继电器控制门的开关。 4. 电源模块:选择12V电源,通过稳压电路提供5V电压给单片机和其他电路元件。 软件设计电子密码锁的软件设计主要包括以下几个部分: 1. IO口初始化:设置51单片机的IO口为输入或输出状态。 2. 矩阵键盘扫描:通过循环扫描矩阵键盘,读取用户输入的密码。 3. 密码比较:将用户输入的密码与预设密码进行比较,如果相同,则控制门的开关。 4. 继电器控制:通过控制继电器开关实现门的开关。 总结: 本文介绍了基于51单片机设计电子密码锁的方法。通过矩阵键盘输入密码,将输入的密码与预设密码进行比较,实现对门的开关控制。该电子密码锁具有较高的安全性和可靠性,可应用于家庭、办公室等多种场所。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值