51单片机实现密码锁(有掉电保护功能)

178 阅读6分钟

简介: \n所用单片机型号为"STC89C52",用到的模块有AT24C02、LCD1602、矩阵键盘和独立键盘、led灯和蜂鸣器。\n主要实现的功能:\n可以模拟日常生活中的密码锁,密码长度为8位,烧录成功后没有初始密码,需要先设置一个初始密码。初始密码设置成功后,通过再次输入设置的密码即可开锁。在掉电后重新上电,设置的密码不变。开锁成功后可进行密码的修改和对led灯的控制。\n具体的现象:\n烧录成功后,按下初始密码设置键,显示屏会出现"Set Password"的字样,在输入初始密码时,led灯会逐个亮起,表示输入密码的位数。输入完成后按下储存键,字样消失,led灯全灭,表示设置成功。在开锁时,密码的输入现象和上边一样,如果输入正确,蜂鸣器长鸣3s,并有"Password Right"字样;如果输入错误,蜂鸣器短鸣三次,显示"Password Wrong"字样,可重新进行密码的输入。开锁成功后,可控制三个不同的流水灯展示和密码的修改。修改密码时,如果修改成功,会出现"Password Resetted"字样。\n密码锁按键示意图\n0——1——2——3\n 4——5——6——7\n 8——9——CO——CP\n IN——IM——IM——IM\n T1——T2——T3——RE\n(CO=储存键,CP=检验密码是否正确键,IN=初始密码设置键,IM=空闲键,T1,T2,T3=流水灯控制键,RE=修改密码键)\n操作时的按键顺序:\n设置初始密码:\n先按下IN键,然后进行8次数字键的输入,最后按下CO键,完成。\n输入密码开锁:\n先进行8次数字键的输入,然后按下CO键,最后按下CP键,完成。(若开锁成功,则进行下边操作,如果不成功,则重复此步骤。)\n流水灯控制:\n直接按T1,T2,T3键实现流水灯的效果(每个流水灯按一次演示一次,不循环。)\n修改密码:\n先进行8位数字键的输入,然后按下CO键,最后按下RE键,完成。 源代码展示:

#include <reg52.h> #include <intrins.h>

typedef unsigned int uint; typedef unsigned char uchar;

sbit Beep=P2^3; sbit SDA=P2^0; sbit SCL=P2^1; sbit RS=P3^5;//命令端 sbit RW=P3^6;//读写端 sbit EN=P3^4;//使能端

uchar a[8]={0};//临时数组 uchar b[8]={0};//储存输入密码的数组 uchar c[8]={0};//储存设置密码的数组 uchar t=0; uchar wei=0;//临时数组标志位 uchar flbg=0;//密码正确标志位 uchar flag=0;//输入密码标志位 uchar fldg=0;//密码输入完成标志位 uchar flcg=0;//修改密码标志位 uchar fleg=1;//设置初始密码标志位

void delay(uint z) { uint x,y; for(x=z;x>0;x--) for(y=114;y>0;y--); }

