01
设计要求
(1)密码为6位长度,初始值是111111。有三次登陆机会,每错一次,红灯及蜂鸣器各亮、响一秒,液晶显示错误信息。错三次后,禁止再登陆。正确登陆后绿灯亮。
(2)可修改密码,但须先正确输入原密码。设置新密码需连续正确输入两次,同时密码须有相应格式,如密码需8位数字。(其余格式,如不能连续8位相同数字、符号*#可作为密码等可根据情况自行设置)。
(3)输入密码时可用*显示已输入密码,用-表示未输入的部分。可设删除按键,可以删除所输入的数字;有取消按键,可以取消修改密码,取消登陆等功能。
02
程序
#include<reg52.h>
#include<intrins.h>
#include "stdio.h"
#include "string.h"
#define uchar unsigned char
#define uint unsigned int
// 定义LCD引脚
sbit LCM_RW=P2^5;
sbit LCM_RS=P2^6;
sbit LCM_E=P2^7;
#define LCM_Data P0
// 用于检测LCM状态字中的Busy标识
#define Busy 0x80
// 按键定义
sbit K1=P1^0;
sbit K2=P1^1;
sbit K3=P1^2;
sbit K4=P1^3;
sbit K5=P1^4;
sbit K6=P1^5;
sbit K7=P1^6;
sbit K8=P1^7;
sbit red=P2^0;
sbit green=P2^1;
sbit beep=P2^2;
void LCMInit(void);
void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData);
void DisplayListChar(unsigned char X, unsigned char Y, unsigned char code *DData);
void WriteDataLCM(unsigned char WDLCM);
void WriteCommandLCM(unsigned char WCLCM,BuysC);
unsigned char ReadDataLCM(void);
unsigned char ReadStatusLCM(void);
void Delay5Ms(void);
void keyscan();
void xianshi();
void keyscan1();
void xianshi1();
void T0_init();
uchar jiance_geshi(uchar *a);
unsigned char code shuru[] ={"shuru:"};
unsigned char code right[] = {"right"};
unsigned char code error[] = {"error"};
unsigned char code fail[] = {" fail "};
unsigned char code kongbai[] ={" "};
unsigned char code g1[] = "------";
uchar mima_chushi[6]="111111";
uchar mima[6]="";
uchar mima_xiu[6]="";
// 变量的定义
uchar mima_num;
uchar flag_num,flag_correct,flag_xiugai,flag_error,flag_xiu1,flag_xiu2,flag_quxiao;
// 5ms延时
void Delay5Ms(void)
{
unsigned int TempCyc = 5552;
while(TempCyc--);
}
void delay(unsigned int i)
{
unsigned int j;
unsigned char k;
for(j=i;j>0;j--)
for(k=125;k>0;k--);
}
// 写数据
void WriteDataLCM(unsigned char WDLCM)
{
// 检测忙
ReadStatusLCM();
LCM_Data = WDLCM;
LCM_RS = 1;
LCM_RW = 0;
// 若晶振速度太高可以在这后加小的延时
LCM_E = 0;
// 延时
LCM_E = 0;
LCM_E = 1;
}
// 写指令
// BuysC为0时忽略忙检测
void WriteCommandLCM(unsigned char WCLCM, BuysC)
{
// 根据需要检测忙
if (BuysC) ReadStatusLCM();
LCM_Data = WCLCM;
LCM_RS = 0;
LCM_RW = 0;
LCM_E = 0;
LCM_E = 0;
LCM_E = 1;
}
// 读数据
unsigned char ReadDataLCM(void)
{
LCM_RS = 1;
LCM_RW = 1;
LCM_E = 0;
LCM_E = 0;
LCM_E = 1;
return(LCM_Data);
}
// 读状态
unsigned char ReadStatusLCM(void)
{
LCM_Data = 0xFF;
LCM_RS = 0;
LCM_RW = 1;
LCM_E = 0;
LCM_E = 0;
LCM_E = 1;
// 检测忙信号
while (LCM_Data & Busy);
return(LCM_Data);
}
// LCM初始化
void LCMInit(void)
{
LCM_Data = 0;
// 三次显示模式设置,不检测忙信号
WriteCommandLCM(0x38,0);
Delay5Ms();
WriteCommandLCM(0x38,0);
Delay5Ms();
WriteCommandLCM(0x38,0);
Delay5Ms();
WriteCommandLCM(0x38,1); // 显示模式设置,开始要求每次检测忙信号
WriteCommandLCM(0x08,1); // 关闭显示
WriteCommandLCM(0x01,1); // 显示清屏
WriteCommandLCM(0x06,1); // 显示光标移动设置
WriteCommandLCM(0x0C,1); // 显示开及光标设置
}
// 按指定位置显示一个字符
void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData) //Y 为1 则是第二行
{
Y &= 0x1;
X &= 0xF; // 限制X不能大于15,Y不能大于1
if (Y) X |= 0x40; // 当要显示第二行时地址码+0x40;
X |= 0x80; // 算出指令码
WriteCommandLCM(X, 1); //发命令字
WriteDataLCM(DData); //发数据
}
// 按指定位置显示一串字符
void DisplayListChar(unsigned char X, unsigned char Y, unsigned char code *DData)
{
unsigned char ListLength;
ListLength = 0;
Y &= 0x1;
X &= 0xF;
// 限制X不能大于15,Y不能大于1
//若到达字串尾则退出
while (DData[ListLength]>0x19)
{
// X坐标应小于0xF
if (X <= 0xF)
{
// 显示单个字符
DisplayOneChar(X, Y, DData[ListLength]);
ListLength++;
X++;
}
}
}
void qing_shuzu(uchar *a)
{
uchar i,length;
length=strlen(a);
for(i=0;i<length;i++)
a[i]=0;
}
/*中断服务特殊功能寄存器配置*/
void T0_init()
{
TMOD = 0x01; //定时器16为计数工作模式
TH0 =0x4b;
TL0 =0xfd; //50ms
ET0 = 1; //开定时器0中断
TR0 = 0;//启动定时器0
EA = 1; //开总中断
}
void keyscan()
{
if(K1==0)
{
delay(10);//延时10ms消除按键抖动
if(K1==0)
{
while(!K1);//若k1键确实按下,则等待k1释放
mima[mima_num]='1';
mima_num++;
delay(5);
}
}
if(K2==0)
{
delay(10);//延时10ms消除按键抖动
if(K2==0)
{
while(!K2);//若k2键确实按下,则等待k2释放
mima[mima_num]='2';
mima_num++;
delay(5);
}
}
if(K3==0)
{
delay(10);//延时10ms消除按键抖动
if(K3==0)
{
while(!K3);//若k3键确实按下,则等待k3释放
mima[mima_num]='3';
mima_num++;
delay(5);
}
}
if(K4==0)
{
delay(10);//延时10ms消除按键抖动
if(K4==0)
{
while(!K4);//若k4键确实按下,则等待k4释放
mima[mima_num]='4';
mima_num++;
delay(5);
}
}
if(K5==0) //删除键
{
delay(10); //软件消抖
if(K5==0)
{
mima_num--;
while(!K5); //松手检测
}
}
}
void xianshi()
{
uchar i;
for(i=0;i<mima_num;i++)
{
DisplayOneChar(i+6,0,'*');
}
for(i=mima_num;i<6;i++)
{
DisplayOneChar(i+6,0,'-');
}
}
/********************功能键扫描 显示*******************************/
void keyscan1()
{
if(K8==0) //取消登陆 键
{
delay(5); //软件消抖
if(K8==0)
{
flag_correct=0; //跳出登陆
while(!K8); //松手检测
}
}
if(K6==0) //修改密码
{
delay(5); //软件消抖
if(K6==0)
{
DisplayListChar(0, 1, " first :");
DisplayListChar(9, 1, g1); //显示----
flag_xiugai=1;
while(!K6); //松手检测
}
}
if(K7==0) //取消 修改密码
{
delay(5); //软件消抖
if(K7==0)
{
flag_xiugai=0;
mima_num=0;
flag_quxiao=1;
while(!K7); //松手检测
}
}
}
void xianshi1()
{
uchar i;
for(i=0;i<mima_num;i++)
{
DisplayOneChar(i+9,1,'*');
}
for(i=mima_num;i<6;i++)
{
DisplayOneChar(i+9,1,'-');
}
}
void luoji_xianshi()
{
//static uchar fa=0;
if(mima_num==0 && flag_num!=3 )
{
DisplayListChar(6, 0, g1); //显示----
//fa=1;
}
/*if(mima_num==1 && flag_num!=3)
{
DisplayListChar(0, 1, kongbai); //清掉错误信息
}*/
if(flag_num==3)
{
DisplayListChar(0, 1, fail); //禁止登陆
while(1); //程序卡死
}
}
uchar jiance_geshi(uchar *a) //0 表示检查 不通过
{
uchar i,length,flag;
flag=0;
length=strlen(a);
for(i=1;i<length;i++)
{if(*(a+i)==(*a))
flag++;
}
if(flag>4)
{
return 0;
}
else return 1;
}
void main()
{
mima_num=0;
flag_xiu2=0;
beep=0;
T0_init();
LCMInit();
DisplayListChar(0, 0, shuru);
DisplayListChar(6, 0, g1);
while(1)
{
if(flag_xiu2==1) //
{
WriteCommandLCM(0x01,1); //显示清屏
DisplayListChar(0, 0, shuru);
DisplayListChar(6, 0, g1);
flag_xiu2=0;
}
keyscan();
xianshi();
if(mima_num==6) //6位输完 开始检测
{
if(strcmp(mima,mima_chushi)==1) //strcmp
{
DisplayListChar(0, 1, error);//错误 strcmp为1 因为mima_chushi 在code区
red=0;
beep=1;
flag_num++; //错误次数
mima_num=0;
TR0=1;
}
else
{
green=0;
TR0=1; //开启定时器
mima_num=0;
flag_correct=1;
}
}
luoji_xianshi();
if(flag_correct)
{WriteCommandLCM(0x01,1); //显示清屏
DisplayListChar(0, 0, right);}
else DisplayListChar(0, 0, shuru);
while(flag_correct) //进入登陆装填
{
if(flag_xiu2==0){
keyscan1();
if(flag_quxiao) //修改密码取消按键
{
DisplayListChar(0,1,kongbai);
flag_quxiao=0;
}
if(flag_xiugai==1)
{
keyscan();
xianshi1();
if(mima_num==6)
{
if(!jiance_geshi(mima)) //检测密码是否符合格式 1表示符合
{
DisplayListChar(9, 0, error); //0 不符合 才显示错误
flag_xiugai=0;
qing_shuzu();
}
else
{
DisplayListChar(0, 1, " second:" );
strcpy(mima_xiu,mima); //符合进入下一步
flag_xiu1=1;
mima_num=0; //为下一次保存密码准备
while(flag_xiu1)
{
keyscan();
xianshi1();
if(mima_num==6)
{
if(strcmp(mima,mima_xiu)==0) //strcmp 比较这两次密码是否一致
{
strcpy(mima_chushi,mima);
flag_xiu1=0;
delay(1000);
mima_num=0;
flag_xiugai=0;
flag_xiu2=1;
}
else
{
DisplayListChar(6, 0, "mistake ");
flag_xiu1=0;
mima_num=0;
flag_xiugai=0;
}
}
}
}
}
}
}
}
}
}
/*中断服务程序*/
void timer0() interrupt 1
{
uchar count;
TH0 =0x4b;
TL0 =0xfd; //50ms
count++;
if (count == 20) //1S
{
count=0;
red=1;
beep=0;
green=1;
TR0=0;
}
}
03
具体操作流程、源码、原理图百度网盘链接:
链接:https://pan.baidu.com/s/1hrss6_tFSxNTgNKiGJiclg
提取码:xxzk