基于51单片机的电子密码锁

软件设计(基于keiluviso5)

1.程序流框图

本设计的程序框架主要包括初始化程序、密码输入程序、蜂鸣器报警程序、蓝牙控制程序和错误次数检测程序等。图1是其流框图。

 

图1

2程序实现

(1)初始化程序

该程序主要是完成系统的初始化设置,包括系统时钟频率设置、显示屏初始化、语音模块初始化、蓝牙模块初始化以及按键中断设置等。

(2)密码输入程序

该程序主要实现了对密码进行输入和验证的过程,通过扫描方式获取密码并在液晶屏幕上显示。当按下确认键后,单片机将会把输入的密码和预设密码进行比对,如果匹配成功则会提示开锁成功,否则提示密码错误。同时,在输入三次错误密码后,系统将自动上锁并暂停密码输入,同时进行报警功能。

具体实现步骤如下:

a. 定义一个全局变量记录密码输入次数;

b. 在键盘模块中断处理函数中,判断按键号码是否是确认键或删除键等特殊按键:

如果是确认键,则将当前输入的数字与预设的密码进行比对;

如果是删除键,则将当前输入的数字清零或删除上一个数字。

c. 如果输入三次错误密码,则自动上锁并暂停密码输入功能。

(3)蜂鸣器报警程序

该程序主要用于实现报警功能,例如输入错误密码自动上锁后报警等等。

具体实现步骤如下:

a. 初始化蜂鸣器报警模块;

b. 在输入三次错误密码自动上锁时,触发报警功能;

c. 在报警完毕后,结束自动上锁。

(4)蓝牙控制程序

该程序主要实现了蓝牙模块的控制功能,可以实现通过手机蓝牙APP对密码锁进行一键上锁和解锁的操作。

具体实现步骤如下:

a. 初始化蓝牙模块;

b. 建立蓝牙连接,并接收蓝牙APP发送的数据;

c. 根据接收到的数据判断是否进行上锁或解锁操作。

(5)错误次数检测程序

该程序主要用于实现输入三次错误密码自动上锁的功能。

具体实现步骤如下:

a. 定义计数器变量记录输入错误密码的次数;

b. 判断密码验证结果是否正确,如果错误则计数器加1,如果正确则计数器清零;

c. 在计数器达到3时,自动上锁并暂停密码输入功能。

#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"
#include "UART.h"
#include "intrins.h"
sbit Buzzer=P2^5;
unsigned char KeyNum;
unsigned int Password,Count,Rdata;
unsigned int LockCount;
unsigned int n;


void main()
{
	LCD_Init();
	UART_Init();
	LCD_ShowString(1,1,"Password:");
	while(1)
	{
		KeyNum=MatrixKey();
		if(KeyNum)
		{
			if(KeyNum<=10)	//如果S1~S10按键按下,输入密码
			{
				if(Count<4)	//如果输入次数小于4
				{
					Password*=10;				//密码左移一位
					Password+=KeyNum%10;		//获取一位密码
					Count++;	//计次加一
				}
				LCD_ShowNum(2,1,Password,4);	//更新显示
			}
			if(KeyNum==11)	//如果S11按键按下,确认
			{
				if(Password==2345)	//如果密码等于正确密码
				{
					LCD_Init();
					LCD_ShowString(1,1,"OK ");	//显示OK
					Delay(500);
					LCD_Init();
					Password=0;		//密码清零
					Count=0;		//计次清零
						LCD_ShowString(1,1,"Password:");
					LCD_ShowNum(2,1,Password,4);	//更新显示
				}
				else				//否则
				{
					LCD_ShowString(1,14,"ERR");	//显示ERR
					Password=0;		//密码清零
					Count=0;		//计次清零
					LCD_ShowNum(2,1,Password,4);	//更新显示
					LockCount++;
				}
			}
			if(KeyNum==12)	//如果S12按键按下,取消
			{
				Password=0;		//密码清零
				Count=0;		//计次清零
				LCD_ShowNum(2,1,Password,4);	//更新显示
			}
			if(LockCount>=3)
			{	
				n=3000;
				LockCount=0;
				LCD_Init();
				LCD_ShowString(1,1,"Locked...");
				while(n--)
				{
					Buzzer=!Buzzer;
					Delay(1);
					if(Rdata==21)
					break;
				}
				Buzzer=0;
				LCD_Init();
				LCD_ShowString(1,1,"Fine...");
				Delay(500);
				LCD_Init();
				LCD_ShowString(1,1,"Password:");
			}
					if(KeyNum==13)
		{
			if(Count>0)	//如果输入次数小于4
				{
					Password/=10;				//密码左移一位
					Count--;	//计次-一
					LCD_ShowNum(2,1,Password,4);
				}
		}
			if(KeyNum==12)	//如果S12按键按下,取消
			{
			//		LCD_ShowString(1,14,"OK ");	//显示OK
					Password=0;		//密码清零
					Count=0;		//计次清零
					LCD_ShowNum(2,1,Password,4);	//更新显示
			}
			
		}
				if(Rdata==20)
			{		
				LockCount=0;
				LCD_Init();
				LCD_ShowString(1,1,"Locked...");
				while(1)
				{
					if(Rdata==21)
					break;
				}
				LCD_Init();
				LCD_ShowString(1,1,"Fine...");
				Delay(500);
				LCD_Init();
				LCD_ShowString(1,1,"Password:");
				}
			if(Rdata==21)
			{
					LCD_Init();
					LCD_ShowString(1,1,"OK ");	//显示OK
					Delay(500);
					LCD_Init();
					Password=0;		//密码清零
					Count=0;		//计次清零
						LCD_ShowString(1,1,"Password:");
					LCD_ShowNum(2,1,Password,4);	//更新显示
			}
	}
	
}

