基于51单片机编写的六位电子密码锁由LCD1602显示
全部内容由本人原创!
从制定计划到焊接调试完成耗时5天!
此程序仅表示完成该项目其中的一个方法,对有兴趣修改,完善的同学表示欢迎!
*注:每个关键的地方都有注释方便理解哈
原理图如下:
#include"reg52.h"
#include"key.h"
#include"lcd.h"
#include “beep.h”
char InputPassword=0;
char PassWordNum=9;
char KeyNum=0; //字符0—9的ASCII码是0x30-0x39 。//任何时候输入的按键值
char PassWordBackup[6]; //原密码
char PassWordBackup2[6]; //临时输入密码
//char Errortimes=3; //定义密码输入错误次数
void Password()
{
char i;
if(KeyChange==1)
{
KeyChange=0; //恢复按键判断状态,让密码只变化一次
PassWordBackup[PassWordNum-9]=KeyNum; //将当前按键的值进行备份
KeyNum=KeyNum%10+0x30; //***此步很重要***将变量转换成字符输出,因为液晶只能显示字符
//0x30-0x39是0-9的ASCLL码字符
LcdShowStr(PassWordNum,1,&KeyNum); //显示相应位
for(i=PassWordNum+1;i<16;i++) //作用是将剩余位清零不显示,避免乱码 “清屏”
{
LcdShowStr(i,1," ");
}
PassWordNum++; //索引下一位显示输出
if(PassWordNum>15)
{
PassWordNum=9; //变量恢复初始值,方便下次输入
KeyChange=1; //为下次按键按下作准备,防止确认界面被频繁刷新
InputPassword=1; //如果输入的密码达到六位,跳转是否确认密码界面
}
}
}
void Determine_password() //判断密码函数
{
if(KeyChange1)
{
KeyChange=0;
LcdAreaClear(0,0,16); //清屏函数,设置起始位和清屏长度
LcdAreaClear(0,1,16);
LcdShowStr(0,0,“Press 1 OK”);
LcdShowStr(0,1,“Press 2 Cancel”);
if(KeyNum1)
{
InputPassword=2; //跳转进入密码设置成功界面
KeyChange=1;
}
else if(KeyNum==2)
{
LcdShowStr(0,0,“Please Set Init”);
LcdShowStr(0,1,"Password: ");
InputPassword=0;
}
}
}
void Password_Set_successfully() //密码设置成功显示跳转界面
{
static long i=0;
if(KeyChange1)
{
KeyChange=0;
LcdAreaClear(0,0,16); //清屏函数,设置起始位和清屏长度
LcdAreaClear(0,1,16);
LcdShowStr(0,0,“Password”);
LcdShowStr(0,1,“Set Successfully”);
}
i++;
if(i%5000) //显示一段时间后准备返回密码输入界面
{
LcdAreaClear(0,0,16); //清屏函数,设置起始位和清屏长度
LcdAreaClear(0,1,16);
LcdShowStr(7,1,“return 3s”);
}
if(i%10000) //显示一段时间后准备返回密码输入界面
{
LcdAreaClear(0,0,16); //清屏函数,设置起始位和清屏长度
LcdAreaClear(0,1,16);
LcdShowStr(7,1,“return 2s”);
}
if(i%15000) //显示一段时间后准备返回密码输入界面
{
LcdAreaClear(0,0,16); //清屏函数,设置起始位和清屏长度
LcdAreaClear(0,1,16);
LcdShowStr(7,1,“return 1s”);
}
if(i%2000==0)
{
i=0;
InputPassword=5; //倒计时结束,进入密码输入界面
LcdAreaClear(0,0,16); //清屏函数,设置起始位和清屏长度
LcdAreaClear(0,1,16);
LcdShowStr(0,0,“Please Input”);
LcdShowStr(0,1,"Password: ");
}
}
void Password2() //正式输入密码函数
{
static char Errortimes=3; //尽量设计为局部变量,否则程序易跑飞
char i;
char n; //定义一个错误次数的备份变量
if(KeyChange)
{
KeyChange=0;
PassWordBackup2[PassWordNum-9]=KeyNum; //将当前按键的值进行备份
KeyNum=KeyNum%10+0x30;
LcdShowStr(PassWordNum,1,&KeyNum);
for(i=PassWordNum+1;i<16;i++) //作用是将剩余位清零不显示,避免乱码 “清屏”
{
LcdShowStr(i,1," “);
}
PassWordNum++;
if(PassWordNum>15) //密码输入完成,进行对比
{
PassWordNum=9;
for(i=0;i<6;i++)
{
if(PassWordBackup2[i]==PassWordBackup[i])InputPassword=6;//如果循环对比后每次都相等则进入正确界面
else
{
LcdAreaClear(0,0,16); //清屏函数,设置起始位和清屏长度
LcdAreaClear(0,1,16);
LcdShowStr(0,0,” Waring !");
LcdShowStr(0,1,"The last ");
n=Errortimes; //将错误次数给变量不改变本身
n=n%10+0x30;
LcdShowStr(9,1,&n);
LcdShowStr(11,1,"times");
Errortimes--;
if(Errortimes<0)
{
InputPassword=8;KeyChange=1;break;
}
InputPassword=7;break ; //否则跳出当前循环; //进入警告界面
}
}
KeyChange=1; //为下次界面只执行一次做准备
}
}
}
void Change_password() //密码对比成功进入改密选项界面
{
if(KeyChange)
{
KeyChange=0;
LcdAreaClear(0,0,16); //清屏函数,设置起始位和清屏长度
LcdAreaClear(0,1,16);
LcdShowStr(0,0,“1 ChangePassword”);
LcdShowStr(0,1,“2 Quit”);
}
if(KeyNum1) //回到初始设置密码状态
{
InputPassword=0;
LcdAreaClear(0,0,16); //清屏函数,设置起始位和清屏长度
LcdAreaClear(0,1,16);
LcdShowStr(0,0,“Please Set Init”);
LcdShowStr(0,1,“Password:”);
}
if(KeyNum2) //退出选项,并且为下次输入密码做准备
{
InputPassword=5;
LcdAreaClear(0,0,16); //清屏函数,设置起始位和清屏长度
LcdAreaClear(0,1,16);
LcdShowStr(0,0,“Please Input”);
LcdShowStr(0,1,"Password: ");
}
}
void Waring()
{
static unsigned int i=0;
i++;
if(i%2==0)Beep=!Beep; //针对无源蜂鸣器调频
if(i>60000)
{
i=0;
InputPassword=5;
LcdAreaClear(0,0,16); //清屏函数,设置起始位和清屏长度
LcdAreaClear(0,1,16);
LcdShowStr(0,0,"Please Input");
LcdShowStr(0,1,"Password: ");
KeyChange=0; //防止输入位错误
}
}
void Locked()
{
if(KeyChange)
{
KeyChange=0;
LcdAreaClear(0,0,16); //清屏函数,设置起始位和清屏长度
LcdAreaClear(0,1,16);
LcdShowStr(0,1,“Has been locked!”);
}
}
void main()
{
char j;
InitLcd1602();
LcdShowStr(0,0,“Please Set Init”);
LcdShowStr(0,1,“Password:”);
Beep=1;
while(1)
{
if(j%10==0)Beep=!Beep;
switch(InputPassword)
{
case 0 :KeyNum=kscan();Password();break; //跳转初始密码输入
case 1 :KeyNum=kscan();Determine_password();break; //判断界面
case 2 :Password_Set_successfully();break; //密码设置成功界面
case 5 :KeyNum=kscan();Password2();break; //正式输入密码界面
case 6 :KeyNum=kscan();Change_password();break;
case 7 :Waring();break; //密码错误警告界面
case 8 :Locked();break; //已被锁定界面
default :break;
}
}
}
LCD1602程序部分:
#ifndef _lcd_h
#include"reg52.h"
#define LCD1602_DB P0
sbit LCD1602_E=P2^7;
sbit LCD1602_RW=P2^5;
sbit LCD1602_RS=P2^6;
/* 等待液晶准备好 */
void LcdWaitReady()
{
unsigned char sta;
LCD1602_DB = 0xFF;
LCD1602_RS = 0;
LCD1602_RW = 1;
do {
LCD1602_E = 1;
sta = LCD1602_DB; //读取状态字
LCD1602_E = 0;
} while (sta & 0x80); //bit7等于1表示液晶正忙,重复检测直到其等于0为止
}
/* 向LCD1602液晶写入一字节命令,cmd-待写入命令值 /
void LcdWriteCmd(unsigned char cmd)
{
LcdWaitReady();
LCD1602_RS = 0;
LCD1602_RW = 0;
LCD1602_DB = cmd;
LCD1602_E = 1;
LCD1602_E = 0;
}
/ 向LCD1602液晶写入一字节数据,dat-待写入数据值 /
void LcdWriteDat(unsigned char dat)
{
LcdWaitReady();
LCD1602_RS = 1;
LCD1602_RW = 0;
LCD1602_DB = dat;
LCD1602_E = 1;
LCD1602_E = 0;
}
/ 设置显示RAM起始地址,亦即光标位置,(x,y)-对应屏幕上的字符坐标 */
void LcdSetCursor(unsigned char x, unsigned char y)
{
unsigned char addr;
if (y == 0) //由输入的屏幕坐标计算显示RAM的地址
addr = 0x00 + x; //第一行字符地址从0x00起始
else
addr = 0x40 + x; //第二行字符地址从0x40起始
LcdWriteCmd(addr | 0x80); //设置RAM地址
}
/* 在液晶上显示字符串,(x,y)-对应屏幕上的起始坐标,str-字符串指针 */
void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str)
{
LcdSetCursor(x, y); //设置起始地址
while (*str != ‘\0’) //连续写入字符串数据,直到检测到结束符
{
LcdWriteDat(*str++);
}
}
/* 区域清除,清除从(x,y)坐标起始的len个字符位 /
void LcdAreaClear(unsigned char x, unsigned char y, unsigned char len)
{
LcdSetCursor(x, y); //设置起始地址
while (len–) //连续写入空格
{
LcdWriteDat(’ ');
}
}
/ 初始化1602液晶 /
void InitLcd1602()
{
LcdWriteCmd(0x38); //162显示,5*7点阵,8位数据接口
LcdWriteCmd(0x0C); //显示器开,光标关闭
LcdWriteCmd(0x06); //文字不动,地址自动+1
LcdWriteCmd(0x01); //清屏
}
#endif
按键部分:
//网站http://proteus.5d6d.com
#ifndef _key_h
#define _key_h
#include"reg52.h"
bit KeyChange=0;
char ksta[4][4]={ //所有按键初始值
{1,1,1,1},
{1,1,1,1},
{1,1,1,1},
{1,1,1,1},
};
char kbackup[4][4]={ //所有按键备份值
{1,1,1,1},
{1,1,1,1},
{1,1,1,1},
{1,1,1,1},
};
char code truetable[]={ //真值表
0xC0,0xF9,0xA4,0xB0,
0x99,0x92,0x82,0xF8,
0x80,0x90,0x88,0x83,
0xC6,0xA1,0x86,0x8E
};
void delay(unsigned int i) //延时函数
{
while(i–);
}
char kscan()
{
char cnt=0; //定义变量
char j,k; //定义行列扫描变量
P1=0xFF; //按键端口赋初值
for(j=0;j<4;j++) //行扫描
{
P1&=~(0x01<
{
ksta[j][k]=P1&(0x10<
{
delay(100); //延时消抖
if(ksta[j][k]==0) //二次确定该按键按下
{
cnt=j*4+k; //改变变量
KeyChange=1; //使主函数内的按键值判断发生变化让密码输入时只执行一次
}
kbackup[j][k]=ksta[j][k]; //备份按键状态,使程序只执行一次
}
}
P1|=0xFF; //端口置1
}
return cnt;
}
#endif
蜂鸣器部分:
#ifndef _beep_H
#define _beep_H
#include"reg52.h"
sbit Beep=P3^7;
#endif
了解整体结构不难的哈,并且有很强的拓展性。