UART Fingerprint Sensor (F) 使用教程

产品说明

简介

采用高性能 Cortex 内核的主控,集成了高安全性商用指纹算法,支持指纹录入、图像采集、特征值提取和指纹比对等功能。无需了解复杂指纹识别算法,只需通过串口发送指令即进行二次开发,可快速集成到各种对体积和精度要求较高的指纹识别应用中。

  • 内置商用算法,支持指纹录入、指纹比对、指纹图像提取和指纹特征值上传等功能,性能稳定,识别速度快
  • 电容式指纹识别,感应灵敏,手指只要轻轻地触碰采集窗就能快速识别
  • 硬件集成度高,主控和指纹传感器集成一体,方便嵌入到小体积应用中
  • 内置人体感应器件,具有掉电睡眠和触摸唤醒功能,功耗更低
  • 采集窗带 LED,提供指纹采集指示
  • 板载 UART 串口和 USB 双通讯接口
  • 方便接入 PC 配合上位机通讯,同时也支持 STM32 和 Raspberry Pi 等嵌入式硬件平台

参数

  • 传感器类型:电容式触摸式传感器
  • 分辨率:508DPI
  • 图像像素阵列:192 x 192
  • 模块尺寸:20.4mm x 33.4mm
  • 传感器感应面积:9.6mm x 9.6mm
  • 指纹容量:1000枚
  • 比对时间:< 0.5s (1:N, 且N≤500)
  • 工作电压:3.3
  • 工作电流:<55mA
  • 静电测试:ESD IEC 61000-4-2 LEVEL 4 正负15KV 隔空放电
  • 通信接口:UART/USB
  • 通信波特率:115200bps (支持 9600bps ~ 115200bps)
  • 工作环境:
    • 温度:-10~60 ℃
    • 湿度: 20%RH ~ 80%RH (无凝霜)

接口说明


硬件使用说明

硬件连接

用户拿到模块后,可先使用测试软件或测试程序对模块进行测试。在对模块有了一定的了解后,可使用指令表进行二次开发。
模块可以通过 UART 串口控制或者通过USB接口控制。

UART串口连接

如果接到开发板上,可以使用UART串口连接。

指纹模块目标主板备注
GNDGND电源地
RXTXUART数据传输引脚,需要交叉接线
TXRXUART数据传输引脚,需要交叉接线
VIN3.3V3.3V供电输入
IRQGPIO指纹触摸检测引脚, 有手指触摸输出高电平,配合VT引脚使用, 可接入普通GPIO引脚,设置为输入状态使用
VTGPIO触摸供电引脚,和IRQ引脚配合使用,可接入普通GPIO

USB接口使用

可以接入配送的USB引脚使用。 如果是自己另外设计线材或者定制线材,注意处理电平转换。 模块只能支持3.3V电平

手指操作说明

本模块采用高精密元件,在采集指纹时:
手指轻轻地触碰到采集窗口就能识别,不需要用力按压指纹采集窗。

正确按指纹


错误按指纹


串口控制说明

1、使用 FT232 USB转UART串口模块进行测试(如用户使用其它 USB 转串口模块,操作也类似,模块需要另外购买),安装 FT232 驱动
2、参考引脚定义#UART串口连接连接模块(注意 RXD TXD 是交叉相连的):
3、将 FT232 连接到 PC 机的 USB 接口,打开设备管理器, 查看相应的 COM 口:

4、下载测试软件:Capacitive-Fingerprint-Reader-(B)-Demo:
打开软件:
选择对应的通信方式:
Serial : 串口通信
Usb : USB通信
选择串口通信时,注意选择对应的波特率和串口号

软件使用说明

注意:提供的上位机软件只能支持Windows PC
串口与USB的操作方式一致,这里使用USB进行演示

检查通信

点击初始化传感器,如果连接成功则会接收到如图所示结果:

设置参数

参数类型:
Device ID :表示本模块设备编号,可设置范围: 1-255
Security Level :表示安全等级,可设置值:1-5,数值越大:误识率(FAR)越低,但拒真率(FRR)越高
Duplication Check :指纹重复检查状态开/关(1/0)。
Baudrate :波特率的索引。
Auto Learn :表示指纹模板自学习状态开/关(1/0)。
选择对应的参数,输入好对应的参数值,点击设置参数即可改变模块的参数;点击获取参数即可获取模块的当前参数。

