电子锁设计.docx
《电子锁设计.docx》由会员分享,可在线阅读,更多相关《电子锁设计.docx(17页珍藏版)》请在冰豆网上搜索。
电子锁设计
摘要
现代社会,单片机技术越来越广泛的应用于生产生活的各个领域,它可以实现我们对军事、工业、航天、农业以及交通等社会生活各领域的实际事件的模型建立及设计。
而随着社会发展的进步,保密工作也已经成为越来越重要的任务,密码锁的设计成为十分显示以及必要的话题。
此次能力拓展训练,通过单片机的控制实现密码锁的设计。
设计的总体思想采取将完整任务模块化的方式,通过对各个功能的分别解决,最终实现任务的完成。
三个独立模块分别是矩阵键盘、数码管显示和显示状态的指示灯电路。
这三个模块分别作为信号的输入或输出部分,与单片机实现连接,单片机通过对信号的接收和处理,控制各个模块电路实现相应功能。
关键词:
密码锁,模块电路,单片机控制
目录
1设计任务及要求分析1
2方案提出及论证说明1
3硬件设计及功能分析2
3.1矩阵键盘2
3.2数码显示3
3.3声光提示电路4
4软件设计分析5
4.1程序的流程图5
4.2模块程序设计及说明6
4.2.1键盘扫描及编码程序6
4.2.2数码管动态显示程序8
5仿真与调试9
心得体会12
参考文献13
附录一硬件原理图14
附录二源程序15
电子密码锁设计
1设计任务及要求分析
本次能力拓展训练设计要求是电子密码锁,在锁开的状态下输入密码,设置的密码共4位,用数据开关K1~K10分别代表数字1,2,…,9,0,输入的密码用数码管显示,最后输入的密码显示在最右边的数码管上,即每输入一位数,密码在数码管上的显示左移一位。
可删除输入的数字,删除的是最后输入的数字,每删除一位,密码在数码管的显示右移一位,并在左边空出的位上补充“0”。
用一位输出电平的状态代表锁的开闭状态。
2方案提出及论证说明
本次设计,可以考虑使用Max+plusⅡ、EDA实验箱完成任务,但由于受到实验设备的限制以及对相关软件的掌握程度。
最终确定本次设计选用AT89C51单片机作为核心控制器。
AT89C51的元件图如下:
图2-1AT89C51元件图
根据要求,不难想出,此次任务的完成需要完成键盘输入、数码显示、报警提示等模块的工作,组成以单片机为核心的总设计电路。
其中键盘输入属于输入部分,数码显示和报警提示属于显示部分。
输入功能可以根据需要配置的键位选择合适的矩阵键盘;而根据要求数字显示部分至少使用四位的数码管,密码锁状态的提示在这里我设计一个发光二极管和扩音器的配合电路实现声光提示从而提示锁的开闭状态。
另外,在本次拓展训练的提高部分提出万能密码的设计,以保证密码锁主人能在忘记密码的情况下仍然可以顺利打开密码锁。
可以考虑在程序设计时,初始化一组数据作为万能密码。
这些任务之后,设计密码锁的关键在于如何确定输入数字匹配设置密码,从而确认是否开锁。
考虑到模块电路设计的简洁性,此次设计仍然采用模块电路逐一完成各个功能的设计思路。
通过以上分析,可以初步确定一下的方案结构框图:
图2-2硬件结构框图
3硬件设计及功能分析
根据第二章的基本思路,分别设计各模块硬件电路如下。
3.1矩阵键盘
数据的输入功能由键盘来完成。
整个设计中除了10个数字键之外还需要一些功能键作为辅助来完成设计任务的要求。
这里用到三个基本的功能键:
设置密码的功能键Kset,删除输入的功能键Kdel。
另外,为了表示和控制锁的开关状态,还需要一个功能键来控制上锁Kclo。
因而总共涉及到13个按键。
键盘选用4x4矩阵键盘其电路图如下图所示:
图3-1矩阵键盘电路
如图所示,矩阵键盘的工作原理分析如下:
1)键盘工作方式
键盘分布成四行四列。
工作时,先让行线全为零,检测列线。
若列线不是全为高电平,则表明有键按下,同时也可以确定按键在第几列。
接下来进行低电平逐行扫描即可获知按键在第几行。
这在程序编写时可以实现。
2)功能键介绍
在该矩阵键盘中设有的三个功能键中Kdel键,可以实现输入数字的删除,删除最后一位输入的数,同时数码管上的显示会向右移一位。
Kset键作为密码设置键,在开锁的状态下,若输入了四位数字,再按一下Kset键,就可以设置其开锁密码。
另外,由于不涉及机械结构,这里用一个按键来表示上锁,即Kclo键。
在开锁状态下,按下Kclo键,数码管的显示将会清空,同时将锁锁上。
各键位的功能可分别在程序编码中实现。
3.2数码显示
显示电路使用的是数码管。
由于电路图的设计采用的是protues软件,其中已有组合好的四位共阳极数码管,设计电路时可以直接调用所需型号,这里采用7SEG-MPX4-CA。
如图3-2所示,它有四个位选端口和八个段选端口。
每一位数字都是由八个发光二极管组成,它们的阳极接在一起,即位选端口。
因而在位选端口上加上正电压就可以选通该位。
四位数字的相同段都接在一起,即段选端口。
因而将段选端口接低电平时就可以点亮该段。
图3-2显示输入数字的数码管
3.3声光提示电路
仿真时,电子锁不同于机械锁,我们无法通过观察知道锁的开关状态,要将密码锁上锁,可以用键盘来控制,而锁打开后必须通过辅助部件的提示确认锁的开关状态。
因此设计了该声光提示电路以提示密码锁的状态,如下图所示。
灯亮并发出响声时表示锁已经打开;灯灭时表示锁已上锁。
图3-3指示灯电路图
该部分也可以通过程序编码实现。
当确认密码输入正确时,打开密码锁,并由C51发出一个高电平信号触发声光显示。
4软件设计分析
4.1程序的流程图
由前章的介绍及分析,已大致了解各模块的程序结构,再结合整个电路图及需要完成的任务,设计流程图如下:
图4-1程序流程图
4.2模块程序设计及说明
这里,还可以从模块入手,将程序所要完成的任务编写成子程序,待需要时直接调用即可。
以下着重介绍实现密码锁功能的几个重要子程序,完整的源程序见附录二。
4.2.1键盘扫描及编码程序
要能够成功输入密码,并使键盘输入数据对应数码管显示,需要正确识别按键;按键的识别包括键盘扫描和编码键值两个部分。
其中键盘扫描程序如下:
unsignedcharkey(void)
{
unsignedcharka,kb;
P2=0xf0;
if((P2&0xf0)!
=0xf0)
{
dlm();//消抖延时
if((P2&0xf0)!
=0xf0)
{
ka=0xfe;
while((ka&0x10)!
=0)//逐行扫描
{
P2=ka;
if((P2&0xf0)!
=0xf0)
{
kb=(P2&0xf0)|0x0f;
return((~ka)+(~kb));//返回特征码
}
else
ka=(ka<<1)|0x01;
}
}
}
return(0x00);//没有按键按下时特征值返回0
}
键盘扫描过程中,便涉及到前面硬件设计中关于键盘工作方式的讨论分析,首先行信号全部赋值为零,并检测列信号,以确定按键所在列。
而后就是逐行赋值为零的扫描,从而确定行数。
于是也就唯一确定了按的是哪一个键。
最后将扫描的特征码做返回值,若无按键则返回0x00。
再将返回的特征值借助编码程序转换成为相应的键值。
键值编码程序如下:
unsignedcharreadkey(void)
{
switch(key())
{
case0x11:
return(0x00);break;
case0x21:
return(0x01);break;
case0x41:
return(0x02);break;
case0x81:
return(0x03);break;
case0x12:
return(0x04);break;
case0x22:
return(0x05);break;
case0x42:
return(0x06);break;
case0x82:
return(0x07);break;
case0x14:
return(0x08);break;
case0x24:
return(0x09);break;
case0x44:
return(0x0a);break;
case0x84:
return(0x0b);break;
case0x18:
return(0x0c);break;
case0x28:
return(0x0d);break;
case0x48:
return(0x0e);break;
case0x88:
return(0x0f);break;
default:
return(0xff);
}
}
如上述程序所示,十六个按键依次编码为十六进制的各位数,对于乱码或是没有按键则返回0xff。
在程序中用数组a[]来存储由键盘输入的数字,该部分程序如下:
voidshuru(void)
{
a[0]=a[1];
a[1]=a[2];
a[2]=a[3];
a[3]=readkey();
}
4.2.2数码管动态显示程序
通过查阅相关知识,我了解到数码管显示数据有静态显示和动态(扫描)显示之分。
静态显示就是显示驱动电路具有输出所存功能,数据送出后就不再管,直到下一次显示数据需要更新时再传送一次新数据,显示数据稳定,占用很少的CPU时间。
动态显示需要CPU时刻对显示器件进行数据刷新,显示数据有闪烁感,占用的CPU时间多。
然而我们此次所需的显示方式显然是当输入密码时需要时刻更新的,故需采用动态显示方式。
虽然动态显示有闪烁感,但是人眼存在视觉暂留,在数码管刚熄灭的一小段时间内,人眼中的图像不会消失,利用这一点,只要在这段时间内再次点亮数码管,人眼就就不会发觉灯的闪烁。
这就是数码管动态显示的基本原理,这也是接受生活中某些例子的启发。
其程序如下:
while
(1)
{
P3=0x01;P0=s[a[0]];dlm();
P3=0x02;P0=s[a[1]];dlm();
P3=0x04;P0=s[a[2]];dlm();
P3=0x08;P0=s[a[3]];dlm();
}
如程序所示,单片机的P3口控制位选端口,P0控制段选端口,利用数组查询的方式将数字转换成相应的显示码。
数码管亮起来也需要短暂的时间,再在其中插入延时环节,并注意延时过长就会出现闪烁现象。
最终实现数码管数据的最终显示。
5仿真与调试
设计要求最后输入的密码显示在最右边的数码管上,即每输入一位数,密码在数码管上的显示左移一位。
调试效果如下图组所示(这里选择设置密码为0687):
首先按下“K10”键时,最右边显示数字0。
再按下“K6”键时,0向左移一位,最右边显示6。
然后按下“K8”键时0和6向左移一位,最右边显示8。
最后按下“K7”键时0,6和8向左移一位,最右边显示7。
最后显示结果如下:
图5-1输入四位数字结果
程序需完成的任务要求是取一次输入数字,后一位都先把值送给前一位,而后把输入的数字赋给最后一位,仿真结果符合设计任务要求
在以上基础上按下删除键Kdel键后,删除的是最后输入的数字7,而其他三位则在数码管的显示分别向右移动一位。
而第一位此时没有数字。
即此时
a[0]=16;a[1]=0;a[2]=6;a[3]=8;
调试的效果图如下所示:
图5-2按下Kdel键后数码管的显示
其中,S[0]~S[9]是数字0~9的显示码,而S[16]则表式显示为空。
符合设计任务要求。
接着再输入7时,又向前面那样已经出现的数字顺次左移一位最右边显示7。
根据设计要求,为保证密码锁主人在主人忘记密码时也能打开密码锁,要设置一个万能密码。
这里我设置的万能密码是4412,程序中将用户的设置密码保存在数组b[]中。
继续上面的调试,再按下Kset键后,则通过执行相应的程序会将0687保存为密码。
此时再按下Kdel键,数码管的显示清空,而且指示灯熄灭,表明密码锁已经上锁。
标志位lock控制指示灯,即用来表示密码锁的开关状态。
经过上面的调试过程,密码锁已经上锁,而且设置的密码为0687,此时数码管显示为空。
当输入密码0687时,效果如下:
图5-3正确输入密码显示结果
开始和前面一样,输入的数字显示在数码管上,但当最后一位短暂显示之后,所有显示立即消失。
同时指示灯变亮并发声提示,表明此时已经开锁。
也就说明密码0687可以开锁。
接下来再来完成万能密码的设置与调试。
对于万能密码的设置可以任意(这里选用4412为万能密码),一旦设置成功,按下Kclo,将锁锁上,接着输入4412,出现的现象如下图所示:
输入万能密码4412的效果和0687一样,显示完之后立即消失,并且发生声光提示,将密码锁打开。
至此,综上仿真调试结果可以发现,本设计已经成功实现了所有的设计要求
心得体会
本次能力拓展训练的设计,在程序中最麻烦的地方就在于如何区分两次按键。
通常情况下会使用循环扫描等待出现空的键值的办法。
但这里却还需要顾虑到数码管的动态显示,它不允许别的程序占用太多时间。
为了解决这个问题,可以另外加设一块显示程序放到它循环等待的过程中去。
一旦检测到按键释放就回归到原来的大循环中去。
问题的不断出现与克服更加深了我对对单片机知识的了解和掌握。
也通过本次拓展训练遇到的很多问题,使自己真正了解到自己在一些方面知识的匮乏,如单片机的P3接口的驱动能力很强不是很适合输入输出数字。
在与同学的积极讨论及自己的不断摸索中,终于完成了此次拓展训练的设计任务,达到了最终的目的。
在以后的学习当中,一定要不断克服,自己在相关知识方面的欠缺,不断提高自己。
参考文献
[1]周航慈等主编,单片机程序设计基础,北京航空航天大学出版社,2001
[2]郑莉等主编,C++语言程序设计,清华大学出版社,2000
[3]康华光主编,电子技术基础-数字部分,高等教育出版社,1998。
[4]张红润等主编,单片机原理及应用,清华大学出版社,2008
[5]马忠梅等主编,单片机的C语言应用程序设计,北京航空航天大学出版社,2003
附录一硬件原理图
附图1系统总电路图
附录二源程序
#include"reg51.h"
sbitlock=P1^0;/***锁标志1为开,0为关***/
unsignedchara[4]={16,16,16,16};//显示
unsignedcharb[4]={4,4,1,2};//密码
unsignedchars[17]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xff};
/*****消抖*****/
voiddlm(void)
{
unsignedchari;
for(i=200;i>0;i--);
}
/*****键盘扫描*****/
unsignedcharkey(void)
{
unsignedcharka,kb;
P2=0xf0;
if((P2&0xf0)!
=0xf0)
{
dlm();//消抖延时
if((P2&0xf0)!
=0xf0)
{
ka=0xfe;
while((ka&0x10)!
=0)//逐行扫描
{
P2=ka;
if((P2&0xf0)!
=0xf0)
{
kb=(P2&0xf0)|0x0f;
return((~ka)+(~kb));//返回特征码
}
else
ka=(ka<<1)|0x01;
}
}
}
return(0x00);//没有按键时返回0
}
/*****编码*****/
unsignedcharreadkey(void)
{
switch(key())
{
case0x11:
return(0x00);break;
case0x21:
return(0x01);break;
case0x41:
return(0x02);break;
case0x81:
return(0x03);break;
case0x12:
return(0x04);break;
case0x22:
return(0x05);break;
case0x42:
return(0x06);break;
case0x82:
return(0x07);break;
case0x14:
return(0x08);break;
case0x24:
return(0x09);break;
case0x44:
return(0x0a);break;
case0x84:
return(0x0b);break;
case0x18:
return(0x0c);break;
case0x28:
return(0x0d);break;
case0x48:
return(0x0e);break;
case0x88:
return(0x0f);break;
default:
return(0xff);
}
}
/*****数值输入*****/
voidshuru(void)
{
a[0]=a[1];
a[1]=a[2];
a[2]=a[3];
a[3]=readkey();
}
/*****删除并修改数值*****/
voidDelete(void)
{
a[3]=a[2];
a[2]=a[1];
a[1]=a[0];
a[0]=16;
}
/*****上锁*****/
voidClose(void)
{
lock=0;
a[0]=16;
a[1]=16;
a[2]=16;
a[3]=16;
}
/*****设置密码*****/
voidset(void)
{
if(lock&&a[0]!
=16)
{
b[0]=a[0];
b[1]=a[1];
b[2]=a[2];
b[3]=a[3];
}
}
/*****开锁*****/
voidkaisuo(void)
{
if(a[0]==2&&a[1]==0&&a[2]==1&&a[3]==2)
lock=1;
if(a[0]==b[0]&&a[1]==b[1]&&a[2]==b[2]&&a[3]==b[3])
lock=1;
if(lock)
{
a[0]=16;
a[1]=16;
a[2]=16;
a[3]=16;
}
}
/*****主函数*****/
main()
{
unsignedcharm,n;
while
(1)
{
if(key()!
=0x00)
{
m=readkey();
if(m<10)
n=9;
else
n=m;
switch(n)
{
case9:
shuru();break;
case10:
xiugai();break;
case11:
shangsuo();break;
case12:
set();break;
}
while(key()!
=0x00)
{
P3=0x01;P0=s[a[0]];dlm();
P3=0x02;P0=s[a[1]];dlm();
P3=0x04;P0=s[a[2]];dlm();
P3=0x08;P0=s[a[3]];dlm();
}
}
P3=0x01;P0=s[a[0]];dlm();
P3=0x02;P0=s[a[1]];dlm();
P3=0x04;P0=s[a[2]];dlm();
P3=0x08;P0=s[a[3]];dlm();
if(!
lock&&a[0]!
=16)
kaisuo();
}
}