你的位置:首页 > 信息动态 > 新闻中心
信息动态
联系我们

动态蓝牙密码锁

2021-11-9 20:38:47

前述:
QQ:961209458
V X:F9986858
承接毕业设计。

功能

1、使用4*4矩阵按键输入密码
2、密码可以定时随机生成
3、有外部EEPROM可以储存密码,以防掉电丢失
4、手机连接蓝牙,输入特定指令获取密保安全问题(密保问题有三个,随机获取)
5、输入密保安全问题的答案,获取密码(10秒之内有效)
6、输入密码解锁
7、开锁提示音(响一声),密码错误三次(响三声,重新生成随机密码,重新回答密保问题)

硬件方案

电子密码锁硬件如下图1所示,其中手机连接蓝牙模块,由单片机通过蓝牙发送密保安全问题,手机端回答答案。用矩阵按键输入密码,通过时钟模块计时,在非解锁状态下实时显示时间。定时更新密码后会将密码存储在外部存储里面,以防掉电丢失。通过OLED显示时间和一些人机交互界面。由电磁锁模拟控制门的开关。
在这里插入图片描述

软件设计方案

电子密码锁软件部分分为俩部分,由蓝牙获取密码解锁和指纹模块解锁俩部分组成。在蓝牙获取密码部分,首先由手机通过蓝牙发送特定指令,单片机发送密保问题,回答正确后会通过蓝牙把密码发送到手机上,此时可以通过密码进行解锁。同时该电子密码锁具有指纹模块解锁的功能,指纹识别正确的话也会进行解锁。在输入密码这一部分,会定时自定生成动态密码,同时会将密码保存在外部存储中。而且就是在连续三次输错密码后,密码会自动重新生成,也需要重新回答密保安全问题。
在这里插入图片描述
在这里插入图片描述

硬件电路图

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

部分核心代码

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "usart2.h"
#include "AS608.h"
#include "timer.h"
#include "oled.h"
#include "DS1302.h"
#include "key.h"
#include "myiic.h"
#include "24cxx.h" 
#include "adc.h"
#include "stm32f10x_adc.h"
#include <stdlib.h>
#include <time.h>

SysPara AS608Para;
u16 ValidN;

//指令:ADDFR 增加指纹
//指令:DELFR 删除指纹
unsigned char FRIGER[6]={'A','D','E','L','F','R'};   //添加或是删除指纹指令
unsigned char Change_HC05[3]={'Z','X','C'};          //修改蓝牙获取密码指令
unsigned char HC05_PassWord[5]={'1','2','3','4','5'};//初始蓝牙获取密码指令
unsigned char PassWord[6]={1,2,3,4,5,6};//6位密码
unsigned char PassBuffer[6]; //输入暂存密码
unsigned char PassWord_OK=0; //0 密码错误   1 密码正确
unsigned char Pass_Count=0;  //输入密码位数计数 0-5
unsigned char old_hour,new_hour;//时间整点生成随机密码

void Add_FR(void);	//添加指纹
void Del_FR(void);	//删除指纹
void Pre_FR(void);  //比对指纹
void Time_Display(void);   //时间显示
void Enter_Password(void); //输入密码
void Check_HC05(void);     //检查蓝牙获取新密码指令
void Send_Time(void);      //串口发送时间
void Generate_Password(void);//重新生成随机密码