用户录入

首先先将ID(指纹存储的编号)设置好,在选择图像数量(需要录入几次手指),然后点击录入指纹,根据提示一步一步的操作,最后成功结果如下图。
如果你不知道ID应该设置成多少,可以使用“可注册编号”、“获取注册状态”、“获取已注册用户列表”来寻找可注册的ID

指纹比对

选择要比对的模板指纹ID,点击 比对(1:1) 如果你开启了自学习功能,比对时间会略大于0.5S,并保存手指上没有保存的那一部分指纹。
点击 比对(1:N) 会自动比对1~3000(设置的指纹容量为多少就会比对到哪)的编号中所有已经注册的指纹,它是连续比对的,即比对成功后停止0.5s左右自动进行下一次比对。

查看用户总数

1、点击用户总数,会查询该模块在1~1000(设置的指纹容量为多少就会查询到哪)的编号中注册了多少指纹。

2、点击获取已注册用户列表,会查询该模块在1~3000(设置的指纹容量为多少就会查询到哪)中注册了多少指纹,滑动结果处的指纹,可以看到已经注册的指纹编号。

获取可注册编号

点击“可注册编号”,会从编号1开始查询第一个没有被注册的编号。

获取当前ID编号的注册状态
点击 获取注册状态 会显示当前ID编号的存储空间是否是空的,下图便是该ID编号的存储空间不是空的(即ID已被注册)。

删除指纹

点击“单个删除”,删除当前ID编号的指纹。
点击全部删除,删除1~3000(设置的指纹容量为多少就会到哪)的编号中所有以注册的指纹。

查看指纹图像(不能查看已经保存的指纹)

点击上传指纹图像,然后在传感器上按下自己的手指。
也可以打开预览图像,这样在每次需要输入指纹时,都会显示指纹图像(注:串口模式下不推荐使用,传输图像数据需要6秒左右)
可以选择打开拉伸显示,满图像的显示指纹

查看指纹特征值(只能查看已经保存的指纹)

选择已经保存过指纹的ID编号
点击上传特征值

点击“批量上传特征值”,选择一个文件夹用来保存特征值文件。会上传1~3000(指纹容量的选择数量)编号的指纹数据。以FPT的格式存放在你选择的文件夹下面。

Capacitive Fingerprint Reader (B) 20.png

使用指纹图像进行用户录入

配置好ID编号和图像数量,具体参考 “用户录入”
点击“从图像注册”,选择指纹模图像。图像大小为242*266


使用特征值进行用户录入

1、单个下载
配置好ID编号。
点击下图所示的打开文件,选择一个FPT格式的文件,点击“下载特征值”。
2、批量下载
点击“批量下载特征值”选择对应的文件夹,文件夹中所有的FPT格式文件按照排序方式依次下载到模块当中,他们的ID号是依次增加的。

使用指纹图像进行识别。

点击下图所示的打开文件,选择指纹图像,点击“下载图像识别”。

使用特征值进行识别

配置好ID编号和图像数量,具体参考 “用户录入”
点击下图所示的打开文件,选择一个FPT格式的文件,点击“下载特征值识别”,将会和你选择的指纹ID编号内的指纹模板进行对比;
点击“下载特征值比对”,将会和你按下的手指进行比对。

查看已被损坏的特征值

点击“坏损特征值编号”,接收到的结果回将显示被损坏的特征值的总数和第一个被损坏的特征值的编号。

休眠

点击“进入休眠”
进入休眠状态后,无论进行什么操作都没有反应,只有重新上电后才有反应

例程使用

树莓派、Arduino、STM32的函数内容可能会有部分不同,但是操作方式与功能是一样的。

连接方式

STM32连接引脚对应关系
模块STM32功能
VIN3.3V电源输入
GNDGND电源地
TXDPA10模块串口发送端
RXDPA9模块串口接收端


Arduino连接引脚对应关系
模块Arduino功能
VIN3.3V电源输入
GNDGND电源地
TXD10模块串口发送端
RXD11模块串口接收端


