200字范文,内容丰富有趣,生活中的好帮手!
200字范文 > 电子密码锁设计-单片机课程设计

电子密码锁设计-单片机课程设计

时间:2020-02-10 03:35:30

相关推荐

电子密码锁设计-单片机课程设计

密码锁

电子密码锁-AT89C51-储存AT24C02

本系统由STC89C52单片机系统(主要是STC89C52单片机最小系统)、4×4矩阵键盘、LCD1602显示和报警系统等组成,具有设置、修改六位用户密码、超次报警、超次锁定、密码错误报警等功能(本设计由P0口控制LCD显示,密码正确显示OPEN! 密码错误显示error!超过三次输入错误自动锁定。由P1口控制矩阵键盘含有0-9数字键和A-F功能键。)

2.本设计拟实现的性能指标如下:

(1)本设计为了防止密码被窃取要求在输入密码时在LCD屏幕上显示号。

(2)设计开锁密码位六位密码的电子密码锁。

(3)能够LCD显示在密码正确时显示OPEN,密码错误时显示ERROR。

(4)实现输入密码错误超过限定的三次电子密码锁定。

(5)4×4的矩阵键盘其中包括0-9的数字键和A-D的功能键和、#按键。

(6)本产品具备报警功能,当输入密码错误时蜂鸣器响提示。

(7)密码可以由用户自己修改设定(只支持6位密码),修改密码之前必须再次输入密码,在输入新密码时候需要二次确认,以防止误操作 。

(8)输入正确的密码继电器闭合,可以随意驱动负载。

AT24C02

AT24C02是美国Atmel公司的低功耗CMOS型E2PROM,内含256×8位存储空间,具有工作电压宽(2.5~5.5 V)、擦写次数多(大于10000次)、写入速度快(小于10 ms)、抗干扰能力强、数据不易丢失、体积小等特点。而且他是采用了I2C总线式进行数据读写的串行器件,占用很少的资源和I/O线,并且支持在线编程,进行数据实时的存取十分方便。AT24C02中带有的片内地址寄存器。每写入或读出一个数据字节后,该地址寄存器自动加1,以实现对下一个存储单元的读写。所有字节均以单一操作方式读取。为降低总的写入时间,一次操作可写入多达8个字节的数据。I2C总线是一种用于IC器件之间连接的二线制总线。他通过SDA(串行数据线)及SCL(串行时钟线)两根线在连到总线上的器件之间传送信息,并根据地址识别每个器件。AT24C02正是运用了I2C规程,使用主/从机双向通信,主机(通常为单片机)和从机(AT24C02)均可工作于接收器和发送器状态。主机产生串行时钟信号(通过SCL引脚)并发出控制字,控制总线的传送方向,并产生开始和停止的条件。无论是主机还是从机,接收到一个字节后必须发出一个确认信号ACK。AT24C02的控制字由8位二进制数构成,在开始信号发出以后,主机便会发出控制字,以选择从机并控制总线传送的方向。

SOIC/ PDIP - 24C02的两种引脚图

AT24C02的电路接线图

图中AT24C02的1、2、3脚是三条地址线,用于确定芯片的硬件地址。第8脚和第4脚分别为正、负电源。第5脚SDA为串行数据输入/输出,数据通过这条双向I2C总线串行传送,第6脚SCL为串行时钟输入线, SDA和SCL都需要和正电源间各接一个10 K的电阻上拉。第7脚需要接地。

24C02中带有片内地址寄存器。每写入或读出一个数据字节后,该地址寄存器自动加1,以实现对下一个存储单元的读写。所有字节均以单一操作方式读取。为降低总的写入时间,一次操作可写入多达8个字节的数据。

LCD显示模块

LCD1602A 是一种工业字符型液晶,能够同时显示16x02 即32个字符。(16列2行)。在日常生活中,我们对液晶显示器并不陌生。液晶显示模块已作为很多电子产品的通过器件,如在计算器、万用表、电子表及很多家用电子产品中都可以看到,显示的主要是数字、专用符号和图形。在单片机的人机交流界面中,一般的输出方式有以下几种:发光管、LED数码管、液晶显示器。发光管和LED数码管比较常用,软硬件都比较简单。

