一、项目功能概述
1、可通过指纹模块增删查改家庭成员的指纹信息,增删查改是否成功的相关信息显示在TFTLCD屏幕,可存储500个指纹信息。
2、在指纹匹配过程中,如果采集的指纹与指纹模块库相匹配,TFTLCD显示“刷指纹成功,确有此人ID”,此时指示灯亮。
3、可以密码解锁(密码6位),如果匹配成功,即可开锁,显示“密码正确”,指示灯亮。
4、如果密码错误或者没有识别到指纹,指示灯灭,蜂鸣器报警。
5、支持TFTLCD触摸屏校准。
6、显示温湿度。
**
资料下载地址:基于STM32指纹密码锁
**
二、材料选择
1、正点原子F103精英板
2、正点原子3.5寸TFTLCD屏
3、正点原子LB301电容式指纹模块
4、DHT11温湿度模块
三、原理图设计
LB301模块连接图
DHT11模块连接图
VCC DATA GND
3.3V PA11 GND
四、成品展示
1、上电界面
需要进行触摸屏校准按K1,不需要则按K0。
2、触摸屏校准
按下K1进入触摸屏校准界面,总共四个对角点,依次按下就行,按好后进入主界面。
3、主界面
4、指纹采集界面
指纹采集时需要将手指放在指纹模块上,指纹采集成功后,需要在键盘上输入录入指纹ID,然后按Enter进行保存。
4、指纹识别成功界面
将手指放在模块上进行识别,识别成功显示“刷指纹成功,确有此人ID”,二极管亮,识别失败显示“没有搜索到指纹”,二极管灭蜂鸣器报警!
5、密码解锁界面
首先点击屏幕的密码解锁,输入6位数密码,正确密码为“55555”,如果密码匹配失败显示“密码错误”,匹配成功显示“密码正确”。
6、删指纹界面
支持单个指纹删除和指纹清空两种功能
源码设计
main.c
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "lcd.h"
#include "key.h"
#include "beep.h"
#include "touch.h"
#include "malloc.h"
#include "usmart.h"
#include "sdio_sdcard.h"
#include "w25qxx.h"
#include "ff.h"
#include "exfuns.h"
#include "fontupd.h"
#include "text.h"
#include "usart2.h"
#include "LB301.h"
#include "timer.h"
#include "string.h"
#define usart2_baund 57600//串口2波特率,根据指纹模块波特率更改
SysPara LB301Para;//指纹模块LB301参数
u16 ValidN;//模块内有效指纹个数
u8** kbd_tbl;
const u8* kbd_menu[15]={"删指纹"," 密码解锁","录指纹","1","2","3","4","5","6","7","8","9","DEL","0","Enter",};//按键表
const u8* kbd_delFR[15]={"返回"," ","清空指纹","1","2","3","4","5","6","7","8","9","DEL","0","Enter",};//按键表
void CheckPassword(uint8_t key_val);//密码检查
void Add_FR(void); //录指纹
void Del_FR(void); //删除指纹
void press_FR(void);//刷指纹
void ShowErrMessage(u8 ensure);//显示确认码错误信息
void LB301_load_keyboard(u16 x,u16 y,u8 **kbtbl);//加载虚拟键盘
u8 LB301_get_keynum(u16 x,u16 y);//获取键盘数
u16 GET_NUM(void);//获取数值
uint8_t shidu = 0;
uint8_t wendu = 0;
char mStrtemp[20];
char mStrhum[20];
uint8_t mFingerErr= 0;
uint8_t mPasswordErr = 0;
int main(void)
{
u8 ensure;
u8 key_num;
char *str;
u16 count = 0;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
delay_init(); //初始化延时函数
uart_init(115200); //初始化串口1波特率为115200,用于支持USMART
usart2_init(usart2_baund);//初始化串口2,用于与指纹模块通讯
BEEP_Init(); //初始化蜂鸣器
led_init();
DHT11_Init();
KEY_Init(); //按键初始化
LCD_Init(); //LCD初始化
W25QXX_Init(); //初始化W25Q128
tp_dev.init(); //初始化触摸屏
usmart_dev.init(72); //初始化USMART
my_mem_init(SRAMIN); //初始化内部内存池
exfuns_init(); //为fatfs相关变量申请内存
f_mount(fs[1],"1:",1); //挂载FLASH.
POINT_COLOR=RED;
while(font_init()) //检查字库
{
LCD_ShowString(60,50,240,16,16,"Font Error!");
delay_ms(200);
LCD_Fill(60,50,240,66,WHITE);//清除显示
delay_ms(200);
}
if(!(tp_dev.touchtype&0x80))//如果是电阻屏
{
Show_Str_Mid(0,30,"是否进行触摸屏校准",16,240);
POINT_COLOR=BLUE;
Show_Str_Mid(0,60,"是:KEY1 否:KEY0",16,240);
while(1)
{
key_num=KEY_Scan(0);
if(key_num==KEY0_PRES)
break;
if(key_num==KEY1_PRES)
{
LCD_Clear(WHITE);
TP_Adjust(); //屏幕校准
TP_Save_Adjdata();//保存校准参数
break;
}
}
}
/*加载指纹识别实验界面*/
LCD_Clear(WHITE);
POINT_COLOR=RED;
Show_Str_Mid(0,20,"智能锁防盗控制系统",16,240);
//Show_Str_Mid(0,460," 金陵科技学院毕业设计",16,240);
//Show_Str_Mid(0,20,"正点原子 @ALIENTEK",16,240);
POINT_COLOR=BLUE;
Show_Str_Mid(0,40,"与LB301模块握手....",16,240);
while(PS_GetImage() == 0xff)//与LB301模块握手(读取图像指令有数据返回说明模块已经连接)
{
delay_ms(400);
LCD_Fill(0,40,240,80,WHITE);
Show_Str_Mid(0,40,"未检测到模块!!!",16,240);
delay_ms(800);
LCD_Fill(0,40,240,80,WHITE);
Show_Str_Mid(0,40,"尝试连接模块...",16,240);
}
LCD_Fill(30,40,240,100,WHITE);
Show_Str_Mid(0,40,"通讯成功!!!",16,240);
str=mymalloc(SRAMIN,30);
sprintf(str,"波特率:%d 地址:%x",usart2_baund,LB301Addr);
//Show_Str(0,60,240,16,(u8*)str,16,0);
ensure=PS_ValidTempleteNum(&ValidN);//读库指纹个数
if(ensure!=0x00)
ShowErrMessage(ensure);//显示确认码错误信息
ensure=PS_ReadSysPara(&LB301Para); //读参数
if(ensure==0x00)
{
mymemset(str,0,50);
sprintf(str,"库容量:%d 对比等级: %d",LB301Para.PS_max-ValidN,LB301Para.PS_level);
//Show_Str(0,80,240,16,(u8*)str,16,0);
}
else
ShowErrMessage(ensure);
myfree(SRAMIN,str);
LB301_load_keyboard(0,170,(u8**)kbd_menu);//加载虚拟键盘
while(1)
{
key_num=LB301_get_keynum(0,170);
if(key_num)
{
if(key_num==1)Del_FR(); //删指纹
if(key_num==3)Add_FR(); //录指纹
CheckPassword(key_num);
}
//查询刷指纹
if(++count > 5)
{
count = 0;
press_FR();
DHT11_Read_Data(&wendu,&shidu);//获取温湿度值
}
delay_ms(1);
sprintf(mStrtemp,"%d",wendu );
sprintf(mStrhum, "%d",shidu);
Show_Str(150,60,240,16,(u8*)mStrhum,16,0);
Show_Str(150,80,240,16,(u8*)mStrtemp,16,0);
Show_Str_Mid(0,60,"湿度:",16,220);
Show_Str_Mid(0,80,"温度:",16,220);
}
}
//加载按键界面(尺寸x,y为240*150)
//x,y:界面起始坐标(240*320分辨率的时候,x必须为0)
void LB301_load_keyboard(u16 x,u16 y,u8 **kbtbl)
{
u16 i;
POINT_COLOR=RED;
kbd_tbl=kbtbl;
LCD_Fill(x,y,x+240,y+150,WHITE);
LCD_DrawRectangle(x,y,x+240,y+150);
LCD_DrawRectangle(x+80,y,x+160,y+150);
LCD_DrawRectangle(x,y+30,x+240,y+60);
LCD_DrawRectangle(x,y+90,x+240,y+120);
POINT_COLOR=BLUE;
for(i=0;i<15;i++)
{
if(i==1)//按键表第2个‘:’不需要中间显示
Show_Str(x+(i%3)*80+2,y+7+30*(i/3),80,30,(u8*)kbd_tbl[i],16,0);
else
Show_Str_Mid(x+(i%3)*80,y+7+30*(i/3),(u8*)kbd_tbl[i],16,80);
}
}
//按键状态设置
//x,y:键盘坐标
//key:键值(0~14)
//sta:状态,0,松开;1,按下;
void LB301_key_staset(u16 x,u16 y,u8 keyx,u8 sta)
{
u16 i=keyx/3,j=keyx%3;
if(keyx>16)return;
if(sta &&keyx!=1)//按键表第2个‘:’不需要清除
LCD_Fill(x+j*80+1,y+i*30+1,x+j*80+78,y+i*30+28,GREEN);
else if(keyx!=1)
LCD_Fill(x+j*80+1,y+i*30+1,x+j*80+78,y+i*30+28,WHITE);
if(keyx!=1)//不是‘:’
Show_Str_Mid(x+j*80,y+7+30*i,(u8*)kbd_tbl[keyx],16,80);
}
//得到触摸屏的输入
//x,y:键盘坐标
//返回值:(1~15,对应按键表)
u8 LB301_get_keynum(u16 x,u16 y)
{
u16 i,j;
static u8 key_x=0;//0,没有任何按键按下
u8 key=0;
tp_dev.scan(0);
if(tp_dev.sta&TP_PRES_DOWN)//触摸屏被按下
{
for(i=0;i<5;i++)
{
for(j=0;j<3;j++)
{
if(tp_dev.x[0]<(x+j*80+80)&&tp_dev.x[0]>(x+j*80)&&tp_dev.y[0]<(y+i*30+30)&&tp_dev.y[0]>(y+i*30))
{
key=i*3+j+1;
break;
}
}
if(key)
{
if(key_x==key)key=0;
else
{
LB301_key_staset(x,y,key_x-1,0);
key_x=key;
LB301_key_staset(x,y,key_x-1,1);
}
break;
}
}
}else if(key_x)
{
LB301_key_staset(x,y,key_x-1,0);
key_x=0;
}
return key;
}
//获取键盘数值
u16 GET_NUM(void)
{
u8 key_num=0;
u16 num=0;
while(1)
{
key_num=LB301_get_keynum(0,170);
if(key_num)
{
if(key_num==1)return 0xFFFF;//‘返回’键
if(key_num==3)return 0xFF00;//
if(key_num>3&&key_num<13&&num<99)//‘1-9’键(限制输入3位数)
num =num*10+key_num-3;
if(key_num==13)num =num/10;//‘Del’键
if(key_num==14&&num<99)num =num*10;//‘0’键
if(key_num==15)return num; //‘Enter’键
}
//LCD_ShowNum(80+15,170+7,num,6,16);
}
}
//显示确认码错误信息
void ShowErrMessage(u8 ensure)
{
LCD_Fill(0,120,lcddev.width,160,WHITE);
Show_Str_Mid(0,120,(u8*)EnsureMessage(ensure),16,240);
}
//录指纹
void Add_FR(void)
{
u8 i=0,ensure ,processnum=1,pressCout=1, str_buffer[40];
u16 ID;
while(1)
{
switch (processnum)
{
case 1: //连续按压4次指纹分别存到4个charBuffer里
i++;
LCD_Fill(0,100,lcddev.width,160,WHITE);
sprintf((char*)str_buffer,"请按指纹(%d)",pressCout);
Show_Str_Mid(0,100,str_buffer,16,240);
ensure=PS_GetImage();
if(ensure==0x00)
{
i=0;
BEEP=1;
delay_ms(100);//这里需要延时一下,模块内部处理图像需要时间
ensure=PS_GenChar(pressCout);//生成特征
BEEP=0;
if(ensure==0x00)
{
LCD_Fill(0,120,lcddev.width,160,WHITE);
Show_Str_Mid(0,120,"指纹正常",16,240);
pressCout++;
if(pressCout >=5)
{
pressCout = 0;
processnum=2;//跳到第二步
}
}else ShowErrMessage(ensure);
}else ShowErrMessage(ensure);
break;
case 2:
LCD_Fill(0,100,lcddev.width,160,WHITE);
Show_Str_Mid(0,100,"生成指纹模板",16,240);
ensure=PS_RegMB();
if(ensure==0x00)
{
LCD_Fill(0,120,lcddev.width,160,WHITE);
Show_Str_Mid(0,120,"生成指纹模板成功",16,240);
processnum=3;//跳到第三步
}else {processnum=0;ShowErrMessage(ensure);}
delay_ms(1200);
break;
case 3:
LCD_Fill(0,100,lcddev.width,160,WHITE);
Show_Str_Mid(0,100,"请输入储存ID,按Enter保存",16,240);
Show_Str_Mid(0,120,"0=< ID <=499",16,240);
do
ID=GET_NUM();
while(!(ID<LB301Para.PS_max));//输入ID必须小于模块容量最大的数值
ensure=PS_StoreMB(CharBuffer1,ID);//储存模板
if(ensure==0x00)
{
LCD_Fill(0,100,lcddev.width,160,WHITE);
Show_Str_Mid(0,120,"录入指纹成功",16,240);
PS_ValidTempleteNum(&ValidN);//读库指纹个数
//LCD_ShowNum(56,80,LB301Para.PS_max-ValidN,3,16);//显示剩余指纹容量
delay_ms(1500);
LCD_Fill(0,100,240,160,WHITE);
return ;
}else {processnum=0;ShowErrMessage(ensure);}
break;
}
delay_ms(200);
if(i>=20)//超过20次没有按手指则退出
{
LCD_Fill(0,100,lcddev.width,160,WHITE);
break;
}
}
}
#define USE_AUTO_IDETIFY 1 // 1使用自动验证方式 0使用分布式验证方式
//刷指纹
void press_FR(void)
{
SearchResult seach;
u8 ensure;
char *str;
#if (USE_AUTO_IDETIFY == 1) //自动验证指纹
ensure=PS_AutoIdentify(&seach);
if(ensure==0x00)//自动验证成功
{
BEEP=1;
LCD_Fill(0,100,lcddev.width,160,WHITE);
Show_Str_Mid(0,100,"刷指纹成功",16,240);
str=mymalloc(SRAMIN,2000);
sprintf(str,"确有此人,ID:%d 匹配得分:%d",seach.pageID,seach.mathscore);
Show_Str_Mid(0,140,(u8*)str,16,240);
myfree(SRAMIN,str);
GPIO_ResetBits(GPIOB,GPIO_Pin_5);//输出0,打开LED灯
delay_ms(500);
BEEP=0;//关闭蜂鸣器
GPIO_SetBits(GPIOB,GPIO_Pin_5);//输出0,关闭LED灯
LCD_Fill(0,100,lcddev.width,160,WHITE);
}
else if(ensure != 0xff)
{
BEEP=1;
ShowErrMessage(ensure);
delay_ms(500);
BEEP=0;//关闭蜂鸣器
LCD_Fill(0,100,lcddev.width,160,WHITE);
GPIO_SetBits(GPIOB,GPIO_Pin_5);//输出0,关闭LED灯
}
#else //分布式验证指纹
ensure=PS_GetImage();
if(ensure==0x00)//获取图像成功
{
BEEP=1;//打开蜂鸣器
delay_ms(100);//这里需要延时一下,模块内部处理图像需要时间
ensure=PS_GenChar(CharBuffer1);
if(ensure==0x00) //生成特征成功
{
BEEP=0;//关闭蜂鸣器
ensure=PS_Search(CharBuffer1,0,299,&seach);//LB301Para.PS_max
if(ensure==0x00)//搜索成功
{
LCD_Fill(0,100,lcddev.width,160,WHITE);
Show_Str_Mid(0,100,"刷指纹成功",16,240);
str=mymalloc(SRAMIN,2000);
sprintf(str,"确有此人,ID:%d 匹配得分:%d",seach.pageID,seach.mathscore);
Show_Str_Mid(0,140,(u8*)str,16,240);
myfree(SRAMIN,str);
}
else
ShowErrMessage(ensure);
}
else
ShowErrMessage(ensure);
delay_ms(500);
BEEP=0;//关闭蜂鸣器
LCD_Fill(0,100,lcddev.width,160,WHITE);
}
#endif
}
//删除指纹
void Del_FR(void)
{
u8 ensure;
u16 num;
LCD_Fill(0,100,lcddev.width,160,WHITE);
Show_Str_Mid(0,100,"删除指纹",16,240);
Show_Str_Mid(0,120,"请输入指纹ID按Enter发送",16,240);
Show_Str_Mid(0,140,"0=< ID <=499",16,240);
delay_ms(50);
LB301_load_keyboard(0,170,(u8**)kbd_delFR);
num=GET_NUM();//获取返回的数值
if(num==0xFFFF)
goto MENU ; //返回主页面
else if(num==0xFF00)
ensure=PS_Empty();//清空指纹库
else
ensure=PS_DeletChar(num,1);//删除单个指纹
if(ensure==0)
{
LCD_Fill(0,120,lcddev.width,160,WHITE);
Show_Str_Mid(0,140,"删除指纹成功",16,240);
}
else
ShowErrMessage(ensure);
delay_ms(1200);
PS_ValidTempleteNum(&ValidN);//读库指纹个数
// LCD_ShowNum(56,80,LB301Para.PS_max-ValidN,3,16);
MENU:
LCD_Fill(0,100,lcddev.width,160,WHITE);
delay_ms(50);
LB301_load_keyboard(0,170,(u8**)kbd_menu);
}