#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
uchar old1,old2,old3,old4,old5,old6; //原始密碼123456
unsigned char PassWord[6];
uchar new1,new2,new3,new4,new5,new6; //每次MCU采集到的密碼輸入
uchar a=16,b=16,c=16,d=16,e=16,f=16; //送入數碼管顯示的變量
uchar wei,key,temp;
unsigned char st=0;
bit allow,genggai,ok,wanbi,retry,close; //各個狀態位
sbit beep=P3^6;
sbit Lock=P3^7;
sbit GLED=P3^4;
sbit RLED=P3^5;
sbit SCL = P3^3; //引腳定義
sbit SDA = P3^2;
unsigned char code table[]=
{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,
0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00,0x40};
void InitI2C();
void I2CStart();
void I2CStop();
void I2CSend(uchar byte);
uchar I2CRead();
uchar read_eeprom(uchar addr);
void write_eeprom(uchar addr, uchar databyte);
/*****************************************************************************
** 函數名稱:delay
** 功能描述:延時
******************************************************************************/
void delay(unsigned int i)
{
uint j,k;
for(j=i;j>0;j--)
for(k=125;k>0;k--);
}
/*****************************************************************************
** 函數名稱:InitI2C
** 功能描述:配置模擬I2C的IO端口
******************************************************************************/
void InitI2C()
{
SDA = 1;
SCL = 1;
}
/*****************************************************************************
** 函數名稱:I2CStart
** 功能描述:發送I2C總線起始狀態
** 輸 入:無
** 輸 出:無
** 全局變量:無
** 調用模塊:delay()
** 可移植性:直接移植
******************************************************************************/
void I2CStart()
{
SDA = 1;
delay(1); // 延時子程序
SCL = 1;
delay(1);
SDA = 0;
delay(1);
SCL = 0;
}
/*****************************************************************************
** 函數名稱:I2CStop
** 功能描述:發送I2C總線停止起始狀態
** 輸 入:無
** 輸 出:無
** 全局變量:無
** 調用模塊:delay()
** 可移植性:直接移植
******************************************************************************/
void I2CStop()
{
SCL = 0;
delay(1);
SDA = 0;
delay(1);
SCL = 1;
delay(1);
SDA = 1;
delay(1);
}
/*****************************************************************************
** 函數名稱:I2CSend
** 功能描述:向I2C總線發送一個字節數據,并檢測應答
** 輸 入:待發送字節byte
** 輸 出:無
** 全局變量:無
** 調用模塊:delay()
** 可移植性:直接移植
******************************************************************************/
void I2CSend(uchar byte)
{
uchar mask;
uchar i;
mask = 0x80;
for(i = 0; i < 8; i++)
{
SCL = 0;
delay(1);
if((mask & byte) == 0)
{
SDA = 0;
}
else
{
SDA = 1;
}
mask >>= 1;
delay(1);
SCL = 1;
delay(1);
}
SCL = 0;
SDA = 1;
delay(1);
SCL = 1;
delay(1);
SCL = 0;
}
/*****************************************************************************
** 函數名稱:I2CRead
** 功能描述:從I2C總線讀取最后一個字節數據,并發送非應答位
** 輸 入:無
** 輸 出:接收到的字節byte
** 全局變量:無
** 調用模塊:delay()
** 可移植性:直接移植
******************************************************************************/
uchar I2CRead()
{
uchar byte;
uchar i;
byte = 0;
for(i = 0; i < 8; i++)
{
SCL = 0;
SDA = 1;
delay(1);
SCL = 1;
delay(1);
byte <<= 1;
if(SDA == 1)
{
byte |= 0x01;
}
delay(1);
}
SCL = 0;
SDA = 1;
delay(1);
SCL = 1;
delay(1);
SCL = 0;
return byte;
}
/*****************************************************************************
** 函數名稱:read_eeprom
** 功能描述:讀取EEPROM數據函數
** 輸 入:EEPROM中目的地址addr
** 輸 出:讀取的數據
******************************************************************************/
uchar read_eeprom(uchar addr)
{
uchar databyte;
I2CStart();
I2CSend(0xa0);
I2CSend(addr);
I2CStart();
I2CSend(0xa1);
databyte = I2CRead();
I2CStop();
return databyte;
}
/*****************************************************************************
** 函數名稱:write_eeprom
** 功能描述:向EEPROM寫入數據函數
** 輸 入:EEPROM中目的地址addr及寫入的數據
** 輸 出:無
******************************************************************************/
void write_eeprom(uchar addr, uchar databyte)
{
I2CStart();
I2CSend(0xa0);
I2CSend(addr);
I2CSend(databyte);
I2CStop();
}
void display(void)
{
switch(st)
{
case 0: st=1;P0=0xff;P2=table[a];P0=0xfe;break;
case 1: st=2;P0=0xff;P2=table[b];P0=0xfd;break;
case 2: st=3;P0=0xff;P2=table[c];P0=0xfb;break;
case 3: st=4;P0=0xff;P2=table[d];P0=0xf7;break;
case 4: st=5;P0=0xff;P2=table[e];P0=0xef;break;
case 5: st=0;P0=0xff;P2=table[f];P0=0xdf;break;
}
}
void Timer0() interrupt 1
{
TR0=0;
TH0 = (65535-2000)/256;
TL0 = (65535-2000)%256;
display();
TR0=1;
}
void keyscan(void)
{
P1=0xfe;
temp=P1;
temp=temp&0xf0;
if(temp!=0xf0)
{
delay(10);
if(temp!=0xf0)
{
temp=P1;
switch(temp)
{
case 0xee: key=0;wei++;break;
case 0xde: key=1;wei++;break;
case 0xbe: key=2;wei++;break;
case 0x7e: key=3;wei++;break;
}
beep=0;delay(50);beep=1;
while(temp!=0xf0)
{
temp=P1;
temp=temp&0xf0;
}
}
}
P1=0xfd;
temp=P1;
temp=temp&0xf0;
if(temp!=0xf0)
{
delay(10);
if(temp!=0xf0)
{
temp=P1;
switch(temp)
{
case 0xed: key=4;wei++;break;
case 0xdd: key=5;wei++;break;
case 0xbd: key=6;wei++;break;
case 0x7d: key=7;wei++;break;
}
beep=0;delay(50);beep=1;
while(temp!=0xf0)
{
temp=P1;
temp=temp&0xf0;
}
}
}
temp=temp&0xf0;
if(temp!=0xf0)
{
delay(10);
if(temp!=0xf0)
{
temp=P1;
switch(temp)
{
case 0xeb: key=8;wei++;break;
case 0xdb: key=9;wei++;break;
case 0xbb: genggai=1;wei=0;break;
case 0x7b: if(allow) ok=1;break;
}
beep=0;delay(50);beep=1;
while(temp!=0xf0)
{
temp=P1;
temp=temp&0xf0;
}
}
}
P1=0xf7;
temp=P1;
temp=temp&0xf0;
if(temp!=0xf0)
{
delay(10);
if(temp!=0xf0)
{
temp=P1;
switch(temp)
{
case 0xe7: retry=1;break;
case 0xd7: close=1;break;
}
beep=0;delay(50);beep=1;
while(temp!=0xf0)
{
temp=P1;
temp=temp&0xf0;
}
}
}
}
void shumima(void) //對按鍵采集來的數據進行分配
{
if(!wanbi)
{
switch(wei)
{
case 1: new1=key;if(!allow)a=17;else a=key; break;
case 2: new2=key;if(a==17) b=17;else b=key; break;
case 3: new3=key;if(a==17) c=17;else c=key; break;
case 4: new4=key;if(a==17) d=17;else d=key; break;
case 5: new5=key;if(a==17) e=17;else e=key; break;
case 6: new6=key;if(a==17) f=17;else f=key;wanbi=1;break;
}
}
}
void yanzheng(void) //驗證密碼是否正確
{
if(wanbi) //只有當六位密碼均輸入完畢后方進行驗證
{
if((new1==PassWord[0])&(new2==PassWord[1])&(new3==PassWord[2])&(new4==PassWord[3])&(new5==PassWord[4])&(new6==PassWord[5]))
allow=1; //當輸入的密碼正確,會得到allow置一
}
}
void WritePassWord(void)
{
unsigned char j=0;
for(j=0;j<6;j++) //從02地址開始寫初始密碼數據
{
write_eeprom(j,PassWord[j]); //初始密碼123456
delay(10);
}
}
void ReadPassWord(void)
{
unsigned char j=0;
for(j=0;j<6;j++) //將24C02中的密碼讀取出來保存在dumima_tab1[]數組中
{
PassWord[j] = read_eeprom(j);
delay(10);
}
}
void WritePassWord_Ini(void)
{
unsigned char j=0;
for(j=0;j<6;j++) //從02地址開始寫初始密碼數據
{
write_eeprom(j,j+1); //初始密碼123456
delay(10);
}
}
void main(void)
{
InitI2C(); //初始化
TMOD = 0x01;
TH0 = (65535-2000)/256;
TL0 = (65535-2000)%256;
EA=1;
ET0=1;
TR0=1;
//WritePassWord_Ini();
ReadPassWord();
if(PassWord[0]==0xff) WritePassWord_Ini();
while(1)
{
keyscan();
shumima();
yanzheng();
if(allow) //驗證完后,若allow為1,則開鎖
{
Lock=0;GLED=0;RLED=1;
if(!genggai) wanbi=0;
}
else
{
Lock=1;GLED=1;RLED=0;
if(wanbi)
{
delay(500);
beep=0;delay(500);beep=1;delay(500);
beep=0;delay(100);beep=1;delay(200);
beep=0;delay(100);beep=1;delay(200);
beep=0;delay(100);beep=1;delay(200);
beep=0;delay(100);beep=1;delay(200);
beep=0;delay(100);beep=1;delay(200);
beep=0;delay(100);beep=1;
wei=0;wanbi=0;allow=0;
a=16;b=16;c=16;d=16;e=16;f=16;
new1=0;new2=0;new3=0;new4=0;new5=0;new6=0;
}
}
if(genggai) //當S16更改密碼鍵被按下,genggai會被置一
{
if(allow) //若已經把鎖打開,才有更改密碼的權限
{
while(!wanbi) //當新的六位密碼沒有設定完,則一直在這里循環
{
delay(20);
keyscan();
shumima();
if(retry|close) //而當探測到重試鍵S18或者關閉密碼鎖鍵S19被按下時,則跳出
{
wanbi=1;
break;
}
}
}
}
if(ok) //更改密碼時,當所有六位新密碼均被按下時,可以按下此鍵,結束密碼更改
{ //其他時間按下此鍵無效
ok=0; wei=0;Lock=1;GLED=1;RLED=0;
genggai=0;
PassWord[0]=new1;PassWord[1]=new2;PassWord[2]=new3; //此時,舊的密碼將被代替
PassWord[3]=new4;PassWord[4]=new5;PassWord[5]=new6;
WritePassWord();
wei=0;wanbi=0;allow=0;
a=16;b=16;c=16;d=16;e=16;f=16;
new1=0;new2=0;new3=0;new4=0;new5=0;new6=0;
}
if(retry) //當重試按鍵S18被按下,retry會被置位
{
retry=0; wei=0;wanbi=0;
a=16;b=16;c=16;d=16;e=16;f=16;
new1=0;new2=0;new3=0;new4=0;new5=0;new6=0;
}
if(close) //當關閉密碼鎖按鍵被按下,close會被置位
{
close=0;genggai=0;//所有變量均被清零。
wei=0; wanbi=0;
allow=0;
Lock=1;GLED=1;RLED=0;
a=16;b=16;c=16;d=16;e=16;f=16;
new1=0;new2=0;new3=0;new4=0;new5=0;new6=0;
}
}
}
|