int main(void)
{
	u8 AS608_Time_Count;//与指纹模块握手时间技术  时间间隔1秒  累计5次
	delay_init();  	    //初始化延时函数
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
	OLED_Init();        //OLED初始化
	uart_init(115200);	//初始化串口1波特率为115200,用于支持USMART
	usart2_init(57600); //初始化串口2,用于与指纹模块通讯
	PS_StaGPIO_Init();	//初始化FR读状态引脚  指纹模块状态引脚
	DS1302_Init();      //时钟芯片初始化
	KEY_Init();         //矩阵按键和蜂鸣器初始化
	Adc_Init();		  	//ADC初始化
	OLED_ShowString(0,0,"Wait Sys Init...",16);delay_ms(500);
	OLED_ShowString(0,2,"ShakHands...    ",16);delay_ms(500);
	while(PS_HandShake(&AS608Addr))//与指纹模块握手
	{delay_ms(1000);if(++AS608_Time_Count>=5) break;}
	if(AS608_Time_Count<5) OLED_ShowString(0,4,"Connect Success!",16);
	else                   OLED_ShowString(0,4,"Connect Fail!   ",16);
	delay_ms(1000);
	if(AS608_Time_Count<5) OLED_ShowString(0,6,"Sys Init Success",16);
	else                   OLED_ShowString(0,6,"AS608 Init Fail!",16);
	delay_ms(1000);AS608_Time_Count=0;
	AT24CXX_Init();//EEPROM初始化 AT24C02
	//AT24CXX_Write(1,PassWord,6);//存入
	AT24CXX_Read(1,PassWord,6);//读取保存的密码
	TIM4_Int_Init(99,7199);	   //10ms中断
	OLED_Clear();              //完成初始化 清屏
	while(1)
	{		
		Time_Display();  //时间显示
		Enter_Password();//输入密码
		Pre_FR();        //对比指纹
		Generate_Password();//重新生成随机密码
		Check_HC05();    //对比蓝牙获取密码指令
	}
}
//重新生成随机密码
void Generate_Password()
{
	char i;
	u16 adcx;
	old_hour=new_hour;
	new_hour=TIME[4];
	if(old_hour!=new_hour)//到达小时整点
	{
		for(i=0;i<6;i++)
		{
			adcx=Get_Adc_Average(ADC_Channel_8,3);//获取ADC值
			srand(adcx);//把adcx作为种子
			PassWord[i] = rand() % 9;//生成0—9内的随机整数
			delay_ms(5);
		}
		AT24CXX_Write(1,PassWord,6);//存入新密码
	}
}
//解析蓝牙指令
void Check_HC05()
{	
	char i;
	u16 mibao_num;
	u8  mibao_dat;
	if(Receive_Flag==1)
	{
		Receive_Flag=0;Receive_sum=0;
		//是否是修改获取密码指令
		if((USART_ReceiveString[0]==Change_HC05[0])&&
		   (USART_ReceiveString[1]==Change_HC05[1])&&
		   (USART_ReceiveString[2]==Change_HC05[2]))
		{
			/*
			for(i=0;i<5;i++) HC05_PassWord[i]=USART_ReceiveString[i+3];
			Send_Time();printf("Modify instruction successfully!!!\r\n");
			printf("Your instruction is:%c%c%c%c%c\r\n\r\n",HC05_PassWord[0],
			HC05_PassWord[1],HC05_PassWord[2],HC05_PassWord[3],HC05_PassWord[4]);
			*/
			mibao_num=Get_Adc_Average(ADC_Channel_8,3);//获取ADC值
			srand(mibao_num);//把adcx作为种子
			mibao_dat = rand() % 3;//生成0—9内的随机整数
			Send_Time();
			if(mibao_dat==0) 
			{
				printf("What is your Phone number?\r\n\r\n");
				HC05_PassWord[0] = '1';
				HC05_PassWord[1] = '3';
				HC05_PassWord[2] = '8';
				HC05_PassWord[3] = '9';
				HC05_PassWord[4] = '1';
			}
			if(mibao_dat==1) 
			{
				printf("What is your QQ number?\r\n\r\n");
				HC05_PassWord[0] = '2';
				HC05_PassWord[1] = '6';
				HC05_PassWord[2] = '4';
				HC05_PassWord[3] = '3';
				HC05_PassWord[4] = '7';
			}
			if(mibao_dat==2) 
			{
				printf("What is your birthday number?\r\n\r\n");
				HC05_PassWord[0] = '9';
				HC05_PassWord[1] = '9';
				HC05_PassWord[2] = '5';
				HC05_PassWord[3] = '2';
				HC05_PassWord[4] = '0';
			}
			
		}
		//是否是添加指纹指令
		else if((USART_ReceiveString[0]==FRIGER[0])&&
				(USART_ReceiveString[1]==FRIGER[1])&&
			    (USART_ReceiveString[2]==FRIGER[1])&&
				(USART_ReceiveString[3]==FRIGER[4])&&
			    (USART_ReceiveString[4]==FRIGER[5]))
		
				{Add_FR();}//添加指纹
				
		//是否是删除指纹指令
		else if((USART_ReceiveString[0]==FRIGER[1])&&
			    (USART_ReceiveString[1]==FRIGER[2])&&
			    (USART_ReceiveString[2]==FRIGER[3])&&
		        (USART_ReceiveString[3]==FRIGER[4])&&
			    (USART_ReceiveString[4]==FRIGER[5]))
					
				{Del_FR();}//删除指纹
		
		else//比对获取密码指令
		{
			for(i=0;i<5;i++)
			{
				if(USART_ReceiveString[i]!=HC05_PassWord[i])
				{
					Send_Time();printf("Getting Password Command Error\r\n\r\n");
					for(i=0;i<12;i++) USART_ReceiveString[i]=0;
					USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
					break;
				}
				if(i==4)
				{
					Send_Time();
					printf("Password: %d %d %d %d %d %d\r\n\r\n",
					PassWord[0],PassWord[1],PassWord[2],PassWord[3],PassWord[4],PassWord[5]);
				}
			}
		}
		for(i=0;i<12;i++) USART_ReceiveString[i]=0;
		USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
	}
}

