单片机论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 563|回复: 2
收起左侧

51单片机电子密码锁Proteus仿真+代码+文档

[复制链接]
1518921 发表于 2018-12-12 18:07 | 显示全部楼层 |阅读模式
电子密码锁仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
0.png 0.png

1.设计任务与设计思路

1.1 设计任务

1.系统通过4×4的矩阵键盘输入或设定开锁密码,用24WC04保存密码
2.可以通过LCD查看已输入的字符个数[显示为*****]   
3. 通过单片机控制继电器通断(可以指示灯亮灭替代)
4、当密码输入正确时,继电器通,绿灯亮;当密码输入错误时,继电器断,红灯亮,控制蜂鸣器报警;


1.2 设计思路

本设计由主控芯片52单片机,24C04断电存储电路、单片机时钟电路,LCD1602显示电路、矩阵按键和蜂鸣器电路组成。单片机负责控制整个系统的执行过程。

2.硬件电路设计

为了达到系统要求,硬件应该包括如下部分:

   单片机最小系统,最小系统主要包括时钟电路和复位电路;

   LCD电路,为了能直观的看到生成的密码,以及用户输入的密码,就需要一个显示设备,而在单片机系统中,比较常见的显示设备就是LED和LCD,相比较于LED来说,LCD显示效果更加美观,更加真实;

  按键电路,为了做到密码的提取以及校验,就需要有人机交互的操作,本设计采用了机械按键充当此功能。

   LED电路,本设计有红绿两个LED,当密码校验正确时,绿灯亮;相反当密码校验错误时,红灯亮。

   继电器电路,为了模拟锁的开和关,用到了继电器的开关来模拟。


2.1 单片机最小系统

本次选用的主控芯片为单片机STC89C52。其引脚图如图2.1-1所示。



图2.1-1 STC89C52引脚图


目前,不管是在工业,农业还是消费电子领域,51系列单片机的身影随处可见,例如,我们可以利用单片机来检测温湿度,来检测空气质量,我们日常使用的电子时钟等等都能很方便的使用51单片机来实现。STC89C52单片机是深圳宏晶科技有限公司生产的一种单片机,它是在一小块很小的集成电路上集成了一个微型计算机。每一个单片机的组成都离不开如下几种组成成分:

CPU:51系列单片机内部集成的CPU都是8位的;

IO口;数据输入输出的并行口,51单片机有32个IO口,分别是P0,P1,P2,P3,每种有8条数据线;

ROM:片内程序存储器,它主要用来存储程序的,一般大小为4K;

RAM:片内数据存储器,它主要用来存储临时数据,一般大小为512K;

中断源;它主要用来引发中断的,有5个中断源;

定时器:它主要用来计数定时用,51单片机有2个,分别是定时器0和定时器1;

图2.1-2 STC89C52最小系统


2.2 液晶显示电路

随着人机界面的越来越人性化,液晶屏应运而生,十九世纪八十年代,奥地利科学家赖倪次在一种植物身上提取出了看起来很奇怪的物质,它既不是液态的,也不是固态的,徘徊于两者之间,但是他即具有固态的特征,也有液态的特征,所以,当时的人们就把它叫做成液态的晶体,这就是当今液晶的前身。

市面上的LCD显示屏可谓是林林总总,大型的有拼接墙,数十寸的等等,从才子上来分,有TFT、LED等等,但对于单片机系统来说,常用的LCD有两种:分别是1602和12864型号。

12864的意思就是该LCD的点阵是128行*64列,总共有8192个像素点, 控制器AIP31020。可显示汉字及图形, 内置8192 个中文汉字 (16X16 点阵)、 128 个字符 (8X16点阵)及64X256点阵显示RAM(GDRAM)。可与CPU 直接接口,提供两种界面来连接微处理机:8-位并行及串行两种连接方式。具有多种功能:光标显示、画面移位、睡眠模式等。而1602的意思就是该LCD的点阵是16行*2列,总共有32个像素点,1602LCD分为带背光和不带背光两种,带背光的用起来就比较方便,但缺点就是比较厚,而不带背光的需要自己加一个背光片,不方便使用,但他比较轻薄。

本次设计采用了LCD1602液晶显示器,本次设计采用了LCD1602液晶显示器。


图2.2-1 液晶显示电路


1602型液晶接口信号说明如表2.2-1所示。

2.3 矩阵按键模块

本实验选用矩阵按键来输入密码值。矩阵按键电路如下图2.3-1所示:


图2.3-1 矩阵按键电路

