电子密码锁设计

更新时间:2024-05-27 21:00:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

单 姓 名:P081613414

片 机 课 程 设 计

题 目:电子密码锁设计学 院: 专业班级:指导教师: 学 号: 电气工程院

基于单片机的电子密码锁设计

课题设计目标

本设计采用AT89S51单片机为主控芯片,结合外围电路,通过软件程序组成电子密码锁系统,实现一个6位密码的密码锁。完成密码设置和密码检验,错误时蜂鸣一声报警,错误超过3次时报警不停。LED辅助显示。 研究目的及意义

通过研究设置一个6位密码锁的方法,使我们重温了基础知识并提高了对单片机的理解,加深了对单片机的用途的认识,加强自我学习能力与动手动脑能力。 主控部分的选择

方案一:采用数字电路控制

用以74LS112双JK触发器构成的数字逻辑电路作为密码锁的核心控制,将密码保存在JK触发器中,与输入密码通过比较器比较,判断结果是否相符合[4]。采用数字电路设计的方案好处就是设计简单,但控制的准确性和灵活性差,故不采用。

方案二:采用以单片机为核心的控制方案

选用单片机作为系统的核心部件,实现控制与处理的功能。

单片机具有资源丰富、速度快、编程容易等优点。利用单片机内部的随机存储器(RAM)和只读存储器(ROM)及其引脚资源,外接液晶显示(LCD),键盘输入等实现数据的处理传输和显示功能,基本上能实现设计指标。 因此综合考虑,本系统采用方案二。 密码输入方式的选择 方案一:指纹输入识别

指纹识别技术主要涉及四个功能:读取指纹图像、提取特征、保存数据和比对。通过指纹读取设备读取到人体指纹的图像,然后要对原始图像进行初步的处理,使之更清晰,再通过指纹辨识软件建立指纹的特征数据。软件从指纹上找到被称为“节点”(minutiae)的数据点,即指纹纹路的分叉、终止或打圈处的坐标位置,这些点同时具有七种以上的唯一性特征。通常手指上平均具有70个节点,所以这种方法会产生大约490个数据。这些数据,通常称为模板。通过计算

机模糊比较的方法,把两个指纹的模板进行比较,计算出它们的相似程度,最终得到两个指纹的匹配结果,从而判断输入结果的正确与否。考虑到本方案软硬件太过复杂,而且成本也高,故不采用。 方案二:矩阵键盘输入识别

由各按键组成的矩阵键盘每条行线和列线都对应一条I/O口线,键位设在行线和列线的交叉点,当一个键按下就会有某一条行线与某一条列线接触,只要确定接触的是哪两条线,即哪两个I/O口线,就可以确定哪一个键被触动。 行线设计成上拉口线,初始时被置高电位,列线悬空,初始置低。通过不断读行线口线,或者中断方式触发键位扫描。当发现有键按下,将列线逐一置低,其他列线置高,读行线口线。当某条列线置低时,某条行线也被拉低,则确定这两条线的交点处的按钮被按下。每个按键都可通过程序赋予功能,从而完成密码识别。本方案简单易行,故采用。 主要芯片介绍

AT89S51具有如下特点:

40个引脚,4k Bytes Flash片内程序存储器,128 bytes的随机存取数据存储器(RAM),32个外部双向输入/输出(I/O)口,5个中断优先级2层中断嵌套中断,2个16位可编程定时计数器,2个全双工串行通信口,看门狗(WDT)电路,片内时钟振荡器。

此外,AT89S51设计和配置了振荡频率可为0Hz并可通过软件设置省电模式。空闲模式下,CPU暂停工作,而RAM定时计数器,串行口,外中断系统可继续工作,掉电模式冻结振荡器而保存RAM的数据,停止芯片其它功能直至外中断激活或硬件复位。同时该芯片还具有PDIP、TQFP和PLCC等三种封装形式,以适应不同产品的需求。 1.、主要特性