Raspberry Pi连接引脚对应关系
模块Raspberry Pi功能
VIN3.3V电源输入
GNDGND电源地
TXDRXD模块串口发送端
RXDTXD模块串口接收端


STM32/Arduino使用

按连接方式连接好对应的STM32/Arduino与指纹模块
Open103Z/Arduino UNO的USB与电脑连接 选择对应的串口:

CMD0 :检查连接是否成功
CMD1 :检查是否有手指按下
CMD2 :注册指纹
CMD3 :删除指纹
CMD4 :比对一个指纹
CMD5 :比对范围内的指纹
CMD6 :查询第一个未注册指纹的编号
CMD7 :查询指纹注册总数
CMD8 :上传指纹图像到主机
CMD9 :下载指纹图像到模块

注:Arduino因为内存的原因,没有CMD8、CMD9两条指令,使用115200波特率时会有丢包现象的发生推荐使用57600的波特率
修改方法:
1、使用软件进行修改
2、使用下面的指令进行修改

设置成115200波特率:
55 AA 00 00 02 00 05 00 03 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0e 01
设置成57600波特率:
55 AA 00 00 02 00 05 00 03 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0d 01
设置成功后的返回值为:
AA 55 01 00 02 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 01

树莓派使用

打开串口

输入命令

sudo raspi-config






重启

sudo reboot

安装wiringpi

sudo apt install git-core
sudo git clone https://github.com/WiringPi/WiringPi
cd WiringPi/
sudo ./build
#查看wiringpi版本,一般在2.70以上
gpio -v

安装python库

#python3的串口库
sudo apt-get install python3-serial
#python2的串口库
sudo apt-get install python-serial

例程下载

wget https://www.waveshare.net/w/upload/1/1d/Capacitive-Fingerprint-Reader%28B%29-Code.zip
unzip unzip Capacitive-Fingerprint-Reader\(B\)-Code
cd cd Capacitive-Fingerprint-Reader\(B\)-Code/RaspberryPi/

例程使用

c

cd c
make 
sudo ./test

python

cd python
sudo python main.py

python3

cd python3
sudo python3 main.py

程序说明

C文件说明

fingerprint.h 用来保存程序运行的主体函数。
cmd.h 用来保存你的指纹图像数据。

部分函数说明

  • 初始化处理

首先处理好握手信号的数据 然后等待模块初始化完成,最后发送握手信号,握手成功则进行下面的操作,不成功等待1秒后再次进行握手,共执行3次。

void CMD_Init(void)
{
	uint8_t i = 0;
	Cmd_Packet_Init();
	Handshake_Signal();
	while(1)
	{
		Tx_cmd();
		if( Rx_cmd(1) )
		{
			printf("Connection closed by server\n\r");
			printf("Try to reconnect\n\r");
			if(i++ > 3)
			{
				printf("Power on the device again");
				while(1);
			}
		}
		else
			break;
		HAL_Delay(1000);
	}
}
  • 等待模块初始化方式选择

取消第四行的注释等待方式为:等待0.5秒 不取消第四行的注释等待方式为:等待模块发送初始化完成标志(该方法必须将RST引脚连接好)

void Handshake_Signal(void)
{
// Select a power-on waiting mode
//#define CMD_DELAY 
	#ifdef CMD_DELAY
		HAL_Delay(500);
	#else
		Handshake_flag = 1;
		HAL_GPIO_WritePin(Finger_RST_GPIO_Port,Finger_RST_Pin,GPIO_PIN_RESET);
		HAL_Delay(250);
		HAL_GPIO_WritePin(Finger_RST_GPIO_Port,Finger_RST_Pin,GPIO_PIN_SET);
		while(1)
		{
			if(flag == 1)
			{
				if(Handshake_data == 0x55)
				{
					Handshake_flag = 0;
					flag = 0;
					break;
				}
				else
				{
					printf("The communication fails. Power on the device again");
					while(1);
				}
			}
			HAL_Delay(1);
		}
	#endif
#undef CMD_DELAY 
}
  • 初始化命令结构体
void Cmd_Packet_Init(void)
{
	CMD.PREFIX = Command;
	CMD.SID = Command_SID;
	CMD.DID = Command_DID;
	CMD.CMD = CMD_TEST_CONNECTION;
	CMD.LEN = DATA_0;
	for(int i = 0 ; i <CMD_Len ; i++)
		CMD.DATA[i] = 0x00;
}
  • 接收用户命令并处理