为了满足输入功能的需要,本设计采用了14个按键,如果全部接成独立式按键,那么就需要14个IO口,资源占用过多,所以这里采用了矩阵式4*4规格的键盘,多余两个按键做备用。它总共占用8个IO口,分别接到了P0口上,由于P0口的特殊结构,必须接一个上拉电阻,才能输出高电平。

其按键功能如下所示:

0-9的数字按键用来输入密码;

“存包”按键  --    按下此键生成四位随机数密码

“取包”按键  --    按下此按键,提示输入密码

“清空”按键 --     在输入密码过程中,按下此键清掉刚才输入的数字

“确认”按键  --    密码输入完毕后,按下此键进行密码的校验。

2.4 i2C 24C02模块

串行E2PROM是基于I2C-BUS 的存储器件,遵循二线制协议,由于其具有接口方便,体积小,数据掉电不丢失等特点,在仪器仪表及工业自动化控制中得到大量的应用。

24C02与单片机的接口非常简单,如下图2.4-1所示

图2.4-1 24C02电路



E0,E1,E2为器件地址线,WP为写保护引脚,SCL,SDA为二线串行接口,符合I2C总线协议。在一般单片机系统中,24C02 数据受到干扰的情况是很少的。

本实验采用AT24C02。AT24WC02是一个2K位串行CMOS,EEPROM内部含有256个8位字节CATALYST公司的先进CMOS技术实质上减少了器件的功耗。AT24WC02有一个16字节页写缓冲器,该器件通过I2C总线接口进行操作有一个专门的写保护功能。



其引脚说明如表2.4-1:

表2.4-1 AT24C02引脚说明

2.5.蜂鸣器电路

在单片机应用的设计上,很多方案都会用到蜂鸣器,大部分都是使用蜂鸣器来做提示或报警,比如按键按下、开始工作、工作结束或是故障等等。

蜂鸣器电路如图2.5-1所示。

图2.5-1 蜂鸣器电路


本次设计使用了ULN2003D来驱动蜂鸣器。其电路如图2.5-2所示

图2.5-2 蜂鸣器驱动电路


本设计 用到了一个红色LED和一个绿色LED来指示输入密码的正确与否。每个LED的正极通过一个限流电阻接到电源正极,然后负极分别接到P33和P34,当IO口为高电平时,灯熄灭,当LED为低电平时,灯亮起来。图2.5-3是其连线图。

图2.5-3 LED提示灯电路

2.6  继电器电路

本设计用继电器来模拟锁的动作,当继电器吸合表示开始锁关闭,当继电器断开表示断开,继电器的控制引脚接在单片机的P37口,高电平让其吸合,低电平让其断开,图2-6是其连接图。


      


主程序里面首先对单片机的硬件资源进行初始化,硬件资源的初始化包括:

  • IO口的初始化,本设计所采用的51单片机有32IO口,并且单片机复位后,所有IO口被默认赋值为高电平(1),这就给一些功能带来了一些不必要的麻烦,所以就需要对某些上电需要置低电平的IO口置低电平(比如本设计中的LCD某些管脚);
  • 定时器的初始化,定时器是单片机中的一个非常重要的资源,有了它,单片机就能“并行”的处理多个事情了,不然为了做到定时,只能用死等来实现,那样会造成单片机资源大量的浪费,更严重的是,单片机运行会相当不流畅;
  • 串口的初始化,串口的存在使得单片机跟外界的通讯带来了很大的方便,因为它遵循标准的RS232协议,所以可以跟任何具有RS232接口的设备通信,

    基本的资源初始化完毕后,程序然后进入了一个while(1)死循环,这样保证了程序不断的运行,在该循环中,多个任务逐一按顺序的执行。


3.2 LCD显示子程序


LCD1602的读时序如图3-2-1所示。


图3-2-1  LCD1602读时序









LCD1602的写时序如图3-2-2 所示。

图3-2-3 LCD2602写时序


从时序图可以看出,首先判断RS和RW,从硬件那一章我们得知,RS代表了是指令的操作(高电平)还是数据的操作(低电平),而RW代表了是往LCD里面写数据(高电平)还是从LCD里面读出数据(低电平)。

然后再通过控制器把使能端拉低(通过上面一章,我们知道此管脚为高表示禁用该芯片,此管脚为低表示使能该芯片),拉低后需要延时一段时间,至于要不要 延时,延时的时间多长,对于51单片机来说,其实关系都不大,不影响其使用。

以上两步准备操作完成后,就可以开始读和写了,也就是从这时候开始数据或地址信号就被送上了数据总线,数据送完之后,然后又将使能端拉高(禁止芯片),当然,这中间需要一个建立时间的延迟,改时间最短为40纳秒。然后再将使能端拉低(启用),就可以将刚才数据总线上的数据送入LCD了。