在单片机系统中应用晶液显示器作为输出器件有以下几个优点:

由于液晶显示器每一个点在收到信号后就一直保持那种色彩和亮度,恒定发光,而不像阴极射线管显示器(CRT)那样需要不断刷新新亮点。因此,液晶显示器画质高且不会闪烁。

液晶显示器都是数字式的,和单片机系统的接口更加简单可靠,操作更加方便。

液晶显示器通过显示屏上的电极控制液晶分子状态来达到显示的目的,在重量上比相同显示面积的传统显示器要轻得多。

相对而言,液晶显示器的功耗主要消耗在其内部的电极和驱动IC上,因而耗电量比其它显示器要少得多。

(1)引脚说明:

第1脚:VSS为地电源。

第2脚:VDD接5V正电源。

第3脚:VL为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度。

第4脚:RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。

第5脚:R/W为读写信号线,高电平时进行读操作,低电平时进行写操作。当RS和R/W共同为低电平时可以写入指令或者显示地址,当RS为低电平

R/W为高电平时可以读忙信号,当RS为高电平R/W为低电平时可以写入数据。

第6脚:E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。

第7~14脚:D0~D7为8位双向数据线。

第15脚:背光源正极。

第16脚:背光源负极。

源文件下载

链接: 源文件下载.

仿真图

代码

