#include
#include "intrins.h"
#define uchar unsigned char
#define uint unsigned int
#define KeyPort P0 //外接键盘,低四位接行,高四位接列
uchar KEY_TABLE[16] =
{
0xEE, 0xDE, 0xBE, 0x7E,
0xED, 0xDD, 0xBD, 0x7D,
0xEB, 0xDB, 0xBB, 0x7B,
0xE7, 0xD7, 0xB7, 0x77
};
int flag1=0; //修改密码标志位
uchar num,i=0,j;
uchar passwordtemp[16],password[16]={'1','2','3','4'},newpassword[16]; //输入的密码,默认的密码
uchar inputtimes; //密码输入错误次数
uint n,m; //输入密码长度,实际密码长度
bit Flag=0;\
uchar light,light1=0,light2=0xf0; //设置成功,开锁,错误,
sbit SCL = P1^0;
sbit SDA = P1^1;
char ADDR = 0x4e; // PCF8574 T 模块的地址码
//char ADDR = 0x7e; // PCF8574 AT 模块的地址码
//***************************** 延时 y ms ***********************************************
void delay1(int y) //
{
;
while(y--)
{
unsigned char a,b,c;
for(c=1;c>0;c--)
for(b=142;b>0;b--)
for(a=2;a>0;a--);
}
}
//******************************** IIC 串口开始 ********************************************
void IIC_start(void)
{
SDA=1;
_nop_();
SCL=1;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
SDA=0;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
SCL=0;
_nop_();
_nop_();
}
//********************************** IIC 串口写1个字节 ******************************************
void IIC_writeByte(char temp)
{
char i;
for(i=0;i<8;i++)
{
SDA=(bit)(temp & 0x80) ; // 根据规定1602的数据最高位必须为 1
temp <<=1;
_nop_();
_nop_();
SCL=1;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
SCL=0;
}
_nop_();
_nop_();
_nop_();
_nop_();
SDA=1;
_nop_();
_nop_();
_nop_();
_nop_();
SCL=1;
_nop_();
_nop_();
_nop_();
while(SDA);
_nop_();
SCL=0;
}
//******************************** 1602写命令 ********************************************
void LCD_write_command(char comm)
{
char tmp;
IIC_start(); // 串口开始
IIC_writeByte(ADDR); // 先选PCF 8574T 的地址 (应该是相当于选中的意思吧)
tmp = comm & 0xF0; // 与0xf0 应该是取第四位的意思吧
tmp |= 0x0C; //保留高4位为指令的高四位,低四位为 RS = 0, RW = 0, EN = 1
IIC_writeByte(tmp); //从串口送出
delay1(20);
tmp &= 0xFB; //Make EN = 0
IIC_writeByte(tmp);
tmp = (comm & 0x0F) << 4 ; //将指令的低四位 送到高位置保存
tmp |= 0x0C; //RS = 0, RW = 0, EN = 1
IIC_writeByte(tmp);
delay1(20);
tmp &= 0xFB; // Make EN = 0
IIC_writeByte(tmp);
}
//******************************** 1602写数据 ********************************************
void LCD_write_data(char data1)
{
char tmp;
IIC_start();
IIC_writeByte(ADDR); // 先选PCF 8574T 的地址 (应该是相当于选中的意思吧)
tmp = data1 & 0xF0;
tmp |= 0x0D; //RS = 1, RW = 0, EN = 1
IIC_writeByte(tmp);
delay1(20);
tmp &= 0xFB; //Make EN = 0
IIC_writeByte(tmp);
tmp = (data1 & 0x0F) << 4 ;
tmp |= 0x0D; //RS = 0, RW = 0, EN = 1
IIC_writeByte(tmp);
delay1(20);
tmp &= 0xFB ; // Make EN = 0
IIC_writeByte(tmp);
}
//******************************** 1602初始化 ********************************************
void Init_Lcd(void)
{
LCD_write_command(0x33); //将8位总线转为4位总线
delay1(50) ;
LCD_write_command(0x32); //
delay1(50) ;
LCD_write_command(0x28); // 4位数据线,显示2行,5*7点阵字符 !如果是0x38 则为8位数据线,显示2行,5*7点阵字符
delay1(50) ;
LCD_write_command(0x0C); // 开显示,关闭光标,不闪烁
delay1(50) ;
LCD_write_command(0x06); // 设定输入方式,增量不位移
delay1(50) ;
LCD_write_command(0x01); // 清屏
delay1(50) ;
}
//*************************************** 在指定位置显示字符串 *************************************
void Write_LCD(int x, int y, char *str)
{
char addr;
if( x < 0)
{
x = 0;
}
if(x > 15)
{
x = 15;
}
if(y<0)
{
y = 0;
}
if(y > 1)
{
y = 1;
}
addr = 0x80 + 0x40 * y + x; // Move cursor 移动光标
LCD_write_command(addr);
while (*str)
{
LCD_write_data(*str++);
}
}
//-------------------------------------------- 显示字符串的函数 ----------------------------------------------------
void LCD_write_word(unsigned char *s) //显示字符串的函数
{
while(*s>0)
{
LCD_write_data(*s);
s++;
}
}
//********************************* 指定位置显示一个字符*******************************************
/*
void Print_Char (unsigned char line,unsigned char num,unsigned char date)
{
LCD_write_command(line+num);
LCD_write_data(date);
}
*/
//按指定位置显示一个字符(针对1602液晶)-用在温度显示
void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData)
{
Y &= 0x1;
X &= 0xF; //限制X不能大于15,Y不能大于1
if (Y) X |= 0x40; //当要显示第二行时地址码+0x40;
X |= 0x80; // 算出指令码
LCD_write_command(X); //这里不检测忙信号,发送地址码
LCD_write_data(DData);
}
//--------------------------------------初始化----------------------------------------------------------------
void initial()
{
P1M0=0;
P1M1=0;
P2M0=0;
P2M1=0;
P0M0=0;
P0M1=0;
}
/*------------------------------------------------
按键扫描函数,返回扫描键值
------------------------------------------------*/
unsigned char KeyScan(void) //键盘扫描函数,使用行列反转扫描法
{
uchar cord_h,cord_l; //行列值中间变量
uchar tempt;
uint i;
KeyPort=0xf0; //列线输出全为0
cord_l=KeyPort&0xf0; //读入行线值
if(cord_l!=0xf0) //先检测有无按键按下
{
delay1(10); //去抖
if(cord_l!=0xf0)
{
cord_l=KeyPort&0xf0; //读入列线值
KeyPort=0x0f; //行线输出为0
cord_h=KeyPort&0x0f; //读入行线值
while((KeyPort&0x0f)!=0x0f);//等待松开并输出
tempt = cord_l+cord_h;
for(i=0;i<16;i++)
if(KEY_TABLE[i]==tempt)
break;
return(KEY_TABLE[i]);
}
}
return(0xff); //返回该值
}
/*------------------------------------------------
按键值处理函数,返回扫键值
------------------------------------------------*/
unsigned char KeyPro(void)
{
switch(KeyScan())
{
case 0xee:return '0';break;//0 按下相应的键显示相对应的码值
case 0xde:return '1';break;//1
case 0xbe:return '2';break;//2
case 0x7e:return '3';break;//3
case 0xed:return '4';break;//4
case 0xdd:return '5';break;//5
case 0xbd:return '6';break;//6
case 0x7d:return '7';break;//7
case 0xeb:return '8';break;//8
case 0xdb:return '9';break;//9
case 0xbb:return 'a';break;//a
case 0x7b:return 'b';break;//b
case 0xe7:return 'c';break;//c
case 0xd7:return 'd';break;//d
case 0xb7:return 'e';break;//e
case 0x77:return 'f';break;//f
default:return 0xff;break;
}
}
//--------------------------------------------------------流水灯--------------------------------------------------------
void RuningLight() //流水灯
{
light=0xfe;
P2=light;
for(j=0;j<8;j++)
{ light<<=1 ;
delay1(250);
P2=light;
}
P2=0xff;
}
//--------------------------------------------------------密码验证--------------------------------------------------------
void VriefytPassword() //验证密码
{ if(flag1)
m=sizeof(newpassword); //记录新密码的长度
else
m=sizeof(password); //记录旧密码的长度
n=sizeof(passwordtemp); //记录输入密码的长度
if(m==n) //长度判断
{
if(flag1) //修改密码后
for(j=0;j
{ if(passwordtemp[j]==newpassword[j])
Flag=0;
else
{ Flag=1;
break;
}
}
else //修改密码前
for(j=0;j
{ if(passwordtemp[j]==password[j])
Flag=0;
else
{ Flag=1;
break;
}
}
}
else
{ Flag=1;
Write_LCD(0,1," "); //清除该行
delay1(10);
Write_LCD(0,1,"Wrong length!"); //密码正确显示的信息
delay1(10);
}
if(Flag) //输入错误提示和输入错误总次数判断,限定三次
{
Write_LCD(0,1," "); //清除该行
delay1(10);
Write_LCD(0,1,"Wrong Retry!"); //输入错误提示
for(j=0;j
passwordtemp[j]='\0';
inputtimes++; //连续输入错误,则次数累加
i=0;
if(inputtimes==3)
{
Write_LCD(0,1," ");//清除该行
delay1(10);
Write_LCD(0,1,"Wrong 3 times!");//密码错误,提示重新输入
while(1)
P2=light2; //停止该位置,重启电源后才能输入,实际实用中则需要等到一定时间后才能再次输入。
}
}
else
{
Write_LCD(0,1," ");//清除该行
delay1(10);
Write_LCD(0,1,"Right Open!>>>>");//密码正确显示的信息
P2=light1;
inputtimes=0;//输入正确则次数清零,重新计数
Flag=0; //清除正确标志
i=0;
}
}
//--------------------------------------------------------修改密码时的密码验证--------------------------------------------------------
void SetPassword() //设置新密码时,先验证
{ while(1)
{ num=KeyPro(); //扫描键盘
if(num!=0xff) //如果扫描是按键有效值则进行处理
{
if(i==0)
Write_LCD(0,1," ");//清除该行
if(num=='f') //确定键按下,进入判断密码对错
{
i=0;
if(flag1)
m=sizeof(newpassword);
else
m=sizeof(password);
n=sizeof(passwordtemp);
if(m==n) //长度判断
{ if(flag1)
for(j=0;j
{ if(passwordtemp[j]==newpassword[j])
Flag=0;
else
{ Flag=1;
break;
}
}
for(j=0;j
{ if(passwordtemp[j]==password[j])
Flag=0;
else
{ Flag=1;
break;
}
}
}
else
{ Flag=1;
Write_LCD(0,1," "); //清除该行
delay1(10);
Write_LCD(0,1,"Wrong length!"); //密码正确显示的信息
delay1(10);
i=0;
P2=light2;
inputtimes++;
}
if(Flag) //输入错误提示和输入错误总次数判断,限定三次
{
Write_LCD(0,1," "); //清除该行
delay1(10);
Write_LCD(0,1,"Wrong Retry!"); //密码错误
for(j=0;j
passwordtemp[j]='\0';
inputtimes++; //连续输入错误,则次数累加
if(inputtimes==3)
{
Write_LCD(0,1," ");//清除该行
delay1(10);
Write_LCD(0,1,"Wrong 3 times!");//密码错误,提示重新输入
while(1)
P2=light2; //停止该位置,重启电源后才能输入,实际实用中则需要等到一定时间后才能再次输入。
}
}
else
{
Write_LCD(0,1," ");//清除该行
delay1(10);
Write_LCD(0,1,"Right Password!");//密码正确
RuningLight();
i=0;
inputtimes=0;//输入正确则次数清零,重新计数
Flag=0; //清除正确标志
break;
}
}
else //没有按确定键,保存键值
{
if(i<16)
{
passwordtemp[i]=num; //保存密码
DisplayOneChar(i,1,num); //输入的密码用"*"代替
i++; //计数,不能超过16位
}
else
{ Write_LCD(0,1," ");//清除该行
delay1(10);
Write_LCD(0,1,"Too Many Retry");
inputtimes++;
i=0;
P2=light2;
}
}
}
}
}
//--------------------------------------------------------新密码输入--------------------------------------------------------
void NewPasswordInput() //新密码输入
{
while(1)
{ num=KeyPro(); //扫描键盘
if(num!=0xff) //如果扫描是按键有效值则进行处理
{
if(i==0)
Write_LCD(0,1," ");//清除该行
if(num=='f')
{ i=0;
RuningLight();
break;
}
else if(i<16) //新密码不能超过16位
{
newpassword[i]=num; //保存密码
DisplayOneChar(i,1,num); //显示新密码
i++; //计数,不能超过16位
}
else
{ i=0;
Write_LCD(0,1," "); //清除该行
delay1(10);
Write_LCD(0,1,"Too Many Retry"); //输入过多,报错
delay1(10);
for(j=0;j
newpassword[j]='\0';
P2=light2;
Write_LCD(0,1," "); //清除该行
delay1(10);
Write_LCD(0,1,"new password!"); //重新输入新密码
delay1(10);
}
}
}
}
//--------------------------------------------------------确认修改的密码--------------------------------------------------------
void AgainInput() //新密码确认
{
while(1)
{
num=KeyPro(); //扫描键盘
if(num!=0xff) //如果扫描是按键有效值则进行处理
{ if(i==0)
Write_LCD(0,1," ");//清除该行
if(num=='f')
{
i=0;
n=sizeof(passwordtemp);
m=sizeof(newpassword);
if(m==n) //长度判断
{
for(j=0;j
{ if(passwordtemp[j]==newpassword[j])
Flag=0;
else
{ Flag=1;
break;
}
}
}
else
Flag=1;
if(Flag) //输入错误提示和输入错误总次数判断,限定三次
{
Write_LCD(0,1," "); //清除该行
delay1(10);
Write_LCD(0,1,"Difference!!"); //密码正确显示的信息
for(j=0;j
passwordtemp[j]='\0';
i=0;
Flag=0;
P2=light2;
}
else
{
Write_LCD(0,1," ");//清除该行
delay1(10);
Write_LCD(0,1,"Right!"); //密码正确显示的信息
delay1(10);
Write_LCD(0,1," ");//清除该行
delay1(10);
Write_LCD(0,1,"Finish!");
RuningLight();
Write_LCD(0,1," ");//清除该行
delay1(10);
Write_LCD(0,1,"Right Open>>>");//清除该行
P2=light1;
inputtimes=0;//输入正确则次数清零,重新计数
Flag=0; //清除正确标志
i=0;
break;
}
}
else if(i<16) //密码不能超过16位
{
passwordtemp[i]=num; //保存密码
DisplayOneChar(i,1,num); //显示新密码
i++; //计数,不能超过16位
}
else
{ Write_LCD(0,1," "); //清除该行
delay1(10);
Write_LCD(0,1,"Too Many Retry"); //输入过多,报错
delay1(10);
for(j=0;j
passwordtemp[j]='\0';
i=0; //重新输入
P2=light2;
Write_LCD(0,1," "); //清除该行
delay1(10);
Write_LCD(0,1,"Input New Again!"); //重新输入新密码
delay1(10);
}
}
}
}
//--------------------------------------------------------主函数--------------------------------------------------------
void main()
{
initial();
Init_Lcd(); //初始化液晶屏
delay1(10); //延时用于稳定,可以去掉
Write_LCD(0,0," Welcome! "); //写入第一行信息,主循环中不再更改此信息,所以在while之前写入
delay1(10);
Write_LCD(0,1,"Input password!"); //写入第二行信息,提示输入密码
delay1(10);
while (1) //主循环
{
num=KeyPro(); //扫描键盘
if(num!=0xff) //如果扫描是按键有效值则进行处理
{
if(i==0)
Write_LCD(0,1," "); //清除该行
if(num=='e') //设置新密码
{ P2=0xff;
for(j=0;j
newpassword[j] = '\0';
Write_LCD(0,1,"Set Password!");
delay1(10);
Write_LCD(0,1," "); //清除该行
delay1(10);
Write_LCD(0,1,"Input Password!"); //用户验证
delay1(10);
SetPassword(); //验证密码
P2=0xff;
Write_LCD(0,1," "); //清除该行
delay1(10);
Write_LCD(0,1,"New Password!"); //新密码输入
delay1(10);
NewPasswordInput(); //新密码输入
P2=0xff;
Write_LCD(0,1," ");
delay1(10);
Write_LCD(0,1,"Again Input!!");
AgainInput(); //新密码确认
for(j=0;j
passwordtemp[j] = '\0';
flag1=1; //修改密码标志位
}
else if(num=='f') //确定键按下,进入判断密码对错
{ i=0; //清除输入标志
VriefytPassword(); //密码认证
}
else if(num=='b') //上锁
{
P2=0xff;
delay1(10);
Write_LCD(0,1," "); //清除该行
delay1(10);
Write_LCD(0,1,"Input password!");
i=0;
for(j=0;j
passwordtemp[j] ='\0';
}
else //没有按确定键,上锁键,设置键,保存键值
{
if(i<16)
{
passwordtemp[i]=num; //保存密码
DisplayOneChar(i,1,num); //输入的密码用"*"代替
i++; //计数,不能超过16位
}
else
{ Write_LCD(0,1," ");//清除该行
delay1(10);
Write_LCD(0,1,"Too Many Retry");
inputtimes++;
i=0;
}
}
}
}
}