AT89S51主要特性 8031 CPU与MCS-51 兼容 ? 32条可编程I/O线 3个16位可编程定时/计数器 全双工UART串行中断口线 2个外部中断源 4k可反复擦写(>1000次)ISP Flash ROM 4.5-5.5V工作电压 时钟频率0-33MHz 128*8位内部RAM 低功耗空闲和省电模式 中断唤醒省电模式 看门狗(WDT)电路 灵活的ISP字节和分页编程 2、管脚说明: VCC:供电电压。 GND:接地。

三级程序存储器保密锁定 软件设置空闲和省电功能 双数据寄存器指针 P0口:P0口为一个8位漏级开路双向I/O口,每脚可吸收8TTL门电流。当P1口的管脚第一次写1时,被定义为高阻输入。P0能够用于外部程序数据存储器,它可以被定义为数据/地址的第八位。在FIASH编程时,P0 口作为原码输入口,当FIASH进行校验时,P0输出原码,此时P0外部必须被拉高。

P1口:P1口是一个内部提供上拉电阻的8位双向I/O口,P1口缓冲器能接收输出4TTL门电流。P1口管脚写入1后,被内部上拉为高,可用作输入,P1口被外部下拉为低电平时,将输出电流,这是由于内部上拉的缘故。在FLASH编程和校验时,P1口作为第八位地址接收。

P2口:P2口为一个内部上拉电阻的8位双向I/O口,P2口缓冲器可接收,输出4个TTL门电流,当P2口被写“1”时,其管脚被内部上拉电阻拉高,且作为输入。并因此作为输入时,P2口的管脚被外部拉低,将输出电流。这是由于内部上拉的缘故。P2口当用于外部程序存储器或16位地址外部数据存储器进行存取时,P2口输出地址的高八位。在给出地址“1”时,它利用内部上拉优势,当对外部八位地址数据存储器进行读写时,P2口输出其特殊功能寄存器的内容。P2口在FLASH编程和校验时接收高八位地址信号和控制信号。

P3口:P3口管脚是8个带内部上拉电阻的双向I/O口,可接收输出4个TTL门电流。当P3口写入“1”后,它们被内部上拉为高电平,并用作输入。作为输入,由于外部下拉为低电平,P3口将输出电流(ILL)这是由于上拉的缘故。 P3.0 RXD(串行输入口) P3.1 TXD(串行输出口) P3.2 /INT0(外部中断0) P3.3 /INT1(外部中断1) P3.4 T0(记时器0外部输入) P3.5 T1(记时器1外部输入) P3.6 /WR(外部数据存储器写选通)

P3.7 /RD(外部数据存储器读选通)

P3口同时为闪烁编程和编程校验接收一些控制信号。 I/O口作为输入口时有两种工作方式。

RST:复位输入。当振荡器复位器件时,要保持RST脚两个机器周期的高电平时间。

ALE/PROG:当访问外部存储器时,地址锁存允许的输出电平用于锁存地址的地位字节。在FLASH编程期间,此引脚用于输入编程脉冲。在平时,ALE端以不变的频率周期输出正脉冲信号,此频率为振荡器频率的1/6。因此它可用作对外部输出的脉冲或用于定时目的。

/PSEN:外部程序存储器的选通信号。在由外部程序存储器取指期间时,有每个机器周期两次/PSEN有效。但在访问外部数据存储器时,这两次有效的/PSEN信号将不出现。

/EA/VPP:当/EA保持低电平时,则在此期间外部程序存储器(0000H-FFFFH),不管是否有内部程序存储器。

XTAL1:反向振荡放大器的输入及内部时钟工作电路的输入。 XTAL2:来自反向振荡器的输出。

硬件设计部分

键盘输入模块

由于本设计所用到的按键数量较多而不适合用独立按键式键盘。采用的是矩阵式按键键盘,它由行和列组成,也称行列式键盘,按键位于行列的交叉点上,密码锁的密码由键盘输入完成,与独立式按键键盘相比,要节省很多I/O口。本设计中使用的这个4×4键盘不但能完成密码的输入还能作特别功能键使用。键盘的每个按键功能在程序设计中设置。它与单片机的连接如下图所示。

密码存储模块

