具體工程檔案和運作截圖在文檔裡面,歡迎大家下載下傳,有問題留言,謝謝!
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();
}
}