具体工程文件和运行截图在文档里面,欢迎大家下载,有问题留言,谢谢!
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();
}
}