基于单片机的智能密码锁

2019-04-15 18:03发布

该密码锁控制器 ,键盘上有0-9个数字按键,功能键:确认和取消等,可设置复合键。密码的位数及密码可以任意设定,,当输入数字和设置的密码相同的时候,锁打开,否则无法打开。采用IIC通信方式,密码锁的密码掉电不丢失。 #include #include #define uint unsigned int #define uchar unsigned char uchar old1,old2,old3,old4,old5,old6; //原始密码000000 uchar new1,new2,new3,new4,new5,new6; //每次MCU采集到的密码输入 uchar a=10,b=10,c=10,d=10,e=10,f=10; //送入数码管显示的变量 uchar wei,key,temp; bit allow,genggai,ok,wanbi,retry,close; //各个状态位,默认初始值为0 sbit dula=P2^6; sbit wela=P2^7; sbit beep=P2^3; sbit led=P1^0; //加一个流水灯,把蜂鸣器换掉 sbit sda=P2^0; //IO口定义 sbit scl=P2^1; unsigned char code table[]= {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40,0x08}; //数码管显示0-9的段码 /*****************i2c芯片24C02存储器驱动程序************************************/ /*驱动延时程序*/ void nop() //10us延时,保证书写i2c驱动时满足大于4us { _nop_(); _nop_(); } /*24C02读写驱动程序*/ void delay1(unsigned int m) { unsigned int n; for(n=0;nvoid init() //24c02初始化子程序 { scl=1; nop(); sda=1; nop(); } void start() //启动I2C总线 { sda=1; nop(); scl=1; nop(); sda=0; nop(); scl=0; nop(); } void stop() //停止I2C总线 { sda=0; nop(); scl=1; nop(); sda=1; nop(); } void writebyte(unsigned char j) //写一个字节 { unsigned char i,temp; temp=j; for (i=0;i<8;i++) { temp=temp<<1; scl=0; nop(); sda=CY; //temp左移时,移出的值放入了CY中 nop(); scl=1; //待sda线上的数据稳定后,将scl拉高 nop(); } scl=0; nop(); sda=1; nop(); } unsigned char readbyte() //读一个字节 { unsigned char i,j,k=0; scl=0; nop(); sda=1; for (i=0;i<8;i++) { nop(); scl=1; nop(); if(sda==1) j=1; else j=0; k=(k<<1)|j; scl=0; } nop(); return(k); } void clock() //I2C总线时钟 { unsigned char i=0; scl=1; nop(); while((sda==1)&&(i<255)) i++; scl=0; nop(); } ////////从24c02的地址address中读取一个字节数据///// unsigned char read24c02(unsigned char address) { unsigned char i; start(); writebyte(0xa0); clock(); writebyte(address); clock(); start(); writebyte(0xa1); clock(); i=readbyte(); stop(); delay1(100); return(i); } //////向24c02的address地址中写入一字节数据info///// void write24c02(unsigned char address,unsigned char info) { start(); writebyte(0xa0); clock(); writebyte(address); clock(); writebyte(info); clock(); stop(); delay1(5000); //这个延时一定要足够长,否则会出错。因为24c02在从sda上取得数据后,还需要一定时间的烧录过程。 } /****************************密码锁程序模块********************************************************/ /*密码锁的延时*/ void delay(unsigned char i) //1ms延时 { uchar j,k; for(j=i;j>0;j--) for(k=114;k>0;k--); } /*数码管驱动显示函数*/ void display(uchar a,uchar b,uchar c,uchar d,uchar e,uchar f) { dula=0; //第一位显示 P0=table[a]; dula=1; dula=0; wela=0; P0=0xfe; wela=1; wela=0; delay(5); P0=table[b]; // 第2位显示 dula=1; dula=0; P0=0xfd; wela=1; wela=0; delay(5); P0=table[c]; // 第3位显示 dula=1; dula=0; P0=0xfb; wela=1; wela=0; delay(5); P0=table[d]; // 第4位显示 dula=1; dula=0; P0=0xf7; wela=1; wela=0; delay(5); P0=table[e]; // 第5位显示 dula=1; dula=0; P0=0xef; wela=1; wela=0; delay(5); P0=table[f]; // 第6位显示 dula=1; dula=0; P0=0xdf; wela=1; wela=0; delay(5); } void keyscan() { { P3=0xfe; temp=P3; temp=temp&0xf0; if(temp!=0xf0) //判断有无按键按下 { delay(10); if(temp!=0xf0) //再次判断,消抖 { temp=P3; switch(temp) //扫描第一行 { case 0xee:key=0;wei++;break; //代表按键值 case 0xde:key=1;wei++;break; case 0xbe:key=2;wei++;break; case 0x7e:key=3;wei++;break; } while(temp!=0xf0) { temp=P3; temp=temp&0xf0; led=0; //每按一次亮一次灯 } led=1; } } P3=0xfd; //第二行 temp=P3; temp=temp&0xf0; if(temp!=0xf0) { delay(10); if(temp!=0xf0) { temp=P3; switch(temp) { case 0xed:key=4;wei++;break; case 0xdd:key=5;wei++;break; case 0xbd:key=6;wei++;break; case 0x7d:key=7;wei++;break; } while(temp!=0xf0) { temp=P3; temp=temp&0xf0; led=0; } led=1; } } P3=0xfb; temp=P3; temp=temp&0xf0; if(temp!=0xf0) { delay(10); if(temp!=0xf0) { temp=P3; switch(temp) { case 0xeb:key=8;wei++;break; case 0xdb:key=9;wei++;break; case 0xbb:genggai=1;wei=0;break; case 0x7b:if(allow)ok=1;break; } while(temp!=0xf0) { temp=P3; temp=temp&0xf0; led=0; } led=1; } } P3=0xf7; temp=P3; temp=temp&0xf0; if(temp!=0xf0) { delay(10); if(temp!=0xf0) { temp=P3; switch(temp) { case 0xe7:retry=1;break; case 0xd7:close=1;break; } while(temp!=0xf0) { temp=P3; temp=temp&0xf0; led=0; } led=1; } } } } void shumima() //对按键采集来的数据进行分配 { if(!wanbi) { switch(wei) { case 1:new1=key; if(!allow) a=11; //输入时显示下划线 else a=key; break; //改密码期间显示当前所改的密码的值 case 2:new2=key; if(a==11) b=11; else b=key; break; case 3:new3=key; if(a==11) c=11; else c=key; break; case 4:new4=key; if(a==11) d=11; else d=key; break; case 5:new5=key; if(a==11) e=11; else e=key; break; case 6:new6=key; if(a==11) f=11; else f=key; wanbi=1; break; } } } void yanzheng() //验证密码是否正确 { if(wanbi) //只有当六位密码均输入完毕后方进行验证 { if((new1==old1)&(new2==old2)&(new3==old3)&(new4==old4)&(new5==old5)&(new6==old6)) allow=1; //当输入的密码正确,会得到allowe置一 } } void main() { init(); //初始化24C02 /*格式化程序*/ // write24c02(110,0x00); // write24c02(111,0x00);//24c02的第110到115地址单元作为密码存储区 // write24c02(112,0x00); // write24c02(113,0x00); // write24c02(114,0x00); // write24c02(115,0x00); old1=read24c02(110); old2=read24c02(111); old3=read24c02(112); old4=read24c02(113); old5=read24c02(114); old6=read24c02(115); while(1) { keyscan(); shumima(); yanzheng(); if(allow) //验证完后,若allow为1,则开锁 { P1=0x00; if(!genggai) wanbi=0; } if(genggai) //当更改密码键被按下会被置一 { if(allow) //若已经把锁打开,才有更改密码的权限 { while(!wanbi) //当新的六位密码没有设定完,则一直在这里循环 { keyscan(); shumima(); if(retry|close) //而当探测到重试键或者关闭密码锁键被按下时,则跳出 { wanbi=1; break; } display(a,b,c,d,e,f); } } } if(ok) //更改密码时,当所有六位新密码均被按下时,可以按下此键,结束密码更改, 其他时间按下此键无效 { ok=0; wei=0; genggai=0; old1=new1;old2=new2;old3=new3; //此时,旧的密码将被代替 old4=new4;old5=new5;old6=new6; write24c02(110,old1); //新密码写入存储区。 write24c02(111,old2); write24c02(112,old3); write24c02(113,old4); write24c02(114,old5); write24c02(115,old6); a=10;b=10;c=10;d=10;e=10;f=10; } if(retry) //当重试按键被按下,retry会被置位 { retry=0; wei=0; wanbi=0; a=10;b=10;c=10;d=10;e=10;f=10; new1=0;new2=0;new3=0;new4=0;new5=0;new6=0; } if(close) //当关闭密码锁按键被按下,close会被置位 { close=0; genggai=0; //所有变量均被清零。 wei=0; wanbi=0; allow=0; P1=0xff; a=10;b=10;c=10;d=10;e=10;f=10; new1=0;new2=0;new3=0;new4=0;new5=0;new6=0; } display(a,b,c,d,e,f); //实时显示 } }