一、 設(shè)計(jì)要求(設(shè)計(jì)一個(gè)由單片機(jī)控制的電子密碼鎖) 1.能設(shè)定一組4位的數(shù)字開啟密碼(設(shè)定密碼功能) 2.用LED小燈代替鎖開啟顯示,輸入密碼正確,則小燈亮起(開鎖功能) 3.如果3次密碼錯(cuò)誤,則進(jìn)行鳴叫報(bào)警,并在1分鐘之內(nèi)不能再次輸入(報(bào)警功能) 4.密碼輸入顯示在數(shù)碼管上,輸入正確顯示on,輸入錯(cuò)誤顯示err(顯示功能) 5.可在以上功能上擴(kuò)展。
二、原理說明(包含流程圖) 密碼鎖因?yàn)槌跏紵o密碼,所以程序首先運(yùn)行一個(gè)設(shè)置密碼程序讓用戶設(shè)置一個(gè)1-4位的密碼,輸入密碼中可回刪。然后程序會(huì)進(jìn)入一個(gè)循環(huán)輸入密碼的環(huán)節(jié)。密碼設(shè)置完成后點(diǎn)擊關(guān)閉鍵后,屏幕關(guān)閉。點(diǎn)擊準(zhǔn)備輸入即可開始輸入密碼,輸入密碼完了點(diǎn)擊確認(rèn)鍵,屏幕會(huì)顯示打開與否即on與err,顯示錯(cuò)誤次數(shù)的數(shù)碼管也會(huì)實(shí)時(shí)顯示錯(cuò)誤次數(shù)。當(dāng)輸入次數(shù)達(dá)到三次后,將在1分鐘內(nèi)無法輸入無法關(guān)閉且在屏幕顯示倒計(jì)時(shí)同時(shí)蜂鳴器報(bào)警,其他時(shí)刻都可點(diǎn)擊關(guān)閉鍵。當(dāng)密碼輸入正確后,小燈亮,且可以點(diǎn)擊修改密碼鍵,讓用戶輸入新的密碼,然后確定。
三、電路設(shè)計(jì) 矩陣鍵盤(輸入):接在P1口且用一個(gè)4與門,上拉電阻來通過中斷方式來實(shí)現(xiàn)。 4位數(shù)碼管(顯示屏幕):位選接P3的0,1,6,7口,段選接在P2的0-6口,不需要點(diǎn)。 1位數(shù)碼管(顯示錯(cuò)誤次數(shù)):通過上拉電阻接在P0的0-6口。 小燈(標(biāo)志密碼輸入正確):接在P3的3口。 蜂鳴器(警報(bào)):接在P3的5口。
仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
四、 仿真結(jié)果 設(shè)置密碼: 輸入密碼 密碼錯(cuò)誤: 密碼錯(cuò)誤三次報(bào)警倒計(jì)時(shí)60s: 密碼正確小燈亮: 修改密碼; 密碼修改成功: 五、 結(jié)果分析 首先初始化,然后讓用戶點(diǎn)擊設(shè)置密碼,點(diǎn)擊準(zhǔn)備輸入鍵,屏幕待輸入狀態(tài),用戶在鍵盤上按下1536(可以點(diǎn)擊delete回刪鍵),點(diǎn)擊確認(rèn)鍵,屏幕顯示on,小燈亮,表示密碼設(shè)置完成。點(diǎn)擊close鍵后又初始化一些標(biāo)志,點(diǎn)擊準(zhǔn)備輸入鍵,屏幕待輸入狀態(tài),用戶輸入453,點(diǎn)擊確認(rèn)鍵,屏幕顯示err,表示密碼輸入錯(cuò)誤,且單位數(shù)碼管顯示1,表示輸入錯(cuò)誤次數(shù)。點(diǎn)擊close鍵關(guān)閉輸入。當(dāng)再次點(diǎn)擊準(zhǔn)備輸入,屏幕待輸入狀態(tài),當(dāng)用戶輸入次數(shù)達(dá)到3次屏幕顯示倒計(jì)時(shí)60s后才能再次操作,蜂鳴器報(bào)警60s,且鍵盤按任何鍵無作用。倒計(jì)時(shí)完了,可再次輸入。當(dāng)用戶輸入1536密碼正確,則屏幕顯示on,小燈亮表示密碼鎖打開,并可以修改密碼,點(diǎn)擊修改密碼,屏幕進(jìn)入待輸入狀態(tài),輸入新密碼123,點(diǎn)擊確認(rèn)鍵,屏幕顯示on,小燈亮表示密碼修改成功。
六、 單片機(jī)代碼 - #include <reg52.h>
- #define uint unsigned int
- #define uchar unsigned char
- sbit LED=P3^3; //小燈
- sbit ALTER=P3^5; //警報(bào)器
- void delay(uint); //延遲函數(shù)
- void Show_Pwd(); //數(shù)碼管顯示密碼
- void Show_on(); //數(shù)碼管顯示on
- void Show_err(); //數(shù)碼管顯示err
- void Sure_on_err(); //判斷密碼是否正確
- void Show_Sixty(); //數(shù)碼管顯示倒計(jì)時(shí)60s
- void Show_Time(uint); //數(shù)碼管顯示給定的數(shù)字(倒計(jì)時(shí))
- void Init(); //初始化
- void Total_Show(); //數(shù)碼管總顯示
- void Close_Init(); //close關(guān)閉后的初始化
- void Pwd_Modity(); //修改密碼
- void SetPwd(); //設(shè)置密碼
- char Key=-1; //保存鍵號
- uchar PwdRight=0; //正確密碼的位數(shù)(因?yàn)槲以O(shè)置的是1-4為密碼都可以,所以判斷比較密碼時(shí)需要密碼位數(shù))
- char PwdDigit=-1; //記錄當(dāng)前輸入密碼的位數(shù)(方便存數(shù)組,比較所以初始值為-1)
- uchar PwdErrTime=0; //密碼錯(cuò)誤次數(shù)(觸發(fā)警報(bào)的判斷依據(jù))
- uchar TimeCount=0; //計(jì)時(shí)器中斷函數(shù)計(jì)數(shù)器 (定時(shí)器計(jì)了50000us即50ms,則加1,達(dá)到20次即計(jì)了1s)
- uchar ShowSign=1; //Total_Show()函數(shù)根據(jù)該標(biāo)志來判斷顯示什么信息
- uchar Keycount=0; //循環(huán)功能按鍵的次數(shù)(當(dāng)該功能按鍵次數(shù)改變即有功能按鍵按下,則進(jìn)入switch-case中選擇執(zhí)行,防止不按功能按鍵時(shí),主程序依然繼續(xù)執(zhí)行上一次的功能)
- char Password[4]={-1,-1,-1,-1}; //儲(chǔ)存密碼
- uchar Pwd_Now[4]={10,10,10,10}; //儲(chǔ)存當(dāng)前輸入的密碼
- uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40,0x37,0x7b,0x31}; //數(shù)模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(); //按鍵時(shí)數(shù)碼管顯示
- }
- Key=j; //獲取鍵值
- if(j<10)
- {
- PwdDigit++; //只有按下數(shù)字鍵該密碼位數(shù)才會(huì)自加
- if(PwdDigit<4)
- Pwd_Now[PwdDigit]=j; //存儲(chǔ)有效密碼
- }
- else if(j!=12&&j!=15)
- Keycount++; //循環(huán)功能(除了setpwd和ready)按鍵的次數(shù)
- P1=0x0f;
- return;
- }
- }
- }
- }
- }
- }
- void Show_Pwd()
- {
- switch(PwdDigit) //通過密碼位數(shù)來實(shí)時(shí)顯示密碼的輸入,當(dāng)前存儲(chǔ)的密碼作為下標(biāo)顯示密碼
- {
- case 3: P3=0x4f;P2=table[Pwd_Now[3]];delay(10); //只打開第四個(gè)位選,P3.2=1(無影響),P3.3=1關(guān)閉LED,P3.5=0關(guān)閉警報(bào)
- case 2: P3=0x8f;P2=table[Pwd_Now[2]];delay(10); //只打開第三個(gè)位選,P3.2=1(無影響),P3.3=1關(guān)閉LED,P3.5=0關(guān)閉警報(bào)
- case 1: P3=0xcd;P2=table[Pwd_Now[1]];delay(10); //只打開第二個(gè)位選,P3.2=1(無影響),P3.3=1關(guān)閉LED,P3.5=0關(guān)閉警報(bào)
- case 0: P3=0xce;P2=table[Pwd_Now[0]];delay(10);break; //只打開第一個(gè)位選,P3.2=1(無影響),P3.3=1關(guān)閉LED,P3.5=0關(guān)閉警報(bào)
- default:P3=0x0c;P2=table[10];PwdDigit=-1;delay(10);break;//打開所有位選,P3.2=1(無影響),P3.3=1關(guān)閉LED,P3.5=0關(guān)閉警報(bào)
- //顯示'-',當(dāng)PwdDigit=-1與delay(10)位置不同有問題
- }
- }
- void Total_Show()
- {
- switch(ShowSign) //根據(jù)數(shù)碼管展示的標(biāo)志位來判斷展示不同的信息
- {
- case 1:Show_Pwd();break; //顯示輸入的密碼
- case 2:Show_on();break; //顯示密碼輸入正確的on并點(diǎn)亮小燈
- case 3:Show_err();break; //顯示密碼輸入錯(cuò)誤的err
- case 4:Show_Sixty();break; //顯示60s倒計(jì)時(shí)并打開警報(bào)
- }
- }
- void Show_on()
- {
- P3=0xc6; //只打開第一個(gè)位選,P3.2=1(無影響),P3.3=0打開LED,P3.5=0關(guān)閉警報(bào)
- P2=table[0]; //顯示0
- delay(15);
- P3=0xc5; //只打開第二個(gè)位選,P3.2=1(無影響),P3.3=0打開LED,P3.5=0關(guān)閉警報(bào)
- P2=table[11]; //顯示n
- delay(15);
- }
- void Show_err()
- {
- P3=0xce; //只打開第一個(gè)位選,P3.2=1(無影響),P3.3=1關(guān)閉LED,P3.5=0關(guān)閉警報(bào)
- P2=table[12]; //顯示'e'
- delay(10);
- P3=0xcd; //只打開第二個(gè)位選,P3.2=1(無影響),P3.3=1關(guān)閉LED,P3.5=0關(guān)閉警報(bào)
- P2=table[13]; //顯示'r'
- delay(10);
- P3=0x8e; //只打開第三個(gè)位選,P3.2=1(無影響),P3.3=1關(guān)閉LED,P3.5=0關(guān)閉警報(bào)
- P2=table[13]; //顯示'r'
- delay(10);
- }
- void Sure_on_err()
- {
- uchar i=0;
- ShowSign=3; //默認(rèn)輸入錯(cuò)誤,數(shù)碼管顯示標(biāo)志為3顯示err
- if(PwdRight==PwdDigit) //當(dāng)正確密碼的位數(shù)與當(dāng)前輸入的密碼的位數(shù)相同
- {
- for(i=0;i<=PwdDigit;i++) //每一位密碼進(jìn)行比較
- {
- if(Password[i]!=Pwd_Now[i]) //當(dāng)有一位不同就退出循環(huán)比較
- break;
- }
- if(i==PwdDigit+1)
- { //如果密碼正確,比較完不滿足判斷條件退出的循環(huán)則i=PwdDigit+1
- ShowSign=2; //更改數(shù)碼管顯示的標(biāo)志為2顯示on點(diǎn)亮小燈
- PwdErrTime=0; //將錯(cuò)誤次數(shù)清0
- }
- else //如果是break退出的循環(huán)則錯(cuò)誤次數(shù)加1,不需要更改數(shù)碼管顯示標(biāo)志
- PwdErrTime++;
- }
- else //如果正確密碼的位數(shù)與當(dāng)前輸入的密碼的位數(shù)不相同,則錯(cuò)誤次數(shù)加1
- PwdErrTime++;
- if(PwdErrTime==3) //密碼錯(cuò)誤次數(shù)達(dá)到三次
- {
- P0=table[PwdErrTime]; //單個(gè)數(shù)碼管先顯示密碼錯(cuò)誤次數(shù)3
- ShowSign=4; //更改數(shù)碼管顯示的標(biāo)志為4顯示倒計(jì)時(shí)并打開警報(bào)
- }
- }
- void SetPwd()
- {
- uchar i=0;
- uchar count=0; //存儲(chǔ)按功能鍵的次數(shù)
- uchar sign=0; //是否確認(rèn)密碼標(biāo)志(0:未確認(rèn),1:已確認(rèn))
- P1=0x7f; //將第四列設(shè)為低電平
- while(P1!=key_buf[12]); //setpwd第一次設(shè)置密碼
- P1=0xef; //將第一列設(shè)為低電平
- while(P1!=key_buf[15]); //查詢是否按下ready鍵
- EX0=1; //打開按鍵中斷開關(guān)
- while(1)
- {
- Total_Show();
- if(count!=Keycount&&Key==11) //當(dāng)有delete功能按鍵按下時(shí)將密碼位數(shù)減1(count!=Keycount為了防止當(dāng)按下delete后,由于在循環(huán)體中位數(shù)會(huì)一直自減)
- {
- count=Keycount; //功能鍵次數(shù)重新賦值給count
- PwdDigit--; //當(dāng)前密碼位數(shù)--
- }
- if(PwdDigit>=0&&Key==10) //輸完1-4位密碼并且按下sure鍵后顯示并保存密碼
- {
- ShowSign=2; //數(shù)碼管顯示on并點(diǎn)亮小燈
- Total_Show();
- sign=1; //表示已確認(rèn)設(shè)置密碼
- for(i=0;i<=PwdDigit;i++) //保存密碼
- Password[i]=Pwd_Now[i];
- PwdRight=PwdDigit; //將當(dāng)前密碼位數(shù)賦值給正確密碼位數(shù)標(biāo)志
- }
- if(Key==14&&sign==1) //只能確認(rèn)設(shè)置完密碼才能點(diǎn)擊close退出
- {
- return;
- }
- }
- }
- void Show_Time(uint number)
- {
- P3=0xee; //只打開第一個(gè)位選,P3.2=1(無影響),P3.3=1關(guān)閉LED,P3.5=1打開警報(bào)
- P2=table[10]; //顯示 -
- delay(5);
- P3=0xed; //只打開第二個(gè)位選,P3.2=1(無影響),P3.3=1關(guān)閉LED,P3.5=1打開警報(bào)
- P2=table[number/10]; //顯示十位
- delay(5);
- P3=0xaf; //只打開第三個(gè)位選,P3.2=1(無影響),P3.3=1關(guān)閉LED,P3.5=1打開警報(bào)
- P2=table[number%10]; //顯示個(gè)位
- delay(5);
- P3=0x6f; //只打開第四個(gè)位選,P3.2=1(無影響),P3.3=1關(guān)閉LED,P3.5=1打開警報(bào)
- P2=table[10]; //顯示 -
- delay(5);
- }
- void Show_Sixty()
- {
- uchar toal=60; //倒計(jì)時(shí)總時(shí)間
- EX0=0; //關(guān)閉鍵盤中斷(防止按鍵進(jìn)行中斷數(shù)碼管顯示)
- TR0=1; //打開定時(shí)器開關(guān)
- do
- {
- if(TimeCount==20) //中斷一次50ms,TimeCount++,當(dāng)達(dá)到20次即1s顯示值減一
- {
- TimeCount=0; //重新賦值為0
- toal--; //顯示值--
- }
- Show_Time(toal); //掉用顯示函數(shù)
- }while(toal>0); //當(dāng)顯示到0時(shí)退出
- TR0=0; //關(guān)閉定時(shí)器開關(guān)
- EX0=1; //打開鍵盤中斷開關(guān)
- PwdErrTime=0; //錯(cuò)誤次數(shù)重新賦值為0
- PwdDigit=-1; //密碼位數(shù)賦值為-1重新輸入
- ShowSign=1; //數(shù)碼管顯示標(biāo)志設(shè)為1,顯示密碼
- }
- int0_srv() interrupt 1
- {
- TimeCount++;
- }
- void Init()
- {
- IT0=0; //設(shè)為跳變沿有問題
- TMOD=0x01; //定時(shí)器0工作方式為1
- TH0=0x3c;
- TL0=0xb0; //一次定時(shí)50ms
- ET0=1; //打開定時(shí)器0的中斷開關(guān)
- EA=1; //打開總開關(guān)
- P0=table[0];//單個(gè)數(shù)碼管顯示0
- LED=1; //關(guān)閉數(shù)碼管
- ALTER=0; //關(guān)閉警報(bào)器
- }
- void Close_Init()
- {
- uchar i=0;
- P3=0xcf; //關(guān)閉所有位選,P3.2=1(無影響),P3.3=1關(guān)閉LED,P3.5=0關(guān)閉警報(bào)
- EX0=0; //關(guān)閉鍵盤中斷
- PwdDigit=-1; //密碼位數(shù)賦值為-1
- P1=0xef; //將第一列設(shè)為低電平
- while(P1!=key_buf[15]);//查詢是否按下ready鍵
- ShowSign=1; //數(shù)碼管顯示密碼
- EX0=1; //打開鍵盤中斷
- for(i=0;i<4;i++) //將當(dāng)前密碼初始化
- Pwd_Now[i]=10;
- }
- void Pwd_Modity()
- {
- uchar count=0; //存儲(chǔ)按功能鍵的次數(shù)
- PwdDigit=-1; //密碼位數(shù)賦值為-1
- ShowSign=1; //數(shù)碼管顯示密碼
- while(1)
- {
-
- Total_Show();
- if(count!=Keycount&&Key==11) //當(dāng)有delete功能按鍵按下時(shí)將密碼位數(shù)減1(count!=Keycount為了防止當(dāng)按下delete后,由于在循環(huán)體中位數(shù)會(huì)一直自減)
- {
- count=Keycount; //功能鍵次數(shù)重新賦值給count
- PwdDigit--; //當(dāng)前密碼位數(shù)--
- }
- 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; //將當(dāng)前密碼位數(shù)賦值給正確密碼位數(shù)標(biāo)志
- ShowSign=2; //數(shù)碼管顯示on并點(diǎn)亮小燈
- Key=12; //防止返回主函數(shù)后進(jìn)入switch-case
- return;
- }
- }
- }
- void main(void)
- {
- uchar count=0;//功能按鍵的次數(shù)
- Init(); //初始化
- SetPwd(); //設(shè)置密碼
- while(1)
- {
- P0=table[PwdErrTime]; //close關(guān)閉后單個(gè)數(shù)碼管關(guān)閉
- if(count!=Keycount) //當(dāng)有功能按鍵按下時(shí)進(jìn)入switch-case(為了防止當(dāng)按下delete后,由于在循環(huán)體中位數(shù)會(huì)一直自減)
- {
- count=Keycount; //功能按鍵次數(shù)重新賦值給count
- switch(Key)
- {
- case 10:Sure_on_err();break; //調(diào)用確認(rèn)密碼函數(shù)
- case 11:if(ShowSign==1){PwdDigit--;Pwd_Now[PwdDigit+1]=10;}break; //密碼位數(shù)減1,并把上一位存儲(chǔ)的密碼初始化為10
- case 13:if(ShowSign==2)Pwd_Modity();break; //當(dāng)密碼正確了才能修改密碼
- case 14:Close_Init();break; //close關(guān)閉后的初始化
- }
- }
- Total_Show();
- }
- }
復(fù)制代碼
Keil代碼與Proteus8.13仿真下載:
密碼鎖.zip
(2.98 MB, 下載次數(shù): 46)
2023-3-1 17:12 上傳
點(diǎn)擊文件名下載附件
仿真+程序+設(shè)計(jì)
|