C51单片机学习——密码锁的实现
- 说在前面:因为我的板子是液晶屏和数码管不能同时用,所以下面我使用的是液晶屏,下面的代码通俗易懂也有注释,如果有的控件不知到如何使用的可以查看我之前的几篇C51文章,这个密码锁就是基于之前的笔记所写的内容
#include
//#include
#define uint unsigned int
#define uchar unsigned char
#define data1602 P0
#define LED P2
/*******引脚定义*******/
//按键的控制引脚
sbit S1 = P3^7;
sbit S2 = P3^6;
sbit S3 = P3^5;
sbit S4 = P3^4;
sbit S5 = P3^3;
sbit S6 = P3^2;
//LCD1602的控制引脚
sbit RS = P1^0;
sbit RW = P1^1;
sbit E = P1^2;
sbit BF = data1602^7; //BF表示data1602的最高位,判断是忙还是闲
sbit Alam = P1^5;//蜂鸣器引脚
//sbit key = P3^3;//开锁
bit isInitPass = 1;//是否在初始化密码
bit pass=0; //密码正确标志
bit isReset = 0; //是否在重设密码
uchar countNum = 0; //选择数字位数
uchar countPass = 1;//输入密码位数
uchar ErrorCont = 0; //错误次数计数
uchar timeNum=0; //计时间次数
uchar trueTime='5'; // 锁定时间
//液晶显示数据数组
uchar code initLock1[] = {" Welcome to "};
uchar code initLock2[] = {" password lock "};
uchar code SetNew[] = {"==SetPassword== "};
uchar code Input[] = {"input: "}; //INPUT
uchar code start_line1[] = {"==please input=="};
uchar code start_line2[] = {"password: "};
uchar code superPassword[] = {"=Super Password="};
uchar code Correct[] = {" correct "}; //输入正确
uchar code Error[] = {" error "}; //输入错误
uchar code codepass[] = {" pass "};
uchar code LockOpen[] = {" open "}; //OPEN
uchar code Reset[] = {"=ResetPassword= "};
uchar code oldPassword[] = {"please input old"}; //输入旧密码
uchar code setOK[] = {"Set Password OK "};
uchar code NULL[] = {" "};
uchar code ResetOK[] = {"ResetPasswordOK!"};
uchar code initword[] = {"Init password..."};
uchar code ErrorTry[] = {"error,try again!"};
uchar code again[] = {"input again "};
uchar code wait[] = {"please wait s "};
uchar code table[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//流水灯
uchar InitPassword[6]={'0','0','0','0','0','0'}; //初始化密码暂存数组
uchar CurrentPassword[6]={'0','0','0','0','0','0'};//输入密码暂存数组
uchar adminpassword[6]={'1','3','1','4','2','0'};//管理员密码
uchar PassNum[10] = {'0','1','2','3','4','5','6','7','8','9'}; //存放所有数字
/*******延时函数*******/
void delay(uint z)//z毫秒
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
/*******空函数*******/
/*void Nop(void) //空操作
{
_nop_(); //仅作延时用一条语句大约1us
_nop_();
_nop_();
_nop_();
}*/
/*******忙检测函数*******/
bit LCD_busy()
{
bit busy;
P0 = 0xff;//防止干扰
RS = 0; //命令模式
RW = 1; //读模式
E = 1;
busy = BF;//将忙标志位的数值赋给busy
E = 0;
return busy;
}
/*******写命令函数*******/
void LCD_write_cmd(uchar cmd)//cmd为需要写的命令
{
while(LCD_busy());//只有当LCD_busy()为0(闲)时才跳出循环
RS = 0; //命令模式
RW = 0; //写模式
data1602 = cmd; //将命令内容的十六进制送到P0端口
delay(1);
E = 1; //拉高使能端,为制造有效的下降沿做准备
delay(1);
E = 0; //由高变低,产生下降沿,液晶执行命令,使命令送到LCD1602的DB0~DB7
}
/*******写数据函数*******/
void LCD_write_data(uchar dat)//dat为需要写的数据
{
while(LCD_busy());//只有当LCD_busy()为0(闲)时才跳出循环
RS = 1; //数据模式
RW = 0; //写模式
data1602 = dat; //将数据内容的十六进制送到P0端口
delay(1);
E = 1;
delay(1);
E = 0; //使能端,高电平有效,使命令送到LCD1602的DB0~DB7
}
/*******IT0中断初始化函数*******/
void IT_init()
{
IT0 = 0; //设置低电平触发外部中断
EA = 1; //开总中断
EX0 = 1;//开外部中断
}
/*******定时器T0中断初始化函数*******/
void Time_init()
{
TMOD = 0x01;//将定时器0设为方式1,即16位定时器
TH0 = (65536-45872)/256;//给定时器的高八位赋初值
TL0 = (65536-45872)%256;//给定时器的低八位赋初值
EA = 1;//开总中断
ET0 = 1;//开定时器0中断
}
/*******LCD初始化函数*******/
void LCD_init()
{
LCD_write_cmd(0x38); //将设置“两行、八位数据、5*7的点阵”命令写入LCD的控制器
LCD_write_cmd(0x0c); //开显示关光标
LCD_write_cmd(0x06); //光标右移指令
LCD_write_cmd(0x01); //清除显示
}
/*******LCD写显示地址函数*******/
void LCD_write_address(uchar x,uchar y)
{
x&=0x0f; //列地址限制在0~15之间
y&=0x01; //行地址限制在0~1
if(y==0)
LCD_write_cmd(x|0x80);//数据指针=80+地址变量,写入列地址
else
LCD_write_cmd((x+0x40)|0x80); //如果是第二行,将列地址写入
}
/*******LCD显示函数*******/
void LCD_display(uchar x,uchar y,uchar buf) //x:列 y:行,buf:显示的字符
{
LCD_write_address(x,y);//先将地址写入
LCD_write_data(buf); //再写入要显示的数据
}
/*******一声提示音,表示有效输入*******/
void OneAlam()
{
Alam=0; //蜂鸣器响
delay(100); //延时5ms
Alam=1; //蜂鸣器关
}
/*******两声提示音,表示操作成功*******/
void TwoAlam()
{
uchar i = 0;
for(i=0;i<2;i++)
{
Alam=0; //蜂鸣器响
delay(100); //延时5ms
Alam=1; //蜂鸣器关
delay(100);
}
}
/*******三声提示音,表示错误*******/
void ThreeAlam()
{
uchar i = 0;
for(i=0;i<3;i++)
{
Alam=0; //蜂鸣器响
delay(100); //延时5ms
Alam=1; //蜂鸣器关
delay(100);
}
}
/*******流水灯函数*******/
void LED_display()
{
uint i;
for(i=0;i<8;i++) //数组控制流水灯
{
LED = table[i];
delay(500);
}
LED = 0x00;
delay(1000);
LED = 0xff;
}
/*******初始化界面函数*******/
void init_display()
{
uchar i;
for(i=0;i<16;i++)
LCD_display(i,0,initLock1[i]);
for(i=0;i<16;i++)
LCD_display(i,1,initLock2[i]);
}
/*******按键控制输入密码函数*******/
void pushBtn_password()
{
countNum = 0;
countPass = 1;
LCD_write_cmd(0x0e); //光标闪烁
while(1)
{
if(S1 == 0) //第一次检测按键被按下
{
delay(8); //延时8ms进行消抖
if(S1 == 0) //再次检测按键被按下,说明确实被按下了
{
if(isInitPass)
LCD_display(6+countPass,1,PassNum[countNum]); //显示数字
else
LCD_display(9+countPass,1,PassNum[countNum]);
LCD_write_cmd(0x10); //光标左移
if(isInitPass)
InitPassword[countPass-1] = PassNum[countNum]; //将输入的数字存到初始化数组中
else
CurrentPassword[countPass-1] = PassNum[countNum];//将输入的数字存到当前数组中
if(countNum == 9)
countNum = 0;
else
countNum++;
}
delay(300);
}
if(S3 == 0) //第一次检测按键被按下
{
delay(8); //延时8ms进行消抖
if(S3 == 0) //再次检测按键被按下,说明确实被按下了
{
countNum = 0;
if(countPass == 6)
countPass = 1;
else
countPass++;
if(isInitPass)
LCD_display(6+countPass,1,InitPassword[countPass-1]);
else
LCD_display(9+countPass,1,CurrentPassword[countPass-1]);
LCD_write_cmd(0x10);
}
delay(250);
}
if(S4 == 0)
{
delay(8); //延时8ms进行消抖
if(S4 == 0) //再次检测按键被按下,说明确实被按下了
{
countNum = 0;
if(countPass>1)
countPass--;
else
countPass = 1;
}
if(isInitPass)
LCD_display(6+countPass,1,InitPassword[countPass-1]);
else
LCD_display(9+countPass,1,CurrentPassword[countPass-1]);
LCD_write_cmd(0x10);
delay(300);
}
if(S5 == 0)
{
delay(8);
if(S5 == 0)
{
break;
}
}
}
LCD_write_cmd(0x0c); //光标不闪烁
}
/*******最初设置密码函数*******/
void init_password()
{
uchar i = 0;
for(i=0;i<16;i++)
LCD_display(i,0,SetNew[i]);
for(i=0;i<16;i++)
LCD_display(i,1,Input[i]);
pushBtn_password(); //按键控制输入密码
for(i=0;i<16;i++)
LCD_display(i,0,NULL[i]);
for(i=0;i<16;i++)
LCD_display(i,1,NULL[i]);
for(i=0;i<13;i++)
LCD_display(i,0,initword[i]);
delay(500);
LCD_display(13,0,initword[13]);//滚动显示初始化中
delay(500);
LCD_display(14,0,initword[14]);
delay(500);
LCD_display(15,0,initword[15]);
delay(500);
for(i=0;i<16;i++)
LCD_display(i,0,setOK[i]);
TwoAlam();//两声提示音,表示操作成功
isInitPass = 0;
}
/*******判断是否输入正确函数*******/
void judge()
{
uchar jg = 0;
uchar i;
if((CurrentPassword[0]==InitPassword[0])&&(CurrentPassword[1]==InitPassword[1])&&(CurrentPassword[2]==InitPassword[2])&&(CurrentPassword[3]==InitPassword[3])&&(CurrentPassword[4]==InitPassword[4])&&(CurrentPassword[5]==InitPassword[5]))
{
if(isReset==0)
jg = 1; //正确输入密码
else
jg = 3; //正确输入密码且在重设密码
pass = 1; //密码正确
}
else if((CurrentPassword[0]==adminpassword[0])&&(CurrentPassword[1]==adminpassword[1])&&(CurrentPassword[2]==adminpassword[2])&&(CurrentPassword[3]==adminpassword[3])&&(CurrentPassword[4]==adminpassword[4])&&(CurrentPassword[5]==adminpassword[5]))
{
if(isReset==0)
jg = 2; //正确输入管理员超级密码
else
jg = 4; //正确输入管理员超级密码且在重设密码
pass = 1;
}
else
ErrorCont++; //错误次数+1
if(jg==1)
{
for(i=0;i<16;i++)
LCD_display(i,0,Correct[i]);
for(i=0;i<16;i++)
LCD_display(i,1,LockOpen[i]);
OneAlam();
LED_display();
}
else if(jg==2)
{
for(i=0;i<16;i++)
LCD_display(i,0,superPassword[i]);
for(i=0;i<16;i++)
LCD_display(i,1,LockOpen[i]);
OneAlam();
LED_display();
}else if(jg==3)
{
for(i=0;i<16;i++)
LCD_display(i,0,Correct[i]);
for(i=0;i<16;i++)
LCD_display(i,1,NULL[i]);
OneAlam();
}
else if(jg==4)
{
for(i=0;i<16;i++)
LCD_display(i,0,superPassword[i]);
for(i=0;i<16;i++)
LCD_display(i,1,NULL[i]);
OneAlam();
}
else
{
for(i=0;i<16;i++)
LCD_display(i,0,ErrorTry[i]);
for(i=0;i<16;i++)
LCD_display(i,1,NULL[i]);
ThreeAlam();
}
}
/*******显示输入密码函数*******/
void input_Password()
{
uchar i;
do{
if(ErrorCont==3)
{
TR0 = 1; //启动定时器T0
ErrorCont = 0;
for(i=0;i<16;i++)
LCD_display(i,0,wait[i]);
LCD_display(12,0,trueTime);
for(i=0;i<16;i++)
LCD_display(i,1,again[i]);
while(trueTime >= 48)
{
if(timeNum == 20) //num=20代表用了50ms*20 = 1s
{
timeNum = 0;
trueTime--; //锁定时间减1
LCD_display(12,0,trueTime);
}
}
TR0 = 0; //关闭定时器T0
trueTime = '5';
}
for(i=0;i<16;i++)
LCD_display(i,0,start_line1[i]);
for(i=0;i<16;i++)
LCD_display(i,1,start_line2[i]);
pushBtn_password();
judge();
}while(pass==0);
}
/*******main函数*******/
void main()
{
LCD_init();
IT_init();
Time_init();
init_display();
delay(2000);
init_password();
delay(2000);
while(1)
{
input_Password();
delay(1000);
}
}
void reSetPassword() interrupt 0
{
uchar i;
isReset = 1;
isInitPass = 0;
do{
/*if(ErrorCont==3)
{
TR0 = 1; //启动定时器T0
ErrorCont = 0;
for(i=0;i<16;i++)
LCD_display(i,0,wait[i]);
LCD_display(12,0,trueTime);
for(i=0;i<16;i++)
LCD_display(i,1,again[i]);
while(trueTime >= 48)
{
if(timeNum == 20) //num=20代表用了50ms*20 = 1s
{
timeNum = 0;
trueTime--; //锁定时间减1
LCD_display(12,0,trueTime);
}
}
TR0 = 0; //关闭定时器T0
trueTime = '5';
}*/
if(ErrorCont==3)
{
}
for(i=0;i<16;i++)
LCD_display(i,0,oldPassword[i]);
for(i=0;i<16;i++)
LCD_display(i,1,start_line2[i]);
pushBtn_password();
judge();
}while(pass==0&&ErrorCont<3);
delay(1000);
if(pass == 1)
{
for(i=0;i<16;i++)
LCD_display(i,0,Reset[i]);
for(i=0;i<16;i++)
LCD_display(i,1,Input[i]);
isInitPass = 1;
pushBtn_password(); //按键控制输入密码
for(i=0;i<16;i++)
LCD_display(i,0,ResetOK[i]);
for(i=0;i<16;i++)
LCD_display(i,1,NULL[i]);
TwoAlam();
delay(1000);
}
for(i=0;i<16;i++)
LCD_display(i,0,start_line1[i]);
for(i=0;i<16;i++)
LCD_display(i,1,start_line2[i]);
isInitPass = 0;
isReset = 0;
}
void TimeCount() interrupt 1
{
TH0 = (65536-45872)/256;//重装初值
TL0 = (65536-45872)%256;
timeNum++; //每发生一次中断后,num++
}