第一張圖貼出來的是生成目標文件時的提醒。第二張圖片是我用的keil軟件和注冊機。
下面是我的程序
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
#define GPIO_jianpan P3
#define GPIO P0
sbit RS=P2^6;
sbit RW=P2^5;
sbit SCL=P2^4;
sbit SDA=P2^3;
sbit E=P2^7;
sbit A=P2^2; //控制開關
sbit gaimi=P3^2; //改密標志位
sbit jingbao=P2^1; //警報 蜂鳴器響起
uint value=0; //鍵盤返回值
uint a=0; //記錄經(jīng)歷過多少個五十毫秒
uint b=0; //記錄輸錯密碼的次數(shù)
uint c=0; //標志密碼的正確與否
uint z=0;
uint compare0,compare1,compare2,compare3,compare4,compare5;
uchar tab_1[16]={1,2,3,1,4,5,6,1,7,8,9,1,1,0,1,1};
uchar code tab_2[15]="Welcome to home";
uchar code tab_3[25]="Please enter the password";
uchar code tab_4[16]="Password mistake";
uchar code tab_5[17]="surplus 2 chances";
uchar code tab_6[17]="surplus 1 chances";
uchar code tab_7[10]="Who is it";
uchar code tab_8[25]="please enter new password";
void init(); //LCD的初始化
jianpan(); //鍵盤輸入
yanzhengmima(); //驗證密碼
void ceshijian_on(); //測輸入密碼所用時間中斷初始化 開中斷
void ceshijian_off(); //測輸入密碼所用時間中斷初始化 關中斷
void gaimima(); //改密碼
void delay5s(); //延遲五秒
void delay10us(); //延遲10us
void delay1h(); //延遲1小時
void delay10ms(); //延遲十毫秒
void LCD00_writedat(uchar dat);
void LCD00_writecom(uchar com);
void at24c0200_write(uchar addre,uchar dat);
jianpan00();
void delay10us00();
void i2c00_write();
i2c00_ack();
void i2c00_start();
void i2c00_stop();
void at24c02_write(uchar addre,uchar dat);
at24c02_read(uchar addre);
void i2c_write();
i2c_read();
i2c_ack();
void i2c_start();
void i2c_stop();
void LCD_writedat(uchar dat);
void LCD_writecom(uchar com);
void LCD_init();
void main()
{gaimi=1;
tab_1[3]=0; //如果tab[3]=1,說明開始執(zhí)行改密程序(外部中斷1的工作)
tab_1[7]=0; //如果tab[7]=1,說明開始輸入密碼
tab_1[11]=0;//如果tab[11]=1,說明取消此次的密碼輸入
tab_1[15]=0;//如果tab[15]=1,說明開始檢查密碼是否輸入正確
//在EEPROM中寫入初始密碼164534
at24c02_write(0x00,1);
at24c02_write(0x01,6);
at24c02_write(0x02,4);
at24c02_write(0x03,5);
at24c02_write(0x04,3);
at24c02_write(0x05,4);
while(1)
{
GOTO:
IT0=1;
EX0=1;
EA=1; //經(jīng)過考慮,改密還是得設置為中斷。因為中斷可以保存和返回斷點。
if(tab_1[3]&&A==1) //而若不設置為中斷,改密程序根本無法運行。因為A的值會一直為0.
{gaimi=0;
gaimi=1;
tab_1[3]=0;
}
LCD_init(); //LCD的初始化
if(tab_1[7]) //按下輸入鍵
{tab_1[7]=0;
//LCD第一行顯示please enter the password
LCD_writecom(0x80);
for(z=0;z<25;z++)
LCD_writedat(tab_3[z]);
ceshijian_on(); //開 測時間的中斷
if(a>100)
{goto GOTO;a=0;} //如果在五秒之內(nèi),沒有輸入完整的六位數(shù),則直接跳回GOTO
//往24c02存入輸入的密碼 如果按下取消鍵,則直接跳回GOTO
jianpan();
at24c02_write(0x06,tab_1[value]);
LCD_writedat(0x2a);
if(tab_1[11])
{goto GOTO;tab_1[11]=0;}
jianpan();
at24c02_write(0x07,tab_1[value]);
LCD_writedat(0x2a);
if(tab_1[11])
{goto GOTO;tab_1[11]=0;}
jianpan();
at24c02_write(0x08,tab_1[value]);
LCD_writedat(0x2a);
if(tab_1[11])
{goto GOTO;tab_1[11]=0;}
jianpan();
at24c02_write(0x09,tab_1[value]);
LCD_writedat(0x2a);
if(tab_1[11])
{goto GOTO;tab_1[11]=0;}
jianpan();
at24c02_write(0x0a,tab_1[value]);
LCD_writedat(0x2a);
if(tab_1[11])
{goto GOTO;tab_1[11]=0;}
jianpan();
at24c02_write(0x0b,tab_1[value]);
LCD_writedat(0x2a);
if(tab_1[11])
{goto GOTO;tab_1[11]=0;}
ceshijian_off(); //關 測時間的中斷
yanzhengmima();
if(c==1)
{ switch(b)
{case(1):
{LCD_writecom(0x80);
for(z=0;z<17;z++)
LCD_writedat(tab_5[z]);
goto GOTO;
c=0;
break;
}
case(2):
{LCD_writecom(0x80);
for(z=0;z<17;z++)
LCD_writedat(tab_6[z]);
goto GOTO;
c=0;
break;
}
case(3):
{LCD_writecom(0x80);
for(z=0;z<10;z++)
LCD_writedat(tab_7[z]);
jingbao=0;
delay1h();
b=0;
c=0;
break;
}
} //蜂鳴器響起,并且一小時之內(nèi)不得再次輸入密碼 b的值將置零。
}
}
}
}
void ceshijian_on() //測輸入時間中斷開
{TMOD=0x01;
TH0=0x3c;
TL0=0xb0;
ET0=1;
TR0=1;
EA=1;
}
void ceshijian_off() //測輸入時間中斷關
{TMOD=0x01;
TH0=0x3c;
TL0=0xb0;
ET0=1;
TR0=0;
EA=0;
}
//測輸入時間用的中斷程序
time() interrupt 1
{TMOD=0x01;
TH0=0x3c;
TL0=0xb0;
a++;
} //改密碼用的中斷程序
//改密碼
void gaimima() interrupt 0
{LCD00_writecom(0x80);
for(z=0;z<25;z++)
LCD00_writedat(tab_8[z]);
jianpan00();
at24c0200_write(0x00,tab_1[value]);
LCD00_writecom(0x80);
LCD00_writedat(0x2a);
jianpan00();
at24c0200_write(0x01,tab_1[value]);
LCD00_writedat(0x2a);
jianpan00();
at24c0200_write(0x02,tab_1[value]);
LCD00_writedat(0x2a);
jianpan00();
at24c0200_write(0x03,tab_1[value]);
LCD00_writedat(0x2a);
jianpan();
at24c0200_write(0x04,tab_1[value]);
LCD00_writedat(0x2a);
jianpan00();
at24c0200_write(0x05,tab_1[value]);
LCD00_writedat(0x2a);
}
//驗證密碼
yanzhengmima()
{uint c0,c1,c2,c3,c4,c5;
if(tab_1[15])
{c0=at24c02_read(0x00)-at24c02_read(0x06);
c1=at24c02_read(0x01)-at24c02_read(0x07);
c2=at24c02_read(0x02)-at24c02_read(0x08);
c3=at24c02_read(0x03)-at24c02_read(0x09);
c4=at24c02_read(0x04)-at24c02_read(0x0a);
c5=at24c02_read(0x05)-at24c02_read(0x0b);
compare0=c0;
compare1=c1;
compare2=c2;
compare3=c3;
compare4=c4;
compare5=c5;
if(!compare0)
if(!compare1)
if(!compare2)
if(!compare3)
if(!compare4)
if(!compare5)
{LCD_writecom(0x80);
for(z=0;z<15;z++)
LCD_writedat(tab_2[z]);
A=1;
delay5s();
A=0;
b=0;
return c=0;}
else
{LCD_writecom(0x80);
for(z=0;z<16;z++)
LCD_writedat(tab_4[z]);
b++;
return c=1;
return b;
}
else
{LCD_writecom(0x80);
for(z=0;z<16;z++)
LCD_writedat(tab_4[z]);
b++;
return c=1;
return b;
}
else
{LCD_writecom(0x80);
for(z=0;z<16;z++)
LCD_writedat(tab_4[z]);
b++;
return c=1;
return b;
}
else
{LCD_writecom(0x80);
for(z=0;z<16;z++)
LCD_writedat(tab_4[z]);
b++;
return c=1;
return b;
}
else
{LCD_writecom(0x80);
for(z=0;z<16;z++)
LCD_writedat(tab_4[z]);
b++;
return c=1;
return b;
}
else
{LCD_writecom(0x80);
for(z=0;z<16;z++)
LCD_writedat(tab_4[z]);
b++;
return c=1;
return b;
}
}
}
//矩陣鍵盤輸入
jianpan()
{GPIO_jianpan=0x0f;
if(GPIO_jianpan!=0x0f)
{delay10ms();
if(GPIO_jianpan!=0x0f)
GPIO_jianpan=0x0f;
switch(GPIO_jianpan)
{case(0x07): value=0;break;
case(0x0b): value=1;break;
case(0x0d): value=2;break;
case(0x0e): value=3;break;
}
GPIO_jianpan=0xf0;
switch(GPIO_jianpan)
{case(0x70): value=value+0;break;
case(0xb0): value=value+4;break;
case(0xd0): value=value+8;break;
case(0xe0): value=value+12;break;
}
}
return value;
}
/*************************************
函數(shù)名:i2c_start()
功 能:i2c總線的起始信號 在SCL時鐘信號高電平期間SDA信號產(chǎn)生一個負跳變
輸 入:無
輸 出:無
備 注:起始之后SDA和SCL都為0
*************************************/
void i2c_start()
{ SDA=1;
delay10us();
SCL=1;
delay10us(); //此時的維持時間應該大于4.7us
SDA=0;
delay10us(); //此時的維持時間應該大于4us
SCL=0;
delay10us();
}
/*************************************
函數(shù)名:i2c_stop()
功 能:i2c總線的終止信號 在SCL時鐘信號高電平期間SDA信號產(chǎn)生一個正跳變
輸 入:無
輸 出:無
備 注:結(jié)束之后SDA和SCL都為1,表示總線空閑
*************************************/
void i2c_stop()
{ SDA=0;
delay10us();
SCL=1;
delay10us();
SDA=1;
delay10us();
}
/*************************************
函數(shù)名:i2c_write()
功 能:i2c總線的寫入信號。
輸 入:無
輸 出:無
備 注:在SCL高電平期間,SDA必須為穩(wěn)定的電平信號;反之,在SCL低電平期間,SDA才能夠進行電平轉(zhuǎn)換。
*************************************/
void i2c_write(uchar dat)
{uchar a;
for(a=0;a<8;a++)
{SDA=dat>>7;
dat=dat<<1;
delay10us();
SCL=1;
delay10us(); //建立時間大于4.7微妙
SCL=0;
delay10us(); //時間大于4us
}
}
/*************************************
函數(shù)名:i2c_read()
功 能:i2c總線的讀出信號。
輸 入:無
輸 出:無
備 注:在SCL高電平期間,SDA必須為穩(wěn)定的電平信號;反之,在SCL低電平期間,SDA才能夠進行電平轉(zhuǎn)換。
*************************************/
i2c_read()
{uchar a,dat=0;
SDA=1;
delay10us();
for(a=0;a<7;a++)
{SCL=1;
delay10us();
if(SDA==1)
dat=dat+1;
else
dat=dat+0;
dat=dat<<1;
SCL=0;
delay10us();
}
return dat;
}
/*************************************
函數(shù)名:i2c_ack()
功 能:i2c總線的應答信號。
輸 入:無
輸 出:無
備 注:數(shù)據(jù)傳輸必須帶響應。相關的響應時鐘脈沖由主機產(chǎn)生。在響應的時鐘脈沖期間,發(fā)送器釋放SDA線。在響應的時鐘脈沖期間,接收器必須將SDA線拉低,使它在這個時鐘脈沖的高定平期間保持穩(wěn)定的低電平。
*************************************/
i2c_ack()
{uint i=0;
SDA=1;
delay10us();
SCL=1;
while(SDA)
{i++;
if(i>200) //如果超過2000us沒有應答表示發(fā)送失敗,或者為非應答,表示接受結(jié)束。
{SCL=0;
delay10us();
return 0;
}
}
SCL=0;
delay10us();
return 1;
}
/*************************************
函數(shù)名:void at24c02_write()
功 能:往24c02的一個地址寫入數(shù)據(jù)
輸 入:無
輸 出:無
備 注:無
*************************************/
void at24c02_write(uchar addre,uchar dat)
{i2c_start();
i2c_write(0xa0);
i2c_ack();
i2c_write(addre);
i2c_ack();
i2c_write(dat);
i2c_ack();
i2c_stop();
}
/*************************************
函數(shù)名:void at24c02_read()
功 能:將at24c02中存儲的數(shù)據(jù)讀出來
輸 入:無
輸 出:無
備 注:無
*************************************/
at24c02_read(uchar addre)
{uchar dat;
i2c_start();
i2c_write(0xa0);
i2c_ack();
i2c_write(addre);
i2c_ack();
i2c_start();
i2c_write(0xa1);
i2c_ack();
dat=i2c_read();
i2c_stop();
return dat;
}
/*************************************
函數(shù)名:LCD_writecom(uchar com);
功 能:往LCD1602寫入命令
輸 入:無
輸 出:無
備 注:無
*************************************/
void LCD_writecom(uchar com)
{RS=0;
RW=0;
GPIO=com;
delay10us();
E=1;
delay10us();
E=0;
}
/*************************************
函數(shù)名:LCD_writedat(uchar dat);
功 能:往LCD1602寫入數(shù)據(jù)
輸 入:無
輸 出:無
備 注:無
*************************************/
void LCD_writedat(uchar dat)
{RS=1;
RW=0;
GPIO=dat;
delay10us();
E=1;
delay10us();
E=0;
}
/*************************************
函數(shù)名:LCD_init();
功 能:LCD_1602的初始化
輸 入:無
輸 出:無
備 注:無
*************************************/
void LCD_init()
{LCD_writecom(0x38);
LCD_writecom(0x0c);
LCD_writecom(0x06);
LCD_writecom(0x01);
LCD_writecom(0x80);
}
void delay10us()
{ulong i;
for(i=0;i<10;i++)
_nop_();
}
void delay5s()
{ulong i;
for(i=0;i<5000000;i++)
_nop_();
}
void delay10ms()
{uint i;
for(i=0;i<10000;i++)
_nop_();
}
void delay1h()
{ulong i;
for(i=0;i<360000000;i++)
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}
void i2c00_write(uchar dat)
{uchar a;
for(a=0;a<8;a++)
{SDA=dat>>7;
dat=dat<<1;
delay10us00();
SCL=1;
delay10us00(); //建立時間大于4.7微妙
SCL=0;
delay10us00(); //時間大于4us
}
}
/*************************************
函數(shù)名:void at24c0200_write()
功 能:往24c02的一個地址寫入數(shù)據(jù)
輸 入:無
輸 出:無
備 注:無
*************************************/
void at24c0200_write(uchar addre,uchar dat)
{i2c00_start();
i2c00_write(0xa0);
i2c00_ack();
i2c00_write(addre);
i2c00_ack();
i2c00_write(dat);
i2c00_ack();
i2c00_stop();
}
/*************************************
函數(shù)名:LCD00_writecom(uchar com);
功 能:往LCD1602寫入命令
輸 入:無
輸 出:無
備 注:無
*************************************/
void LCD00_writecom(uchar com)
{RS=0;
RW=0;
GPIO=com;
delay10us00();
E=1;
delay10us00();
E=0;
}
/*************************************
函數(shù)名:LCD00_writedat(uchar dat);
功 能:往LCD1602寫入數(shù)據(jù)
輸 入:無
輸 出:無
備 注:無
*************************************/
void LCD00_writedat(uchar dat)
{RS=1;
RW=0;
GPIO=dat;
delay10us00();
E=1;
delay10us00();
E=0;
}
//矩陣鍵盤輸入
jianpan00()
{GPIO_jianpan=0x0f;
if(GPIO_jianpan!=0x0f)
{delay10ms();
if(GPIO_jianpan!=0x0f)
GPIO_jianpan=0x0f;
switch(GPIO_jianpan)
{case(0x07): value=0;break;
case(0x0b): value=1;break;
case(0x0d): value=2;break;
case(0x0e): value=3;break;
}
GPIO_jianpan=0xf0;
switch(GPIO_jianpan)
{case(0x70): value=value+0;break;
case(0xb0): value=value+4;break;
case(0xd0): value=value+8;break;
case(0xe0): value=value+12;break;
}
}
return value;
}
void delay10us00()
{ulong i;
for(i=0;i<10;i++)
_nop_();
}
i2c00_ack()
{uint i=0;
SDA=1;
delay10us00();
SCL=1;
while(SDA)
{i++;
if(i>200) //如果超過2000us沒有應答表示發(fā)送失敗,或者為非應答,表示接受結(jié)束。
{SCL=0;
delay10us00();
return 0;
}
}
SCL=0;
delay10us00();
return 1;
}
/*************************************
函數(shù)名:i2c_start()
功 能:i2c總線的起始信號 在SCL時鐘信號高電平期間SDA信號產(chǎn)生一個負跳變
輸 入:無
輸 出:無
備 注:起始之后SDA和SCL都為0
*************************************/
void i2c00_start()
{ SDA=1;
delay10us00();
SCL=1;
delay10us00(); //此時的維持時間應該大于4.7us
SDA=0;
delay10us00(); //此時的維持時間應該大于4us
SCL=0;
delay10us00();
}
/*************************************
函數(shù)名:i2c00_stop()
功 能:i2c總線的終止信號 在SCL時鐘信號高電平期間SDA信號產(chǎn)生一個正跳變
輸 入:無
輸 出:無
備 注:結(jié)束之后SDA和SCL都為1,表示總線空閑
*************************************/
void i2c00_stop()
{ SDA=0;
delay10us00();
SCL=1;
delay10us00();
SDA=1;
delay10us00();
}
|