二○一六~二○一七学年第一学期电子信息工程系电子综合设计II报告书班级:电信(产业)1401班设计时间:2016/12/29学生姓名:学号:指导教师:二○一六年十二月一、设计要求.题目内容:设计一个基于51单片机的电子密码锁:1.可以使用4*4的矩阵键盘与红外遥控器输入密码。
2.可以通过按特殊组合键重设开锁密码。
3.显示通过1602液晶屏显示电子密码锁界面,输入密码时显示输入个数显示为‘*’,如果密码正确,进入欢迎界面。
4.密码连续输入3次错误报警,LCD显示报警,倒计时十秒后重新进入密码输入界面。
5.可以通过特殊的按键组合跳过输入界面直接进入欢迎界面。
实现方法:1.通过红外接收头,连接单片机的P3.2外部中断INT0口,可以实现单片机接收遥控器的信号输入。
2.通过矩阵键盘扫描函数,可以实现对键盘输入的响应。
3.通过引脚的高低电平变化频率,控制蜂鸣器的输入占空比和频率(低电平时间固定,通过输入给函数值的不同改变高电平时间,固定响300个周期),对不同按键实现不同声音响应。
4.1602显示屏有16*2个单元格,每个单元格由5*8个像素点组成,可以很好的显示数字,符号,英文字符。
功能需求分析:液晶屏显示:根据题意,需要设计并显示输入密码界面、修改密码界面、欢迎界面、错误警告界面密码输入:根据题意,每次输入一个数字,则显示一个‘*’符号代替,只能看出输入的位数,若输入密码位数达到六位,则与正确密码比较,若正确,进入系统。
根据日常的手机使用习惯,默认长度为6位,且第六位输入之后立即判断,正确则进入,错误则清空重输。
组合键实现密码修改:密码修改必须通过不易被他人发现的特殊方法改变,所以设计为,若同时按住矩阵键盘的5,10 或6,9两个键,则进入密码修改函数。
输入密码错误三次则报错:一般的密码系统对密码输入错误次数过多的情况进行了限制,所以在密码锁里设置,若密码输入错误三次,则进入警报界面,显示10s倒计时,必须在倒计时结束后才能再次输入密码。
组合键实现跳过密码:如果系统主人临时忘记了密码,则需要一些补救的备用措施,所以在电子锁里设计了,如果同时按下0,15或3,12键,则跳过密码输入阶段,直接进入欢迎界面。
红外控制:在很多时候,需要通过远程通信输入密码,进入某个远程服务器系统。
所以,通过红外设备模拟远程通信就显得很有必要。
再此系统中,通过把红外接收引脚接到外部中断INT0口,实现接收红外遥控器的数据。
重新输入:如果密码输入的过程中,发现输错了一位数,方便起见,要设置重新输入的功能,即矩阵按键为11,或红外遥控键值为12时,重新输入密码,并且不计入输错次数。
二、 系统总体设计框架系统模块分布图:电子密码锁系统密码输入及显示蜂鸣器模块重设密码跳过密码输入过程警告音1602显示模块按键音管理员模块输入密码界面警告界面重设密码界面欢迎界面详细流程框图:开始若为重置密码指令红外外部中断键盘扫描错误警报进入欢迎界面输入界面是否为特殊组合键输入是否达到6位是否与正确密码相同错误次数达到三次?系统锁定,并倒计时十秒将输入密码暂存在数组用*显示密码位数是否是否是否是否将输入的六位六位密码数组与正确值比较若为跳过密码指令输入密码界面重置密码界面输入是否达到6位将输入密码存入正确密码数组中,完成重置否是三、运行结果密码输入:每次输入一个数字,则显示一个‘*’符号。
密码修改:通过特殊组合按键,进入密码修改函数。
三次报错:若密码输入错误三次,则进入警报界面。
特殊键清除:通过特殊组合按键,进入密码修改函数。
红外控制:通过红外遥控器输入密码。
重新输入:通过红外遥控器的12号按键或矩阵键盘的11号按键可以重新输入密码。
四、实验小结本次实验,用51单片机实现了电子密码锁系统,虽然内容较基础,但是还是新学到了一些新知识,如红外线的数据传输方式,外部中断的合理使用。
同时也遇到了一些问题:用红外遥控器输入密码的时候,总会在短时间内把一个键值发给单片机发送两次,但是原因不是太清楚,可能是红外遥控器的抬起也算一个命令,然后我再判断主函数的红外线标志位判断的地方,加了0.5秒的延迟,解决了问题。
以后有时间再把红外接收器的数据手册详细看看,研究问题出在哪里。
总体来说,这一次的动手设计还是让自身能力提高了不少,但其实我学习的东西还远远不够,在以后的学习里,我会抓紧课外时间多学习知识,才能将自身解决实际问题的能力快速提高。
五、参考文献[1] 谭浩强,C语言程序设计,清华大学出版社,2005[2] 张毅刚,单片机原理及接口技术,人民邮电出版社,2011六、附录:源程序/******************************************************************************* * 电子密码锁系统 Designed By 曹子龙 2016/12/29 * *******************************************************************************/#include<reg51.h>#include"lcd.h" //包含控制1602的初始化程序及写入命令的程序#define GPIO_KEY P1 //矩阵键盘接口sbit IRIN=P3^2; //红外线接口sbit Beep = P2^0; //蜂鸣器接口unsigned char code CDIS0[16]={" Set Code: "}; //用来初始化1602屏幕显示内容的字符串数组unsigned char code CDIS1[16]={" Enter Code: "};unsigned char code CDIS2[16]={" Code: "};unsigned char code CDIS3[16]={" Welcome to "};unsigned char code CDIS4[16]={" My System!"};unsigned char code CDIS5[16]={" Warning: "};unsigned char code CDIS6[16]={" Please Wait s!"};unsigned int RIGHTCODE[6]={9,7,0,2,2,9};//初始正确密码unsigned int Code[6]; //用来存放输入密码unsigned int KeyValue; //用来储存键值unsigned int Key_Flag=0; //有按键按下时置为1unsigned int HongwaiValue; //用来储存键值unsigned int Hongwai_Flag=0; //有红外信号时置为1unsigned int Annum=0; //用来储存按键次数unsigned int Wrongnum=0; //用来储存错误次数unsigned int CodeFlag=0; //用来标识密码是否输入正确unsigned int CodeDel=0; //特殊组合键可以清除密码unsigned char IrValue[6]; //暂存接收到的红外信号unsigned char Time;unsigned char WrongTime; //用来储存错误等待时间void SetCode(); //重置密码函数void hongwai(); //将红外接收的值变为对应的按键值void IrInit(); //红外初始化void DelayMs(unsigned int );void beep(unsigned int); //可让蜂鸣器实现不同频率声音的函数void KeyScan(); //键盘扫描函数/******************************************************************************* * 函数名 : main* 函数功能 : 主函数*******************************************************************************/void main(){unsigned char i;IrInit();LcdInit();LcdWriteCom(0x80); //初始化LCD1602显示,展示密码输入界面for(i=0;i<16;i++){LcdWriteData(CDIS1[i]);}LcdWriteCom(0x80+0x40);for(i=0;i<16;i++){LcdWriteData(CDIS2[i]);}while(1){KeyScan(); //扫描键盘if(CodeDel==4) //若输入正确的组合按键,可重设密码SetCode();else if(CodeDel==2) //若输入正确的组合按键,则清除密码,直接进入系统{Wrongnum=0; //若输入正确,错误次数清零Annum=0; //密码计数器清零CodeDel=0; //组合键标志位清0Key_Flag=0; //按键标志位清0Hongwai_Flag=0; //红外标志位清0LcdWriteCom(0x80); //进入欢迎界面 5sfor(i=0;i<16;i++){LcdWriteData(CDIS3[i]);}LcdWriteCom(0x80+0x40);for(i=0;i<16;i++){LcdWriteData(CDIS4[i]);}DelayMs(50000);LcdWriteCom(0x80);for(i=0;i<16;i++) //等待结束后,次数清零,显示输入密码界面{LcdWriteData(CDIS1[i]);}LcdWriteCom(0x80+0x40);for(i=0;i<16;i++){LcdWriteData(CDIS2[i]);}}if(Key_Flag==1){Key_Flag=0;Code[Annum-1]=KeyValue; //将输入值存入密码数组中beep(KeyValue * 30);LcdWriteCom(0xc0+6+Annum);LcdWriteData(42);}if(Hongwai_Flag==1) //若接受到了红外数据{DelayMs(500);if(Hongwai_Flag==1) //不知道因为什么原因,红外接收的中断会开启两次,为了防止数据重复,写了此次延时判断{Annum++; //按键次数加1Hongwai_Flag=0;Code[Annum-1]=HongwaiValue;//将输入值存入密码数组中beep(HongwaiValue * 40);LcdWriteCom(0xc0+6+Annum);LcdWriteData(42);}}if(Annum>=6) //6位密码输入完毕或检测到特殊组合按键{CodeFlag=1; //暂时令标志位为1,若密码有错误,则再置0for(i=0;i<6;i++){if(Code[i]!=RIGHTCODE[i]) //若密码与正确密码不相等CodeFlag=0;}if(CodeFlag==0) //若输入错误,清零重新输入,并将错误输入次数加一{Wrongnum++;if(Wrongnum==3) //若错误次数达到三次{beep(100); //警报LcdWriteCom(0x80); //显示错误信息,等待10sfor(i=0;i<16;i++){LcdWriteData(CDIS5[i]);}LcdWriteCom(0x80+0x40);for(i=0;i<16;i++){LcdWriteData(CDIS6[i]);}WrongTime='9'; //等待时间while(WrongTime!='0'){LcdWriteCom(0x80+0x40+13);LcdWriteData(WrongTime);DelayMs(10000);WrongTime--;}Wrongnum=0;}Annum=0;Key_Flag=0; //按键标志位清0Hongwai_Flag=0; //红外标志位清0LcdWriteCom(0x80);for(i=0;i<16;i++) //等待结束后,次数清零,显示输入密码界面{LcdWriteData(CDIS1[i]);}LcdWriteCom(0x80+0x40);for(i=0;i<16;i++){LcdWriteData(CDIS2[i]);}}if(CodeFlag==1) //密码输入正确{Wrongnum=0; //若输入正确,错误次数清零Annum=0; //密码计数器清零LcdWriteCom(0x80); //进入欢迎界面 5sfor(i=0;i<16;i++){LcdWriteData(CDIS3[i]);}LcdWriteCom(0x80+0x40);for(i=0;i<16;i++){LcdWriteData(CDIS4[i]);}DelayMs(50000);LcdWriteCom(0x80);for(i=0;i<16;i++) //等待结束后,次数清零,显示输入密码界面{LcdWriteData(CDIS1[i]);}LcdWriteCom(0x80+0x40);for(i=0;i<16;i++){LcdWriteData(CDIS2[i]);}/*标志清零需放在后面,因为在密码输入正确后的显示时间内,外部中断或按键都会使标志位为1,进而在再次显示密码时弹出一位密码值*/Key_Flag=0; //按键标志位清0Hongwai_Flag=0; //红外标志位清0}}}}/******************************************************************************* * 函数名 : SetCode()* 函数功能: 设置密码*******************************************************************************/ void SetCode(){int i,j=0;Wrongnum=0; //错误次数清零Annum=0; //密码计数器清零CodeDel=0; //组合键标志位清0Key_Flag=0; //按键标志位清0Hongwai_Flag=0; //红外标志位清0LcdWriteCom(0x80);for(i=0;i<16;i++) //初始化LCD1602显示,显示设置密码界面{LcdWriteData(CDIS0[i]);}LcdWriteCom(0x80+0x40);for(i=0;i<16;i++){LcdWriteData(CDIS2[i]);}DelayMs(1000);while(j<6){KeyScan(); //扫描键盘if(Key_Flag==1){Key_Flag=0;RIGHTCODE[j]=KeyValue;beep(KeyValue * 30);LcdWriteCom(0xc0+7+j);LcdWriteData(42);j++;DelayMs(1000);}if(Hongwai_Flag==1) //若接受到了红外数据{DelayMs(500);if(Hongwai_Flag==1) //不知道因为什么原因,红外接收的中断会开启两次,为了防止数据重复,写了此次延时判断{Hongwai_Flag=0;RIGHTCODE[j]=HongwaiValue;beep(HongwaiValue * 40);LcdWriteCom(0xc0+7+j);LcdWriteData(42);j++;DelayMs(1000);}}}LcdWriteCom(0x80);for(i=0;i<16;i++) //初始化LCD1602显示,展示密码输入界面{LcdWriteData(CDIS1[i]);}LcdWriteCom(0x80+0x40);for(i=0;i<16;i++){LcdWriteData(CDIS2[i]);}Wrongnum=0; //错误次数清零Annum=0; //密码计数器清零Key_Flag=0; //按键标志位清0Hongwai_Flag=0; //红外标志位清0}/******************************************************************************* * 函数名 : DelayMs()* 函数功能 : 延时*******************************************************************************/void DelayMs(unsigned int x) //0.14ms误差 0us{unsigned char i;while(x--){for (i = 0; i<13; i++){}}}/******************************************************************************* * 函数名 : IrInit()* 函数功能 : 初始化红外线接收*******************************************************************************/void IrInit(){IT0=1;//下降沿触发EX0=1;//打开中断0允许EA=1; //打开总中断IRIN=1;//初始化端口}/******************************************************************************* * 函数名 : ReadIr()* 函数功能 : 读取红外数值的中断函数*******************************************************************************/void ReadIr() interrupt 0{unsigned char j,k;unsigned int err;Time=0;DelayMs(70);if(IRIN==0) //确认是否真的接收到正确的信号{err=1000; //1000*10us=10ms,超过说明接收到错误的信号/*当两个条件都为真是循环,如果有一个条件为假的时候跳出循环,免得程序出错的时侯,程序死在这里*/while((IRIN==0)&&(err>0)) //等待前面9ms的低电平过去{DelayMs(1);err--;}if(IRIN==1) //如果正确等到9ms低电平{Hongwai_Flag=1; //正确收到信号,标志位置1err=500;while((IRIN==1)&&(err>0)) //等待4.5ms的起始高电平过去{DelayMs(1);err--;}for(k=0;k<4;k++) //共有4组数据{for(j=0;j<8;j++) //接收一组数据{err=60;while((IRIN==0)&&(err>0))//等待信号前面的560us低电平过去{DelayMs(1);err--;}err=500;while((IRIN==1)&&(err>0)) //计算高电平的时间长度。