前述:
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); //分离出周个位
}