void UART_Routine() interrupt 4
{
	if(RI==1)					//如果接收标志位为1,接收到了数据
	{
		Rdata=SBUF;		//将受到的数据发回串口
		RI=0;					//接收标志位清0
	}
}

上述是主函数文件,下面介绍头文件函数

#include "intrins.h"
void Delay(unsigned int xms)
{
	unsigned char i, j;
	while(xms--)
	{
		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
	}
}

void Delay_s(unsigned int n)		//@11.0592MHz
{
	unsigned char i, j, k;
while(n--)
{
	_nop_();
	_nop_();
	i = 43;
	j = 4;
	k = 150;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}
}
#include <REGX52.H>

//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0

//函数定义:
/**
  * @brief  LCD1602延时函数,12MHz调用可延时1ms
  * @param  无
  * @retval 无
  */
void LCD_Delay()
{
	unsigned char i, j;

	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
}

/**
  * @brief  LCD1602写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void LCD_WriteCommand(unsigned char Command)
{
	LCD_RS=0;
	LCD_RW=0;
	LCD_DataPort=Command;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void LCD_WriteData(unsigned char Data)
{
	LCD_RS=1;
	LCD_RW=0;
	LCD_DataPort=Data;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602设置光标位置
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @retval 无
  */
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
	if(Line==1)
	{
		LCD_WriteCommand(0x80|(Column-1));
	}
	else if(Line==2)
	{
		LCD_WriteCommand(0x80|(Column-1+0x40));
	}
}

/**
  * @brief  LCD1602初始化函数
  * @param  无
  * @retval 无
  */
void LCD_Init()
{
	LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
	LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
	LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
	LCD_WriteCommand(0x01);//光标复位,清屏
}

/**
  * @brief  在LCD1602指定位置上显示一个字符
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的字符
  * @retval 无
  */
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
	LCD_SetCursor(Line,Column);
	LCD_WriteData(Char);
}

/**
  * @brief  在LCD1602指定位置开始显示所给字符串
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串
  * @retval 无
  */
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=0;String[i]!='\0';i++)
	{
		LCD_WriteData(String[i]);
	}
}


/**
  * @brief  返回值=X的Y次方
  */
int LCD_Pow(int X,int Y)
{
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++)
	{
		Result*=X;
	}
	return Result;
}

/**
  * @brief  在LCD1602指定位置开始显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~65535
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以有符号十进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-32768~32767
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
	unsigned char i;
	unsigned int Number1;
	LCD_SetCursor(Line,Column);
	if(Number>=0)
	{
		LCD_WriteData('+');
		Number1=Number;
	}
	else
	{
		LCD_WriteData('-');
		Number1=-Number;
	}
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以十六进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xFFFF
  * @param  Length 要显示数字的长度,范围:1~4
  * @retval 无
  */
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i,SingleNumber;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		SingleNumber=Number/LCD_Pow(16,i-1)%16;
		if(SingleNumber<10)
		{
			LCD_WriteData(SingleNumber+'0');
		}
		else
		{
			LCD_WriteData(SingleNumber-10+'A');
		}
	}
}

/**
  * @brief  在LCD1602指定位置开始以二进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
	}
}
#include <REGX52.H>
#include "Delay.h"

/**
  * @brief  矩阵键盘读取按键键码
  * @param  无
  * @retval KeyNumber 按下按键的键码值
			如果按键按下不放,程序会停留在此函数,松手的一瞬间,返回按键键码,没有按键按下时,返回0
  */
unsigned char MatrixKey()
{
	unsigned char KeyNumber=0;
	
	P1=0xFF;
	P1_3=0;
	if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=1;}
	if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=5;}
	if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=9;}
	if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=13;}
	
	P1=0xFF;
	P1_2=0;
	if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=2;}
	if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=6;}
	if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=10;}
	if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=14;}
	
	P1=0xFF;
	P1_1=0;
	if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=3;}
	if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=7;}
	if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=11;}
	if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=15;}
	
	P1=0xFF;
	P1_0=0;
	if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=4;}
	if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=8;}
	if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=12;}
	if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=16;}
	
	return KeyNumber;
}
#include <REGX52.H>


void UART_Init()
{
TMOD = 0x20; //定时器T1使用工作方式2
TL1 = 0xfa;
TH1 = 0xfa;
TR1 = 1; // 开始计时
SCON = 0x50; //工作方式1,波特率9600bps @ 11.0592,允许接收
PCON |= 0x80;
ES = 1;
EA = 1; // 打开所有中断

}

void UART_SendByte(unsigned char Byte)
{
	SBUF=Byte;
	while(TI==0);
	TI=0;
}

  • 5
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值