proteus仿真c51简单密码锁

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_42398342/article/details/98506596

具体工程文件和运行截图在文档里面,欢迎大家下载,有问题留言,谢谢!
https://pan.baidu.com/s/1h5evW4UYoknQLxmORouCGA

密码锁:

功能介绍:
1.可设置1-4位密码
2.密码输入显示在数码管上
3.密码验证结果显示在数码管上
4.显示密码错误次数
5.输入可回退
6.可更改密码
7.密码正确小灯亮起
8.错误次数达到3次数码管显示倒计时60s并报警
密码锁工作使用流程:
1.一个密码锁必须有密码,所以最开始我们点击SETKEY开始设置密码,点击输入准备READY开始输入密码,DELETE可回退,输入完成后点击SURE保存密码然后点击CLOSE
2.每次要输入密码时都需点击READY准备输入然后进行输入密码开锁
3.当密码正确小灯会亮,数码管显示ON即密码锁打开,并且可以点击MODIFY进行修改密码
4.当密码错误时数码管显示err,并且单独的数码管显示错误次数,当错误达到三次则会进行倒计时报警
仿真原理图:

矩阵键盘(输入):接在P1口且用一个4与门,上拉电阻来通过中断方式来实现。

4位数码管(显示屏幕):位选接P3的0,1,6,7口,段选接在P2的0-6口,不需要点。

1位数码管(显示错误次数):通过上拉电阻接在P0的0-6口。

小灯(标志密码输入正确):接在P3的3口。

蜂鸣器(警报):接在P3的5口。

在这里插入图片描述
流程图:

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

具体代码分析注释以及运行结果截图分析在文档里面,欢迎大家下载! ! !

#include <reg52.h>
#define uint unsigned int
#define uchar unsigned char
sbit LED=P3^3;   //小灯
sbit ALTER=P3^5;  //警报器
void delay(uint);  //延迟函数
void Show_Pwd();  //数码管显示密码
void Show_on();   //数码管显示on
void Show_err();  //数码管显示err
void Sure_on_err();     //判断密码是否正确
void Show_Sixty();  //数码管显示倒计时60s
void Show_Time(uint); //数码管显示给定的数字(倒计时)
void Init();   //初始化
void Total_Show();  //数码管总显示
void Close_Init();  //close关闭后的初始化
void Pwd_Modity();  //修改密码
void SetPwd();   //设置密码
char Key=-1;       //保存键号
uchar PwdRight=0;        //正确密码的位数(因为我设置的是1-4为密码都可以,所以判断比较密码时需要密码位数)
char PwdDigit=-1;     //记录当前输入密码的位数(方便存数组,比较所以初始值为-1)
uchar PwdErrTime=0;      //密码错误次数(触发警报的判断依据)
uchar TimeCount=0;       //计时器中断函数计数器   (定时器计了50000us即50ms,则加1,达到20次即计了1s)
uchar ShowSign=1;        //Total_Show()函数根据该标志来判断显示什么信息
uchar Keycount=0;        //循环功能按键的次数(当该功能按键次数改变即有功能按键按下,则进入switch-case中选择执行,防止不按功能按键时,主程序依然继续执行上一次的功能)
char Password[4]={-1,-1,-1,-1};      //储存密码
uchar Pwd_Now[4]={10,10,10,10};       //储存当前输入的密码
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)
uchar code key_buf[]={0xd7,0xeb,0xdb,0xbb,0xed,0xdd,0xbd,0xee,
                      0xde,0xbe,0xb7,0x7e,0x7d,0x7b,0x77,0xe7};    
     //键模0-9,sure(10),delete(11),setpwd(12),modify(13),close(14),ready(15)
