1 课程设计任务
任务:矩阵键盘控制输入,具有密码设置功能,和多次输错后一定时间内锁定的功能。
功能实现:
(1)输入密码功能。
输入密码时,用“*”代替真实的密码以防密码泄露。在输入密码时,具有清除前一位/或多位的密码功能(用清除键)。密码输入完毕,按(确认/开锁键)确认并生效。
(2)上锁功能。在锁开状态下,通过上锁键上锁。并生效。
(3)在锁合的状态下,通过输入密码开锁功能。开锁时,先按确认/开锁键后,再在键盘上输入六位密码,然后按确认/开锁键,如果密码正确,进入锁开状态。
(4)在锁开状态下,设置新密码功能。按设置新密码键,在键盘上输入六位新的密码按(确认/开锁)键确认,代替旧密码。
(5)在开锁时,如果输入密码三次错误,产生声、光报警功能。每错误一次,告警一次, 若连续三次错误,则系统屏蔽输入功能,直到系统复位后重新开始。
2 硬件电路设计
2.1硬件系统组成
2.1硬件系统组成
本项目使用Proteus8仿真STM32单片机控制器,使用LCD1602液晶、矩阵按键、蜂鸣器、EEPROM模块、继电器模块等。采用STC89C51作为主控芯片,结合矩阵按键输入模块、数码管显示模块、LCD1602液晶显示、LED、蜂鸣器报警器等电路模块实现开锁、上锁、报警、密码更改等功能,设计一款可修改密码且具有报警功能的液晶显示电子密码锁。
主要由STM32单片机+最小系统+LCD1602液晶显示模块+蜂鸣器模块+LED指示灯模块+矩阵键盘模块。
proteus图
原理图
密码正确仿真图
上锁状态仿真图
C代码实现
#include <reg51.h>
#include <stdio.h>
//宏定义
#define uchar unsigned char
#define uint unsigned int
#define GPIO_KEY P1 //按键端口
//LCD显示
sbit RS=P2^2;//寄存器选择,高电平选择数据寄存器,低电平选择指令寄存器
sbit RW=P2^3;//读写信号线,高电平时进行读操作,低电平时进行写操作
sbit E=P2^4; //使能端,下降沿使能
sbit LED = P2^0; //定义LED灯端口
sbit BEEZ = P2^1; //定义蜂鸣器端口
uchar welcome[]="Hello Welcom"; //密码正确显示
uchar pw_error[]="Password Error"; //密码错误显示
uchar Lock[]="XXXXXXXXXXXXXXXX"; //密码三次输入错误显示
uchar set_pw[]="Set PassWord"; //设置新密码显示
uchar input_pw[]="Please Input"; //输入密码显示
uchar pw[6]={0,0,0,0,0,0}; //初始密码
uchar temp_pw[6]={0,0,0,0,0,0}; //初始密码
uchar KeyValue; //按下的按键值
uchar flag=0; //标志位
uchar pw_count; //输入密码的数量
uchar pw_errnum=0; //密码错误次数
void lcd_int(); //LCD初始化
void lcd_w_cmd(uchar com); //写命令
void lcd_w_dat(uchar dat); //写数据
uchar lcd_r_start(); //读状态字
void show_Status(uchar *str); //状态显示
void show_pw(uchar num); //屏幕密码显示
void Input_Key(); //按键扫描 并且执行相应的操作 密码输入
void KeyDown(void); //矩阵键盘扫描
void open(); //锁打开的执行动作
void alarm(); //密码错误蜂鸣器警告
void Lock_Device(); //密码错误设备锁定
void delay(uint j) //延时函数
{
uint x;
for(x=0;x<j;x++);
}
void main() //主函数
{
lcd_int(); //LCD初始化
show_Status(&input_pw); //状态显示 请输入密码
show_pw(0); //密码显示为空,等待输入
while(1)
{
Input_Key(); //按键扫描 并且执行相应的操作 密码输入
}
}
void KeyDown(void) //矩阵键盘扫描
{
GPIO_KEY=0x0f;
if(GPIO_KEY!=0x0f)//判断按键是否按下
{
delay(3);//软件消抖
if(GPIO_KEY!=0x0f)//再次检测键盘是否按下
{
//列扫描
GPIO_KEY=0X0F;
switch(GPIO_KEY)
{
case(0X07): KeyValue=0;break;
case(0X0b): KeyValue=1;break;
case(0X0d): KeyValue=2;break;
case(0X0e): KeyValue=3;break;
}
//行扫描
GPIO_KEY=0XF0;
switch(GPIO_KEY)
{
case(0X70): KeyValue=KeyValue;break;
case(0Xb0): KeyValue=KeyValue+4;break;
case(0Xd0): KeyValue=KeyValue+8;break;
case(0Xe0): KeyValue=KeyValue+12;break;
}
while(GPIO_KEY!=0xf0); //松手检测
return ;
}
}
KeyValue = 0xff;
}
void open() //锁打开的执行动作
{
}
void alarm() //密码错误蜂鸣器警告
{
uchar i;
LED = 0; //LED灯亮
for(i = 0;i<100;i++)
{
BEEZ = ~BEEZ; //蜂鸣器报警
delay(100);
}
LED = 1; //LED灯灭
}
void Lock_Device()//密码错误设备锁定时
{
while(1)
{
alarm(); //锁定时蜂鸣器长鸣警告
}
}
void Input_Key() //按键扫描 并且执行相应的操作
{
//刷新按键的值若没有按键按下则返回0xff
KeyDown();
if(KeyValue == 0xff||pw_errnum>=3) //检测是否有按键按下
return;
//当1-9按下时
if(KeyValue>=0&&KeyValue<=9)
{
if((flag == 0 || flag ==2)&&pw_count<6)
{
pw_count++;//密码下标
temp_pw[pw_count] = KeyValue;//保存按键值
show_pw(pw_count); //屏幕显示'*'
}
}
else if(KeyValue == 12)//上锁键
{
if(flag == 1) //如果设备在开锁时按下
{
flag = 0;
show_Status(&input_pw);//显示请输入密码
}
}
else if(KeyValue == 13)//按下了清除键
{
if(pw_count>0)pw_count--;//下标左移
show_pw(pw_count); //刷新屏幕密码
}
else if(KeyValue == 14)//按下了确定键
{
if(pw_count == 6) //判断数量是否有6位
{
if(flag == 0) //锁关闭状态
{
if(temp_pw[0] == pw[0]&&temp_pw[1] == pw[1]&&temp_pw[2] == pw[2]&&temp_pw[3] == pw[3]&&temp_pw[4] == pw[4]&&temp_pw[5] == pw[5])//校验密码
{
show_Status(&welcome);//显示欢迎您
flag = 1; //切换状态
pw_count = 0; //密码清0
pw_errnum = 0; //错误密码次数清0
show_pw(pw_count); //刷新屏幕密码
open(); //执行开门时的回调函数
}
else
{
pw_errnum++; //错误次数+1
pw_count = 0; //密码清0
show_pw(pw_count); //刷新屏幕密码
show_Status(&pw_error); //显示密码错误
alarm(); //发出警告
if(pw_errnum>=3) //当密码错误达到3次时
{
show_Status(&Lock); //显示设备锁定
Lock_Device(); //报警
}
}
}
else if(flag == 1)//锁打开状态,按下确定键无反应
{
}
else if(flag == 2)//设置密码状态 保存新密码
{
//保存密码
pw[0] = temp_pw[0];
pw[1] = temp_pw[1];
pw[2] = temp_pw[2];
pw[3] = temp_pw[3];
pw[4] = temp_pw[4];
pw[5] = temp_pw[5];
show_Status(&welcome); //显示欢迎你
flag = 1; //标志位置位
pw_count = 0; //密码清0
show_pw(pw_count); //刷新屏幕密码
}
}
else
{
//密码未到6位不能操作
}
}
else if(KeyValue == 15)//按下了设置密码键
{
if(flag == 1) //判断锁是否已经打开,打开才能设置密码
{
show_Status(set_pw);//显示请设置密码
flag = 2; //标志位改成设置密码
}
}
}
void show_pw(uchar num) //屏幕密码显示
{
uchar i;
lcd_w_cmd(0xC5); //更改显示位置
for(i=0;i<6;i++) //显示空字符串,字符串结束符为‘0’
{
lcd_w_dat(' ');
}
lcd_w_cmd(0xC5); //更改显示位置
for(i=0;i<num;i++) //显示'*'字符串,字符串结束符为‘0’
{
lcd_w_dat('*');
}
}
void show_Status(uchar *str) //状态显示
{
uchar i=0;
lcd_w_cmd(0x80); //设置显示地址(第一行)
for(i=0;str[i]!='\0';i++) //此处显示传入的字符串,字符串结束符为‘0’
{
lcd_w_dat(str[i]);
}
}
void lcd_int() //LCD初始化
{
lcd_w_cmd(0x3c); //设置工作方式
lcd_w_cmd(0x0c); //设置显示状态
lcd_w_cmd(0x01); //清屏
lcd_w_cmd(0x06); //设置输入方式
lcd_w_cmd(0x80); //设置初始显示位置
}
void lcd_w_cmd(uchar com) //写命令 命令字存入com中
{
uchar i;
do
{ //查lcd忙状态
i=lcd_r_start(); //调用读状态字函数
i&=0x80; //“与”操作屏蔽掉低7位
delay(2);
}while(i!=0); //lcd忙,继续查询,否则退出循环
RW=0;
delay(1);
RS=0; //RW=0,RS=0,写lcd命令字
delay(1);
E=1; //E端时序以0或1高低波动
delay(1);
P0=com; //将com中的命令字写入lcd数据口
delay(1);
E=0;
delay(1);
RW=1;
delay(2);
}
void lcd_w_dat(uchar dat) //写数据
{
uchar i;
do
{ //查忙操作
i=lcd_r_start(); //调用读状态字函数
i&=0x80; //“与”操作屏蔽掉低7位
delay(2);
}while(i!=0); //lcd忙,继续查询,否则退出循环
RW=0;
delay(1);
RS=1; //RW=0,RS=1,写lcd命令字
delay(1);
E=1; //E端时序以0或1高低波动
delay(1);
P0=dat; //将dat中的显示数据写入lcd数据口
delay(1);
E=0;
delay(1);
RW=1;
delay(2);
}
uchar lcd_r_start() //读状态字
{
uchar s;
RW=1; //RW=1,RS=0,读lcd状态
delay(1);
RS=0;
delay(1);
E=1; //E端时序以0或1高低波动
delay(1);
s=P0; //从lcd的数据口读状态
delay(1);
E=0;
delay(1);
RW=0;
delay(1);
return(s); //返回值s读取状态忙或空闲