24C02C的1、2、3脚是三条地址线,用于确定芯片的硬件地址。在24C02C试验开发板上它们都接地,第5脚和第6脚分别接P3.0和P3.1。第7脚通过一开关与P3.2相连,当按下开关时密码锁直接开启。24C02C中带有片内地址寄存器。每写入或读出一个数据字节后,该地址寄存器自动加1,以实现对下一个存储单元的读写。所有字节均以单一操作方式读取。它与单片机的连接如下图所示。

复位部分

单片机复位是使CPU和系统中的其他功能部件都处在一个确定的初始状态,并从这个状态开始工作。该电路在简单的复位电路下增加了手动复位按键,在接通电源瞬间,电容C1上的电压很小,复位下拉电阻上的电压接近电源电压,即RST为高电平,在电容充电的过程中RST端电压逐渐下降,当RST端的电压小于某一数值后,CPU脱离复位状态,由于电容C1足够大,可以保证RST高电平有效时间大于24个振荡周期,CPU能够可靠复位。增加手动复位按键是为了避免死机时无法可靠复位。当复位按键按下后电容C1通过R1放电。当电容C1放电结束后,RST端的电位由R1与R2分压比决定。由于R1<

晶振部分

AT89S51引脚XTAL1和XTAL2与晶体振荡器及电容C2、C3按下图所示方式连接。晶振、电容C2/C3及片内与非门(作为反馈、放大元件)构成了电容三点式振荡器,振荡信号频率与晶振频率及电容C2、C3的容量有关,但主要由晶振频率决定,范围在0~33MHz之间,电容C2、C3取值范围在5~30pF之间。根据实际情况,本设计中采用12MHZ作为系统的外部晶振。电容取值为30pF。

显示模块

显示部分由液晶显示器LM016L取代普通的数码管完成。开锁时,按下键盘上的开锁按键后,利用键盘上的数字键0-9输入密码,每按下一个数字键后在显示器上显示一个*,输入多少位就显示多少个*。当密码输入完成时,按下确认键,如果输入的密码正确的话, LCD显示“correct”,电子密码锁被打开,如果密

码不正确,LCD显示屏会显示“error”,电子密码锁不能打开。通过LCD显示屏,可以清楚地判断出密码锁所处的状态。电路图如下图所示。

报警部分

报警部分由陶瓷压电发声装置及外围电路组成,加电后不发声,当有键按下时,“叮”声,每按一下,发声一次,密码正确时,不发声直接开锁,当密码输入错误时,蜂鸣器发出噪声报警。如下图所示。

设计总结

1、在本次课程设计中,我通过查阅网络与图书馆搜集到很多相关资料,结合生活中对密码锁的功能特性要求,初步设计出了这一套电子密码锁系统的主要硬件结构和软件结构,基本完成了课题的要求,并在Proteus软件上进行了仿真。

不过由于了解的专业知识尚浅,对课题的研究经验的不足,使得在技术的解决与运用上显得粗糙了一些,特别是功能按键的设定。所幸该系统能基本上完成一个电子密码锁应有的功能特性:开锁提示,输错报警,密码修改,掉电存储。本系统用的是6位密码输入,有106种密码输入方案,相较于机械锁具,防盗能力已经相当不俗。这个系统软硬件设计简单,易于开发,成本较低,安全可靠,操作方便。

2、通过本次毕业设计的锻炼,我学到了很多有关电子密码锁的设计方法与工作原理,巩固了单片机知识。也锻炼了我实践动手能力。

作为一名电气工程及其自动化专业的大三学生,我觉得做单片机课程设计是十分有意义的,而且是十分必要的。在已度过的大学时间里,我们大多数接触的是专业课。我们在课堂上掌握的仅仅是专业课的理论知识,如何去锻炼我们的实践能力?如何把我们所学的专业基础课理论知识运用到实践中去呢?我想做类似的课程设计就为我们提供了良好的实践平台。