//包含头文件#include <REG51.h>#include<intrins.h>//宏定义#define LCM_Data P0 //将P0口定义为LCM_Data#define uchar unsigned char #define uint unsigned int//1602的控制脚sbit lcd1602_rs=P2^5;sbit lcd1602_rw=P2^6;sbit lcd1602_en=P2^7;sbit Scl=P3^4;//24C02串行时钟sbit Sda=P3^5;//24C02串行数据sbit ALAM = P2^1;//报警sbit KEY = P3^6;//开锁bit pass=0;//密码正确标志bit ReInputEn=0;//重置输入允许标志bit s3_keydown=0;//3秒按键标志位bit key_disable=0;//锁定键盘标志unsigned char countt0,second;//t0中断计数器,秒计数器void Delay5Ms(void);//声明延时函数unsigned char code a[]={0xFE,0xFD,0xFB,0xF7}; //控盘扫描控制表//液晶显示数据数组unsigned char code start_line[]= {"password: "};unsigned char code name[] = {"===Coded Lock==="};//显示名称unsigned char code Correct[] = {"correct "};//输入正确unsigned char code Error[] = {"error"}; //输入错误unsigned char code codepass[]= {"pass"}; unsigned char code LockOpen[]= {"open"};//OPENunsigned char code SetNew[] = {"SetNewWordEnable"};unsigned char code Input[] = {"input:"};//INPUTunsigned char code ResetOK[] = {"ResetPasswordOK "};unsigned char code initword[]= {"Init password..."};unsigned char code Er_try[]= {"error,try again!"};unsigned char code again[]= {"input again"};unsigned char InputData[6];//输入密码暂存区unsigned char CurrentPassword[6]={0,0,0,0,0,0}; //读取EEPROM密码暂存数组unsigned char TempPassword[6];unsigned char N=0;//密码输入位数记数unsigned char ErrorCont;//错误次数计数unsigned char CorrectCont;//正确输入计数unsigned char ReInputCont; //重新输入计数unsigned char code initpassword[6]={0,0,0,0,0,0};//输入管理员密码后将密码初始为000000unsigned char code adminpassword[6]={1,3,1,4,2,0};//输入管理员密码后将密码初始为000000//=====================5ms延时==============================void Delay5Ms(void){unsigned int TempCyc = 5552;while(TempCyc--);}//===================400ms延时==============================void Delay400Ms(void){unsigned char TempCycA = 5;unsigned int TempCycB;while(TempCycA--){TempCycB=7269;while(TempCycB--);}}//=============================================================================================//================================24C02========================================================//=============================================================================================void mDelay(uint t) //延时{uchar i;while(t--){for(i=0;i<125;i++){;}}}void Nop(void) //空操作{_nop_(); //仅作延时用一条语句大约1us_nop_();_nop_();_nop_();}/*****24c02程序参照24c02时序图*****//*起始条件*/void Start(void){Sda=1;Scl=1;Nop();Sda=0;Nop();}/*停止条件*/void Stop(void){Sda=0;Scl=1;Nop();Sda=1;Nop();}/*应答位*/void Ack(void){Sda=0;Nop();Scl=1;Nop();Scl=0;}/*反向应答位*/void NoAck(void){Sda=1;Nop();Scl=1;Nop();Scl=0;}/*发送数据子程序,Data为要求发送的数据*/void Send(uchar Data){uchar BitCounter=8;uchar temp;do{temp=Data; //将待发送数据暂存tempScl=0;Nop();if((temp&0x80)==0x80) //将读到的数据&0x80Sda=1;else Sda=0;Scl=1;temp=Data<<1; //数据左移Data=temp; //数据左移后重新赋值DataBitCounter--; //该变量减到0时,数据也就传送完成了}while(BitCounter); //判断是否传送完成Scl=0;}/*读一字节的数据,并返回该字节值*/uchar Read(void){uchar temp=0;uchar temp1=0;uchar BitCounter=8;Sda=1;do{Scl=0;Nop();Scl=1;Nop();if(Sda) //数据位是否为1temp=temp|0x01; //为1 temp的最低位为1(|0x01,就是将最低位变为1)else //如果为0temp=temp&0xfe; //temp最低位为0(&0xfe(11111110)最低位就是0)if(BitCounter-1) //BitCounter减1后是否为真{temp1=temp<<1; //temp左移temp=temp1;}BitCounter--; //BitCounter减到0时,数据就接收完了}while(BitCounter); //判断是否接收完成return(temp);}void WrToROM(uchar Data[],uchar Address,uchar Num){uchar i;uchar *PData;PData=Data;for(i=0;i<Num;i++){Start();Send(0xa0);Ack();Send(Address+i);Ack();Send(*(PData+i));Ack();Stop();mDelay(20);}}void RdFromROM(uchar Data[],uchar Address,uchar Num){uchar i;uchar *PData;PData=Data;for(i=0;i<Num;i++){Start();Send(0xa0);Ack();Send(Address+i);Ack();Start();Send(0xa1);Ack();*(PData+i)=Read();Scl=0;NoAck();Stop();}}//==================================================================================================//=======================================LCD1602====================================================//==================================================================================================#define yi 0x80 //LCD第一行的初始位置,因为LCD1602字符地址首位D7恒定为1(100000000=80)#define er 0x80+0x40 //LCD第二行初始位置(因为第二行第一个字符位置地址是0x40)//----------------延时函数,后面经常调用----------------------void delay(uint xms)//延时函数,有参函数{uint x,y;for(x=xms;x>0;x--)for(y=110;y>0;y--);}//--------------------------写指令---------------------------void write_1602com(uchar com)//****液晶写入指令函数****{lcd1602_rs=0;//数据/指令选择置为指令lcd1602_rw=0; //读写选择置为写P0=com;//送入数据delay(1);lcd1602_en=1;//拉高使能端,为制造有效的下降沿做准备delay(1);lcd1602_en=0;//en由高变低,产生下降沿,液晶执行命令}//-------------------------写数据-----------------------------void write_1602dat(uchar dat)//***液晶写入数据函数****{lcd1602_rs=1;//数据/指令选择置为数据lcd1602_rw=0; //读写选择置为写P0=dat;//送入数据delay(1);lcd1602_en=1; //en置高电平,为制造下降沿做准备delay(1);lcd1602_en=0; //en由高变低,产生下降沿,液晶执行命令}//-------------------------初始化-------------------------void lcd_init(void){write_1602com(0x38);//设置液晶工作模式,意思:16*2行显示,5*7点阵,8位数据write_1602com(0x0c);//开显示不显示光标write_1602com(0x06);//整屏不移动,光标自动右移write_1602com(0x01);//清显示}//========================================================================================//=========================================================================================//==============将按键值编码为数值=========================unsigned char coding(unsigned char m) {unsigned char k;switch(m){case (0x11): k=1;break;case (0x21): k=2;break;case (0x41): k=3;break;case (0x81): k='A';break;case (0x12): k=4;break;case (0x22): k=5;break;case (0x42): k=6;break;case (0x82): k='B';break;case (0x14): k=7;break;case (0x24): k=8;break;case (0x44): k=9;break;case (0x84): k='C';break;case (0x18): k='*';break;case (0x28): k=0;break;case (0x48): k='#';break;case (0x88): k='D';break;}return(k);}//=====================按键检测并返回按键值===============================unsigned char keynum(void){unsigned char row,col,i;P1=0xf0;if((P1&0xf0)!=0xf0){Delay5Ms();Delay5Ms();if((P1&0xf0)!=0xf0){row=P1^0xf0;//确定行线i=0;P1=a[i];//精确定位while(i<4){if((P1&0xf0)!=0xf0){col=~(P1&0xff); //确定列线break; //已定位后提前退出 }else {i++;P1=a[i];}}}else {return 0;}while((P1&0xf0)!=0xf0);return (row|col); //行线与列线组合后返回}else return 0; //无键按下时返回0}//=======================一声提示音,表示有效输入========================void OneAlam(void){ALAM=0;Delay5Ms();ALAM=1;}//========================二声提示音,表示操作成功========================void TwoAlam(void){ALAM=0;Delay5Ms();ALAM=1;Delay5Ms();ALAM=0;Delay5Ms();ALAM=1;}//========================三声提示音,表示错误========================void ThreeAlam(void){ALAM=0;Delay5Ms();ALAM=1;Delay5Ms();ALAM=0;Delay5Ms();ALAM=1;Delay5Ms();ALAM=0;Delay5Ms();ALAM=1;}//=======================显示提示输入=========================void DisplayChar(void){unsigned char i;if(pass==1){//DisplayListChar(0,1,LockOpen);write_1602com(er); //在二行开始显示for(i=0;i<16;i++){write_1602dat(LockOpen[i]); //显示open 开锁成功}}else{if(N==0){//DisplayListChar(0,1,Error);write_1602com(er);for(i=0;i<16;i++){write_1602dat(Error[i]);//显示错误}}else{//DisplayListChar(0,1,start_line);write_1602com(er);for(i=0;i<16;i++){write_1602dat(start_line[i]);//显示开始输入}}}}//========================重置密码==================================================//==================================================================================void ResetPassword(void){unsigned char i;unsigned char j;if(pass==0){pass=0; DisplayChar(); //显示错误ThreeAlam(); //没开锁时按下重置密码报警3声}else //开锁状态下才能进行密码重置程序{if(ReInputEn==1) //开锁状态下,ReInputEn置1,重置密码允许{if(N==6) //输入6位密码{ReInputCont++;//密码次数计数if(ReInputCont==2)//输入两次密码{for(i=0;i<6;){if(TempPassword[i]==InputData[i])//将两次输入的新密码作对比i++;else//如果两次的密码不同{//DisplayListChar(0,1,Error);write_1602com(er);for(j=0;j<16;j++){write_1602dat(Error[j]);//显示错误Error}ThreeAlam();//错误提示pass=0;//关锁ReInputEn=0;//关闭重置功能,ReInputCont=0;DisplayChar();break;}} if(i==6){//DisplayListChar(0,1,ResetOK);write_1602com(er);for(j=0;j<16;j++){write_1602dat(ResetOK[j]); //密码修改成功,显示}TwoAlam();//操作成功提示WrToROM(TempPassword,0,6);//将新密码写入24C02存储ReInputEn=0;}ReInputCont=0;CorrectCont=0;}else //输入一次密码时{OneAlam();//DisplayListChar(0, 1, again); //显示再次输入一次write_1602com(er);for(j=0;j<16;j++){write_1602dat(again[j]);//显示再输入一次}for(i=0;i<6;i++){TempPassword[i]=InputData[i];//将第一次输入的数据暂存起来}}N=0;//输入数据位数计数器清零}}}}//=======================输入密码错误超过三过,报警并锁死键盘======================void Alam_KeyUnable(void){P1=0x00;{ALAM=~ALAM; //蜂鸣器一直闪烁鸣响Delay5Ms();}}//=======================取消所有操作============================================void Cancel(void){unsigned char i;unsigned char j;//DisplayListChar(0, 1, start_line); write_1602com(er);for(j=0;j<16;j++){write_1602dat(start_line[j]); //显示开机输入密码界面}TwoAlam();//提示音for(i=0;i<6;i++){InputData[i]=0;//将输入密码清零}KEY=1;//关闭锁ALAM=1;//报警关pass=0;//密码正确标志清零ReInputEn=0;//重置输入充许标志清零ErrorCont=0;//密码错误输入次数清零CorrectCont=0;//密码正确输入次数清零ReInputCont=0;//重置密码输入次数清零 s3_keydown=0;key_disable=0;//锁定键盘标志清零N=0;//输入位数计数器清零}//==========================确认键,并通过相应标志位执行相应功能===============================void Ensure(void){unsigned char i,j;RdFromROM(CurrentPassword,0,6); //从24C02里读出存储密码if(N==6){if(ReInputEn==0)//重置密码功能未开启{for(i=0;i<6;){if(CurrentPassword[i]==InputData[i])//判断输入密码和24c02中的密码是否相同{i++;//相同一位 i就+1}else //如果有密码不同{ErrorCont++;//错误次数++if(ErrorCont==3)//错误输入计数达三次时,报警并锁定键盘{write_1602com(er);for(i=0;i<16;i++){write_1602dat(Error[i]);}doAlam_KeyUnable();while(1);}else //错误次数小于3次时,锁死键盘3秒,然后重新可以输入{TR0=1;//开启定时key_disable=1;//锁定键盘pass=0;//pass位清零break;//跳出}}}if(i==6) //密码输入对时{if((InputData[0]==adminpassword[0])&&(InputData[1]==adminpassword[1])&&(InputData[2]==adminpassword[2])&&(InputData[3]==adminpassword[3])&&(InputData[4]==adminpassword[4])&&(InputData[5]==adminpassword[5])){WrToROM(initpassword,0,6); //强制将初始密码写入24C02存储write_1602com(er);for(j=0;j<16;j++){write_1602dat(initword[j]);//显示初始化密码}TwoAlam();//成功提示音Delay400Ms();//延时400msTwoAlam();//成功提示音N=0;//输入位数计数器清零}else {CorrectCont++;//输入正确变量++if(CorrectCont==1)//正确输入计数,当只有一次正确输入时,开锁{//DisplayListChar(0,1,LockOpen);write_1602com(er);for(j=0;j<16;j++){write_1602dat(LockOpen[j]); //显示open开锁画面}TwoAlam();//操作成功提示音KEY=0;//开锁pass=1;//置正确标志位TR0=1;//开启定时for(j=0;j<6;j++)//将输入清除{InputData[i]=0;//开锁后将输入位清零}}else//当两次正确输入时,开启重置密码功能{write_1602com(er);for(j=0;j<16;j++){write_1602dat(SetNew[j]);//显示重置密码界面}TwoAlam(); //操作成功提示ReInputEn=1;//允许重置密码输入CorrectCont=0;//正确计数器清零}}}else//=========================当第一次使用或忘记密码时可以用131420对其密码初始化============{if((InputData[0]==adminpassword[0])&&(InputData[1]==adminpassword[1])&&(InputData[2]==adminpassword[2])&&(InputData[3]==adminpassword[3])&&(InputData[4]==adminpassword[4])&&(InputData[5]==adminpassword[5])){WrToROM(initpassword,0,6); //强制将初始密码写入24C02存储write_1602com(er);for(j=0;j<16;j++){write_1602dat(initword[j]);//显示初始化密码}TwoAlam();//成功提示音Delay400Ms();//延时400msTwoAlam();//成功提示音N=0;//输入位数计数器清零}else//密码输入错误{write_1602com(er);for(j=0;j<16;j++){write_1602dat(Error[j]); //显示错误信息}ThreeAlam();//错误提示音pass=0;}}}else//当已经开启重置密码功能时,而按下开锁键,{//DisplayListChar(0,1,Er_try);write_1602com(er);for(j=0;j<16;j++){write_1602dat(Er_try[j]); //错误,请重新输入}ThreeAlam(); //错误提示音}}else //密码没有输入到6位时,按下确认键时{//DisplayListChar(0,1,Error);write_1602com(er);for(j=0;j<16;j++){write_1602dat(Error[j]); //显示错误}ThreeAlam();//错误提示音pass=0;}N=0;//将输入数据计数器清零,为下一次输入作准备}//==============================主函数===============================void main(void){unsigned char KEY,NUM;unsigned char i,j;P1=0xFF; //P1口复位TMOD=0x11; //定义工作方式TL0=0xB0;TH0=0x3C; //定时器赋初值EA=1; //打开中断总开关ET0=1; //打开中断允许开关TR0=0; //打开定时器开关Delay400Ms(); //启动等待,等LCM讲入工作状态lcd_init(); //LCD初始化write_1602com(yi);//日历显示固定符号从第一行第0个位置之后开始显示for(i=0;i<16;i++){write_1602dat(name[i]);//向液晶屏写开机画面}write_1602com(er);for(i=0;i<16;i++){write_1602dat(start_line[i]);//写输入密码等待界面}write_1602com(er+9);//设置光标位置write_1602com(0x0f);//设置光标为闪烁Delay5Ms(); //延时片刻(可不要)N=0;//初始化数据输入位数while(1) //进入循环{if(key_disable==1)//锁定键盘标志为1时Alam_KeyUnable();//报警键盘锁elseALAM=1;//关报警KEY=keynum();//读按键的位置码if(KEY!=0)//当有按键按下时{if(key_disable==1)//锁定键盘标志为1时{second=0;//秒清零}else//没有锁定键盘时{NUM=coding(KEY);//根据按键的位置将其编码,编码值赋值给NUM{switch(NUM)//判断按键值{case ('A'): ; break;case ('B'):;break;case ('C'):write_1602com(yi);//日历显示固定符号从第一行第0个位置之后开始显示for(i=0;i<16;i++){write_1602dat(name[i]);//向液晶屏写开机画面}if(N>=1) N--;OneAlam();//按键提示音//DisplayOneChar(6+N,1,'*');for(j=N;j<16;j++){write_1602com(er+6+j);write_1602dat(' ');}for(j=0;j<N;j++){write_1602com(er+6+j);//显示位数随输入增加而增加write_1602dat('*');//但不显示实际数字,用*代替} InputData[N]=N+4;break;//ABC是无定义按键case ('D'): ResetPassword();break;//重新设置密码case ('*'): Cancel();break;//取消当前输入case ('#'): Ensure(); break; //确认键,default: //如果不是功能键按下时,就是数字键按下{//DisplayListChar(0,1,Input);if(N<6) //当输入的密码少于6位时,接受输入并保存,大于6位时则无效。{write_1602com(er);for(i=0;i<16;i++){write_1602dat(Input[i]);//显示输入画面} OneAlam();//按键提示音for(j=0;j<=N;j++){write_1602com(er+6+j);//显示位数随输入增加而增加write_1602dat('*');//但不显示实际数字,用*代替}InputData[N]=NUM;//将数字键的码赋值给InputData[]数组暂存N++;//密码位数加}else//输入数据位数大于6后,忽略输入{N=6;//密码输入大于6位时,不接受输入break;}}}}}} }}//*********************************中断服务函数**************************************void time0_int(void) interrupt 1 //定时器T0{TL0=0xB0;TH0=0x3C; //定时器重新赋初值//TR0=1;countt0++; //计时变量加,加1次时50msif(countt0==20) //加到20次就是1s{countt0=0; //变量清零second++; //秒加if(pass==1) //开锁状态时{if(second==1)//秒加到1s时{TR0=0;//关定时器TL0=0xB0;TH0=0x3C;//再次赋初值second=0;//秒清零}}else//不在开锁状态时{if(second==3)//秒加到3时{TR0=0;//关闭定时器second=0;//秒清零key_disable=0;//锁定键盘清零s3_keydown=0;TL0=0xB0;TH0=0x3C;//重新赋初值}elseTR0=1;//打开定时器}}}

源文件下载

链接: 源文件下载.

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。