找回密码
 立即注册

QQ登录

只需一步,快速开始

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

基于51单片机的电子密码锁设计仿真程序流程图资料

[复制链接]
ID:1064818 发表于 2023-3-1 17:12 | 显示全部楼层 |阅读模式
一、 设计要求(设计一个由单片机控制的电子密码锁)
1.能设定一组4位的数字开启密码(设定密码功能)
2.用LED小灯代替锁开启显示,输入密码正确,则小灯亮起(开锁功能)
3.如果3次密码错误,则进行鸣叫报警,并在1分钟之内不能再次输入(报警功能)
4.密码输入显示在数码管上,输入正确显示on,输入错误显示err(显示功能)
5.可在以上功能上扩展。

二、原理说明(包含流程图)
密码锁因为初始无密码,所以程序首先运行一个设置密码程序让用户设置一个1-4位的密码,输入密码中可回删。然后程序会进入一个循环输入密码的环节。密码设置完成后点击关闭键后,屏幕关闭。点击准备输入即可开始输入密码,输入密码完了点击确认键,屏幕会显示打开与否即on与err,显示错误次数的数码管也会实时显示错误次数。当输入次数达到三次后,将在1分钟内无法输入无法关闭且在屏幕显示倒计时同时蜂鸣器报警,其他时刻都可点击关闭键。当密码输入正确后,小灯亮,且可以点击修改密码键,让用户输入新的密码,然后确定。

三、电路设计
矩阵键盘(输入):接在P1口且用一个4与门,上拉电阻来通过中断方式来实现。
4位数码管(显示屏幕):位选接P3的0,1,6,7口,段选接在P2的0-6口,不需要点。
1位数码管(显示错误次数):通过上拉电阻接在P0的0-6口。
小灯(标志密码输入正确):接在P3的3口。
蜂鸣器(警报):接在P3的5口。
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
四、        仿真结果
设置密码:
输入密码
密码错误:
密码错误三次报警倒计时60s:
密码正确小灯亮:
修改密码;
密码修改成功:
五、        结果分析
首先初始化,然后让用户点击设置密码,点击准备输入键,屏幕待输入状态,用户在键盘上按下1536(可以点击delete回删键),点击确认键,屏幕显示on,小灯亮,表示密码设置完成。点击close键后又初始化一些标志,点击准备输入键,屏幕待输入状态,用户输入453,点击确认键,屏幕显示err,表示密码输入错误,且单位数码管显示1,表示输入错误次数。点击close键关闭输入。当再次点击准备输入,屏幕待输入状态,当用户输入次数达到3次屏幕显示倒计时60s后才能再次操作,蜂鸣器报警60s,且键盘按任何键无作用。倒计时完了,可再次输入。当用户输入1536密码正确,则屏幕显示on,小灯亮表示密码锁打开,并可以修改密码,点击修改密码,屏幕进入待输入状态,输入新密码123,点击确认键,屏幕显示on,小灯亮表示密码修改成功。

