第一张图贴出来的是生成目标文件时的提醒。第二张图片是我用的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; //记录经历过多少个五十毫秒
uint b=0; //记录输错密码的次数
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,说明开始执行改密程序(外部中断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; //经过考虑,改密还是得设置为中断。因为中断可以保存和返回断点。
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;} //如果在五秒之内,没有输入完整的六位数,则直接跳回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;
}
} //蜂鸣器响起,并且一小时之内不得再次输入密码 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;
}
/*************************************
函数名:i2c_start()
功 能:i2c总线的起始信号 在SCL时钟信号高电平期间SDA信号产生一个负跳变
输 入:无
输 出:无
备 注:起始之后SDA和SCL都为0
*************************************/
void i2c_start()
{ SDA=1;
delay10us();
SCL=1;
delay10us(); //此时的维持时间应该大于4.7us
SDA=0;
delay10us(); //此时的维持时间应该大于4us
SCL=0;
delay10us();
}
/*************************************
函数名:i2c_stop()
功 能:i2c总线的终止信号 在SCL时钟信号高电平期间SDA信号产生一个正跳变
输 入:无
输 出:无
备 注:结束之后SDA和SCL都为1,表示总线空闲
*************************************/
void i2c_stop()
{ SDA=0;
delay10us();
SCL=1;
delay10us();
SDA=1;
delay10us();
}
/*************************************
函数名:i2c_write()
功 能:i2c总线的写入信号。
输 入:无
输 出:无
备 注:在SCL高电平期间,SDA必须为稳定的电平信号;反之,在SCL低电平期间,SDA才能够进行电平转换。
*************************************/
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
}
}
/*************************************
函数名:i2c_read()
功 能:i2c总线的读出信号。
输 入:无
输 出:无
备 注:在SCL高电平期间,SDA必须为稳定的电平信号;反之,在SCL低电平期间,SDA才能够进行电平转换。
*************************************/
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;
}
/*************************************
函数名:i2c_ack()
功 能:i2c总线的应答信号。
输 入:无
输 出:无
备 注:数据传输必须带响应。相关的响应时钟脉冲由主机产生。在响应的时钟脉冲期间,发送器释放SDA线。在响应的时钟脉冲期间,接收器必须将SDA线拉低,使它在这个时钟脉冲的高定平期间保持稳定的低电平。
*************************************/
i2c_ack()
{uint i=0;
SDA=1;
delay10us();
SCL=1;
while(SDA)
{i++;
if(i>200) //如果超过2000us没有应答表示发送失败,或者为非应答,表示接受结束。
{SCL=0;
delay10us();
return 0;
}
}
SCL=0;
delay10us();
return 1;
}
/*************************************
函数名:void at24c02_write()
功 能:往24c02的一个地址写入数据
输 入:无
输 出:无
备 注:无
*************************************/
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();
}
/*************************************
函数名:void at24c02_read()
功 能:将at24c02中存储的数据读出来
输 入:无
输 出:无
备 注:无
*************************************/
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;
}
/*************************************
函数名:LCD_writecom(uchar com);
功 能:往LCD1602写入命令
输 入:无
输 出:无
备 注:无
*************************************/
void LCD_writecom(uchar com)
{RS=0;
RW=0;
GPIO=com;
delay10us();
E=1;
delay10us();
E=0;
}
/*************************************
函数名:LCD_writedat(uchar dat);
功 能:往LCD1602写入数据
输 入:无
输 出:无
备 注:无
*************************************/
void LCD_writedat(uchar dat)
{RS=1;
RW=0;
GPIO=dat;
delay10us();
E=1;
delay10us();
E=0;
}
/*************************************
函数名: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
}
}
/*************************************
函数名:void at24c0200_write()
功 能:往24c02的一个地址写入数据
输 入:无
输 出:无
备 注:无
*************************************/
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();
}
/*************************************
函数名:LCD00_writecom(uchar com);
功 能:往LCD1602写入命令
输 入:无
输 出:无
备 注:无
*************************************/
void LCD00_writecom(uchar com)
{RS=0;
RW=0;
GPIO=com;
delay10us00();
E=1;
delay10us00();
E=0;
}
/*************************************
函数名:LCD00_writedat(uchar dat);
功 能:往LCD1602写入数据
输 入:无
输 出:无
备 注:无
*************************************/
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没有应答表示发送失败,或者为非应答,表示接受结束。
{SCL=0;
delay10us00();
return 0;
}
}
SCL=0;
delay10us00();
return 1;
}
/*************************************
函数名:i2c_start()
功 能:i2c总线的起始信号 在SCL时钟信号高电平期间SDA信号产生一个负跳变
输 入:无
输 出:无
备 注:起始之后SDA和SCL都为0
*************************************/
void i2c00_start()
{ SDA=1;
delay10us00();
SCL=1;
delay10us00(); //此时的维持时间应该大于4.7us
SDA=0;
delay10us00(); //此时的维持时间应该大于4us
SCL=0;
delay10us00();
}
/*************************************
函数名:i2c00_stop()
功 能:i2c总线的终止信号 在SCL时钟信号高电平期间SDA信号产生一个正跳变
输 入:无
输 出:无
备 注:结束之后SDA和SCL都为1,表示总线空闲
*************************************/
void i2c00_stop()
{ SDA=0;
delay10us00();
SCL=1;
delay10us00();
SDA=1;
delay10us00();
}
|