单片机课程设计电子密码锁:矩阵键盘控制输入,具有密码设置功能,和多次输错后一定时间内锁定的功能。(报告,proteus图和代码见主页)

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读取状态忙或空闲
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

早日提码跑路!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值