一、基本組成:
電機(控制口P2.4)
二、基本功能描述:
1.驗證密碼、修改密碼
a)鎖的初始密碼是123456(密碼最長為10位,最短為1位)。
2.恢復初始密碼
a)系統可以恢復初始密碼,否則一旦忘記密碼而又不能恢復初始密碼,該鎖就永遠打不開。但是又不能讓用戶自行修改密碼,否則其他人也可以恢復該初始密碼,使得鎖的安全性大大下降。
3.使系統進入低功耗狀態
a)在實際使用中,鎖只有在開門時才被使用。因而在大多數的時間里,應該讓鎖進入休眠狀態、以降低功耗,這使系統進入掉電狀態,可以大大降低系統功耗。
b)同時將LCD背光燈關閉
4.DC電機模擬開鎖動作。
a)DC電機啟動時解除開鎖把手的鎖定,允許通過把手開鎖。DC電機不直接開鎖,使得DC電機的功率不用太大,系統的組成和維護將變得簡單,功耗也降了下來。
三、密碼鎖特點說明:
1.0 輸入將被以字符形式輸入,最長為10位。
2.0 開鎖10秒后不允許更改密碼、并提示修改超時_進入初始態,需要重新輸入密碼方可再次修改密碼。
3.0 系統未使用存儲器存儲密碼故掉電后密碼自動恢復為初始密碼。
4.0 若2分鐘內無任何操作,系統自動進入省電模式運行,同時關閉液晶顯示,以節省電力。
5.0 輸入密碼正確后、電機允許開鎖時間為5秒, 5秒后需要再次輸入密碼才可以再次開鎖。
6.0 修改密碼鍵和恢復初始密碼鍵最好置于室內。
這是Proteus仿真結果:
輸入密碼123456:
顯示結果:
開鎖鍵是接INT0引腳接的一個獨立按鍵,用于喚醒CPU工作、進而開啟整個系統
密碼正確時可以修改密碼:
當然你可以隨時放棄修改密碼
改進:
1.0 密碼鎖的秘密沒有存儲,因而在掉電時最新的密碼將丟失,重新上電后密碼將恢復成為初始密碼。這使得每次換電池或停電后密碼都得恢復一次,給使用帶來不便,但是為了要存儲一個最多只有十幾字節的密碼就增加一個存儲器、似乎不是很值,最好是所選的單片機自帶這樣的存儲器(容量很小、如32B)。當然如果電源來自市電的話,就不會經常掉電了。
2.0 系統的最好再增加電源監測的設計,在電池電力不夠時發出提示。這時還可以增加備用電池,這樣就可以保證系統不會掉電。但是這些都要依賴于成本。
3.0 液晶的顯示最好采用中文。通過對1602的CGRAM的操作可以實現中文顯示,使得用戶界面更好。
主函數:
確認函數_ confirm()操作:
0_將 '\0' 置于輸入table_input[]結尾
(table_input[]的長度返回值在length里面)
根據操作標識選擇任務:
1_確認密碼:判定輸入密碼正確與否
2_修改密碼:確認第一次輸入并保存
根據比較結果選擇任務:
修改失敗,進入輸入密碼態
修改成功,將輸入復制到table_password[]
確認函數_confirm()相關標識位目錄:
flag_display;//根據其值可以確定顯示信息
flag_allow;//允許修改密碼標識,在密碼比較正確時置1
flag_amend;//第一/二次輸入新密碼標識
flag_M;//允許電機開鎖標識
相關變量
sbit M=P3^6;//電機控制口
flag_confirm;//操作任務標識位
flag_compare;//比較輸入與密碼|相等時返回1,否則返回0
第一次輸入前=1,輸入后置2
第二次輸入前=2,輸入后置0
lcd_display()函數中標識位flag_display的值與意義:
=0:不顯示|不刷新顯示
=1:密碼錯誤
=2:密碼正確
=3:請輸入新密碼
=4:請再次輸入新密碼
=5:密碼修改成功
=6:密碼修改失敗
=7:顯示輸入密碼狀態_The password!
=8:放棄修改密碼
=9:已開鎖
流圖不怎么清晰、不過下一篇就是程序了,可以從程序推出流圖。
程序比較多,所以寫成了幾個文件,同時應用了相當多的標識位來進行信號傳遞。
我覺得邊看程序邊畫它的流程圖會更好地幫助我們讀程序。
1.0 main.c文件
#include<reg52.h>
#include<string.h>
#include"mydefine_2.h"
static void delay(unsigned int N)//N ms延時_12MHz/準確性高
{
unsigned int i=0,j=0;
for(i=1;i<=N;i++)
for(j=1;j<=355;j++) ;
}
void clock()
{
key_clock=0;
delay(15);
key_clock=1;
}
void init()
{
key_LCD=0;
init_1602();
TMOD=0x01;
TH0=0x3C;//=(65535-5000)/256
TL0=0xAF;//(65535-5000)%256
EA=1;
ET0=1;
TR0=0;
EA=1;//外部中斷0喚醒CPU(空閑方式)
EX0=1;
IT0=1;
command(0x80);
lcd_display(7);
}
void main()
{
init();
while(1)
{
temp=keyboard_matrix();//掃描輸入
if(temp)//有按鍵輸入信息
{
clock();//按鍵聲
TR0=0;//關閉計時
timer=0;
receive(temp);//輸入的字符串長度為length( <= 10)
if(i!=length)//輸入時顯示"*"
{
command(0xC0+length);//為顯示密碼輸入設定位置
display('*');
i=length;
}
switch(temp)//根據按鍵號調用任務
{
//修改密碼
case 12: if((flag_allow) && (flag_amend==0))//輸入密碼正確的條件下可以更改
{
table_input[0]='\0';
flag_display=3;//請輸入新密碼
flag_confirm=1;//確認鍵進入確認修改密碼功能
flag_amend=1;//每次按下修改鍵時都是第一次輸入新密碼
length=0; //重按修改鍵時也是第一次輸入新密碼
i=0;
}
else
{
flag_confirm=0;//恢復初始態
flag_amend=0;
lcd_display(1);//密碼不正確
delay(500);
flag_display=7;
length=0;
i=0;
}
break;
case 11: //取消
command(0xC0+length);//擦出顯示
display(' ');//顯示后光標_顯示地址又加了1
command(0xC0+length);//重置光標_顯示地址|實為將光標拉回來
i=0;
if(length > 0)
{
length--;//input[]位置后退一位
}
break;
case 10: confirm();//確定
i=0;
break;
case 13: //修改密碼的過程中取消修改密碼|將系統置于初始態即可
if((flag_amend==1) || (flag_amend==2))
{
flag_amend=0;
flag_confirm=0;
lcd_display(8);
delay(500);
flag_display=7;
length=0;
i=0;
}
break;
}
lcd_display(flag_display);
}
else
{
TR0=1;//開始計時等待
}
DC_Moter();
resume_password();
if(flag_clear)//恢復密碼和開鎖鍵_外部中斷有效時重新計時
{
flag_clear=0;
timer=0;
}
if(timer==100)//10秒后不允許更改密碼
{
flag_allow=0;
flag_amend=0;
flag_confirm=0;
length=0;
i=0;
lcd_display(7);//顯示初始態,以提示修改超時
}
if(timer==1200)//≈2分鐘后休眠|空閑方式
{
TR0=0;
timer=0;
clear_system();//恢復初始態
i=0;
key_clock=0;
delay(250);
key_clock=1;
PCON|=0x01;
lcd_display(7);//喚醒CPU后顯示初始態
}
}
}
void int0() interrupt 0
{
key_LCD=0;//開液晶電源
key_clock=0;
delay(250);
key_clock=1;
flag_clear=1;
}
void Timer0() interrupt 1 //50ms
{
TH0=0x3C;//(65535-50000)/256
TL0=0xAF;//(65535-50000)%256
timer++;
}
2.0 負責實現具體操作的 process_char.c 文件
#include<reg52.h>
#include<string.h>
#include"mydefine.h"
sbit key_self=P2^1;//獨立按鍵,用于恢復初始密碼
sbit key_LED=P2^0;
sbit key_M=P2^4;//DC電機控制口
sbit key_LCD=P2^7;//液晶電源控制口
extern bit flag_clear;//恢復密碼和開鎖鍵_外部中斷的有效標識
extern unsigned int timer;//定時器0計數時段標記_50ms一次定時中斷
extern unsigned char length=0;//跟蹤記錄輸入table_input[11]的字符長度( <=10 )
extern unsigned char flag_display=0;//根據其值可以確定顯示信息
extern unsigned char flag_confirm=0;//確認鍵根據此標識判定任務,默認為0_即為確定密碼狀態
extern unsigned char flag_allow=0;//允許修改密碼標識,在密碼比較正確時置1
extern unsigned char flag_amend=0;//第一/二次輸入新密碼標識
unsigned char flag_M=0;//允許電機開鎖標識
extern void command(unsigned char command);
extern void display(unsigned char date);
//向I2C地址為address處寫入數據date
extern void write_I2C(unsigned char address,unsigned char date);
//讀出I2C地址為address處的數據
extern unsigned char read_I2C(unsigned char address);
static void delay(unsigned int N)//N ms延時/準確性高
{
unsigned int i=0,j=0;
for(i=1;i<=N;i++)
for(j=1;j<=355;j++) ;
}
//休眠前清除table_input中的值
extern void clear_system()
{
table_input[0]='\0';//恢復初始態
length=0;
flag_allow=0;
flag_confirm=0;
flag_amend=0;
flag_clear=0;
key_LCD=1;//關液晶電源
}
//接收鍵盤輸入|以字符形式存入table_input[11]
extern void receive(unsigned char temp)
{
//按鍵在松手時讀取按鍵號,故不會重復讀取按鍵值
if(temp && length<=9)//如此,則無按鍵時執行效率高
{
switch(temp)
{
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9: table_input[length++]=temp+48;//以字符形式存入table_input[11]
break;
case 14: table_input[length++]=48;//字符0
}
}
}
//根據任務選擇顯示信息
extern void lcd_display(unsigned char temp)
{
unsigned char i=0,*p=NULL;
if(temp)
{
switch(temp)//選擇顯示信息
{
case 1: p=table_error;//密碼不正確
break;
case 2: p=table_pass;//密碼正確
break;
case 3: p=table_new;//請輸入新密碼
break;
case 4: p=table_again;//請再次輸入新密碼
break;
case 5: p=table_changed;//密碼修改成功
break;
case 6: p=table_fail;//密碼修改失敗
break;
case 7: p=table_enter;//顯示輸入密碼:The password!
break;
case 8: p=table_abandon;//放棄修改密碼
break;
case 9: p=table_close;//鎖閉
break;
case 10: p=table_resume;//鎖閉
break;
}
command(0x01);
delay(1);
command(0x80);
while(*p!='\0')
{
display(*(p++));
}
flag_display=0;//顯示后清0,避免重復顯示
}
}
//確認
extern void confirm(void)
{
unsigned char flag_compare=0;//用于記錄比較輸入與密碼的結果|相等時返回1,否則返回0
unsigned char flag_compare_2=0;//用于記錄對兩次輸入的新密碼的比較結果|相等時返回1,否則返回0
unsigned char i=0;
if(length > 0)//輸入不為空
{
table_input[length]='\0';
length=0;//輸入字符串長度清0
if(flag_confirm)//修改密碼
{
switch(flag_amend)
{
case 1: strcpy(table_newpassword,table_input);//第一次輸入新密碼
table_input[1]='\0';//避免第一次輸入的內容在放棄修改時再次被利用
flag_amend=2;
flag_display=4;//請再次輸入密碼
break;
case 2: flag_compare_2=strcmp(table_input,table_newpassword);//第二次輸入新密碼
flag_amend=0;//清0,允許再次修改
flag_confirm=0;//進入初始之確認密碼狀態
if(!flag_compare_2)//兩次輸入相同==0
{
strcpy(table_password,table_input);
table_input[1]='\0';//避免修改完成后再次被利用,造成重復修改,同時避免剛修改了就是pass狀態
lcd_display(5);//修改成功
delay(500);
flag_display=7;
}
else
{
lcd_display(6);//修改失敗
delay(500);
flag_display=7;
}
break;
}
}
else//驗證密碼
{
flag_compare=strcmp(table_input,table_password);
if(!flag_compare)//密碼正確==0
{
flag_allow=1;//允許修改密碼
flag_M=1;//允許開鎖
flag_display=2;//密碼正確信息:Pass!
table_input[1]='\0';//改變輸入,使不致出亂
}
else//密碼錯誤
{
flag_allow=0;//不允許修改密碼
lcd_display(1);//密碼錯誤信息:Error!
delay(500);
flag_display=7;
}
}
}
}
//電機控制
extern void DC_Moter()
{
if(flag_M)//允許開鎖
{
flag_M=0;
key_M=0;//開鎖
key_LED=0;
delay(1250);
key_M=1;
key_LED=1;
timer=0;
lcd_display(7);//進入初始態
}
}
//恢復初始密碼
extern void resume_password()
{
if(!key_self)//==0
{
delay(3);
if(!key_self)//==0
{
while(!key_self) ;//==0
strcpy(table_password,table_original);
flag_clear=1;
lcd_display(10);
delay(500);
lcd_display(7);
}
}
}
確認函數_ confirm()操作:
0_將 '\0' 置于輸入table_input[]結尾
(table_input[]的長度返回值在length里面)
根據操作標識選擇任務:
1_確認密碼:判定輸入密碼正確與否
2_修改密碼:確認第一次輸入并保存
要求第二次輸入
比較兩次輸入是否相同
根據比較結果選擇任務:
修改失敗,進入輸入密碼態
修改成功,將輸入復制到table_password[]
確認函數_confirm()相關標識位目錄:
flag_display;//根據其值可以確定顯示信息
flag_confirm;//確認鍵根據此標識判定任務,默認為0_即為確定密碼狀態
flag_allow;//允許修改密碼標識,在密碼比較正確時置1
flag_amend;//第一/二次輸入新密碼標識
flag_M;//允許電機開鎖標識
相關變量
sbit M=P3^6;//電機控制口
flag_confirm;//操作任務標識位
flag_compare;//比較輸入與密碼|相等時返回1,否則返回0
static flag_amend;//修改密碼時的標識
第一次輸入前=1,輸入后置2
第二次輸入前=2,輸入后置0
flag_display=0;//確認鍵操作的返回值根據返回值可以確定顯示信息
flag_allow;//允許改密碼標識,在密碼比較正確時置1,不正確時置0
process_char()函數::_M;//DC電機控制口
process_char()函數::_length;//跟蹤記錄輸入table_input[11]的字符長度( <=10 )
lcd_display()函數中標識位flag_display的值與意義:
=0:不顯示|不刷新顯示
=1:密碼錯誤
=2:密碼正確
=3:請輸入新密碼
=4:請再次輸入新密碼
=5:密碼修改成功
=6:密碼修改失敗
=7:顯示輸入密碼狀態_The password!
=8:放棄修改密碼
=9:已開鎖
3.0 定義各個數組的頭文件mydefine.h
extern unsigned char table_input[11]={0}; //接收鍵盤輸入
unsigned char table_password[11]="123456"; //密文
unsigned char table_newpassword[11]="456"; //接收新密碼
unsigned char code table_original[11]="123456"; //初始密碼
//顯示信息
unsigned char code table_pass[]="Pass!"; //成功進入
unsigned char code table_error[]="Operate Error!"; //密碼錯誤信息
unsigned char code table_enter[]="The password:"; //輸入密碼
unsigned char code table_new[]="New password:"; //輸入新密碼
unsigned char code table_again[]="Enter again:"; //再次輸入新密碼
unsigned char code table_changed[]="Changed!"; //密碼修改成功
unsigned char code table_fail[]="Fail changce!"; //密碼修改失敗
unsigned char code table_abandon[]="Abandon changce!";//放棄修改密碼
unsigned char code table_close[]="Locked!";//鎖閉
unsigned char code table_resume[]="Resumed!";//恢復初始密碼
4.0 頭文件mydefine_2.h
定義了各個外部文件向主函數用到的操作函數和外部變量
#ifndef _mydefine_2_h_
#define _mydefine_2_h_
sbit key_LED=P2^0;
sbit key_clock=P3^3;//蜂鳴器
sbit key_LCD=P2^7;//液晶電源控制口
extern bit flag_clear=0;//恢復密碼和開鎖鍵_外部中斷的有效標識
extern unsigned int timer=0;//定時器0計數時段標記_50ms一次定時中斷
static unsigned char i=0;//顯示*用變量
unsigned char temp=0;//用于接收鍵盤輸入(按鍵在松手時讀取按鍵號)
extern unsigned int table_input[11];//接收輸入
extern unsigned char flag_allow;//允許改密碼標識,在密碼比較正確時置1
extern unsigned char flag_confirm;//確認鍵根據此標識判定任務,默認為0_即為確定密碼狀態
extern unsigned char flag_display;//確認鍵操作的返回值,根據返回值可以確定顯示信息
extern unsigned char flag_amend;//第一/二次輸入新密碼標識
extern unsigned char length;//輸入input的字符長度(length <= 16)
//1602液晶:extern_1602.c *****************************************************************
extern void init_1602();
extern void command(unsigned char command);
extern void display(unsigned char date);
//鍵盤:extern_keyboard_no_T0_2.c *********************************************************
//矩陣鍵盤.無按鍵動作時其返回值num_key=0,否則返回按鍵號num_key
extern unsigned char keyboard_matrix();//(在松手時讀取按鍵號****檢測高四位)
//密碼處理:process_char.c ****************************************************************
//電機控制
extern void DC_Moter();
//接收鍵盤輸入|以bit形式存入input__返回值為輸入的字符串長度length(length <= 10)
extern void receive(unsigned char temp);//涉及文件間變量length
//確認按鍵操作
extern void confirm(void);//涉及跨文件調用的變量flag_confirm,flag_allow,flag_amend
//根據任務選擇顯示信息
extern void lcd_display(unsigned char flag_display);//涉及跨文件調用的變量flag_display
extern void clear_system();//恢復初始態
extern void resume_password();//恢復初始密碼
//****************************************************************************************
#endif
鍵盤和1602顯示的程序見其他文章。