电子密码锁论文1.docx
《电子密码锁论文1.docx》由会员分享,可在线阅读,更多相关《电子密码锁论文1.docx(97页珍藏版)》请在冰豆网上搜索。
电子密码锁论文1
基于单片机的电子密码锁设计报告
引言
目前,最常用的锁是20世纪50年代意大利人设计的机械锁,其机构简单、使用方便、价格便宜。
但在使用中暴露了很多缺点:
一是机械锁是靠金属制成的钥匙上的不同齿形与锁芯的配合来工作的。
据统计,每4000把锁中就有两把锁的钥匙齿牙相同或类似,故安全性低。
二是钥匙一旦丢失,无论谁捡到都可以将锁打开。
三是机械锁的材料大多为黄铜,质地较软,容易损坏。
四是机械锁钥匙易于复制,不适于诸如宾馆等公共场所使用。
由于人们对锁的安全性,方便性等性能有更高的要求,许多智能锁也相继问世,但这类产品的特点是针对特定指纹或有效卡,但能适用于保密要求高且仅供个别人使用的箱、柜、房间,其成本一般较高,在一定程度上限制了这类产品的普及和推广。
随着人们生活水平的提高,电子密码防盗锁作为防盗卫士的作用日趋重要。
电子密码防盗锁用密码代替钥匙,不但省去了佩戴钥匙的烦恼,也从根本上解决了普通门锁保密性差的缺点。
随着人们生活水平的提高,如何实现防盗这一问题也变的尤其的突出,传统的机械锁由于其构造的简单,被撬的事件屡见不鲜,机械锁的这些弊端为一种新型的锁---电子密码锁,提供了发展的空间。
随着人们对安全的重视和科技的发展,许多电子智能锁已在国内外相继面世。
但是这些产品的特点是针对特定的指纹和有效卡,只能适用于保密要求的箱、柜、门等。
而且指纹识识别器若在公共场所使用存在容易机械损坏,IC卡还存在容易丢失、损坏等特点。
加上其成本较高,一定程度上限制了这类产品的普及和推广。
电子锁由于其保密性高,使用灵活性好,安全系数高,受到了广大用户的欢迎。
鉴于目前的技术水平与市场的接收程度,电子密码锁是这类电子防盗产品的主流。
主要功能(详细说明见附录1)
1.输入密码正确开锁、密码修改(密码可为1-6位,断电密码不丢失);
2.输入密码错误次数超出设定值报警,并锁定键盘30s(后错误次数并不会改变,除非输入正确密码。
时间日期的显示与调整(断电不归零);
3.自动上锁(时间可自行设定);
设计方案
该方案采用的是一种以STC-AT89C52为核心的单片机控制方案,利用单片机灵活的编程设计方式和丰富的I/O端口以及其控制的准确性,不但可以实现密码锁的基本功能,还能添加时间日期显示、无线报警甚至遥控控制等拓展功能。
第一章系统模块电路的设计
I系统总电路
II系统程序流程:
III开锁电路
在本次项目设计中,暂时用发光二极管代替电磁锁,开锁指示灯亮,表示锁开;电路如下所示:
IV报警电路
本设计的报警装置采用的是蜂鸣器。
当用户输入密码错误次数超过设定值时,蜂鸣器将发出报警信号。
第二章按键电路模块设计
本项目设计采用的是3*4矩阵键盘,这样能减少键盘与单片机接口时所占用的I/O线的数目,并增加了长按键的功能,在按键比较多的时候,这样能减少材料并降低成本。
电路原理图如下所示:
在这种行列式矩阵键盘非键盘编码的单片机系统中,键盘处理程序首先执行等待按键并确认有无按键按下的程序段(即键盘扫描程序段)。
当确认有按键按下后,下一步就要识别哪一个按键按下。
对键的识别通常有两种方法:
一种是常用的逐行扫描法;另一种是速度较快的线反转法。
由于添加了长按键功能,本设计采用逐行扫描法。
线反转法,通过获取行检测得到行值,再将行值做与运算赋给端口,然后检测到列值,最后行值与列值做或运算得到键值。
长按键是本设计的独特处之一,通过长按键可以精简按键版面,使操作更有趣味(看起来就那么多按键但功能有待发掘),同时节约了材料。
这里略谈一下逐行扫描法。
此法将一个端口的8位分成高低两个部分(低四位,高四位),通过令一个部分的一位置低电平,检测另一部分与之有交集(按下按键后相交)是哪一个端口从而确定是哪一个按键被按下。
程序编写过程中需要考虑两个方面:
去抖和松手检测。
源程序如下(一般矩阵键盘检测,非长按键检测):
ucharkeyscan()
{
P3=0xf6;//第一竖扫描
temp=P3;//读取端口数值
temp=temp&0xf0;//将端口值运算,便于判断是否有键按下
while(temp!
=0xf0)
{
delay(1000);//延时,以消抖
temp=P3;
temp=temp&0xf0;
while(temp!
=0xf0)//再次判断端口值,检查按键是否仍按下
{
temp=P3;//读取此时端口值
switch(temp)
{
case0xe6:
key=1;
break;
case0xd6:
key=4;
break;
case0xb6:
key=7;
break;
case0x76:
key=11;
break;
}
while(temp!
=0xf0)//通过松键跳出循环,同时消除尾抖
{
temp=P3;
temp=temp&0xf0;
}
}
}
P3=0xf5;//第二竖扫描
temp=P3;
temp=temp&0xf0;
while(temp!
=0xf0)
{
delay(5);
temp=P3;
temp=temp&0xf0;
while(temp!
=0xf0)
{
temp=P3;
switch(temp)
{
case0xe5:
key=2;
break;
case0xd5:
key=5;
break;
case0xb5:
key=8;
break;
case0x75:
key=0;
break;
}
while(temp!
=0xf0)
{
temp=P3;
temp=temp&0xf0;
}
}
}
P3=0xf3;//第三竖扫描
temp=P3;
temp=temp&0xf0;
while(temp!
=0xf0)
{
delay(5);
temp=P3;
temp=temp&0xf0;
while(temp!
=0xf0)
{
temp=P3;
switch(temp)
{
case0xe3:
key=3;
break;
case0xd3:
key=6;
break;
case0xb3:
key=9;
break;
case0x73:
key=12;
break;
}
while(temp!
=0xf0)
{
temp=P3;
temp=temp&0xf0;
}
}
}
return(key);
}
(各按键功能见文末附件)
第三章LED数码管显示模块设计
本电子密码锁系统设计采用的是6段LED数码显示管作为显示器。
为了保存数据以及时显示稳定,添加了两个锁存器。
(后接锁存器及显示器具体说明)。
电路原理图如下所示:
说明:
本电路中使用的是74hc573,但在实物中开发板使用了一个74hc573和一个74hc138。
所以在程序控制上有较大的改变。
但是其使用的原理是一样的。
锁存器上各有一个控制是否让数据通过并保存的端口,高电平则表示接受数据并将数据传到输出口供电给数码管,以达到对显示的控制。
数码管选用的是共阴极型。
每个数码管的共阴极都是独立的,只要在某个数码管的共阴极加以低电平就可打开此数码管。
所有数码管所显示的内容在同一时间是一样的。
它的内容显示由8个引脚来控制,这些引脚接在一个锁存器的输出端,该锁存器的控制端叫做段显。
控制哪一个数码管的锁存器的控制端叫做位选。
这样可以在一个时间只让一个数码管显示一个图像,也可以让几个数码管显示同样的图像。
静态显示:
在几个数码管或一个数码管上同时显示同样的图像,直接对锁存器操作便可。
动态显示:
由于人的视觉暂留,让数码管很快地在不同的数码管上显示不同的图像(但一个数码管应显示一个固定的信息),人眼将看到稳定的多个信息(如数码管上显示“012345”)。
通过动态显示,用户可以在同一时间得到直观的信息。
这里再谈一下74hc138。
74hc138使用三个输入端口控制8个输出端口,故同一时间只能让一个数码管开启。
这样虽然使图像控制变得困难一些,但是节约了硬件资源(上图的连接方式更节约资源,但是我们在选用开发板时由于条件的限制未能采用)。
下图为其硬件布局和真值表:
第四章时钟模块
本项目设计采用的是DS1302芯片来控制时间及日期的显示。
下图为DS1302的典型操作模式
电路原理图如下所示:
下图为其操作时序:
下图为其寄存器地址:
Ds1302属于spi总线操作方式
首先看DS1302的datasheet中的相关介绍。
上面是它的一些基本的应用介绍。
DS1302和单片机的连接很简单。
只需一根复位线,一根时钟线,一根数据线即可。
同时它本身还需要接一个32.768KHz的晶振来提供时钟源。
对于晶振的两端可以分别接一个6PF左右的电容以提高晶振的精确度。
同时可以在第8脚接上一个3.6V的可充电的电池。
当系统正常工作时可以对电池进行涓流充电。
当系统掉电时,DS1302由这个电池提供的能量继续工作。
下面是一段从网上摘抄的源代码:
sbitio_DS1302_RST=P2^0;
sbitio_DS1302_IO=P2^1;
sbitio_DS1302_SCLK=P2^2;
//-------------------------------------常数宏---------------------------------//
#defineDS1302_SECOND_WRITE0x80//写时钟芯片的寄存器位置
#defineDS1302_MINUTE_WRITE0x82
#defineDS1302_HOUR_WRITE0x84
#defineDS1302_WEEK_WRITE0x8A
#defineDS1302_DAY_WRITE0x86
#defineDS1302_MONTH_WRITE0x88
#defineDS1302_YEAR_WRITE0x8C
#defineDS1302_SECOND_READ0x81//读时钟芯片的寄存器位置
#defineDS1302_MINUTE_READ0x83
#defineDS1302_HOUR_READ0x85
#defineDS1302_WEEK_READ0x8B
#defineDS1302_DAY_READ0x87
#defineDS1302_MONTH_READ0x89
#defineDS1302_YEAR_READ0x8D
//-----------------------------------操作宏----------------------------------//
#defineDS1302_SCLK_HIGHio_DS1302_SCLK=1;
#defineDS1302_SCLK_LOWio_DS1302_SCLK=0;
#defineDS1302_IO_HIGHio_DS1302_IO=1;
#defineDS1302_IO_LOWio_DS1302_IO=0;
#defineDS1302_IO_READio_DS1302_IO
#defineDS1302_RST_HIGHio_DS1302_RST=1;
#defineDS1302_RST_LOWio_DS1302_RST=0;
/******************************************************
*保存时间数据的结构体*
******************************************************/
struct
{
uint8Second;
uint8Minute;
uint8Hour;
uint8Day;
uint8Week;
uint8Month;
uint8Year;
}CurrentTime;
/******************************************************************************
*Function:
staticvoidv_DS1302Write_f(uint8Content)*
*Description:
向DS1302写一个字节的内容*
*Parameter:
uint8Content:
要写的字节*
**
******************************************************************************/
staticvoidv_DS1302Write_f(uint8Content)
{
uint8i;
for(i=8;i>0;i--)
{
if(Content&0x01)
{
DS1302_IO_HIGH
}
else
{
DS1302_IO_LOW
}
Content>>=1;
DS1302_SCLK_HIGH
DS1302_SCLK_LOW
}
}
/******************************************************************************
*Function:
staticuint8v_DS1302Read_f(void)*
*Description:
从DS1302当前设定的地址读取一个字节的内容*
*Parameter:
*
*Return:
返回读出来的值(uint8)*
******************************************************************************/
staticuint8v_DS1302Read_f(void)
{
uint8i,ReadValue;
DS1302_IO_HIGH
for(i=8;i>0;i--)
{
ReadValue>>=1;
if(DS1302_IO_READ)
{
ReadValue|=0x80;
}
else
{
ReadValue&=0x7f;
}
DS1302_SCLK_HIGH
DS1302_SCLK_LOW
}
returnReadValue;
}
/******************************************************************************
*Function:
voidv_DS1302WriteByte_f(uint8Address,uint8Content)*
*Description:
从DS1302指定的地址写入一个字节的内容*
*Parameter:
Address:
要写入数据的地址*
*Content:
写入数据的具体值*
*Return:
*
******************************************************************************/
voidv_DS1302WriteByte_f(uint8Address,uint8Content)
{
DS1302_RST_LOW
DS1302_SCLK_LOW
DS1302_RST_HIGH
v_DS1302Write_f(Address);
v_DS1302Write_f(Content);
DS1302_RST_LOW
DS1302_SCLK_HIGH
}
/******************************************************************************
*Function:
uint8v_DS1302ReadByte_f(uint8Address)*
*Description:
从DS1302指定的地址读出一个字节的内容*
*Parameter:
Address:
要读出数据的地址*
**
*Return:
指定地址读出的值(uint8)*
******************************************************************************/
uint8v_DS1302ReadByte_f(uint8Address)
{
uint8ReadValue;
DS1302_RST_LOW
DS1302_SCLK_LOW
DS1302_RST_HIGH
v_DS1302Write_f(Address);
ReadValue=v_DS1302Read_f();
DS1302_RST_LOW
DS1302_SCLK_HIGH
returnReadValue;
}
/******************************************************************************
*Function:
voidv_ClockInit_f(void)*
*Description:
初始化写入DS1302时钟寄存器的值(主程序中只需调用一次即可)*
*Parameter:
*
**
*Return:
*
******************************************************************************/
voidv_ClockInit_f(void)
{
if(v_DS1302ReadByte_f(0xc1)!
=0xf0)
{
v_DS1302WriteByte_f(0x8e,0x00);//允许写操作
v_DS1302WriteByte_f(DS1302_YEAR_WRITE,0x08);//年
v_DS1302WriteByte_f(DS1302_WEEK_WRITE,0x04);//星期
v_DS1302WriteByte_f(DS1302_MONTH_WRITE,0x12);//月
v_DS1302WriteByte_f(DS1302_DAY_WRITE,0x11);//日
v_DS1302WriteByte_f(DS1302_HOUR_WRITE,0x13);//小时
v_DS1302WriteByte_f(DS1302_MINUTE_WRITE,0x06);//分钟
v_DS1302WriteByte_f(DS1302_SECOND_WRITE,0x40);//秒
v_DS1302WriteByte_f(0x90,0xa5);//充电
v_DS1302WriteByte_f(0xc0,0xf0);//判断是否初始化一次标识写入
v_DS1302WriteByte_f(0x8e,0x80);//禁止写操作
}
}
/******************************************************************************
*Function:
voidv_ClockUpdata_f(void)*
*Description:
读取时间数据,并保存在结构体CurrentTime中*
*Parameter:
*
**
*Return:
*
******************************************************************************/
voidv_ClockUpdata_f(void)
{
CurrentTime.Second=v_DS1302ReadByte_f(DS1302_SECOND_READ);
CurrentTime.Minute=v_DS1302ReadByte_f(DS1302_MINUTE_READ);
CurrentTime.Hour=v_DS1302ReadByte_f(DS1302_HOUR_READ);
CurrentTime.Day=v_DS1302ReadByte_f(DS1302_DAY_READ);
CurrentTime.Month=v_DS1302ReadByte_f(DS1302_MONTH_READ);
CurrentTime.Week=v_DS1302ReadByte_f(DS1302_WEEK_READ);
CurrentTime.Year=v_DS1302ReadByte_f(DS1302_YEAR_READ);
}
下面是我们项目所使用的代码(延时的成功与否决定了程序能不能正常运行):
voidWrite_Ds1302_Byte(unsignedchartemp)
{
unsignedchari;
for(i=0;i<8;i++)//循环8次写入数据
{
SCK=0;
SDA=temp&0x01;//每次传输低字节
temp>>=1;//右移一位
SCK=1;
}
}
voidWrite_Ds1302(unsignedcharaddress,unsignedchardat)
{
RST=0;
_nop_();
SCK=0;
_nop_();
RST=1;
_nop_();//启动
Write_Ds1302_Byte(address);//发送地址
Write_Ds1302_Byte(dat);//发送数据
RST=0;//恢复
}
unsignedcharRead_Ds1302(unsignedcharaddress)
{