void Send_Time()
{
	printf("Time: %d%d%d%d-%d%d-%d%d  %d%d:%d%d:%d%d\r\n",
	DS1302_Time[0],DS1302_Time[1],DS1302_Time[2],DS1302_Time[3],DS1302_Time[4],
	DS1302_Time[5],DS1302_Time[6],DS1302_Time[7],DS1302_Time[8],DS1302_Time[9],
	DS1302_Time[10],DS1302_Time[11],DS1302_Time[12],DS1302_Time[13]);
}

//输入密码
void Enter_Password()
{
	char i;
	
	/*-矩阵按键扫描-*/
	KEY_Scan();
	
	/*-------------------------按键输入密码-------------------------*/
	//数字0-9
	if((Key_Number==11)&&(PassWord_OK==0)&&(Pass_Count<6)) {Key_Number=0;PassBuffer[Pass_Count]=0;Pass_Count++;}
	if((Key_Number==1 )&&(PassWord_OK==0)&&(Pass_Count<6)) {Key_Number=0;PassBuffer[Pass_Count]=1;Pass_Count++;}
	if((Key_Number==2 )&&(PassWord_OK==0)&&(Pass_Count<6)) {Key_Number=0;PassBuffer[Pass_Count]=2;Pass_Count++;}
	if((Key_Number==3 )&&(PassWord_OK==0)&&(Pass_Count<6)) {Key_Number=0;PassBuffer[Pass_Count]=3;Pass_Count++;}
	if((Key_Number==4 )&&(PassWord_OK==0)&&(Pass_Count<6)) {Key_Number=0;PassBuffer[Pass_Count]=4;Pass_Count++;}
	if((Key_Number==5 )&&(PassWord_OK==0)&&(Pass_Count<6)) {Key_Number=0;PassBuffer[Pass_Count]=5;Pass_Count++;}
	if((Key_Number==6 )&&(PassWord_OK==0)&&(Pass_Count<6)) {Key_Number=0;PassBuffer[Pass_Count]=6;Pass_Count++;}
	if((Key_Number==7 )&&(PassWord_OK==0)&&(Pass_Count<6)) {Key_Number=0;PassBuffer[Pass_Count]=7;Pass_Count++;}
	if((Key_Number==8) &&(PassWord_OK==0)&&(Pass_Count<6)) {Key_Number=0;PassBuffer[Pass_Count]=8;Pass_Count++;}
	if((Key_Number==9) &&(PassWord_OK==0)&&(Pass_Count<6)) {Key_Number=0;PassBuffer[Pass_Count]=9;Pass_Count++;}

	/*------------------------比对已输入密码------------------------*/
	if((Key_Number==12)&&(Pass_Count==6)&&(PassWord_OK==0))
	{
		Key_Number=0;Pass_Count=0;
		for(i=0;i<6;i++)//对比6位密码
		{
			if(PassBuffer[i]!=PassWord[i])    //密码错误
			{
				Send_Time();
				printf("Password is error.\r\n\r\n");
				OLED_ShowString(0,6,"Password Error  ",16);
				PassWord_OK=0;Pass_Count=0;
				BEEP_ON();delay_ms(1000);BEEP_OFF();
				OLED_ShowString(0,6,"                ",16);
				OLED_ShowString(72,4,"      ",16);break;
			}
			if(i==5)                          //密码正确
			{
				Send_Time();
				printf("Door is open by Password.\r\n\r\n");
				OLED_ShowString(0,6,"Password Right  ",16);
				PassWord_OK=1;Pass_Count=0;DOOR_ON();
				delay_ms(1000);delay_ms(1000);
				OLED_ShowString(0,6,"                ",16);
				OLED_ShowString(72,4,"      ",16);
			}
		}
	}
	/*------------------------删除已输入密码------------------------*/
	if(Key_Number==10)
	{
		Key_Number=0;
		if(Pass_Count>0) Pass_Count--;
		PassBuffer[Pass_Count]=0;//清零
		OLED_ShowString(72+Pass_Count*8,4," ",16);//在已删除位置写空白字符
	}
	/*------------------------显示已输入密码------------------------*/
	OLED_ShowString(0,4,"Password:",16);
	for(i=0;i<Pass_Count;i++)
		OLED_ShowString(64+Pass_Count*8,4,"*",16);//对已经输入的密码显示 * 
}