void display2() { uchar i,temp; P1=0XFE; for(i=0;i<7;i++) { temp=P1; P1=crol(temp,1); delay(200); }//8 P1=0XFE&0X7F; temp=0xfe; for(i=0;i<6;i++) { temp=crol(temp,1); P1=temp&0x7f; delay(200); }//7 P1=0xfe&0x3F; temp=0xfe; for(i=0;i<5;i++) { temp=crol(temp,1); P1=temp&0x3f; delay(200); }//6 P1=0XFE&0X1f; temp=0xfe; for(i=0;i<4;i++) { temp=crol(temp,1); P1=temp&0x1f; delay(200); }//5 P1=0XFE&0X07; temp=0xfe; for(i=0;i<3;i++) { temp=crol(temp,1); P1=temp&0x07; delay(200); }//4 P1=0XFE&0X03; temp=0xfe; for(i=0;i<2;i++) { temp=crol(temp,1); P1=temp&0x03; delay(200); }//3 P1=0XFE&0X01; temp=0xfe; for(i=0;i<1;i++) { temp=crol(temp,1); P1=temp&0x01; delay(200); }//2 P1=0x00; delay(200); }

void display1() { uchar temp,i; P1=0x7e;//1 8 temp=0xfe; for(i=0;i<7;i++) { P1=0x7e; P1=P1&temp; delay(200); temp=crol(temp,1); } for(i=0;i<7;i++) { P1=0x7e; P1=P1&temp; delay(180); temp=cror(temp,1); } //1 P1=0xbd; temp=0xfd; for(i=0;i<5;i++) { P1=0xbd; P1=P1&temp; delay(200); temp=crol(temp,1); } for(i=0;i<5;i++) { P1=0xbd; P1=P1&temp; delay(180); temp=cror(temp,1); } //2 P1=0XDB; temp=0xfb; for(i=0;i<3;i++) { P1=0XDB; P1=P1&temp; delay(200); temp=crol(temp,1); } for(i=0;i<3;i++) { P1=0XDB; P1=P1&temp; delay(180); temp=cror(temp,1); } P1=0XE7; }

void display3() { P1=0XFE; delay(300); P1=(~P1)|0X7E; delay(300); P1=0XFC; delay(300); P1=(~P1)|0X3C; delay(300); P1=0XF8; delay(300); P1=(~P1)|0X18; delay(300); P1=0xf0; delay(300); P1=~P1; delay(300); P1=0xf0; delay(300); P1=~P1; delay(300); P1=0XF1; delay(300); P1=(~P1)|0X81; delay(300); P1=0XF3; delay(300); P1=(~P1)|0XC3; delay(300); P1=0XF7; delay(300); P1=(~P1)|0XE7; delay(300); } /LCD1602/ void Read_Busy()//读状态 { uchar busy; P0=0XFF; RS=0; RW=1; do { EN=1; busy=P0; EN=0; }while(busy&0x80); }

void Write_cmd(uchar cmd)//写指令 { Read_Busy(); RS=0; RW=0; P0=cmd; EN=1; EN=0;//触发信号 RS=1;//进行复位从而不影响矩阵键盘 RW=1; EN=1; }

void Write_dat(uchar dat)//写数据 { Read_Busy(); RS=1; RW=0; P0=dat; EN=1; EN=0;//触发信号 RS=1;//进行复位从而不影响矩阵键盘 RW=1; EN=1; }

void LCD1602Init() { Write_cmd(0x38);//设置显示模式 Write_cmd(0x0c);//单纯开显示 Write_cmd(0x01);//数据指针清零 }

void LCDdata1() { Write_cmd(0x80|0x02);//Set Password Write_dat(0x53); Write_cmd(0x80|0x03); Write_dat(0x65); Write_cmd(0x80|0x04); Write_dat(0x74); Write_cmd(0x80|0x05); Write_dat(0x20); Write_cmd(0x80|0x06); Write_dat(0x50); Write_cmd(0x80|0x07); Write_dat(0x61); Write_cmd(0x80|0x08); Write_dat(0x73); Write_cmd(0x80|0x09); Write_dat(0x73); Write_cmd(0x80|0x0a); Write_dat(0x77); Write_cmd(0x80|0x0b); Write_dat(0x6f); Write_cmd(0x80|0x0c); Write_dat(0x72); Write_cmd(0x80|0x0d); Write_dat(0x64); }

void LCDdata2()//"Password Right" { Write_cmd(0x80|0x01); Write_dat(0x50); Write_cmd(0x80|0x02); Write_dat(0x61); Write_cmd(0x80|0x03); Write_dat(0x73); Write_cmd(0x80|0x04); Write_dat(0x73); Write_cmd(0x80|0x05); Write_dat(0x77); Write_cmd(0x80|0x06); Write_dat(0x6f); Write_cmd(0x80|0x07); Write_dat(0x72); Write_cmd(0x80|0x08); Write_dat(0x64); Write_cmd(0x80|0x09); Write_dat(0x20); Write_cmd(0x80|0x0a); Write_dat(0x52); Write_cmd(0x80|0x0b); Write_dat(0x69); Write_cmd(0x80|0x0c); Write_dat(0x67); Write_cmd(0x80|0x0d); Write_dat(0x68); Write_cmd(0x80|0x0e); Write_dat(0x74); }

void LCDdata3()//"Password Wrong" { Write_cmd(0x80|0x01); Write_dat(0x50); Write_cmd(0x80|0x02); Write_dat(0x61); Write_cmd(0x80|0x03); Write_dat(0x73); Write_cmd(0x80|0x04); Write_dat(0x73); Write_cmd(0x80|0x05); Write_dat(0x77); Write_cmd(0x80|0x06); Write_dat(0x6f); Write_cmd(0x80|0x07); Write_dat(0x72); Write_cmd(0x80|0x08); Write_dat(0x64); Write_cmd(0x80|0x09); Write_dat(0x20); Write_cmd(0x80|0x0a); Write_dat(0x57); Write_cmd(0x80|0x0b); Write_dat(0x72); Write_cmd(0x80|0x0c); Write_dat(0x6f); Write_cmd(0x80|0x0d); Write_dat(0x6e); Write_cmd(0x80|0x0e); Write_dat(0x67); }

void LCDdata4()//"Password Remade" { Write_cmd(0x80|0x01); Write_dat(0x50); Write_cmd(0x80|0x02); Write_dat(0x61); Write_cmd(0x80|0x03); Write_dat(0x73); Write_cmd(0x80|0x04); Write_dat(0x73); Write_cmd(0x80|0x05); Write_dat(0x77); Write_cmd(0x80|0x06); Write_dat(0x6f); Write_cmd(0x80|0x07); Write_dat(0x72); Write_cmd(0x80|0x08); Write_dat(0x64); Write_cmd(0x80|0x09); Write_dat(0x20); Write_cmd(0x80|0x0a); Write_dat(0x52); Write_cmd(0x80|0x0b); Write_dat(0x65); Write_cmd(0x80|0x0c); Write_dat(0x6d); Write_cmd(0x80|0x0d); Write_dat(0x61); Write_cmd(0x80|0x0e); Write_dat(0x64); Write_cmd(0x80|0x0f); Write_dat(0x65); } /* void LCDdata5()//"********" { Write_cmd(0x80|0x44); Write_dat(0x2a); Write_cmd(0x80|0x45); Write_dat(0x2a); Write_cmd(0x80|0x46); Write_dat(0x2a); Write_cmd(0x80|0x47); Write_dat(0x2a); Write_cmd(0x80|0x48); Write_dat(0x2a); Write_cmd(0x80|0x49); Write_dat(0x2a); Write_cmd(0x80|0x4a); Write_dat(0x2a); Write_cmd(0x80|0x4b); Write_dat(0x2a); }*/ /矩阵键盘/ void keyscan()//矩阵键盘的扫描 { uchar temp; P3=0XFF; P3=0XFE; temp=P3&0XF0; if(temp!=0xf0) { delay(20); P3=0XFE; temp=0xf0&P3; if(temp!=0xf0) { temp=P3; switch(temp) { case 0xee:if(t==1){a[wei]=0;P1=P1>>1;} if(t==0){a[wei]=0;P1=0X7F;t=1;}wei++;break; case 0xde:if(t==1){a[wei]=1;P1=P1>>1;} if(t==0){a[wei]=1;P1=0X7F;t=1;}wei++;break; case 0xbe:if(t==1){a[wei]=2;P1=P1>>1;} if(t==0){a[wei]=2;P1=0X7F;t=1;}wei++;break; case 0x7e:if(t==1){a[wei]=3;P1=P1>>1;} if(t==0){a[wei]=3;P1=0X7F;t=1;}wei++;break; } while(temp!=0xf0) { temp=P3&0XF0; } } } P3=0XFF; P3=0XFd; temp=P3&0XF0; if(temp!=0xf0) { delay(20); P3=0XFd; temp=0xf0&P3; if(temp!=0xf0) { temp=P3; switch(temp) { case 0xed:if(t==1){a[wei]=4;P1=P1>>1;} if(t==0){a[wei]=4;P1=0X7F;t=1;}wei++;break; case 0xdd:if(t==1){a[wei]=5;P1=P1>>1;} if(t==0){a[wei]=5;P1=0X7F;t=1;}wei++;break; case 0xbd:if(t==1){a[wei]=6;P1=P1>>1;} if(t==0){a[wei]=6;P1=0X7F;t=1;}wei++;break; case 0x7d:if(t==1){a[wei]=7;P1=P1>>1;} if(t==0){a[wei]=7;P1=0X7F;t=1;}wei++;break; } while(temp!=0xf0) { temp=P3&0XF0; } } } P3=0XFF; P3=0XFb; temp=P3&0XF0; if(temp!=0xf0) { delay(20); P3=0XFb; temp=0xf0&P3; if(temp!=0xf0) { temp=P3; switch(temp) { case 0xeb:if(t==1){a[wei]=8;P1=P1>>1;} if(t==0){a[wei]=8;P1=0X7F;t=1;}wei++;break; case 0xdb:if(t==1){a[wei]=9;P1=P1>>1;} if(t==0){a[wei]=9;P1=0X7F;t=1;}wei++;break; case 0xbb:for(wei=0;wei<8;wei++){b[wei]=a[wei];} if(wei==8){fldg=1;wei=0;P1=0XFF;}break;//按完八位后触发密码的储存 case 0x7b:if(flag==0) {flag=2;}break;//进行密码的比较 } while(temp!=0xf0) { temp=P3&0XF0; } } } P3=0XFF; P3=0XF7; temp=P3&0XF0; if(temp!=0xf0) { delay(20); P3=0XF7; temp=0xf0&P3; if(temp!=0xf0) { temp=P3; switch(temp) { case 0xe7:if(fleg==1){flag=1;fleg=0;LCDdata1();}break;//"Set Password"触发键 case 0xd7:break; case 0xb7:break; case 0x77:break; } while(temp!=0xf0) { temp=P3&0XF0; } } } P3=0XFF; } /独立键盘/ void keyscan1() { P3=0XFF; if(P3==0XFE) { delay(20); if(P3==0XFE) { display1(); P1=0XFF; while(P3==0XFE); } } P3=0XFF; if(P3==0XFD) { delay(20); if(P3==0XFD) { display2(); P1=0XFF; while(P3==0XFD); } } P3=0XFF; if(P3==0XFB) { delay(20); if(P3==0XFB) { display3(); P1=0XFF; while(P3==0XFB); } } P3=0XFF; if(P3==0XF7) { delay(20); if(P3==0XF7) { flcg=1; LCDdata4(); while(P3==0XF7); } } P3=0XFF; }

void compare() { uchar x,t=0,i=0; for(i=0;i<8;i++) { if(c[i]==b[i]) t++; if(c[i]!=b[i]) t=100; } if(t==8) { LCDdata2(); Beep=0; delay(3000); Beep=1; flag=0; flbg=1; } if(t!=8) { LCDdata3(); for(x=0;x<3;x++) { Beep=0; delay(200); Beep=1; delay(200); } flag=0; } } /AT24C02/ void delay_10us() { nop(); nop(); }

void delay_write(uint a) { uint b; for(b=0;b<a;b++); }

void Init()
{ SCL=1; delay_10us(); SDA=1; delay_10us(); }

void Start() { SDA=1; delay_10us(); SCL=1; delay_10us(); SDA=0; delay_10us(); SCL=0; delay_10us(); }

void Stop() { SDA=0; delay_10us(); SCL=1; delay_10us(); SDA=1; delay_10us(); }

void Writebyte(uchar a)
{ uchar b,temp; temp=a; for (b=0;b<8;b++) { temp=temp<<1; SCL=0; delay_10us(); SDA=CY; delay_10us(); SCL=1; delay_10us(); } SCL=0; delay_10us(); SDA=1; delay_10us(); }

uchar Readbyte() { uchar i,j,k=0; SCL=0; delay_10us(); SDA=1; for (i=0;i<8;i++) {
delay_10us(); SCL=1; delay_10us(); if(SDA==1) j=1; else j=0; k=(k<<1)|j; SCL=0; } delay_10us(); return k; }

void ACK() { uchar i=0; SCL=1; delay_10us(); while((SDA==1)&&(i<255)) i++; SCL=0; delay_10us(); }

uchar ReadAT24C02(uchar ADDR) { uchar i; Start(); Writebyte(0xa0); ACK(); Writebyte(ADDR); ACK(); Start(); Writebyte(0xa1); ACK(); i=Readbyte(); Stop(); delay_write(100); return i; }

void WriteAT24C02(uchar ADDR,uchar DATA) { Start(); Writebyte(0xa0); ACK(); Writebyte(ADDR); ACK(); Writebyte(DATA); ACK(); Stop(); delay_write(500); } /main函数/ void main() { uchar x=0;//AT24C02储存地址变量 Init();//时钟线和数据线的初始化 LCD1602Init();//打开LCD液晶屏 P1=0XFF; while(1) { keyscan();//用于扫描初始密码设置键 if(flag==1)//开始初始密码的设置 { keyscan();//用于密码的输入 if(fldg==1)//进行密码的储存 { while(x<8) { WriteAT24C02(0x00+x,b[x]); x++; } x=0; flag=0;//之后不再进入此函数,表示只有初次使用才能设置初始密码 fldg=0;//重置密码储存标志位 Write_cmd(0x01); } } if(flag==2)//验证密码是否正确 { while(x<8) { c[x]=ReadAT24C02(0x00+x); x++; } compare(); x=0; Write_cmd(0x01);//清空显示屏 } if(flbg==1)//密码正确后解锁独立键盘 { keyscan1(); keyscan(); if(flcg==1)//修改密码标志位 { while(x<8) { WriteAT24C02(0x00+x,b[x]); x++; } flcg=0; x=0; delay(1000);//用于保持关键字的显示 Write_cmd(0x01);//清空显示屏 } } } }