电子密码锁设计,以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
#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
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
#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
需要工程文件评论区留言