Capacitive Fingerprint Reader (B)
| |||||||||||||||||||||
| |||||||||||||||||||||
说明
简介
Capacitive Fingerprint Reader (B)是一款专用于二次开发集成应用的电容式指纹开发模块,高速度、快识别、高稳定性。
Capacitive Fingerprint Reader (B)电容式指纹模块采用高性能 Cortex 内核的主控,结合高安全性商用指纹算法, 配高级半导体指纹传感器,并具有指纹录入、图像处理、模板生成、模板储存、指纹比对和搜索等功能的智能型集成模块;专业为科研单位,指纹产品生产企业, 应用集成厂商提供标准二次开发指纹组件,快速、方便集成应用
特性
- 使用方便,不需要了解指纹技术 ,模块内部结构和运算,只需简单的指令就能完成相应操作
- 采用商用算法,性能稳定,识别速度快
- 手指感应灵敏,手指只要轻轻地触碰采集窗就能快速识别,不需要用按压
- 可以自由输入、输出指纹图片、指纹特征值文件及各种指纹操作
- 提供UART串口和 USB 双通讯方式
- 提供完善的配套资料手册(配有相关的指令文档、相关的工具和Raspberry/Arduino/STM32等示例程序)
参数
- 传感器类型:电容式触摸式传感器
- 分辨率:508DPI
- 图像像素阵列:208 x 288
- 图像灰度等级:256 灰度值
- 模块尺寸:34mm x 28.5mm
- 传感器尺寸:33.4mm x 20.4mm
- 传感器感应面积:14.6mm x 10.6mm
- 指纹容量:3000枚
- 比对时间:<0.5s
- 工作电压:3.3/5V
- 工作电流:<40mA
- 睡眠电流:<4mA
- 静电测试:ESD IEC 61000-4-2 LEVEL 4 正负15KV 隔空放电
- 通信接口:UART/USB
- 通信波特率:9600、19200、38400、57600、115200、230400、460800、921600bps
- 工作环境:
- 温度:-20~60 ℃
- 湿度: < RH 90% (无凝霜)
- 存储环境:
- 温度: -40°C~85°C
- 湿度:<90%RH(无凝霜)
接口说明
- VCC:电源 3.3V/5V
- GND:地
- RX:串口数据输入(TTL 电平)
- TX:串口数据输出(TTL 电平)
- RST:
- 高电平:模块供电-启动
- 低电平:模块掉电-关闭
硬件连接
传感器和主控板之间通过同向排线连接,接线如下:
用户拿到模块后,可先使用测试软件或测试程序对模块进行测试。在对模块有了一定的了解后,可使用指令表进行二次开发。
模块可以通过 UART 串口控制或者通过主控板上的 Type-C 接口控制。
操作说明
本模块采用高精密元件,在采集指纹时:
手指轻轻地触碰到采集窗口就能识别,不需要用力按压指纹采集窗。
正确按指纹
错误按指纹
传感器尺寸图
串口控制说明
1、使用 FT232 USB转UART串口模块进行测试(如用户使用其它 USB 转串口模块,操作也类似,模块需要另外购买),安装 FT232 驱动
2、按下图连接模块(注意 RXD TXD 是交叉相连的):
3、将 FT232 连接到 PC 机的 USB 接口,打开设备管理器, 查看相应的 COM 口:
4、下载测试软件:Capacitive-Fingerprint-Reader-(B)-Demo:
打开软件:
选择对应的通信方式:
Serial : 串口通信
Usb : USB通信
选择串口通信时,注意选择对应的波特率和串口号
实际操作
串口与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~3000(设置的指纹容量为多少就会查询到哪)的编号中注册了多少指纹。
2、点击获取已注册用户列表,会查询该模块在1~3000(设置的指纹容量为多少就会查询到哪)中注册了多少指纹,滑动结果处的指纹,可以看到已经注册的指纹编号。
获取可注册编号
点击“可注册编号”,会从编号1开始查询第一个没有被注册的编号。
获取当前ID编号的注册状态
点击 获取注册状态 会显示当前ID编号的存储空间是否是空的,下图便是该ID编号的存储空间不是空的(即ID已被注册)。
删除指纹
点击“单个删除”,删除当前ID编号的指纹。
点击全部删除,删除1~3000(设置的指纹容量为多少就会到哪)的编号中所有以注册的指纹。
查看指纹图像(不能查看已经保存的指纹)
点击上传指纹图像,然后在传感器上按下自己的手指。
也可以打开预览图像,这样在每次需要输入指纹时,都会显示指纹图像(注:串口模式下不推荐使用,传输图像数据需要6秒左右)
可以选择打开拉伸显示,满图像的显示指纹
查看指纹特征值(只能查看已经保存的指纹)
选择已经保存过指纹的ID编号
点击上传特征值
点击“批量上传特征值”,选择一个文件夹用来保存特征值文件。会上传1~3000(指纹容量的选择数量)编号的指纹数据。以FPT的格式存放在你选择的文件夹下面。
使用指纹图像进行用户录入
配置好ID编号和图像数量,具体参考 “用户录入”
点击“从图像注册”,选择指纹模图像。图像大小为242*266
使用特征值进行用户录入
1、单个下载
配置好ID编号。
点击下图所示的打开文件,选择一个FPT格式的文件,点击“下载特征值”。
2、批量下载
点击“批量下载特征值”选择对应的文件夹,文件夹中所有的FPT格式文件按照排序方式依次下载到模块当中,他们的ID号是依次增加的。
使用指纹图像进行识别。
点击下图所示的打开文件,选择指纹图像,点击“下载图像识别”。
使用特征值进行识别
配置好ID编号和图像数量,具体参考 “用户录入”
点击下图所示的打开文件,选择一个FPT格式的文件,点击“下载特征值识别”,将会和你选择的指纹ID编号内的指纹模板进行对比;
点击“下载特征值比对”,将会和你按下的手指进行比对。
查看已被损坏的特征值
点击“坏损特征值编号”,接收到的结果回将显示被损坏的特征值的总数和第一个被损坏的特征值的编号。
休眠
例程使用
树莓派、Arduino、STM32的函数内容可能会有部分不同,但是操作方式与功能是一样的。
连接方式
模块 | STM32 | 功能 |
VCC | 5/3.3V | 电源输入 |
GND | GND | 电源地 |
TXD | PA10 | 模块串口发送端 |
RXD | PA9 | 模块串口接收端 |
RST | PB5 | 模块复位引脚,低电平有效 |
模块 | Arduino | 功能 |
VCC | 5/3.3V | 电源输入 |
GND | GND | 电源地 |
TXD | 10 | 模块串口发送端 |
RXD | 11 | 模块串口接收端 |
RST | 9 | 模块复位引脚,低电平有效 |
模块 | Raspberry Pi | 功能 |
VCC | 5/3.3V | 电源输入 |
GND | GND | 电源地 |
TXD | RXD | 模块串口发送端 |
RXD | TXD | 模块串口接收端 |
RST | GPIO5(wiringpi编码) | 模块复位引脚,低电平有效 |
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; }
FAQ