密码锁
电子密码锁-AT89C51-储存AT24C02
本系统由STC89C52单片机系统(主要是STC89C42单片机最小系统×4矩阵键盘、LCD由1602显示和报警系统组成,具有六个用户密码、超级报警、超级锁定、密码错误报警等功能。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是美国Atmel公司功耗低CMOS型E2PROM,内含256×工作电压宽为8位存储空间(2.5~5.5 V)、擦写次数多(超过1000次),写入速度快(小于1000次) ms)、抗干扰能力强,数据不易丢失,体积小。而且他采用了I2C数据读写总线串行器件占用资源少I/O支持在线编程,实时访问数据非常方便。AT24C片内地址寄存器在02中。每次写入或读取数据字节后,地址寄存器自动添加1,以便读写下一个存储单元。所有字节都是单一操作读取的。一个操作可以写入多达8个字节的数据,以减少总写入时间。I2C总线是一种用途IC连接到设备之间的二线总线。他通过SDA(串行数据线)及SCL(串行时钟线)将信息传输到连接到总线的设备之间,并根据地址识别每个设备。AT24C02正是运用了I2C使用主/从机双向通信,主机(通常是单片机)和从机(AT24C02)可以在接收器和发送器状态下工作。主机产生串行时钟信号(通过SCL引脚)并发出控制字,控制总线的传输方向,并产生开始和停止的条件。无论是主机还是从机,接收字节后都必须发出确认信号ACK。AT24C02的控制字由8位二进制数组成信号发出后,主机会发出控制字,选择从机和控制总线传输方向。 SOIC/ PDIP - 24C两种引脚图02 AT24C02电路接线图 图中AT24C021、2、3脚是确定芯片硬件地址的三条地址线。第8脚和第4脚是正负电源。SDA数据通过这个双向输入/输出串行数据I2C总线串行传输,第六脚SCL串行时钟输入线, SDA和SCL都需要和正电源间接一个10 K电阻上拉。第七脚需要接地。 24C电影中有一个地址寄存器。每次写入或读取一个数据字节后,地址寄存器自动添加1,以便读写下一个存储单元。所有字节都以单一的方式读取。为了减少总写入时间,一个操作可以写入多达8个字节的数据。 LCD1602A 可同时显示16个工业字符液晶x02 即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 " } ; //OPEN unsigned char code SetNew [ ] = { "SetNewWordEnable" } ; unsigned char code Input [ ] = { "input: " } ; //INPUT unsigned 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 } ; //输入管理员密码后将密码初始为000000 unsigned 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 ; //将待发送数据暂存temp Scl = 0 ; Nop ( ) ; if ( (temp & 0x80 ) == 0x80 ) //将读到的数据&0x80 Sda = 1 ; else Sda = 0 ; Scl = 1 ; temp =Data << 1 ; //数据左移 Data =temp ; //数据左移后重新赋值Data BitCounter -- ; //该变量减到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 ) //数据位是否为1 temp =temp | 0x01 ; //为1 temp的最低位为1(|0x01,就是将最低位变为1) else //如果为0 temp =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 ; 标签:
单片机应如何正确驱动继电器