基于STM32的指纹识别系统实现方案
一、系统架构与硬件选型
1.1 硬件连接表(以AS608光学指纹模块为例)
| 指纹模块引脚 | STM32F103C8T6引脚 | 说明 |
|---|---|---|
| VCC | 3.3V / 5V | AS608支持3.3V-5V,建议5V供电以保证LED亮度 |
| GND | GND | 共地 |
| TXD | PA3 (USART2_RX) | 模块发送,STM32接收 |
| RXD | PA2 (USART2_TX) | 模块接收,STM32发送 |
| Touch | PA0 | 触摸感应输出(高电平有效,可选) |
1.2 系统工作流程
[用户触摸] -> [STM32唤醒] -> [发送“采集指纹”指令] -> [模块采集图像] -> [生成特征值] -> [搜索指纹库] -> [返回结果] -> [控制继电器/LED显示]二、核心代码实现
2.1 指纹模块协议定义(fingerprint.h)
#ifndef__FINGERPRINT_H#define__FINGERPRINT_H#include"stm32f10x.h"#include<string.h>// AS608 指令定义#defineFP_HEAD0xEF01#defineFP_ADDR0xFFFFFFFF// 指令包标识#defineCMD_GENIMG0x01// 采集图像#defineCMD_GENCHAR0x02// 生成特征#defineCMD_MATCH0x03// 精确比对(1:1)#defineCMD_SEARCH0x04// 搜索指纹(1:N)#defineCMD_REG_MODEL0x05// 合并特征(生成模板)#defineCMD_STORE0x06// 储存模板#defineCMD_DELETE0x0C// 删除模板#defineCMD_UP_CHAR0x08// 上传特征#defineCMD_DOWN_CHAR0x09// 下载特征#defineCMD_UP_IMAGE0x0A// 上传图像#defineCMD_DOWN_IMAGE0x0B// 下载图像#defineCMD_EMPTY0x0D// 清空指纹库#defineCMD_READ_CONF0x0E// 读系统参数// 确认码(返回值)#defineACK_OK0x00// 指令执行完毕或OK#defineACK_FAIL0x01// 数据包接收错误#defineACK_NO_FINGER0x02// 没有手指#defineACK_ENTRY_FAIL0x03// 录入指纹图像失败#defineACK_DISORDER0x06// 指纹库满#defineACK_NOT_FOUND0x09// 没搜索到// 缓冲区定义#defineCHAR_BUFFER_A0x01#defineCHAR_BUFFER_B0x02// 全局变量externuint8_tfp_rx_buffer[64];externuint8_tfp_tx_buffer[64];externuint8_tfp_rx_flag;// 函数声明voidFP_Init(uint32_tbaudrate);voidFP_SendCmd(uint8_tcmd,uint8_t*data,uint8_tlen);uint8_tFP_GetResponse(void);uint8_tFP_GetImage(void);uint8_tFP_GenChar(uint8_tbuffer_id);uint8_tFP_Search(uint8_tbuffer_id,uint16_tstart_page,uint16_tpage_num);uint8_tFP_Store(uint8_tbuffer_id,uint16_tpage_id);uint8_tFP_Delete(uint16_tpage_id,uint16_tnum);uint8_tFP_Empty(void);voidFP_ShowSystemParams(void);#endif2.2 串口驱动与指令发送(fingerprint.c)
#include"fingerprint.h"#include"usart.h"#include"delay.h"uint8_tfp_rx_buffer[64];uint8_tfp_rx_flag=0;staticuint8_trx_cnt=0;/** * @brief 指纹模块串口初始化 */voidFP_Init(uint32_tbaudrate){USART_InitTypeDef USART_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);// PA2 -> TX, PA3 -> RXGPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;GPIO_Init(GPIOA,&GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOA,&GPIO_InitStructure);USART_InitStructure.USART_BaudRate=baudrate;USART_InitStructure.USART_WordLength=USART_WordLength_8b;USART_InitStructure.USART_StopBits=USART_StopBits_1;USART_InitStructure.USART_Parity=USART_Parity_No;USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;USART_Init(USART2,&USART_InitStructure);USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);USART_Cmd(USART2,ENABLE);printf("Fingerprint Module Init OK\r\n");}/** * @brief 发送指令包 * @param cmd: 指令码 * @param data: 附加数据 * @param len: 数据长度 */voidFP_SendCmd(uint8_tcmd,uint8_t*data,uint8_tlen){uint16_tchecksum=0;uint8_ti;// 包头USART_SendData(USART2,0xEF);while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);USART_SendData(USART2,0x01);while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);// 地址USART_SendData(USART2,0xFF);while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);USART_SendData(USART2,0xFF);while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);USART_SendData(USART2,0xFF);while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);USART_SendData(USART2,0xFF);while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);// 包标识 (0x01 命令包)USART_SendData(USART2,0x01);while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);// 包长度 (指令码1字节 + 数据长度 + 校验和2字节)uint16_tpkg_len=1+len+2;USART_SendData(USART2,pkg_len>>8);while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);USART_SendData(USART2,pkg_len&0xFF);while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);// 指令码USART_SendData(USART2,cmd);while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);checksum+=cmd;// 数据for(i=0;i<len;i++){USART_SendData(USART2,data[i]);while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);checksum+=data[i];}// 校验和USART_SendData(USART2,checksum>>8);while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);USART_SendData(USART2,checksum&0xFF);while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);}/** * @brief 获取图像 */uint8_tFP_GetImage(void){FP_SendCmd(CMD_GENIMG,NULL,0);returnFP_GetResponse();}/** * @brief 生成特征 * @param buffer_id: 缓冲区号 (1 or 2) */uint8_tFP_GenChar(uint8_tbuffer_id){uint8_tdata[1]={buffer_id};FP_SendCmd(CMD_GENCHAR,data,1);returnFP_GetResponse();}/** * @brief 搜索指纹 * @param buffer_id: 缓冲区号 * @param start_page: 起始页 * @param page_num: 页数 */uint8_tFP_Search(uint8_tbuffer_id,uint16_tstart_page,uint16_tpage_num){uint8_tdata[5];data[0]=buffer_id;data[1]=start_page>>8;data[2]=start_page&0xFF;data[3]=page_num>>8;data[4]=page_num&0xFF;FP_SendCmd(CMD_SEARCH,data,5);returnFP_GetResponse();}/** * @brief 存储模板 */uint8_tFP_Store(uint8_tbuffer_id,uint16_tpage_id){uint8_tdata[3];data[0]=buffer_id;data[1]=page_id>>8;data[2]=page_id&0xFF;FP_SendCmd(CMD_STORE,data,3);returnFP_GetResponse();}/** * @brief 删除指纹 */uint8_tFP_Delete(uint16_tpage_id,uint16_tnum){uint8_tdata[4];data[0]=page_id>>8;data[1]=page_id&0xFF;data[2]=num>>8;data[3]=num&0xFF;FP_SendCmd(CMD_DELETE,data,4);returnFP_GetResponse();}/** * @brief 清空指纹库 */uint8_tFP_Empty(void){FP_SendCmd(CMD_EMPTY,NULL,0);returnFP_GetResponse();}/** * @brief 获取系统参数 */voidFP_ShowSystemParams(void){FP_SendCmd(CMD_READ_CONF,NULL,0);Delay_ms(200);// 解析fp_rx_buffer中的状态寄存器、容量等信息printf("Status: 0x%02X\r\n",fp_rx_buffer[7]);}/** * @brief 获取响应 */uint8_tFP_GetResponse(void){uint32_ttimeout=0;while(fp_rx_flag==0){Delay_ms(10);timeout++;if(timeout>200)// 2秒超时{printf("FP Response Timeout!\r\n");return0xFF;}}fp_rx_flag=0;returnfp_rx_buffer[7];// 返回确认码}2.3 中断接收(stm32f10x_it.c)
#include"fingerprint.h"voidUSART2_IRQHandler(void){if(USART_GetITStatus(USART2,USART_IT_RXNE)!=RESET){uint8_tdata=USART_ReceiveData(USART2);if(rx_cnt<sizeof(fp_rx_buffer)){fp_rx_buffer[rx_cnt++]=data;}// 简单判断是否接收完成(通常看最后两个字节校验和,这里简化为固定长度)if(rx_cnt>=12)// 假设最小包长度为12{fp_rx_flag=1;rx_cnt=0;}}}2.4 主程序逻辑(main.c)
#include"stm32f10x.h"#include"fingerprint.h"#include"usart.h"#include"delay.h"#include"led.h"#include"relay.h"intmain(void){SystemInit();Delay_Init();USART1_Init(115200);// 调试串口LED_Init();Relay_Init();// 初始化指纹模块,波特率57600(AS608默认)FP_Init(57600);uint8_tresult;uint16_tuser_id=0;while(1){printf("Place your finger...\r\n");LED_Blink(500);// LED闪烁提示// 1. 采集图像result=FP_GetImage();if(result!=ACK_OK){if(result==ACK_NO_FINGER)printf("No finger detected.\r\n");elseprintf("Get Image Failed: 0x%02X\r\n",result);Delay_ms(1000);continue;}printf("Image captured.\r\n");// 2. 生成特征result=FP_GenChar(CHAR_BUFFER_A);if(result!=ACK_OK){printf("Generate Char Failed: 0x%02X\r\n",result);Delay_ms(1000);continue;}// 3. 搜索指纹库printf("Searching...\r\n");result=FP_Search(CHAR_BUFFER_A,0,100);// 搜索前100个指纹if(result==ACK_OK){// 搜索成功,fp_rx_buffer中包含页码和匹配度user_id=(fp_rx_buffer[8]<<8)|fp_rx_buffer[9];printf("Match Found! User ID: %d, Score: %d\r\n",user_id,fp_rx_buffer[10]);// 控制继电器开门Relay_ON();LED_ON();Delay_ms(3000);Relay_OFF();LED_OFF();}elseif(result==ACK_NOT_FOUND){printf("No Match Found.\r\n");LED_Blink(100);// 快闪表示拒绝}else{printf("Search Error: 0x%02X\r\n",result);}Delay_ms(2000);// 防止重复识别}}三、指纹录入流程(需在上位机或按键触发)
录入通常需要两步(录入两次以确认):
uint8_tEnroll_Fingerprint(uint16_tuser_id){uint8_tres;printf("Enroll: Place finger first time\r\n");res=FP_GetImage();if(res!=ACK_OK)returnres;res=FP_GenChar(CHAR_BUFFER_A);if(res!=ACK_OK)returnres;printf("Remove finger\r\n");Delay_ms(2000);printf("Enroll: Place finger second time\r\n");res=FP_GetImage();if(res!=ACK_OK)returnres;res=FP_GenChar(CHAR_BUFFER_B);if(res!=ACK_OK)returnres;// 精确比对两次特征是否一致// 这里省略精确比对指令,直接存储res=FP_Store(CHAR_BUFFER_A,user_id);if(res==ACK_OK)printf("Enroll Success! ID: %d\r\n",user_id);returnres;}参考代码 基于STM32的指纹识别www.youwenfan.com/contentcsu/56232.html
四、调试与避坑指南
4.1 常见问题排查
| 现象 | 原因 | 解决方案 |
|---|---|---|
| 无响应 | 波特率不匹配 | AS608默认57600,STM32串口初始化需一致 |
| 图像采集失败 | 手指太干/太湿 | 提示用户湿润手指或擦拭传感器 |
| 搜索速度慢 | 搜索范围过大 | 缩小搜索页码范围,或升级为1:N搜索算法 |
| 误识率高 | 指纹质量差 | 增加录入时的图像质量检测,录入时旋转手指 |
4.2 硬件优化建议
- 电源稳定性:指纹模块工作时电流较大(>100mA),建议在VCC并联100uF电容。
- 抗干扰:指纹模块尽量远离电机、继电器等强干扰源。
- 触摸唤醒:使用模块的Touch引脚连接STM32外部中断,平时STM32休眠,触摸时唤醒,降低功耗。
五、总结
这套方案实现了基于STM32的指纹录入、存储、1:N搜索全流程。核心在于串口协议的正确封装和对返回状态码的严谨处理。
应用场景:
- 智能门锁
- 考勤打卡机
- 保险柜/枪柜
- 身份授权终端
