资源描述
二○一六~二○一七学年第 一 学期
电子信息工程系
电子综合设计II
报告书
班 级: 电信(产业)1401班
设计时间: 2016/12/29
学生姓名: 曹子龙
学 号: 201404135024
指导教师: 赵敏
二○一六年 十二 月
一、 设计要求.
题目内容:
设计一个基于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时,重新输入密码,并且不计入输错次数。
二、 系统总体设计框架
系统模块分布图:
详细流程框图:
三、 运行结果
密码输入:
每次输入一个数字,则显示一个‘*’符号。
密码修改:
通过特殊组合按键,进入密码修改函数。
三次报错:
若密码输入错误三次,则进入警报界面。
特殊键清除:
通过特殊组合按键,进入密码修改函数。
红外控制:
通过红外遥控器输入密码。
重新输入:
通过红外遥控器的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; //有按键按下时置为1
unsigned int HongwaiValue; //用来储存键值
unsigned int Hongwai_Flag=0; //有红外信号时置为1
unsigned 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; //组合键标志位清0
Key_Flag=0; //按键标志位清0
Hongwai_Flag=0; //红外标志位清0
LcdWriteCom(0x80); //进入欢迎界面 5s
for(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++; //按键次数加1
Hongwai_Flag=0;
Code[Annum-1]=HongwaiValue;//将输入值存入密码数组中
beep(HongwaiValue * 40);
LcdWriteCom(0xc0+6+Annum);
LcdWriteData(42);
}
}
if(Annum>=6) //6位密码输入完毕或检测到特殊组合按键
{
CodeFlag=1; //暂时令标志位为1,若密码有错误,则再置0
for(i=0;i<6;i++)
{
if(Code[i]!=RIGHTCODE[i]) //若密码与正确密码不相等
CodeFlag=0;
}
if(CodeFlag==0) //若输入错误,清零重新输入,并将错误输入次数加一
{
Wrongnum++;
if(Wrongnum==3) //若错误次数达到三次
{
beep(100); //警报
LcdWriteCom(0x80); //显示错误信息,等待10s
for(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; //按键标志位清0
Hongwai_Flag=0; //红外标志位清0
LcdWriteCom(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); //进入欢迎界面 5s
for(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; //按键标志位清0
Hongwai_Flag=0; //红外标志位清0
}
}
}
}
/*******************************************************************************
* 函数名 : SetCode()
* 函数功能 : 设置密码
*******************************************************************************/
void SetCode()
{
int i,j=0;
Wrongnum=0; //错误次数清零
Annum=0; //密码计数器清零
CodeDel=0; //组合键标志位清0
Key_Flag=0; //按键标志位清0
Hongwai_Flag=0; //红外标志位清0
LcdWriteCom(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; //按键标志位清0
Hongwai_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; //正确收到信号,标志位置1
err=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)) //计算高电平的时间长度。
{
DelayMs(1);//0.14ms
Time++;
err--;
if(Time>30)
{
EX0=1;
return;
}
}
IrValue[k]>>=1; //k表示第几组数据
if(Time>=8) //如果高电平出现大于565us,那么是1
{
IrValue[k]|=0x80;
}
Time=0; //用完时间要重新赋值
}
}
hongwai();
}
if(IrValue[2]!=~IrValue[3])
{
return;
}
}
}
/*******************************************************************************
* 函数名 : KeyScan
* 函数功能 : 扫描矩阵键盘
*******************************************************************************/
void KeyScan(void) //读取按键值
{
char a = 0;
int j;
GPIO_KEY=0x0f;
if(GPIO_KEY!=0x0f)//读取按键是否按下
{
DelayMs(10);//延时10ms进行消抖
if(GPIO_KEY!=0x0f)//再次检测键盘是否按下
{
Key_Flag=1;
Annum++; //按键次数加1
//测试行
GPIO_KEY=0X0F;
switch(GPIO_KEY)
{
case(0X07): KeyValue=12;break;
case(0X0b): KeyValue=8;break;
case(0X0d): KeyValue=4;break;
case(0X0e): KeyValue=0;break;
case(0X06): CodeDel=1;break; //特殊按键组合可以清除密码
case(0X09): CodeDel=3;break; //特殊按键组合可以重设密码
}
//测试列
GPIO_KEY=0XF0;
switch(GPIO_KEY)
{
case(0X70): KeyValue=KeyValue+3;break;
case(0Xb0): KeyValue=KeyValue+2;break;
case(0Xd0): KeyValue=KeyValue+1;break;
case(0Xe0): KeyValue=KeyValue;break;
case(0X60): if(CodeDel==1) CodeDel=2;break; //按键0和15组合可以清除密码
case(0X90): if(CodeDel==3) CodeDel=4;break; //按键5和6组合可以重设密码
}
while((a<50) && (GPIO_KEY!=0xf0)) //检测按键松手检测
{
DelayMs(10);
a++;
}
if(KeyValue==11) //11按键可以重新输入密码
{
Annum=0; //密码计数器清零
Key_Flag=0; //按键标志位清0
Hongwai_Flag=0; //红外标志位清0
LcdWriteCom(0x80+0x40);//清除密码输入的*符号
for(j=0;j<16;j++)
{
LcdWriteData(CDIS2[j]);
}
}
}
}
}
/*******************************************************************************
* 函数名 : hongwai
* 函数功能 : 将接收到的16进制红外信号转化为0-12的键值
*******************************************************************************/
void hongwai() //根据红外线遥控器键值表,将接收的代码值转化为0-12的键值
{
int j;
IrValue[4]=IrValue[2]>>4; //高位
IrValue[5]=IrValue[2]&0x0f; //低位
if(IrValue[4]==1&&IrValue[5]==6)
HongwaiValue=0;
else if(IrValue[4]==0&&IrValue[5]==12)
HongwaiValue=1;
else if(IrValue[4]==1&&IrValue[5]==8)
HongwaiValue=2;
else if(IrValue[4]==5&&IrValue[5]==14)
HongwaiValue=3;
else if(IrValue[4]==0&&IrValue[5]==8)
HongwaiValue=4;
else if(IrValue[4]==1&&IrValue[5]==12)
HongwaiValue=5;
else if(IrValue[4]==5&&IrValue[5]==10)
HongwaiValue=6;
else if(IrValue[4]==4&&IrValue[5]==2)
HongwaiValue=7;
else if(IrValue[4]==5&&IrValue[5]==2)
HongwaiValue=8;
else if(IrValue[4]==4&&IrValue[5]==10)
HongwaiValue=9;
else if(IrValue[4]==1&&IrValue[5]==9)
HongwaiValue=10;
else if(IrValue[4]==0&&IrValue[5]==13)
HongwaiValue=11;
else
HongwaiValue=12;
if(HongwaiValue==11) //按键可以重新输入密码
{
Annum=0; //密码计数器清零
Key_Flag=0; //按键标志位清0
Hongwai_Flag=0; //红外标志位清0
LcdWriteCom(0x80+0x40);//清除密码输入的*符号
for(j=0;j<16;j++)
{
LcdWriteData(CDIS2[j]);
}
}
}
void delay(unsigned int i)
{
char j;
for(i; i > 0; i--)
for(j = 200; j > 0; j--);
}
/*******************************************************************************
* 函数名 : beep
* 函数功能 : 可以实现不同频率和占空比的蜂鸣器鸣叫程序
*******************************************************************************/
void beep(unsigned int type) //按键值不同,对应蜂鸣器不同的声音
{
unsigned int n = 300;
while(n!=0)
{
Beep= 1;
delay(25);
Beep= 0;
delay(type/20);
n--;
}
}
展开阅读全文