最后,要做好一个课程设计,就必须做到:在设计程序之前,对所用单片机的内部结构有一个系统的了解,知道该单片机内有哪些资源;要有一个清晰的思路和一个完整的的软件流程图;在设计程序时,不能妄想一次就将整个程序设计好,反复修改、不断改进是程序设计的必经之路;要养成注释程序的好习惯,一个程序的完美与否不仅仅是实现功能,而应该让人一看就能明白你的思路,这样也为资料的保存和交流提供了方便;在设计课程过程中遇到问题是很正常德,但我们应该将每次遇到的问题记录下来,并分析清楚,以免下次再碰到同样的问题。

3、这次课程设计让我感到了团队合作的重要性。在团队中,我们互帮互助,对整个课程设计来说,这是至关重要的,缺少每一个人都会对我们的设计产生影响。还有要感谢指导老师在我们遇到困难时,给予我们的建议与鼓励。 4、一个月的课程设计结束了,但是从中学到的知识会让我受益终身。发现、提出、分析、解决问题和实践能力的提高都会受益于我在以后的学习、工作和生活中。

源程序

#include #include #include

#define uchar unsigned char #define uint unsigned int

#define C02_write 0xa0 //c02写地址 #define C02_read 0xa1 //c02读地址 #define no0 0x28//定义键码 #define no1 0x14 #define no2 0x24 #define no3 0x44 #define no4 0x12 #define no5 0x22 #define no6 0x42 #define no7 0x11 #define no8 0x21 #define no9 0x41 #define open 0x81 #define modify 0x82 #define enter 0x88

#define backspace 0x84

#define lcm_write_cmd_add XBYTE[0x80FF]//LM016L 控制地址 #define lcm_write_data_add XBYTE[0x81FF] #define lcm_read_busy_add XBYTE[0x82FF]

uchar idata temp5_password[6]={0x00,0x00,0x00,0x00,0x00,0x00}; uchar idata key_code[]={no0,no1,no3,no4,no5,no6,no7,no8,no9}; sbit SCL=P3^0; sbit SDA=P3^1; sbit i=P3^2; sbit led=P3^3; sbit beep=P3^4; bit ack; void delay0(uchar x) // 延时函数 { uchar i; while(x--)

{ for (i = 0; i<13; i++);}}

void delayms(uchar i){uchar j; for(;i>0;i--)for(j=124;j>0;j--);} void longdelay(uchar i)

{uint j;for(;i>0;i--)for(j=10000;j>0;j--);} void keysound() //按键声音函数

{uchar i; for (i=0;i<180;i++){delay0(5); beep=!beep; //BEEP取反} }void alarm1()//报警函数

{ uchar k; for (k=0; k<10; k++)keysound();} void lcm_wait()

{while(lcm_read_busy_add&0x80);//读取 LCM忙标志

}void lcm_write_cmd(uchar lcm_cmd)//写控制字 {lcm_wait();lcm_write_cmd_add=lcm_cmd;}

void lcm_write_data(uchar lcm_data)//写显示数据 {lcm_wait();lcm_write_data_add=lcm_data;}

void lcm_setxy(uchar x,uchar y)//光标定位,x定位字符位置,y为行数 {if(y==1) lcm_write_cmd(x|0x80);//定位第一行 if(y==2) lcm_write_cmd(x|0xc0);//定位第二行 }void lcm_write_string(uchar *string)//字符串显示 {uchar i=0;while(string[i]!='\\0') {lcm_write_data(string[i]);i++;}} void lcm_init()//LCM初始化

{delayms(20);lcm_write_cmd_add=0x38;delayms(4);

lcm_write_cmd_add=0x38;delayms(1);lcm_write_cmd_add=0x38; lcm_write_cmd(0x38);lcm_write_cmd(0x0f);lcm_write_cmd(0x01; lcm_write_cmd(0x06);}

void I2C_start(void)//I2C开始信号

{SDA=1;SCL=1;_nop_();_nop_();_nop_();_nop_();_nop_(); SDA=0;_nop_();_nop_();_nop_();_nop_();_nop_();SCL=0; _nop_();_nop_();}void I2C_stop(void)//I2C结束

{SDA=0;SCL=1;_nop_();_nop_();_nop_();_nop_();_nop_(); SDA=1;_nop_();_nop_();_nop_();_nop_();_nop_();SCL=0; _nop_();_nop_();}

void I2C_no_ackownledge(void)//发送noack信号

{SDA=1;_nop_();_nop_();SCL=1;_nop_();_nop_();_nop_(); _nop_();_nop_();SCL=0;_nop_();_nop_();_nop_();} void I2C_sendB(uchar byte)//发送一字节数据 {uchar counter;

for(counter=0;counter<8;counter++)

{if(byte&0x80) SDA=1;else SDA=0;_nop_();SCL=1;_nop_();

_nop_();_nop_();_nop_();_nop_();SCL=0;_nop_();_nop_();byte<<=1;}_nop_();_nop_();SDA=1;_nop_();_nop_();_nop_();SCL=1; _nop_();_nop_();_nop_();

if(SDA==0) ack=1;else ack=0;SCL=0;_nop_();_nop_();} uchar I2C_receiveB(void) //接受一字节数据

{uchar temp;uchar counter;temp=0;SDA=1;_nop_();_nop_();

for(counter=0;counter<8;counter++){_nop_();_nop_();_nop_();_nop_();_nop_();SCL=1;_nop_();_nop_();

if(SDA==1) temp=(temp<<1)|0x01;else temp=temp<<1; nop_();_nop_();SCL=0;_nop_();_nop_();_nop_();} _nop_();_nop_();return(temp);}

bit I2C_send_string(uchar *string,uchar no,uchar address)//发送六位密码 {uchar counter;for(counter=0;counter

if(ack==0) return(0);I2C_sendB(address+counter);

if(ack==0) return(0);I2C_sendB(string[counter]); I2C_stop();delayms(20); }return(1);}