1602液晶显示子程序主要是对内部控制指令进行指定如液晶初始化,显示空白,读,写,判断液晶是否忙及指定字符的位置等函数构成。液晶显示子程序流程图如图所示。首先进行液晶初始化,再写地址命令到LCD,然后放发送字符串,最终液晶显示。

  根据上面描述的时序,可以得出如图3-2-4所示的流程图



3.3 矩阵按键子程序


16个按键接在了P0的8个口,其中P00-P03为四行,P04-P07为四列,本设计采用的是行扫描法,也就是说每次给四行当中的一行输出低电平(其他三行为高电平),然后再读取四列的值,如果发现四列全部为高电平,那么就表示没有按键按下,如果有某一列为低电平,就表示有按键按下了。


3.4 密码比对子程序

  密码比对过程主要是将按键输入的密码与正确密码进行比较的过程。该过程要求把密码放入24C02芯片中存储,每按下一个按键则与芯片中相应位进行比较。流程如图3.4-1所示   



4.系统调试

整个系统设计完成后,要进行运行调试,排除软件和硬件的故障,同时验证系统的可靠性及稳定性,使系统符合设计要求。本系统的调试主要分两个步骤:单片机系统调试(硬件调试和软件调试)及整个控制系统试运行调试。

单片机系统的调试应包括硬件及软件两部分,主要是通过调试发现硬件及软件中存在的问题,查看其运行结果是否符合设计要求。

    系统硬件和软件的研制可以相互独立的平行进行,软件调试可以在硬件完成之前,硬件也可以在无完整应用软件的情况下进行调试,但它们需要借助另外的工具提供调试环境。硬件和软件分调完成之后,还要再进行软件和硬件的联调,在调试中找出问题,判断故障源,修改软硬件。


4.1 硬件调试

静态调试主要是排除明显的硬件故障。在电路搭建好后,对其进行仔细检查,查看端口是否正确连接,连接是否可靠。同时还应当用万用表检查电路,看应当开路的地方是否开路,应当短路的地方是否短路,电源地线连接是否可靠。在焊接后,查看焊接是否牢固,有无虚焊或短路等。在将芯片、传感器等元件插到电路板上时,要保证各处电源极性、电压正确,以防止因电源极性接反或电压过高损坏芯片或传感器。此外,插入芯片必须在断电的情况下进行,特别注意芯片的方向不要插反。


4.2 软件调试

    系统软件程序在编制好以后,可通过汇编软件对源程序进行汇编,变为可执行的目标代码,在汇编过程中出现的错误,要及时纠正。在软件调试时采用软件模拟开发系统对程序进行调试,这种模拟开发系统是在计算机上利用模拟软件实现对单片机的硬件模拟、指令模拟及运行状态模拟,从而完成应用软件开发的全过程。调试过程中的运行状态、各寄存器状态、端口状态等都可以在指定的窗口区域显示出来,通过这些显示结果随时跟踪程序运行状态,以确定程序运行无误。

4.3动态调试

    控制系统的软件和硬件是密切相关的,软件模拟开发系统不能对硬件部分进行诊断,同时也不能实时在线仿真,所以用户程序还需跟硬件连接起来进行联调,同时对软件和硬件进行检查和诊断。整个单片机系统进行在线调试时,需借助仿真开发工具来对用户软件及硬件电路进行诊断、调试。在应用系统各电路板调试成功后,将用户程序加载到在线仿真器上,这时就能单步、多步或连续地执行目标程序,同时也可以根据需要分段设置断点执行用户程序。系统中的硬件故障(如各个部件内部存在的故障和部件之间连接的逻辑错误)主要是靠联机仿真来排除的。对于与硬件无联系的用户程序,例如定时标志等,虽然已经没有语法错误,但可能存在逻辑错误,这时,就借助于动态在线调试手段发现逻辑错误,直至逻辑错误纠正为止。而对于一些与硬件相关的用户程序,如接口驱动程序等,则需要配合硬件,进行在线调试,如果有逻辑错误,也要及时纠正修改。程序调试完毕后,利用在线编程器将程序固化到单片机中,使整个系统运行起来。


0.png





4.4 实验图


按下取包键,获取密码,得到密码为2392,此时继电器为关闭状态:


调试图a:


调试图a



              当输入密码错误时红灯亮,即D1灯亮,此时继电器为关闭状态:


调试图b:



调试图b






当输入密码正确是绿灯亮,即D2灯亮,此时继电器为打开状态:


结果图:



结果图



附录

附录1:电路原理图