uint8_t Tx_Data_Process(void)
{
	while(1)
	{
		if( Usart2_ReceiveStruct.RX_flag == 1 )        
		{
			Usart2_ReceiveStruct.RX_Size=0;    
			Usart2_ReceiveStruct.RX_flag=0;	
			flag = 0;
			if((Usart2_ReceiveStruct.RX_pData[0] == 'C') && (Usart2_ReceiveStruct.RX_pData[1] == 'M') && (Usart2_ReceiveStruct.RX_pData[2] == 'D'))
			{
				switch(Usart2_ReceiveStruct.RX_pData[3])
				{
					case '0': CmdTestConnection( 0 ) ; break;
					case '1': CmdFingerDetect( 0 ) ; break;
					case '2': AddUser( ) ; break;
					case '3': ClearUser( 0 ) ; break;
					case '4': VerifyUser( ) ; break;
					case '5': ScopeVerifyUser( ) ; break;
					case '6': CmdGetEmptyID( 0 ) ; break;
					case '7': GetUserCount( 1 ) ; break;
					case '8': CmdUpImageCode( 1 ) ; break;
					case '9': CmdDownImage( ) ; break;
				}
				break;
			}
		}
		HAL_Delay(1);
	}
	return 0;
}
  • 构建命令数组并发送
void Tx_cmd(void)
{ 
	uint16_t 		CKS = 0 ;
	if(mode == 0 || mode == 2)
	{
		cmd[0] = CMD.PREFIX & 0xff;
		cmd[1] = (CMD.PREFIX & 0xff00) >> 8;
		cmd[2] = CMD.SID;
		cmd[3] = CMD.DID;
		cmd[4] = CMD.CMD ;
		cmd[5] = 0x00 ;
		cmd[6] = CMD.LEN & 0xff;
		cmd[7] = (CMD.LEN & 0xff00) >> 8;
		for(int i = 0 ; i < CMD.LEN ; i++)
			cmd[8+i] = CMD.DATA[i];
		for(int i = 0 ; i < 24 ; i++)
			CKS = CKS + cmd[i];
		cmd[24] = CKS & 0xff;
		cmd[25] = (CKS & 0xff00) >> 8;
		HAL_UART_Transmit(&huart1,cmd, 26,2); 
	}
	else
	{
		cmd_data[0] = CMD_DATA.PREFIX & 0xff ;
		cmd_data[1] = (CMD_DATA.PREFIX & 0xff00) >> 8 ;
		cmd_data[2] = CMD_DATA.SID ;
		cmd_data[3] = CMD_DATA.DID ;
		cmd_data[4] = CMD_DATA.CMD ;
		cmd_data[5] = 0x00 ;
		cmd_data[6] = CMD_DATA.LEN & 0xff;
		cmd_data[7] = (CMD_DATA.LEN & 0xff00) >> 8; 
		if(SN <129 )
		{
			for(int i = 0 ; i < CMD_DATA.LEN ; i++)
				cmd_data[8+i] = CMD_DATA.DATA[i]; 
			for(int i = 0 ; i < 506 ; i++)
				CKS = CKS + cmd_data[i];
			cmd_data[506] = CKS & 0xff;
			cmd_data[507] = (CKS & 0xff00) >> 8;
			HAL_UART_Transmit(&huart1,cmd_data, 508 , 44); 
		}
		else
		{
			for(int i = 0 ; i < CMD_DATA.LEN ; i++)
				cmd_data[8+i] = CMD_DATA.DATA[i]; 
			for(int i = 0 ; i < 398 ; i++)
				CKS = CKS + cmd_data[i];
			cmd_data[398] = CKS & 0xff;
			cmd_data[399] = (CKS & 0xff00) >> 8;
			HAL_UART_Transmit(&huart1,cmd_data, 400,38);
		}
	}	      
}
  • 对接收到的响应数组进行处理