bit I2C_receive_string(uchar *string,uchar no,uchar address)//接受六位密码 {uchar counter;for(counter=0;counter

if(ack==0) return(0);I2C_start();I2C_sendB(C02_read); if(ack==0) return(0);*(string+counter)=I2C_receiveB(); I2C_no_ackownledge();I2C_stop();}}

uchar get_key()//键盘扫描{uchar row_code;uchar

col_code;P1=0xf0;if(P1!=0xf0){delayms(10);if(P1!=0xf0) {row_code=0xfe;while(row_code!=0xef){P1=row_code; if(P1!=row_code){col_code=P1;while(col_code==P1); col_code=(col_code&0xf0)|0x0f; return( (~col_code)|(~row_code));}

row_code=((row_code<<1)|0x01);}}}return(0x00);} void convert_code(uchar *string)//密码转换 {uchar counter=0;

for(counter=0;counter<6;counter++) {switch(*string)

{case no0: *string=0x00; break; case no1: *string=0x01; break; case no2: *string=0x02;break; case no3: *string=0x03;break; case no4: *string=0x04;break; case no5: *string=0x05;break; case no6: *string=0x06;break; case no7: *string=0x07;break; case no8: *string=0x08;break; case no9: *string=0x09;break; default: break;}string++; }}

bit compare_string(uchar *string1,uchar *string2)//密码比较 {uchar counter;for(counter=0;counter<6;counter++) {if(string1[counter]!=string2[counter])return(0);} return(1);}

uchar step_choose(void)//系统初始化

