单片机电子密码锁课程设计报告.docx
《单片机电子密码锁课程设计报告.docx》由会员分享,可在线阅读,更多相关《单片机电子密码锁课程设计报告.docx(24页珍藏版)》请在冰点文库上搜索。
单片机电子密码锁课程设计报告
单片机技术及应用综合训练(设计报告)
前言
随着人们生活水平的提高,如何实现家庭防盗这一问题也变得尤为突出。
在科学技术不断发展的今天,电子密码防盗锁作为防盗卫士的作用显得日趋重要。
本文从经济实用的角度出发,系统由STC89C52与低功耗CMOS型E²PROMAT24C02作为主控芯片与数据存储器单元,结合外围的键盘输入、LCD显示、报警、开锁等电路模块。
它能完成以下功能:
正确输入密码前提下,开锁;错误输入密码情况下,报警;密码可以根据用户需要更改。
用C语言编写的主控芯片控制程序与EEPROMAT24C02读写程序相结合,并用Keil软件进行编译,设计了一款可以多次更改密码,具有报警功能的电子密码控制系统。
本密码锁具有设计方法合理,简单易行,成本低,安全实用,性强,灵活性高等特点,具有一定的推广价值。
关键词:
电子密码锁、报警、液晶显示
一、选题要求·····································1
二、硬件电路设计·································1
2.151单片机································2
2.2键盘电路·································2
2.3液晶显示电路·····························2
2.4警报电路·································3
2.5密码储存电路·····························3
2.6晶振、复位及关锁·························3
三、软件设计·····································4
四、软硬件调试结果·······························9
4.1电路总原理图·····························9
4.2调试结果································10
五、总结········································11
一、选题要求
本文从经济实用的角度出发,设计采用单片机为主控芯片,结合外围电路,组成电子密码控制系统,密码锁共6位密码,每位的取值围为0~9,用户可以自行设定和修改密码。
用户想要打开锁,必先通过提供的键盘输入正确的密码才可以,密码输入错误有提示,为了提高安全性,当密码输入错误三次将报警,期间输入密码无效,以防窃贼多次试探密码。
6位密码同时输入正确,锁才能打开。
锁有备用电池,只有部上电复位时才能设置或修改密码,因此,仅在门外按键是不能修改或设置密码的,因此性强、灵活性高。
其特点如下:
1)性好,编码量多,远远大于弹子锁。
随机开锁成功率几乎为零。
2)密码可变,用户可以随时更改密码,防止密码被盗,同时也可以避免因人员的更替而使锁的密级下降。
3)误码输入保护,当输入密码多次错误时,报警系统自动启动。
4)无活动零件,不会磨损,寿命长。
5)使用灵活性好,不像机械锁必须佩带钥匙才能开锁。
6)电子密码锁操作简单易行,一学即会。
二、硬件电路设计
下面是整个设计的流程图:
2.151单片机
这次课程设计采用的是5系列单片机AT89C52。
其外部封装如下图所示:
AT89C52单片机有4组8位的可编程I/O口,分别位P0、P1、P2、P3口,每个口有8位(8根引脚),共32根[8]。
P0口(Pin39~Pin32):
8位双向I/O口线,名称为P0.0~P0.7
P1口(Pin1~Pin8):
8位准双向I/O口线,名称为P1.0~P1.7
P2口(Pin21~Pin28):
8位准双向I/O口线,名称为P2.0~P2.7
P3口(Pin10~Pin17):
8位准双向I/O口线,名称为P3.0~P3.7
2.2键盘电路
本次试验采用的是行列键盘,C语言程序中有相应的驱动程序,其硬件电路如下所示,下右对应的为各个按键所对应的数字及功能。
0
1
2
3
4
5
6
7
8
9
确认
重输
改密
2.3液晶显示电路
实验中采用的是LM016L液晶显示,其数据端口采集数据通过单片机的P0口,接法如下图所示。
不同情况下会有不同的显示,显示容包括:
Wele、HelloBoss、Wrong、OK等容。
2.4警报电路
下图是警报电路连接图,警报触发为:
连续三次输错密码,警报触发后会有一个时间延迟,延迟时间任何操作都是无效的,过后通过关锁按钮可解除。
2.5密码储存电路
实验中考虑到实用性方面时,就想到了密码储存及修改的问题,于是采用了FM24C02F作为面膜储存模块,电路连接如下所示:
2.6晶振、复位及关锁
晶振、复位及关锁电路如下所示(作图所示按钮为复位按钮):
三、软件设计
C语言源程序:
#include
#defineCHECK_BUSY
#defineDataPortP0
#defineKeyPortP1
sbitRS=P2^4;//液晶显示的定义端口
sbitRW=P2^5;
sbitEN=P2^6;
sbitscl=P3^0;//24c02端口定义
sbitsda=P3^1;
sbitbaojing=P2^1;//报警器
sbitjdq=P2^0;//继电器
sbit=P2^3;//警报灯
sbitclose=P2^2;
unsignedcharold1,old2,old3,old4,old5,old6;//原始密码000000
unsignedcharnew1,new2,new3,new4,new5,new6;//代表新密码
voiddelay1(unsignedintm)
{
unsignedintn;
for(n=0;n}voiddelay(unsignedintm){unsignedinta;unsignedcharb;for(a=0;a{for(b=0;b<125;b++);}}voidDelayUs2x(unsignedchart){while(--t);}voidDelayMs(unsignedchart){while(t--){DelayUs2x(256);DelayUs2x(256);}}voidbaojingqi(){baojing=0;DelayUs2x(256);if(baojing==0){baojing=0;DelayUs2x(256);}}bitLCD_Check_Busy(void)//判忙函数{#ifdefCHECK_BUSYDataPort=0xFF;RS=0;RW=1;EN=0;_nop_();EN=1;return(bit)(DataPort&0x80);#elsereturn0;#endif}voidLCD_Write_(unsignedchar)//写入命令函数{//while(LCD_Check_Busy());//忙则等待DelayMs(5);RS=0;RW=0;EN=1;DataPort=;_nop_();EN=0;}voidLCD_Write_Data(unsignedcharData)//写入数据函数{//while(LCD_Check_Busy());//忙则等待DelayMs(5);RS=1;RW=0;EN=1;DataPort=Data;_nop_();EN=0;}voidLCD_Clear(void)//清屏函数{LCD_Write_(0x01);DelayMs(5);}voidLCD_Write_Char(unsignedcharx,unsignedchary,unsignedcharData)//写入字符函数{if(y==0){LCD_Write_(0x80+x);}else{LCD_Write_(0xC0+x);}LCD_Write_Data(Data);}voidLCD_Write_String(unsignedcharx,unsignedchary,unsignedchar*s)//写入字符串函数{while(*s){LCD_Write_Char(x,y,*s);s++;x++;}}voidLCD_Init(void)//液晶显示的初始化函数{LCD_Write_(0x38);//显示模式设置DelayMs(5);LCD_Write_(0x38);DelayMs(5);LCD_Write_(0x38);DelayMs(5);LCD_Write_(0x38);LCD_Write_(0x08);//显示关闭LCD_Write_(0x01);//显示清屏LCD_Write_(0x06);//显示光标移动设置DelayMs(5);LCD_Write_(0x0C);//显示开及光标设置}unsignedcharKeyScan(void)//键盘扫描函数,使用行列反转扫描法{unsignedcharcord_h,cord_l;//行列值中间变量KeyPort=0x0f;//行线输出全为0cord_h=KeyPort&0x0f;//读入列线值if(cord_h!=0x0f)//先检测有无按键按下{DelayMs(10);//去抖if((KeyPort&0x0f)!=0x0f){cord_h=KeyPort&0x0f;//读入列线值KeyPort=cord_h|0xf0;//输出当前列线值cord_l=KeyPort&0xf0;//读入行线值while((KeyPort&0xf0)!=0xf0);//等待松开并输出return(cord_h+cord_l);//键盘最后组合码值}}return(0xff);//返回该值}unsignedcharKeyPro(void){switch(KeyScan()){case0x7e:return0;break;//0按下相应的键显示相对应的码值case0x7d:return1;break;//1case0x7b:return2;break;//2case0x77:return3;break;//3case0xbe:return4;break;//4case0xbd:return5;break;//5case0xbb:return6;break;//6case0xb7:return7;break;//7case0xde:return8;break;//8case0xdd:return9;break;//9case0xdb:return10;break;//10case0xd7:return11;break;//11case0xee:return12;break;//12case0xed:return13;break;//13case0xeb:return14;break;//14case0xe7:return15;break;//15default:return0xff;break;}}voidinit()//24c02初始化子程序{scl=1;_nop_();_nop_();sda=1;_nop_();_nop_();}voidrespons()//应答{unsignedchari;scl=1;_nop_();_nop_();while((sda==1)&&(i<250))i++;scl=0;_nop_();_nop_();}voidclock()//I2C总线时钟{unsignedchari=0;scl=1;_nop_();_nop_();while((sda==1)&&(i<255))i++;scl=0;_nop_();_nop_();}voidstart()//启动I2C总线{sda=1;_nop_();_nop_();scl=1;_nop_();_nop_();sda=0;_nop_();_nop_();scl=0;_nop_();_nop_();}voidstop()//停止I2C总线{sda=0;_nop_();_nop_();scl=1;_nop_();_nop_();sda=1;_nop_();_nop_();}voidwritebyte(unsignedchara)//写一个字节{unsignedcharb,tem;tem=a;for(b=0;b<8;b++){tem=tem<<1;scl=0;_nop_();_nop_();sda=CY;//temp左移时,移出的值放入了CY中_nop_();_nop_();scl=1;//待sda线上的数据稳定后,将scl拉高_nop_();_nop_();}scl=0;_nop_();_nop_();sda=1;_nop_();nop_();}unsignedcharreadbyte()//读一个字节{unsignedchari,j,k=0;scl=0;_nop_();_nop_();sda=1;for(i=0;i<8;i++){_nop_();_nop_();scl=1;_nop_();_nop_();if(sda==1)j=1;elsej=0;k=(k<<1)|j;scl=0;}_nop_();_nop_();return(k);}unsignedcharread24c02(unsignedcharaddress)//从24c02的地址address中读取一个字节数据{unsignedchardate;start();writebyte(0xa0);clock();writebyte(address);clock();start();writebyte(0xa1);clock();date=readbyte();stop();delay1(100);return(date);}voidwrite24c02(unsignedcharaddress,unsignedcharinfo)//向24c02的address地址中写入一字节数据info{start();writebyte(0xa0);clock();writebyte(address);clock();writebyte(info);clock();stop();delay1(5000);//这个延时一定要足够长,否则会出错。因为24c02在从sda上取得数据后,还需要一定时间的烧录过程。}main(){unsignedcharnum,i,bj,c=0;unsignedchartemp[6];bitFlag;init();//初始化24C02LCD_Init();//初始化液晶屏DelayMs(10);//延时用于稳定,可以去掉LCD_Clear();//清屏LCD_Write_String(0,0,"wele");//写入第一行信息old1=read24c02(110);old2=read24c02(111);old3=read24c02(112);old4=read24c02(113);old5=read24c02(114);old6=read24c02(115);while(1)//主循环{num=KeyPro();//扫描键盘if(num!=0xff)//如果扫描是按键有效值则进行处理{if(i==0)//输入是第一个字符的时候需要把改行清空,方便观看密码LCD_Write_String(0,1,"");//清除该行if(i<6)//密码是6位,大于6位时不再输入按键值{temp[i]=num;LCD_Write_Char(i,1,'*');}i++;//输入数值累加if(num==11)//重试键{i=0;LCD_Write_String(0,1,"");}}if(num==12){i=0;LCD_Write_String(0,1,"");if(bj==0){while(i<=6){num=KeyPro();//扫描键盘if(num!=0xff)//如果扫描是按键有效值则进行处理{if(i==0)//输入是第一个字符的时候需要把改行清空,方便观看密码LCD_Write_String(0,1,"");//清除该行if(i<6)//密码是6位,大于6位时不再输入按键值{temp[i]=num;LCD_Write_Char(i,1,'*');}i++;//输入数值累加if(num==11)//重试键{i=0;LCD_Write_String(0,1,"");}}if(num==10){num=0;new1=temp[0];new2=temp[1];new3=temp[2];new4=temp[3];new5=temp[4];new6=temp[5];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);LCD_Write_String(0,1,"ok");bj=1;DelayMs(220);DelayMs(220);DelayMs(220);}if(close==0){bj=1;i=0;LCD_Write_String(0,1,"");}}}i=0;}if(num==10)//数字10为确认键{new1=temp[0];new2=temp[1];new3=temp[2];new4=temp[3];new5=temp[4];new6=temp[5];if(i==7)//6位后的按键输入数值,相当于确认按键(任意按键即可){i=0;//计数器复位Flag=1;//先把比较位置1old1=read24c02(110);old2=read24c02(111);old3=read24c02(112);old4=read24c02(113);old5=read24c02(114);old6=read24c02(115);Flag=Flag&(new1==old1)&(new2==old2)&(new3==old3)&(new4==old4)&(new5==old5)&(new6==old6);//比较输入值和已有密码if(Flag)//如果比较全部相同,标志位置1{i=0;LCD_Write_String(0,1,"HelloBoss!");//密码正确显示的信息jdq=0;bj=0;delay(3000);jdq=1;LCD_Write_String(0,1,"");}else{i=0;c++;LCD_Write_String(0,1,"error!");//密码错误,提示重新输入while(c==3){baojingqi();=0;DelayMs(255);DelayMs(255);baojing=1;i=0;=1;LCD_Write_String(0,1,"");if(close==0){i=0;bj=1;=1;c=0;baojing=1;LCD_Write_String(0,1,"");}}}}else//当密码不是6位数字时按下确认键也算输错密码一次{i=0;LCD_Write_String(0,1,"error!");c++;while(c==3){baojingqi();=0;DelayMs(255);DelayMs(255);if(close==0){i=0;=1;bj=1;c=0;baojing=1;LCD_Write_String(0,1,"");}}}}if(close==0){i=0;bj=1;=1;c=0;jdq=1;baojing=1;LCD_Write_String(0,1,"");jdq=1;}}四、软硬件调试结果4.1电路总原理图电路总原理图如下所示:4.2调试结果各种情况下的的调试结果如下个图所示:依次为开机、开锁、成功修改密码、密码错误。五、总结在这次实验中,用到了单片机和C语言的知识,这两门知识都是非常具有实用性的。在这次实验中再次加深了对此的认识。首先,在一开始输程序的时候,在程序仿真过程中出现了不能打开头文件的现象,后来经老师知道后知道了头文件的具体作用和使用方式
}
voiddelay(unsignedintm)
unsignedinta;
unsignedcharb;
for(a=0;a{for(b=0;b<125;b++);}}voidDelayUs2x(unsignedchart){while(--t);}voidDelayMs(unsignedchart){while(t--){DelayUs2x(256);DelayUs2x(256);}}voidbaojingqi(){baojing=0;DelayUs2x(256);if(baojing==0){baojing=0;DelayUs2x(256);}}bitLCD_Check_Busy(void)//判忙函数{#ifdefCHECK_BUSYDataPort=0xFF;RS=0;RW=1;EN=0;_nop_();EN=1;return(bit)(DataPort&0x80);#elsereturn0;#endif}voidLCD_Write_(unsignedchar)//写入命令函数{//while(LCD_Check_Busy());//忙则等待DelayMs(5);RS=0;RW=0;EN=1;DataPort=;_nop_();EN=0;}voidLCD_Write_Data(unsignedcharData)//写入数据函数{//while(LCD_Check_Busy());//忙则等待DelayMs(5);RS=1;RW=0;EN=1;DataPort=Data;_nop_();EN=0;}voidLCD_Clear(void)//清屏函数{LCD_Write_(0x01);DelayMs(5);}voidLCD_Write_Char(unsignedcharx,unsignedchary,unsignedcharData)//写入字符函数{if(y==0){LCD_Write_(0x80+x);}else{LCD_Write_(0xC0+x);}LCD_Write_Data(Data);}voidLCD_Write_String(unsignedcharx,unsignedchary,unsignedchar*s)//写入字符串函数{while(*s){LCD_Write_Char(x,y,*s);s++;x++;}}voidLCD_Init(void)//液晶显示的初始化函数{LCD_Write_(0x38);//显示模式设置DelayMs(5);LCD_Write_(0x38);DelayMs(5);LCD_Write_(0x38);DelayMs(5);LCD_Write_(0x38);LCD_Write_(0x08);//显示关闭LCD_Write_(0x01);//显示清屏LCD_Write_(0x06);//显示光标移动设置DelayMs(5);LCD_Write_(0x0C);//显示开及光标设置}unsignedcharKeyScan(void)//键盘扫描函数,使用行列反转扫描法{unsignedcharcord_h,cord_l;//行列值中间变量KeyPort=0x0f;//行线输出全为0cord_h=KeyPort&0x0f;//读入列线值if(cord_h!=0x0f)//先检测有无按键按下{DelayMs(10);//去抖if((KeyPort&0x0f)!=0x0f){cord_h=KeyPort&0x0f;//读入列线值KeyPort=cord_h|0xf0;//输出当前列线值cord_l=KeyPort&0xf0;//读入行线值while((KeyPort&0xf0)!=0xf0);//等待松开并输出return(cord_h+cord_l);//键盘最后组合码值}}return(0xff);//返回该值}unsignedcharKeyPro(void){switch(KeyScan()){case0x7e:return0;break;//0按下相应的键显示相对应的码值case0x7d:return1;break;//1case0x7b:return2;break;//2case0x77:return3;break;//3case0xbe:return4;break;//4case0xbd:return5;break;//5case0xbb:return6;break;//6case0xb7:return7;break;//7case0xde:return8;break;//8case0xdd:return9;break;//9case0xdb:return10;break;//10case0xd7:return11;break;//11case0xee:return12;break;//12case0xed:return13;break;//13case0xeb:return14;break;//14case0xe7:return15;break;//15default:return0xff;break;}}voidinit()//24c02初始化子程序{scl=1;_nop_();_nop_();sda=1;_nop_();_nop_();}voidrespons()//应答{unsignedchari;scl=1;_nop_();_nop_();while((sda==1)&&(i<250))i++;scl=0;_nop_();_nop_();}voidclock()//I2C总线时钟{unsignedchari=0;scl=1;_nop_();_nop_();while((sda==1)&&(i<255))i++;scl=0;_nop_();_nop_();}voidstart()//启动I2C总线{sda=1;_nop_();_nop_();scl=1;_nop_();_nop_();sda=0;_nop_();_nop_();scl=0;_nop_();_nop_();}voidstop()//停止I2C总线{sda=0;_nop_();_nop_();scl=1;_nop_();_nop_();sda=1;_nop_();_nop_();}voidwritebyte(unsignedchara)//写一个字节{unsignedcharb,tem;tem=a;for(b=0;b<8;b++){tem=tem<<1;scl=0;_nop_();_nop_();sda=CY;//temp左移时,移出的值放入了CY中_nop_();_nop_();scl=1;//待sda线上的数据稳定后,将scl拉高_nop_();_nop_();}scl=0;_nop_();_nop_();sda=1;_nop_();nop_();}unsignedcharreadbyte()//读一个字节{unsignedchari,j,k=0;scl=0;_nop_();_nop_();sda=1;for(i=0;i<8;i++){_nop_();_nop_();scl=1;_nop_();_nop_();if(sda==1)j=1;elsej=0;k=(k<<1)|j;scl=0;}_nop_();_nop_();return(k);}unsignedcharread24c02(unsignedcharaddress)//从24c02的地址address中读取一个字节数据{unsignedchardate;start();writebyte(0xa0);clock();writebyte(address);clock();start();writebyte(0xa1);clock();date=readbyte();stop();delay1(100);return(date);}voidwrite24c02(unsignedcharaddress,unsignedcharinfo)//向24c02的address地址中写入一字节数据info{start();writebyte(0xa0);clock();writebyte(address);clock();writebyte(info);clock();stop();delay1(5000);//这个延时一定要足够长,否则会出错。因为24c02在从sda上取得数据后,还需要一定时间的烧录过程。}main(){unsignedcharnum,i,bj,c=0;unsignedchartemp[6];bitFlag;init();//初始化24C02LCD_Init();//初始化液晶屏DelayMs(10);//延时用于稳定,可以去掉LCD_Clear();//清屏LCD_Write_String(0,0,"wele");//写入第一行信息old1=read24c02(110);old2=read24c02(111);old3=read24c02(112);old4=read24c02(113);old5=read24c02(114);old6=read24c02(115);while(1)//主循环{num=KeyPro();//扫描键盘if(num!=0xff)//如果扫描是按键有效值则进行处理{if(i==0)//输入是第一个字符的时候需要把改行清空,方便观看密码LCD_Write_String(0,1,"");//清除该行if(i<6)//密码是6位,大于6位时不再输入按键值{temp[i]=num;LCD_Write_Char(i,1,'*');}i++;//输入数值累加if(num==11)//重试键{i=0;LCD_Write_String(0,1,"");}}if(num==12){i=0;LCD_Write_String(0,1,"");if(bj==0){while(i<=6){num=KeyPro();//扫描键盘if(num!=0xff)//如果扫描是按键有效值则进行处理{if(i==0)//输入是第一个字符的时候需要把改行清空,方便观看密码LCD_Write_String(0,1,"");//清除该行if(i<6)//密码是6位,大于6位时不再输入按键值{temp[i]=num;LCD_Write_Char(i,1,'*');}i++;//输入数值累加if(num==11)//重试键{i=0;LCD_Write_String(0,1,"");}}if(num==10){num=0;new1=temp[0];new2=temp[1];new3=temp[2];new4=temp[3];new5=temp[4];new6=temp[5];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);LCD_Write_String(0,1,"ok");bj=1;DelayMs(220);DelayMs(220);DelayMs(220);}if(close==0){bj=1;i=0;LCD_Write_String(0,1,"");}}}i=0;}if(num==10)//数字10为确认键{new1=temp[0];new2=temp[1];new3=temp[2];new4=temp[3];new5=temp[4];new6=temp[5];if(i==7)//6位后的按键输入数值,相当于确认按键(任意按键即可){i=0;//计数器复位Flag=1;//先把比较位置1old1=read24c02(110);old2=read24c02(111);old3=read24c02(112);old4=read24c02(113);old5=read24c02(114);old6=read24c02(115);Flag=Flag&(new1==old1)&(new2==old2)&(new3==old3)&(new4==old4)&(new5==old5)&(new6==old6);//比较输入值和已有密码if(Flag)//如果比较全部相同,标志位置1{i=0;LCD_Write_String(0,1,"HelloBoss!");//密码正确显示的信息jdq=0;bj=0;delay(3000);jdq=1;LCD_Write_String(0,1,"");}else{i=0;c++;LCD_Write_String(0,1,"error!");//密码错误,提示重新输入while(c==3){baojingqi();=0;DelayMs(255);DelayMs(255);baojing=1;i=0;=1;LCD_Write_String(0,1,"");if(close==0){i=0;bj=1;=1;c=0;baojing=1;LCD_Write_String(0,1,"");}}}}else//当密码不是6位数字时按下确认键也算输错密码一次{i=0;LCD_Write_String(0,1,"error!");c++;while(c==3){baojingqi();=0;DelayMs(255);DelayMs(255);if(close==0){i=0;=1;bj=1;c=0;baojing=1;LCD_Write_String(0,1,"");}}}}if(close==0){i=0;bj=1;=1;c=0;jdq=1;baojing=1;LCD_Write_String(0,1,"");jdq=1;}}四、软硬件调试结果4.1电路总原理图电路总原理图如下所示:4.2调试结果各种情况下的的调试结果如下个图所示:依次为开机、开锁、成功修改密码、密码错误。五、总结在这次实验中,用到了单片机和C语言的知识,这两门知识都是非常具有实用性的。在这次实验中再次加深了对此的认识。首先,在一开始输程序的时候,在程序仿真过程中出现了不能打开头文件的现象,后来经老师知道后知道了头文件的具体作用和使用方式
{for(b=0;b<125;b++);}
voidDelayUs2x(unsignedchart)
while(--t);
voidDelayMs(unsignedchart)
while(t--)
DelayUs2x(256);
voidbaojingqi()
baojing=0;
if(baojing==0)
bitLCD_Check_Busy(void)//判忙函数
#ifdefCHECK_BUSY
DataPort=0xFF;
RS=0;
RW=1;
EN=0;
_nop_();
EN=1;
return(bit)(DataPort&0x80);
#else
return0;
#endif
voidLCD_Write_(unsignedchar)//写入命令函数
//while(LCD_Check_Busy());//忙则等待
DelayMs(5);
RS=0;RW=0;EN=1;
DataPort=;
_nop_();EN=0;
voidLCD_Write_Data(unsignedcharData)//写入数据函数
RS=1;RW=0;EN=1;
DataPort=Data;
voidLCD_Clear(void)//清屏函数
LCD_Write_(0x01);
voidLCD_Write_Char(unsignedcharx,unsignedchary,unsignedcharData)//写入字符函数
if(y==0)
{LCD_Write_(0x80+x);}
else
{LCD_Write_(0xC0+x);}
LCD_Write_Data(Data);
voidLCD_Write_String(unsignedcharx,unsignedchary,unsignedchar*s)//写入字符串函数
while(*s)
LCD_Write_Char(x,y,*s);
s++;x++;
voidLCD_Init(void)//液晶显示的初始化函数
LCD_Write_(0x38);//显示模式设置
LCD_Write_(0x38);
LCD_Write_(0x08);//显示关闭
LCD_Write_(0x01);//显示清屏
LCD_Write_(0x06);//显示光标移动设置
LCD_Write_(0x0C);//显示开及光标设置
unsignedcharKeyScan(void)//键盘扫描函数,使用行列反转扫描法
unsignedcharcord_h,cord_l;//行列值中间变量
KeyPort=0x0f;//行线输出全为0
cord_h=KeyPort&0x0f;//读入列线值
if(cord_h!
=0x0f)//先检测有无按键按下
DelayMs(10);//去抖
if((KeyPort&0x0f)!
=0x0f)
KeyPort=cord_h|0xf0;//输出当前列线值
cord_l=KeyPort&0xf0;//读入行线值
while((KeyPort&0xf0)!
=0xf0);//等待松开并输出
return(cord_h+cord_l);//键盘最后组合码值
}}return(0xff);//返回该值
unsignedcharKeyPro(void)
switch(KeyScan())
case0x7e:
return0;break;//0按下相应的键显示相对应的码值
case0x7d:
return1;break;//1
case0x7b:
return2;break;//2
case0x77:
return3;break;//3
case0xbe:
return4;break;//4
case0xbd:
return5;break;//5
case0xbb:
return6;break;//6
case0xb7:
return7;break;//7
case0xde:
return8;break;//8
case0xdd:
return9;break;//9
case0xdb:
return10;break;//10
case0xd7:
return11;break;//11
case0xee:
return12;break;//12
case0xed:
return13;break;//13
case0xeb:
return14;break;//14
case0xe7:
return15;break;//15
default:
return0xff;break;
voidinit()//24c02初始化子程序
scl=1;
_nop_();_nop_();
sda=1;
voidrespons()//应答
unsignedchari;
while((sda==1)&&(i<250))
i++;
scl=0;_nop_();_nop_();
voidclock()//I2C总线时钟
unsignedchari=0;
while((sda==1)&&(i<255))
scl=0;
voidstart()//启动I2C总线
sda=0;
voidstop()//停止I2C总线
voidwritebyte(unsignedchara)//写一个字节
unsignedcharb,tem;
tem=a;
for(b=0;b<8;b++)
tem=tem<<1;
sda=CY;//temp左移时,移出的值放入了CY中
scl=1;//待sda线上的数据稳定后,将scl拉高
_nop_();nop_();
unsignedcharreadbyte()//读一个字节
unsignedchari,j,k=0;
for(i=0;i<8;i++)
scl=1;_nop_();
if(sda==1)j=1;
elsej=0;
k=(k<<1)|j;
return(k);
unsignedcharread24c02(unsignedcharaddress)//从24c02的地址address中读取一个字节数据
unsignedchardate;
start();
writebyte(0xa0);
clock();
writebyte(address);
writebyte(0xa1);
date=readbyte();
stop();
delay1(100);
return(date);
voidwrite24c02(unsignedcharaddress,unsignedcharinfo)//向24c02的address地址中写入一字节数据info
writebyte(info);
delay1(5000);//这个延时一定要足够长,否则会出错。
因为24c02在从sda上取得数据后,还需要一定时间的烧录过程。
main()
unsignedcharnum,i,bj,c=0;
unsignedchartemp[6];
bitFlag;
init();//初始化24C02
LCD_Init();//初始化液晶屏
DelayMs(10);//延时用于稳定,可以去掉
LCD_Clear();//清屏
LCD_Write_String(0,0,"wele");//写入第一行信息
old1=read24c02(110);
old2=read24c02(111);
old3=read24c02(112);
old4=read24c02(113);
old5=read24c02(114);
old6=read24c02(115);
while
(1)//主循环
num=KeyPro();//扫描键盘
if(num!
=0xff)//如果扫描是按键有效值则进行处理
if(i==0)//输入是第一个字符的时候需要把改行清空,方便观看密码
LCD_Write_String(0,1,"");//清除该行
if(i<6)//密码是6位,大于6位时不再输入按键值
temp[i]=num;
LCD_Write_Char(i,1,'*');
i++;//输入数值累加
if(num==11)//重试键
{i=0;LCD_Write_String(0,1,"");}
if(num==12)
{i=0;LCD_Write_String(0,1,"");
if(bj==0)
while(i<=6)
if(num==10)
num=0;
new1=temp[0];new2=temp[1];new3=temp[2];
new4=temp[3];new5=temp[4];new6=temp[5];
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);
LCD_Write_String(0,1,"ok");
bj=1;DelayMs(220);
DelayMs(220);DelayMs(220);
if(close==0)
bj=1;i=0;
LCD_Write_String(0,1,"");}
i=0;
if(num==10)//数字10为确认键
new1=temp[0];new2=temp[1];
new3=temp[2];new4=temp[3];
new5=temp[4];new6=temp[5];
if(i==7)//6位后的按键输入数值,相当于确认按键(任意按键即可)
i=0;//计数器复位
Flag=1;//先把比较位置1
Flag=Flag&(new1==old1)&(new2==old2)&(new3==old3)&(new4==old4)&(new5==old5)&(new6==old6);//比较输入值和已有密码
if(Flag)//如果比较全部相同,标志位置1
LCD_Write_String(0,1,"HelloBoss!
");//密码正确显示的信息
jdq=0;bj=0;
delay(3000);
jdq=1;
LCD_Write_String(0,1,"");
i=0;c++;
LCD_Write_String(0,1,"error!
");//密码错误,提示重新输入
while(c==3)
baojingqi();
=0;
DelayMs(255);DelayMs(255);
baojing=1;i=0;=1;LCD_Write_String(0,1,"");
i=0;bj=1;=1;c=0;baojing=1;LCD_Write_String(0,1,"");
else//当密码不是6位数字时按下确认键也算输错密码一次
i=0;LCD_Write_String(0,1,"error!
");
c++;
i=0;=1;bj=1;c=0;baojing=1;LCD_Write_String(0,1,"");
}}}}
i=0;bj=1;=1;c=0;
jdq=1;baojing=1;
四、软硬件调试结果
4.1电路总原理图
电路总原理图如下所示:
4.2调试结果
各种情况下的的调试结果如下个图所示:
依次为开机、开锁、成功修改密码、密码错误。
五、总结
在这次实验中,用到了单片机和C语言的知识,这两门知识都是非常具有实用性的。
在这次实验中再次加深了对此的认识。
首先,在一开始输程序的时候,在程序仿真过程中出现了不能打开头文件的现象,后来经老师知道后知道了头文件的具体作用和使用方式
copyright@ 2008-2023 冰点文库 网站版权所有
经营许可证编号:鄂ICP备19020893号-2