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

基于51单片机的密码锁设计设计思路电子密码锁设计 以 AT89C51 为主控 晶振电路和复位电路共同组成最小系统 使得单片机可以正常运行

设计思路

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

使用方法

 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); //写默认密码至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 

需要工程文件评论区留言

今天的文章 基于51单片机的密码锁设计分享到此就结束了,感谢您的阅读。
编程小号
上一篇 2024-12-18 08:17
下一篇 2024-12-18 08:11

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/bian-cheng-ji-chu/89955.html