{uinti;ucharkey;do{lcm_write_cmd(0x01);lcm_write_cmd(0x06); lcm_setxy(5,1);lcm_write_string(\ \lcm_setxy(0,2);lcm_write_string(\

for(i=0;i<30000;i++){key=get_key();if((key==open)||(key==modify)) break;} } while((key!=open)&&(key!=modify));return(key);} bit input_password(uchar *password)//密码输入 {uchar counter;uchar key;lcm_setxy(0,2); for(counter=0;counter<7;counter++)

{longdelay(3);if(counter<6){do{key=get_key();}

while(key==0x00);if((key!=backspace)&&(key!=enter)) {lcm_write_data('*');keysound();password[counter]=key;} if(key==backspace){if(counter>0)

{lcm_setxy(--counter,2);lcm_write_data(' '); password[counter]=0x00;lcm_setxy(counter,2); counter--;keysound();}}

if(key==enter){lcm_setxy(0,1);keysound(); return(0);}} if(counter==6){do{key=get_key();}

while((key!=backspace)&&(key!=enter));if(key==backspace) {lcm_setxy(--counter,2);lcm_write_data('');

password[counter]=0x00;lcm_setxy(counter,2);counter--; keysound();}if(key==enter){keysound(); return(1);}}}} void lock() //主函数 {uchar key;

uchar error_counter_1; uchar error_counter_2; uchar idata temp1_password[6]={0,0,0,0,0,0}; uchar idata temp3_password[6]={0,0,0,0,0,0}; uchar idata temp2_password[6]={0,0,0,0,0,0}; uchar idata temp4_password[6]={0,0,0,0,0,0}; key=step_choose();if(key==open)

{keysound();I2C_receive_string(temp1_password,6,0x00); lcm_write_cmd(0x01); lcm_write_cmd(0x06);

lcm_setxy(2,0); lcm_write_string(\

if(input_password(temp2_password)){convert_code(temp2_password);if(compare_string(temp1_password,temp2_password))

{lcm_setxy(0,2); lcm_write_string(\ \

led=0; longdelay(20);led=1; return; }else {lcm_setxy(0,2); lcm_write_string(\ \

if(error_counter_1<3){alarm1();}else{ while(1){ lcm_write_cmd(0x01);lcm_write_cmd(0x06);lcm_setxy(4,1);lcm_write_strig(\

\lcm_write_string(\

else{lcm_setxy(0,2); lcm_write_string(\ \longdelay(15); } }

else{keysound();I2C_receive_string(temp1_password,6,0x00); lcm_write_cmd(0x01); lcm_write_cmd(0x06);lcm_setxy(0,1); lcm_write_string(\if(input_password(temp2_password)) {convert_code(temp2_password);

if(compare_string(temp1_password,temp2_password)) {lcm_setxy(0,2); lcm_write_string(\ \longdelay(10); lcm_write_cmd(0x01); lcm_write_cmd(0x06); lcm_setxy(0,1);

lcm_write_string(\ \if(input_password(temp3_password))

{lcm_write_cmd(0x01); lcm_write_cmd(0x06);

lcm_setxy(0,1); lcm_write_string(\ again \if(input_password(temp4_password))

{if(compare_string(temp3_password,temp4_password)) {convert_code(temp3_password);

I2C_send_string(temp3_password,6,0x00);

lcm_write_cmd(0x01); lcm_write_cmd(0x06);lcm_setxy(2,1); lcm_write_string(\lcm_write_string(\ \return; }

else{lcm_write_cmd(0x01); lcm_write_cmd(0x06); lcm_setxy(2,1); lcm_write_string(\ input\

lcm_setxy(2,2); lcm_write_string(\ different! \longdelay(10); return;}}

else{lcm_setxy(0,2); lcm_write_string(\ \longdelay(15); return;}}

else{lcm_setxy(0,2); lcm_write_string(\ \longdelay(15); return;}}

else {lcm_setxy(0,2); lcm_write_string(\ \error_counter_2++ ; if(error_counter_2<3) {alarm1();else{while(1)

{ lcm_write_cmd(0x01);lcm_write_cmd(0x06);

lcm_setxy(4,1); lcm_write_string(\ \keysound();lcm_write_cmd(0x01);lcm_write_cmd(0x06); lcm_setxy(16,1); lcm_write_string(\ }}

return;}}

else{lcm_setxy(0,2); lcm_write_string(\ \longdelay(15); return; }}}

void int_service(void) using 0 interrupt 0 //密码初始化中断函数 {EA=0; EX0=0; lcm_write_cmd(0x01); lcm_write_cmd(0x06); lcm_setxy(0,1); lcm_write_string(\ reset success! \longdelay(3); I2C_send_string(temp5_password,6,0x00); EA=1; EX0=1; return;}void main(void) {IT0=1; EX0=1; EA=1; led=1; lcm_init(); while(1){lock();}}

本文来源:https://www.bwwdw.com/article/c277.html

Top