//增加指纹
void Add_FR(void)
{
	u8 i=0,ensure ,processnum=0;
	u16 ID;
	while(1)
	{
		switch (processnum)
		{
			case 0:
				i++;
				OLED_ShowString(0,6,"Touch finger!   ",16);//请按手指
				ensure=PS_GetImage();
				if(ensure==0x00) 
				{
					ensure=PS_GenChar(CharBuffer1);//生成特征
					if(ensure==0x00)
					{
						OLED_ShowString(0,6,"Fingerpr correct",16);//指纹正确
						i=0;
						processnum=1;//跳到第二步	
					}			
				}					
				break;
			
			case 1:
				i++;
				OLED_ShowString(0,6,"Touch again!!   ",16);	
				ensure=PS_GetImage();
				if(ensure==0x00) 
				{
					ensure=PS_GenChar(CharBuffer2);//生成特征			
					if(ensure==0x00)
					{
						OLED_ShowString(0,6,"Fingerpr correct",16);//指纹正确
						i=0;
						processnum=2;//跳到第三步
					}	
				}	
				break;

			case 2:
				OLED_ShowString(0,6,"Compare fingerpr",16);//对比两次指纹
				ensure=PS_Match();
				if(ensure==0x00) 
				{
					OLED_ShowString(0,6,"Twice finge same",16);//两次指纹是一样的
					processnum=3;
				}
				else 
				{
					OLED_ShowString(0,6,"Compare fail!!! ",16);
					i=0;processnum=0;
				}
				delay_ms(1000);
				break;

			case 3:

				OLED_ShowString(0,6,"Generate Success",16);//创建成功
				delay_ms(1000);
				ensure=PS_RegModel();
				if(ensure==0x00) 
				{
					OLED_ShowString(0,6,"Save Success!!! ",16);//生成指纹模板成功
					processnum=4;
				}else {processnum=0;}
				delay_ms(1000);
				break;
				
			case 4:	
				OLED_ShowString(0,6,"Please enter ID ",16);
				while((Key_Number==0)||(Key_Number>9))
				{KEY_Scan();}//输入ID
				ID=Key_Number;Key_Number=0;
				ensure=PS_StoreChar(CharBuffer2,ID);//储存模板
				if(ensure==0x00) 
				{
					Send_Time();
					OLED_ShowString(0,6,"Add success!!!! ",16);
					printf("Add fingerprint succeed!!!\r\n");
					printf("Dingerprint ID is:%d\r\n",ID);
					PS_ValidTempleteNum(&ValidN);
					delay_ms(1500);OLED_ShowString(0,6,"                ",16);
					return ;
				}
				else {processnum=0;}					
				break;				
		}
		delay_ms(800);
		if(i==5)
		{
			break;	
		}				
	}
}