单片机源程序如下:
  1. #include <reg51.h>
  2. #include <intrins.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include<absacc.h>
  6. #include "lcd1602.h"
  7. #include "main.h"
  8. #include "key.h"

  9. sbit Lock = P3^7;  //代表锁控的继电器IO   高电平关锁,低电平开锁
  10. sbit LEDRED = P2^0;  //代表密码输入错误的红灯IO  高电平熄灭,低电平点亮
  11. sbit LEDGREEN = P2^1;  //代表密码输入正确的绿灯IO  高电平熄灭,低电平点亮
  12. sbit beep=P1^5;         
  13. uchar genPasswd[4];           //存储生成的四位随机数密码
  14. uchar inpPasswd[4];           //存储取包时输入的四位密码
  15. uchar code welcome[8]="welcome";  //开机显示的欢迎标语
  16. uchar code set[7]="Passwd";    //显示生成的密码标题
  17. uchar code  close[12]="close door!";   //提示关门
  18. uchar code         input[13] = "input passwd";   //提示请输入密码

  19. /****************定时器设置相关的变量***********************/
  20. unsigned char TL0_temp;         /*暂存TL0的初值*/
  21. unsigned char TH0_temp;         /*暂存TH0的初值*/
  22. #define INT_CLOCK 10    /*INT_CLOCK为定时值,单位为ms ,此处定义为10ms*/
  23. #define CRY_FREQUENCY 11059200 /*CRY_FREQUENCY为晶振频率,单位为Hz*/





  24. /*延时程序*/
  25. void delay(uint z)               
  26. {
  27.         unsigned int i,j;
  28.    for(i=0;i<z;i++)
  29.     for(j=0;j<100;j++);
  30. }
  31. /******************************
  32. 显示首页 welcome
  33. ******************************/
  34. void display1()
  35. {
  36.    unsigned char i;
  37.    for(i = 0;i < 7;i++)
  38.    {
  39.                    wr_com(0x85+i);
  40.                 wr_dat(welcome[i]);
  41.    }
  42. }


  43. /************************************
  44. 显示密码生成界面
  45. ************************************/
  46. void display2()
  47. {
  48.    unsigned char i;
  49.    
  50.    for(i = 0;i < 6;i++)
  51.    {
  52.                    wr_com(0x85+i);
  53.                 wr_dat(set[i]);
  54.    }
  55.    for(i = 0;i < 4;i++)
  56.    {
  57.                    wr_com(0xc6+i);
  58.                 wr_dat(genPasswd[i]+0x30);
  59.                
  60.    }
  61. }

  62. /************************************
  63. 显示请关门界面
  64. ************************************/

  65. void display3()
  66. {
  67.      unsigned char i;
  68.    for(i = 0;i < 11;i++)
  69.    {
  70.                    wr_com(0x83+i);
  71.                 wr_dat(close[i]);
  72.    }

  73. }


  74. /************************************
  75. 显示密码输入界面
  76. ************************************/
  77. void display4()
  78. {
  79.    unsigned char i;
  80.    for(i = 0;i < 12;i++)
  81.    {
  82.                    wr_com(0x82+i);
  83.                 wr_dat(input[i]);
  84.    }
  85.    for(i = 0;i < 4;i++)
  86.    {
  87.                    wr_com(0xc6+i);
  88.                 wr_dat(inpPasswd[i]+0x30);
  89.                
  90.    }

  91. }
  92.         




  93. /***********************************
  94. 定时器0初始化
  95. ***********************************/
  96. void Timer0_init()
  97. {
  98.         unsigned long T0_temp;                                     /*暂存T0的初始值        */
  99.         T0_temp = 65536-((INT_CLOCK *CRY_FREQUENCY /1000)/12);    /*T0初始值计算公式,参考教科书*/
  100.         TL0_temp = T0_temp & 0xff;
  101.         TH0_temp = T0_temp >> 8;
  102.         TL0 = TL0_temp;
  103.         TH0 = TH0_temp;
  104.         TMOD |= 0x01;
  105.         TR0 = 1;                        /*开定时器0中断*/
  106.         ET0 = 1;  
  107.         EA = 1;                    /*开总中断*/                                       

  108. }






  109. /*主函数*/
  110. uchar global_state = 0;
  111. uchar count_num = 0;  //输入的数字个数
  112. void main()
  113. {  
  114.    uchar i,j;
  115.    uchar passwd;
  116.    
  117.            uchar key_value = 0;
  118.         uchar temp_key_value = 0xff;
  119.         Lock = 1;  //刚上电 锁是需要保持闭合
  120.         Timer0_init();        //定时器初始化
  121.          lcd_init();        //LCD1602初始化
  122.    
  123.         while(1)        //进入不断循环
  124.         {
  125.                    temp_key_value = Calkey_scan();          //读取矩阵按键的键值
  126.                 if(temp_key_value != 0xff)
  127.                 {
  128.                         key_value = temp_key_value;
  129.                 }
  130.                 switch(global_state)
  131.                 {
  132.                         case 0:         //初始化状态
  133.                                 display1();         //显示欢迎语句        -- "welcome"
  134.                         

  135.                                 if(key_value == 13)  //存包按键被按下
  136.                                 {
  137.                                     key_value = 0xff;  //将按键值清除
  138.                                         Lock = 0;    //开锁
  139.                                        
  140.                                         display3();    //显示关门提示语        -- "close door!"
  141.                                     delay(1900);    //等待关门 大约3秒
  142.                                         Lock = 1;   //关门
  143.                                         clear();                 //清屏,准备下一屏的显示
  144.                                         global_state = 1;   //切换运行状态
  145.                                         passwd = TL0;  //采用定时器寄存器的值作为密码
  146.                                         genPasswd[0] = passwd/100;                  //存储密码
  147.                                         genPasswd[1] = passwd%100/10;
  148.                                         genPasswd[2] = passwd%10;
  149.                                         genPasswd[3] = (genPasswd[1]+genPasswd[2])%10;
  150.                                 }
  151.                                 if(key_value == 14)  //取包按键被按下
  152.                                 {
  153.                                     key_value = 0xff;  //将按键值清除
  154.                                         clear();    //清屏,准备下一屏的显示
  155.                                         global_state = 2;  //切换运行状态
  156.                                         count_num = 0;   //清除数字按键变量
  157.                                         for(i = 0;i < 4;i++)  //清空输入的密码数组
  158.                                             inpPasswd[i] = ' '-0x30;
  159.                                 }
  160.                         break;
  161.                         case 1:                //密码生成状态
  162.                                    display2();         //显示密码生成界面
  163.                                 delay(1900);    //等待大约3秒
  164.                                 global_state = 0;  //返回到初始界面
  165.                                 clear();        //清屏,准备下一屏的显示
  166.                                 
  167.                         break;
  168.                         case 2:          //输入密码状态
  169.                            display4();           //显示输入密码界面
  170.                            if((key_value >= 0) && (key_value <= 9))          //如果按下的为0-9的数字按键
  171.                            {
  172.                               
  173.                                 if(count_num <= 3)         //如果按键次数小于4次
  174.                                         {
  175.                                         inpPasswd[count_num] = key_value; //将按键值存入数组,并显示
  176.                                                    count_num++;
  177.                                     }
  178.                                          key_value = 0xff;  //将按键值清除
  179.                            }
  180.                            if(key_value == 15) //清除按键被按下
  181.                            {
  182.                                 key_value = 0xff;  //将按键值清除
  183.                                            for(i = 0;i < 4;i++)
  184.                                           inpPasswd[i] = ' '-0x30;  //清除刚刚输入的密码
  185.                            }
  186.                            if(key_value == 16) //确认按键被按下
  187.                            {
  188.                                 key_value = 0xff;  //将按键值清除
  189.                                            for(i = 0;i < 4;i++)
  190.                                         {
  191.                                                 if(inpPasswd[i] != genPasswd[i])
  192.                                                    break;
  193.                                         }
  194.                                         if(i == 4)          //密码输入正确
  195.                                         {
  196.                                                 LEDRED = 1;         //红灯熄灭
  197.                                                 LEDGREEN = 0;  //绿灯亮
  198.                                                 Lock = 1;  //开锁
  199.                                                 delay(1900);    //等待大约3秒
  200.                                                 Lock = 0;  //关锁
  201.                                                 LEDGREEN = 1;  //绿灯熄灭
  202.                                         }
  203.                                         else   //密码输入错误
  204.                                         {        

  205.                                                 for(j = 0;j <19009 ;j++)
  206.                                                 {
  207.                                                         beep=~beep;
  208. ……………………

  209. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码

所有资料51hei提供下载:
电子密码锁(自改).rar (141.51 KB, 下载次数: 35)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

姬火火 发表于 2019-1-9 19:14 | 显示全部楼层
没有仿真的dsn文件吗?
回复

使用道具 举报

hkxinghu 发表于 2019-3-15 20:55 | 显示全部楼层
好东西
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|单片机论坛 |51黑电子论坛单片机. 联系QQ:125739409;技术交流QQ群582644647

Powered by 单片机教程网

快速回复 返回顶部 返回列表