uint8_t Rx_cmd( uint8_t back )
{ 
	uint8_t a=1;
	uint16_t CKS = 0;
	while(a)
	{
		if( flag == 1 )        
		{
			a = 0;
			flag = 0;
			if(rps[4] == 0xff)
				return 1;
			Rx_CMD_Process();
			if(mode == 0)
			{
 				for(int i=0 ; i<24 ; i++)
					CKS = CKS + rps[i];
				if(CKS == RPS.CKS)
					return Rx_Data_Process(back);
			}
			else
			{
				for(int i=0 ; i<10 ; i++)
					CKS = CKS + rps[i];
				if(CKS == RPS.CKS)
					return 0;
				else
					return RPS.CMD;
			}
		}
		HAL_Delay(1);
	}
	return 1;
}
  • 更新接收命令结构体
void Rx_CMD_Process(void)
{
	RPS.PREFIX = rps[0] + rps[1] * 0x100;
	RPS.SID = rps[2];
	RPS.DID = rps[3];
	RPS.CMD = rps[4] + rps[5] * 0x100;
	RPS.LEN = rps[6] + rps[7] * 0x100;
	RPS.RET = rps[8] + rps[9] * 0x100;
	if(mode == 0)
	{
		for(int i=0 ; i<RPS_Len ; i++)
			RPS.DATA[i] = rps[10 +i];
		RPS.CKS = rps[24] + rps[25] * 0x100;
	}
	else
		RPS.CKS = rps[10] + rps[11] * 0x100;
}
  • 处理响应数据
uint8_t Rx_Data_Process( uint8_t back )
{
	uint8_t a = 0;
	switch(RPS.CMD)
	{
		case CMD_TEST_CONNECTION: a = RpsTestConnection(back); break;
		case CMD_FINGER_DETECT: a = RpsFingerDetect(back) ; break;
		case CMD_GET_IMAGE: a = RpsGetImage(back); break;
		case CMD_GENERATE: a = RpsGenerate(back); break;
		case CMD_MERGE: a = RpsMerge(back); break;
		case CMD_DEL_CHAR : a = RpsDelChar(back); break;
		case CMD_STORE_CHAR: a =RpsStoreCher(back) ; break;
		case CMD_SEARCH: a = RpsSearch(back) ; break;
		case CMD_VERIFY: a= RpsVerify(back) ; break;
		case CMD_GET_EMPTY_ID : a = RpsGetEmptyID(back); break;
		case CMD_GET_ENROLL_COUNT : a = RpsGetEnrollCount(back); break;
		case CMD_DOWN_IMAGE : a = RpsDownImage(back); break;
	}
	return a;
}
  • 响应和错误代码列表
uint8_t RPS_RET(void)
{
	switch(RPS.RET)
	{
		case ERR_SUCCESS: printf("Instruction processing succeeded\r\n"); break;
		case ERR_FAIL: printf("Instruction processing failure\r\n"); break;
		case ERR_TIME_OUT: printf("No prints were entered within the time limit\r\n"); break;
		case ERR_FP_NOT_DETECTED: printf("There is no fingerprint input on the collector\r\n"); break;
		case ERR_FP_CANCEL: printf("Instruction cancelled\r\n"); break;
		case ERR_INVALID_BUFFER_ID: printf("The Ram Buffer number is invalid\r\n"); break;
		case ERR_BAD_QUALITY: printf("Poor fingerprint image quality\r\n"); break;
		case ERR_GEN_COUNT: printf("Invalid number of combinations\r\n"); break;
		case ERR_INVALID_TMPL_NO: printf("The specified Template number is invalid\r\n"); break;
		case ERR_DUPLICATION_ID: printf("The fingerprint has been registered, and the id is : %d\r\n",RPS.DATA[0]+RPS.DATA[1]*0x100 ); break;
		case ERR_INVALID_PARAM: printf("Specified range invalid\r\n"); break;
		case ERR_TMPL_EMPTY: printf("Template is not registered in the specified range\r\n"); break;
		case ERR_VERIFY: printf("Description Failed to specify fingerprint comparison\r\n"); break;
 		case ERR_IDENTIFY: printf("Fingerprint comparison failed for the specified range\r\n"); break;
	}
	return RPS.RET;
}


资料

文档

程序

软件

售后

周一-周五(9:30-6:30)周六(9:30-5:30)

手机:13434470212

邮箱:services04@spotpear.cn

QQ:202004841