设计思路
电子密码锁设计,以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单片机的密码锁设计分享到此就结束了,感谢您的阅读。需要工程文件评论区留言
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/bian-cheng-ji-chu/89955.html