一、 設計要求(設計一個由單片機控制的電子密碼鎖) 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,小燈亮表示密碼修改成功。
六、 單片機代碼 - #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();
- }
- }
復制代碼
Keil代碼與Proteus8.13仿真下載:
密碼鎖.zip
(2.98 MB, 下載次數: 46)
2023-3-1 17:12 上傳
點擊文件名下載附件
仿真+程序+設計
|