//对比指纹
void Pre_FR(void)
{
	SearchResult seach;
	u8 ensure;
	if((GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==1)&&(PassWord_OK==0))
	{
		OLED_ShowString(0,6,"Search Finger...",16);delay_ms(1000);
		ensure=PS_GetImage();
		if(ensure==0x00)//获取图像成功 
		{	//生成特征
			ensure=PS_GenChar(CharBuffer1);
			if(ensure==0x00)//生成特征成功
			{	//高速搜索指纹数据库
				ensure=PS_HighSpeedSearch(CharBuffer1,0,300,&seach);
				if(ensure==0x00)//搜索成功
				{
					PassWord_OK=1;
					OLED_ShowString(0,6,"Search Success!!",16);
					delay_ms(1000);DOOR_ON();
					Send_Time();printf("Door is open by Fingerprint.\r\n\r\n");
				}
				else //搜索失败
				{
					Send_Time();printf("Fingerprint is error.\r\n\r\n");
					OLED_ShowString(0,6,"Search Fail     ",16);
					BEEP_ON();delay_ms(1000);BEEP_OFF();
				}	
			}
			else //生成特征失败
			{OLED_ShowString(0,6,"Generate Fail   ",16);delay_ms(1000);}	
		}
		else//获取图像失败
		{
			OLED_ShowString(0,6,"PS_GetImage Fail",16);
			BEEP_ON();delay_ms(1000);BEEP_OFF();
		}
		Pass_Count=0;
		OLED_ShowString(0,6,"                ",16);
		OLED_ShowString(72,4,"      ",16);
	}
}
//删除指纹
void Del_FR(void)
{
	u8 ensure;
	ensure=PS_Empty();//开始删除删除
	if(ensure==0)//删除成功
	{
		OLED_ShowString(0,6,"DEL FRIGER OK   ",16);
		Send_Time();printf("Delete fingerprint succeed!!!\r\n\r\n");
		delay_ms(1000);
		OLED_ShowString(0,6,"                ",16);
	}
}
//时间显示
void Time_Display()
{
	DS1302_ReadTime();//读取时间
	OLED_ShowNum(0,0, DS1302_Time[0],1,16);	 //年千位
	OLED_ShowNum(8,0, DS1302_Time[1],1,16);  //年百位
	OLED_ShowNum(16,0,DS1302_Time[2],1,16);	 //年十位
	OLED_ShowNum(24,0,DS1302_Time[3],1,16);	 //年个位
	OLED_ShowNum(40,0,DS1302_Time[4],1,16);	 //月十位
	OLED_ShowNum(48,0,DS1302_Time[5],1,16);	 //月个位
	OLED_ShowNum(64,0 ,DS1302_Time[6],1,16); //日十位
	OLED_ShowNum(72,0, DS1302_Time[7],1,16); //日个位
	//OLED_ShowNum(106,0,DS1302_Time[14],1,16);//周十位
	OLED_ShowNum(114,0,DS1302_Time[15],1,16);//周个位
	OLED_ShowNum(0,2 ,DS1302_Time[8],1,16);	 //小时十位
	OLED_ShowNum(17,2,DS1302_Time[9],1,16);  //小时个位
	OLED_ShowNum(49,2,DS1302_Time[10],1,16); //分钟十位
	OLED_ShowNum(65,2,DS1302_Time[11],1,16); //分钟个位
	OLED_ShowNum(97,2, DS1302_Time[12],1,16);//秒钟十位
	OLED_ShowNum(113,2,DS1302_Time[13],1,16);//秒钟个位
	
	OLED_ShowString(32,0,"-",16);OLED_ShowString(56,0,"-",16);
	
	if(DS1302_Time[13]%2)
	{OLED_ShowString(33,2,":",16);OLED_ShowString(81,2,":",16); }
	else
	{OLED_ShowString(81,2," ",16); OLED_ShowString(33,2," ",16);}
}