void delay(uint time)
{
 uchar i=0;
 for(;time>0;time--)
  for(i=0;i<113;i++);
}
void Getkey(void) interrupt 0
{
 uchar key_scan[]={0xef,0xdf,0xbf,0x7f}; //键扫描码(1-4列)
 uchar i=0,j=0;
 for(i=0;i<4;i++)
 {
  P1=key_scan[i];      //P1送出键扫描码
  if((P1&0x0f)!=0x0f)       //判断有无按键按下
  {
   delay(10);
   if((P1&0x0f)!=0x0f)
   {
    for(j=0;j<16;j++)
    { 
     if(key_buf[j]==P1)  //找到按键
     {
          while(P1!=key_scan[i])  //按键松开
       {
        Total_Show();  //按键时数码管显示
       }  
       Key=j;        //获取键值
       if(j<10)
       {
        PwdDigit++;   //只有按下数字键该密码位数才会自加
      if(PwdDigit<4)
         Pwd_Now[PwdDigit]=j;  //存储有效密码
       }
       else if(j!=12&&j!=15)
        Keycount++; //循环功能(除了setpwd和ready)按键的次数
       P1=0x0f;
       return;
     }
    }
   }
  }
 }
}
void Show_Pwd()
{
  switch(PwdDigit)   //通过密码位数来实时显示密码的输入,当前存储的密码作为下标显示密码
  {
     case 3: P3=0x4f;P2=table[Pwd_Now[3]];delay(10);    //只打开第四个位选,P3.2=1(无影响),P3.3=1关闭LED,P3.5=0关闭警报
      case 2: P3=0x8f;P2=table[Pwd_Now[2]];delay(10);    //只打开第三个位选,P3.2=1(无影响),P3.3=1关闭LED,P3.5=0关闭警报
      case 1: P3=0xcd;P2=table[Pwd_Now[1]];delay(10);    //只打开第二个位选,P3.2=1(无影响),P3.3=1关闭LED,P3.5=0关闭警报
      case 0: P3=0xce;P2=table[Pwd_Now[0]];delay(10);break;  //只打开第一个位选,P3.2=1(无影响),P3.3=1关闭LED,P3.5=0关闭警报
      default:P3=0x0c;P2=table[10];PwdDigit=-1;delay(10);break;//打开所有位选,P3.2=1(无影响),P3.3=1关闭LED,P3.5=0关闭警报
                  //显示'-',当PwdDigit=-1与delay(10)位置不同有问题
  }
}
void Total_Show()
{
 switch(ShowSign)   //根据数码管展示的标志位来判断展示不同的信息
 {
  case 1:Show_Pwd();break;  //显示输入的密码
  case 2:Show_on();break;      //显示密码输入正确的on并点亮小灯
  case 3:Show_err();break;     //显示密码输入错误的err
  case 4:Show_Sixty();break;   //显示60s倒计时并打开警报
 }
}
void Show_on()
{
 P3=0xc6;    //只打开第一个位选,P3.2=1(无影响),P3.3=0打开LED,P3.5=0关闭警报
 P2=table[0];   //显示0
 delay(15);
 P3=0xc5;    //只打开第二个位选,P3.2=1(无影响),P3.3=0打开LED,P3.5=0关闭警报
 P2=table[11];  //显示n
 delay(15);
}
void Show_err()
{
 P3=0xce;    //只打开第一个位选,P3.2=1(无影响),P3.3=1关闭LED,P3.5=0关闭警报
 P2=table[12];  //显示'e'
 delay(10);
 P3=0xcd;    //只打开第二个位选,P3.2=1(无影响),P3.3=1关闭LED,P3.5=0关闭警报
 P2=table[13];  //显示'r'
 delay(10);
 P3=0x8e;    //只打开第三个位选,P3.2=1(无影响),P3.3=1关闭LED,P3.5=0关闭警报
 P2=table[13];  //显示'r'
 delay(10);
}   
void Sure_on_err()
{ 
 uchar i=0;
 ShowSign=3;                              //默认输入错误,数码管显示标志为3显示err
 if(PwdRight==PwdDigit)      //当正确密码的位数与当前输入的密码的位数相同
 {
  for(i=0;i<=PwdDigit;i++)    //每一位密码进行比较
  {
   if(Password[i]!=Pwd_Now[i])   //当有一位不同就退出循环比较
    break;
  }
  if(i==PwdDigit+1)
  {                      //如果密码正确,比较完不满足判断条件退出的循环则i=PwdDigit+1
   ShowSign=2;       //更改数码管显示的标志为2显示on点亮小灯
   PwdErrTime=0;      //将错误次数清0
  }                  
  else         //如果是break退出的循环则错误次数加1,不需要更改数码管显示标志
   PwdErrTime++; 
 }
 else          //如果正确密码的位数与当前输入的密码的位数不相同,则错误次数加1
  PwdErrTime++;  
 if(PwdErrTime==3)       //密码错误次数达到三次
 {
  P0=table[PwdErrTime];     //单个数码管先显示密码错误次数3
  ShowSign=4;        //更改数码管显示的标志为4显示倒计时并打开警报
 }  
}
void SetPwd()
{
 uchar i=0;
 uchar count=0;                    //存储按功能键的次数
 uchar sign=0;      //是否确认密码标志(0:未确认,1:已确认)
 P1=0x7f;                         //将第四列设为低电平
 while(P1!=key_buf[12]);          //setpwd第一次设置密码 
 P1=0xef;                         //将第一列设为低电平
 while(P1!=key_buf[15]);          //查询是否按下ready键
 EX0=1;                           //打开按键中断开关
 while(1)
 {
  Total_Show(); 
  if(count!=Keycount&&Key==11) //当有delete功能按键按下时将密码位数减1(count!=Keycount为了防止当按下delete后,由于在循环体中位数会一直自减)
  { 
   count=Keycount;    //功能键次数重新赋值给count
   PwdDigit--;     //当前密码位数--
  } 
  if(PwdDigit>=0&&Key==10)     //输完1-4位密码并且按下sure键后显示并保存密码
   {
   ShowSign=2;              //数码管显示on并点亮小灯
   Total_Show();
   sign=1;               //表示已确认设置密码  
   for(i=0;i<=PwdDigit;i++) //保存密码
    Password[i]=Pwd_Now[i];
   PwdRight=PwdDigit;   //将当前密码位数赋值给正确密码位数标志
  }
  if(Key==14&&sign==1)         //只能确认设置完密码才能点击close退出
  {
   return;
  }
 }
}
void Show_Time(uint number)
{ 
 P3=0xee;    //只打开第一个位选,P3.2=1(无影响),P3.3=1关闭LED,P3.5=1打开警报
 P2=table[10];   //显示 -
 delay(5);
 P3=0xed;    //只打开第二个位选,P3.2=1(无影响),P3.3=1关闭LED,P3.5=1打开警报
 P2=table[number/10]; //显示十位
 delay(5);
 P3=0xaf;    //只打开第三个位选,P3.2=1(无影响),P3.3=1关闭LED,P3.5=1打开警报
 P2=table[number%10]; //显示个位
 delay(5);
 P3=0x6f;    //只打开第四个位选,P3.2=1(无影响),P3.3=1关闭LED,P3.5=1打开警报
 P2=table[10];   //显示 -
 delay(5);
}
void Show_Sixty()
{
 uchar toal=60;    //倒计时总时间
 EX0=0;      //关闭键盘中断(防止按键进行中断数码管显示)
 TR0=1;      //打开定时器开关
 do
 {
  if(TimeCount==20) //中断一次50ms,TimeCount++,当达到20次即1s显示值减一
  {
   TimeCount=0;  //重新赋值为0
   toal--;    //显示值--
  }
  Show_Time(toal);  //掉用显示函数
  }while(toal>0);   //当显示到0时退出      
  TR0=0;      //关闭定时器开关
  EX0=1;      //打开键盘中断开关
  PwdErrTime=0;    //错误次数重新赋值为0
  PwdDigit=-1;    //密码位数赋值为-1重新输入
  ShowSign=1;    //数码管显示标志设为1,显示密码
}
int0_srv() interrupt 1
{
 TimeCount++;        
}      
void Init()
{
 IT0=0;      //设为跳变沿有问题
 TMOD=0x01;  //定时器0工作方式为1
 TH0=0x3c;
 TL0=0xb0;   //一次定时50ms
 ET0=1;     //打开定时器0的中断开关
 EA=1;     //打开总开关
 P0=table[0];//单个数码管显示0
 LED=1;  //关闭数码管
 ALTER=0; //关闭警报器
}
void Close_Init()
{ 
  uchar i=0;    
 P3=0xcf;      //关闭所有位选,P3.2=1(无影响),P3.3=1关闭LED,P3.5=0关闭警报
 EX0=0;       //关闭键盘中断
 PwdDigit=-1;     //密码位数赋值为-1
 P1=0xef;      //将第一列设为低电平
 while(P1!=key_buf[15]);//查询是否按下ready键
 ShowSign=1;      //数码管显示密码
 EX0=1;       //打开键盘中断
 for(i=0;i<4;i++)    //将当前密码初始化
  Pwd_Now[i]=10; 
}
void Pwd_Modity()
{ 
 uchar count=0;       //存储按功能键的次数
 PwdDigit=-1;       //密码位数赋值为-1
 ShowSign=1;        //数码管显示密码
 while(1)
 { 
  
  Total_Show();
  if(count!=Keycount&&Key==11)  //当有delete功能按键按下时将密码位数减1(count!=Keycount为了防止当按下delete后,由于在循环体中位数会一直自减)
  { 
   count=Keycount;     //功能键次数重新赋值给count
   PwdDigit--;      //当前密码位数--
  } 
  if(PwdDigit>=0&&Key==10)   //输完1-4位密码并且按下sure键后显示并保存密码
  {
   uchar i=0;
   for(i=0;i<=PwdDigit;i++)  //保存密码
    Password[i]=Pwd_Now[i];
   for(i=PwdDigit+1;i<4;i++) //将不是密码位初始化位-1
    Password[i]=-1;
   PwdRight=PwdDigit;     //将当前密码位数赋值给正确密码位数标志
   ShowSign=2;       //数码管显示on并点亮小灯
   Key=12;                    //防止返回主函数后进入switch-case
   return;
  }
 }
}       
void main(void)
{
 uchar count=0;//功能按键的次数
 Init();   //初始化
 SetPwd();  //设置密码
 while(1)
 {  
    P0=table[PwdErrTime]; //close关闭后单个数码管关闭
    if(count!=Keycount)        //当有功能按键按下时进入switch-case(为了防止当按下delete后,由于在循环体中位数会一直自减)
    {
      count=Keycount;       //功能按键次数重新赋值给count
   switch(Key)
   {
    case 10:Sure_on_err();break;      //调用确认密码函数
    case 11:if(ShowSign==1){PwdDigit--;Pwd_Now[PwdDigit+1]=10;}break; //密码位数减1,并把上一位存储的密码初始化为10
    case 13:if(ShowSign==2)Pwd_Modity();break;   //当密码正确了才能修改密码
    case 14:Close_Init();break;       //close关闭后的初始化
   }
    }
       Total_Show();
 } 
}

猜你喜欢

转载自blog.csdn.net/qq_42398342/article/details/98506596