六、        单片机代码
  1. #include <reg52.h>
  2. #define uint unsigned int
  3. #define uchar unsigned char
  4. sbit LED=P3^3;                    //小灯
  5. sbit ALTER=P3^5;         //警报器
  6. void delay(uint);            //延迟函数
  7. void Show_Pwd();          //数码管显示密码
  8. void Show_on();                   //数码管显示on
  9. void Show_err();            //数码管显示err
  10. void Sure_on_err();     //判断密码是否正确
  11. void Show_Sixty();         //数码管显示倒计时60s
  12. void Show_Time(uint);   //数码管显示给定的数字(倒计时)
  13. void Init();                    //初始化
  14. void Total_Show();         //数码管总显示
  15. void Close_Init();           //close关闭后的初始化
  16. void Pwd_Modity();              //修改密码
  17. void SetPwd();                     //设置密码
  18. char Key=-1;                     //保存键号
  19. uchar PwdRight=0;        //正确密码的位数(因为我设置的是1-4为密码都可以,所以判断比较密码时需要密码位数)
  20. char PwdDigit=-1;      //记录当前输入密码的位数(方便存数组,比较所以初始值为-1)
  21. uchar PwdErrTime=0;      //密码错误次数(触发警报的判断依据)
  22. uchar TimeCount=0;       //计时器中断函数计数器       (定时器计了50000us即50ms,则加1,达到20次即计了1s)
  23. uchar ShowSign=1;        //Total_Show()函数根据该标志来判断显示什么信息
  24. uchar Keycount=0;        //循环功能按键的次数(当该功能按键次数改变即有功能按键按下,则进入switch-case中选择执行,防止不按功能按键时,主程序依然继续执行上一次的功能)
  25. char Password[4]={-1,-1,-1,-1};      //储存密码
  26. uchar Pwd_Now[4]={10,10,10,10};       //储存当前输入的密码
  27. uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40,0x37,0x7b,0x31}; //数模0-9与'-'(10),'n'(11),'e'(12),'r'(13)
  28. uchar code key_buf[]={0xd7,0xeb,0xdb,0xbb,0xed,0xdd,0xbd,0xee,
  29.                       0xde,0xbe,0xb7,0x7e,0x7d,0x7b,0x77,0xe7};   
  30.                                    //键模0-9,sure(10),delete(11),setpwd(12),modify(13),close(14),ready(15)
  31. void delay(uint time)
  32. {
  33.        uchar i=0;
  34.        for(;time>0;time--)
  35.               for(i=0;i<113;i++);
  36. }
  37. void Getkey(void) interrupt 0
  38. {
  39.        uchar key_scan[]={0xef,0xdf,0xbf,0x7f}; //键扫描码(1-4列)
  40.        uchar i=0,j=0;
  41.        for(i=0;i<4;i++)
  42.        {
  43.               P1=key_scan[i];                                 //P1送出键扫描码
  44.               if((P1&0x0f)!=0x0f)                   //判断有无按键按下
  45.               {
  46.                      delay(10);
  47.                      if((P1&0x0f)!=0x0f)
  48.                      {
  49.                             for(j=0;j<16;j++)
  50.                             {     
  51.                                    if(key_buf[j]==P1)  //找到按键
  52.                                    {
  53.                                   while(P1!=key_scan[i])  //按键松开
  54.                                      {
  55.                                          Total_Show();  //按键时数码管显示
  56.                                      }
  57.                                      Key=j;         //获取键值
  58.                                      if(j<10)
  59.                                      {
  60.                                          PwdDigit++;     //只有按下数字键该密码位数才会自加
  61.                                           if(PwdDigit<4)
  62.                                                 Pwd_Now[PwdDigit]=j;  //存储有效密码
  63.                                      }
  64.                                      else if(j!=12&&j!=15)
  65.                                          Keycount++;  //循环功能(除了setpwd和ready)按键的次数
  66.                                      P1=0x0f;
  67.                                      return;
  68.                                    }
  69.                             }
  70.                      }
  71.               }
  72.        }
  73. }
  74. void Show_Pwd()
  75. {
  76.               switch(PwdDigit)   //通过密码位数来实时显示密码的输入,当前存储的密码作为下标显示密码
  77.               {
  78.                     case 3: P3=0x4f;P2=table[Pwd_Now[3]];delay(10);                  //只打开第四个位选,P3.2=1(无影响),P3.3=1关闭LED,P3.5=0关闭警报
  79.                     case 2: P3=0x8f;P2=table[Pwd_Now[2]];delay(10);                  //只打开第三个位选,P3.2=1(无影响),P3.3=1关闭LED,P3.5=0关闭警报
  80.                     case 1: P3=0xcd;P2=table[Pwd_Now[1]];delay(10);                 //只打开第二个位选,P3.2=1(无影响),P3.3=1关闭LED,P3.5=0关闭警报
  81.                     case 0: P3=0xce;P2=table[Pwd_Now[0]];delay(10);break;  //只打开第一个位选,P3.2=1(无影响),P3.3=1关闭LED,P3.5=0关闭警报
  82.                     default:P3=0x0c;P2=table[10];PwdDigit=-1;delay(10);break;//打开所有位选,P3.2=1(无影响),P3.3=1关闭LED,P3.5=0关闭警报
  83.                                                                                                                         //显示'-',当PwdDigit=-1与delay(10)位置不同有问题
  84.               }
  85. }
  86. void Total_Show()
  87. {
  88.        switch(ShowSign)   //根据数码管展示的标志位来判断展示不同的信息
  89.        {
  90.               case 1:Show_Pwd();break;    //显示输入的密码
  91.               case 2:Show_on();break;            //显示密码输入正确的on并点亮小灯
  92.               case 3:Show_err();break;     //显示密码输入错误的err
  93.               case 4:Show_Sixty();break;   //显示60s倒计时并打开警报
  94.        }
  95. }
  96. void Show_on()
  97. {
  98.        P3=0xc6;    //只打开第一个位选,P3.2=1(无影响),P3.3=0打开LED,P3.5=0关闭警报
  99.        P2=table[0];   //显示0
  100.        delay(15);
  101.        P3=0xc5;    //只打开第二个位选,P3.2=1(无影响),P3.3=0打开LED,P3.5=0关闭警报
  102.        P2=table[11];  //显示n
  103.        delay(15);
  104. }
  105. void Show_err()
  106. {
  107.        P3=0xce;    //只打开第一个位选,P3.2=1(无影响),P3.3=1关闭LED,P3.5=0关闭警报
  108.        P2=table[12];  //显示'e'
  109.        delay(10);
  110.        P3=0xcd;    //只打开第二个位选,P3.2=1(无影响),P3.3=1关闭LED,P3.5=0关闭警报
  111.        P2=table[13];  //显示'r'
  112.        delay(10);
  113.        P3=0x8e;    //只打开第三个位选,P3.2=1(无影响),P3.3=1关闭LED,P3.5=0关闭警报
  114.        P2=table[13];  //显示'r'
  115.        delay(10);
  116. }                  
  117. void Sure_on_err()
  118. {     
  119.        uchar i=0;
  120.        ShowSign=3;                               //默认输入错误,数码管显示标志为3显示err
  121.        if(PwdRight==PwdDigit)                                   //当正确密码的位数与当前输入的密码的位数相同
  122.        {
  123.               for(i=0;i<=PwdDigit;i++)                    //每一位密码进行比较
  124.               {
  125.                      if(Password[i]!=Pwd_Now[i])        //当有一位不同就退出循环比较
  126.                             break;
  127.               }
  128.               if(i==PwdDigit+1)
  129.               {                                                   //如果密码正确,比较完不满足判断条件退出的循环则i=PwdDigit+1
  130.                      ShowSign=2;                                     //更改数码管显示的标志为2显示on点亮小灯
  131.                      PwdErrTime=0;                                  //将错误次数清0
  132.               }                                                   
  133.               else                                                  //如果是break退出的循环则错误次数加1,不需要更改数码管显示标志
  134.                      PwdErrTime++;   
  135.        }
  136.        else                                                         //如果正确密码的位数与当前输入的密码的位数不相同,则错误次数加1
  137.               PwdErrTime++;           
  138.        if(PwdErrTime==3)                                    //密码错误次数达到三次
  139.        {
  140.               P0=table[PwdErrTime];                       //单个数码管先显示密码错误次数3
  141.               ShowSign=4;                                            //更改数码管显示的标志为4显示倒计时并打开警报
  142.        }            
  143. }
  144. void SetPwd()
  145. {
  146.        uchar i=0;
  147.        uchar count=0;                    //存储按功能键的次数
  148.        uchar sign=0;                             //是否确认密码标志(0:未确认,1:已确认)
  149.        P1=0x7f;                         //将第四列设为低电平
  150.        while(P1!=key_buf[12]);           //setpwd第一次设置密码      
  151.        P1=0xef;                         //将第一列设为低电平
  152.        while(P1!=key_buf[15]);          //查询是否按下ready键
  153.        EX0=1;                            //打开按键中断开关
  154.        while(1)
  155.        {
  156.               Total_Show();
  157.               if(count!=Keycount&&Key==11) //当有delete功能按键按下时将密码位数减1(count!=Keycount为了防止当按下delete后,由于在循环体中位数会一直自减)
  158.               {     
  159.                      count=Keycount;                 //功能键次数重新赋值给count
  160.                      PwdDigit--;                          //当前密码位数--
  161.               }
  162.               if(PwdDigit>=0&&Key==10)     //输完1-4位密码并且按下sure键后显示并保存密码
  163.               {
  164.                      ShowSign=2;               //数码管显示on并点亮小灯
  165.                      Total_Show();
  166.                      sign=1;                       //表示已确认设置密码            
  167.                      for(i=0;i<=PwdDigit;i++) //保存密码
  168.                             Password[i]=Pwd_Now[i];
  169.                      PwdRight=PwdDigit;            //将当前密码位数赋值给正确密码位数标志
  170.               }
  171.               if(Key==14&&sign==1)         //只能确认设置完密码才能点击close退出
  172.               {
  173.                      return;
  174.               }
  175.        }
  176. }
  177. void Show_Time(uint number)
  178. {     
  179.        P3=0xee;               //只打开第一个位选,P3.2=1(无影响),P3.3=1关闭LED,P3.5=1打开警报
  180.        P2=table[10];         //显示 -
  181.        delay(5);
  182.        P3=0xed;               //只打开第二个位选,P3.2=1(无影响),P3.3=1关闭LED,P3.5=1打开警报
  183.        P2=table[number/10]; //显示十位
  184.        delay(5);
  185.        P3=0xaf;               //只打开第三个位选,P3.2=1(无影响),P3.3=1关闭LED,P3.5=1打开警报
  186.        P2=table[number%10]; //显示个位
  187.        delay(5);
  188.        P3=0x6f;               //只打开第四个位选,P3.2=1(无影响),P3.3=1关闭LED,P3.5=1打开警报
  189.        P2=table[10];         //显示 -
  190.        delay(5);
  191. }
  192. void Show_Sixty()
  193. {
  194.        uchar toal=60;                //倒计时总时间
  195.        EX0=0;                           //关闭键盘中断(防止按键进行中断数码管显示)
  196.        TR0=1;                           //打开定时器开关
  197.        do
  198.        {
  199.               if(TimeCount==20) //中断一次50ms,TimeCount++,当达到20次即1s显示值减一
  200.               {
  201.                      TimeCount=0;  //重新赋值为0
  202.                      toal--;              //显示值--
  203.               }
  204.               Show_Time(toal);  //掉用显示函数
  205.         }while(toal>0);        //当显示到0时退出                           
  206.         TR0=0;                         //关闭定时器开关
  207.         EX0=1;                         //打开键盘中断开关
  208.         PwdErrTime=0;             //错误次数重新赋值为0
  209.         PwdDigit=-1;                //密码位数赋值为-1重新输入
  210.         ShowSign=1;          //数码管显示标志设为1,显示密码
  211. }
  212. int0_srv() interrupt 1
  213. {
  214.        TimeCount++;      
  215. }                                
  216. void Init()
  217. {
  218.        IT0=0;      //设为跳变沿有问题
  219.        TMOD=0x01;  //定时器0工作方式为1
  220.        TH0=0x3c;
  221.        TL0=0xb0;   //一次定时50ms
  222.        ET0=1;        //打开定时器0的中断开关
  223.        EA=1;          //打开总开关
  224.        P0=table[0];//单个数码管显示0
  225.        LED=1;           //关闭数码管
  226.        ALTER=0; //关闭警报器
  227. }
  228. void Close_Init()
  229. {
  230.        uchar i=0;                           
  231.        P3=0xcf;                   //关闭所有位选,P3.2=1(无影响),P3.3=1关闭LED,P3.5=0关闭警报
  232.        EX0=0;                            //关闭键盘中断
  233.        PwdDigit=-1;            //密码位数赋值为-1
  234.        P1=0xef;                  //将第一列设为低电平
  235.        while(P1!=key_buf[15]);//查询是否按下ready键
  236.        ShowSign=1;                   //数码管显示密码
  237.        EX0=1;                            //打开键盘中断
  238.        for(i=0;i<4;i++)         //将当前密码初始化
  239.               Pwd_Now[i]=10;   
  240. }
  241. void Pwd_Modity()
  242. {     
  243.        uchar count=0;                                    //存储按功能键的次数
  244.        PwdDigit=-1;                                //密码位数赋值为-1
  245.        ShowSign=1;                                       //数码管显示密码
  246.        while(1)
  247.        {     
  248.             
  249.               Total_Show();
  250.               if(count!=Keycount&&Key==11)  //当有delete功能按键按下时将密码位数减1(count!=Keycount为了防止当按下delete后,由于在循环体中位数会一直自减)
  251.               {     
  252.                      count=Keycount;                   //功能键次数重新赋值给count
  253.                      PwdDigit--;                            //当前密码位数--
  254.               }
  255.               if(PwdDigit>=0&&Key==10)   //输完1-4位密码并且按下sure键后显示并保存密码
  256.               {
  257.                      uchar i=0;
  258.                      for(i=0;i<=PwdDigit;i++)  //保存密码
  259.                             Password[i]=Pwd_Now[i];
  260.                      for(i=PwdDigit+1;i<4;i++) //将不是密码位初始化位-1
  261.                             Password[i]=-1;
  262.                      PwdRight=PwdDigit;               //将当前密码位数赋值给正确密码位数标志
  263.                      ShowSign=2;                          //数码管显示on并点亮小灯
  264.                      Key=12;                    //防止返回主函数后进入switch-case
  265.                      return;
  266.               }
  267.        }
  268. }                                               
  269. void main(void)
  270. {
  271.        uchar count=0;//功能按键的次数
  272.        Init();              //初始化
  273.        SetPwd();       //设置密码
  274.        while(1)
  275.        {     
  276.           P0=table[PwdErrTime]; //close关闭后单个数码管关闭
  277.           if(count!=Keycount)        //当有功能按键按下时进入switch-case(为了防止当按下delete后,由于在循环体中位数会一直自减)
  278.           {
  279.                     count=Keycount;         //功能按键次数重新赋值给count
  280.                      switch(Key)
  281.                      {
  282.                             case 10:Sure_on_err();break;                             //调用确认密码函数
  283.                             case 11:if(ShowSign==1){PwdDigit--;Pwd_Now[PwdDigit+1]=10;}break; //密码位数减1,并把上一位存储的密码初始化为10
  284.                             case 13:if(ShowSign==2)Pwd_Modity();break;           //当密码正确了才能修改密码
  285.                             case 14:Close_Init();break;                                       //close关闭后的初始化
  286.                      }
  287.           }
  288.        Total_Show();
  289.        }
  290. }
复制代码

Keil代码与Proteus8.13仿真下载: 密码锁.zip (2.98 MB, 下载次数: 46)

评分

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

查看全部评分

回复

使用道具 举报

ID:301191 发表于 2023-3-4 04:00 | 显示全部楼层
顶一下
回复

使用道具 举报

ID:1079325 发表于 2023-5-31 22:58 | 显示全部楼层
有仿真吗
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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