void DS1302_Init(void)
{
	Ds1302_gpio_init();  //端口初始化
	DS1302_CE = 0;  DS1302_delay_us(2);
	DS1302_SCK = 0; DS1302_delay_us(2);

	Ds1302_writedata(0x8e,0x00); //撤销写保护,允许写入数据,0x8e,0x00

	Ds1302_writedata(ds1302_year_add,TIME[1]);		//年
	Ds1302_writedata(ds1302_month_add,TIME[2]);	    //月
	Ds1302_writedata(ds1302_date_add,TIME[3]);		//日
	Ds1302_writedata(ds1302_hr_add,TIME[4]);		//时
	Ds1302_writedata(ds1302_min_add,TIME[5]);		//分
	Ds1302_writedata(ds1302_sec_add,TIME[6]);		//秒
	Ds1302_writedata(ds1302_day_add,TIME[7]);		//周
	Ds1302_writedata(0x8e,0x80);//打开写保护功能,防止干扰造成的数据写入。
	DS1302_ReadTime();//读取时间
	new_hour=TIME[4];old_hour=new_hour;//避免每次上电都重新生成密码
}

void DS1302_ReadTime()
{
	TIME[1]=Ds1302_readdata(ds1302_year_add);		//年 
	TIME[2]=Ds1302_readdata(ds1302_month_add);		//月 
	TIME[3]=Ds1302_readdata(ds1302_date_add);		//日 
	TIME[4]=Ds1302_readdata(ds1302_hr_add);		    //时 
	TIME[5]=Ds1302_readdata(ds1302_min_add);		//分 
	TIME[6]=(Ds1302_readdata(ds1302_sec_add))&0x7f; //秒,屏蔽秒的第7位,避免超出59
	TIME[7]=Ds1302_readdata(ds1302_day_add);		//周 
	
	
	DS1302_Time[0]=(TIME[0]>>4);   //分离出年千位
	DS1302_Time[1]=(TIME[0]&0x0F); //分离出年百位 
	DS1302_Time[2]=(TIME[1]>>4);   //分离出年十位
	DS1302_Time[3]=(TIME[1]&0x0F); //分离出年个位 

	DS1302_Time[4]=(TIME[2]>>4);   //分离出月十位
	DS1302_Time[5]=(TIME[2]&0x0F); //分离出月个位 

	DS1302_Time[6]=(TIME[3]>>4);   //分离出日十位
	DS1302_Time[7]=(TIME[3]&0x0F); //分离出日个位 

	DS1302_Time[8]=(TIME[4]>>4);   //分离出小时十位
	DS1302_Time[9]=(TIME[4]&0x0F); //分离出小时个位
	DS1302_Time[10]=(TIME[5]>>4);   //分离出分钟十位
	DS1302_Time[11]=(TIME[5]&0x0F); //分离出分钟个位
	DS1302_Time[12]=(TIME[6]>>4);   //分离出秒钟十位
	DS1302_Time[13]=(TIME[6]&0x0F); //分离出秒钟个位
	
	DS1302_Time[14]=(TIME[7]>>4);   //分离出周十位
	DS1302_Time[15]=(TIME[7]&0x0F); //分离出周个位
}