AS608光学指纹模组编程和应用详解
一、前言
二、芯片介绍
1、芯片简介
AS608是一个集成的光学指纹芯片,内部有指纹算法,其实指纹识别最难的地方在于算法,目前的算法是前人不断开发完善得到的,所以在前几年,算法都是某些大企业独有的技术,他们只卖芯片不卖算法。当然现在的话,光学指纹的算法也逐渐放出来了,因为现在用的更多的是半导体,超声波指纹识别,光学指纹他们已经玩腻了。说远了,回归正题,虽然AS608内部的算法我们是看不到的,但是它预留了一个串口和相关的串口指令集,我们可以用这些指令调用指纹算法,从而实现我们需要的功能。
2、引脚定义



三、通讯原理和通讯的流程讲解
1、通讯方法
通过给AS608串口发送特定的指令,就可以调用里面的算法,进行相应的操作。这些指令有三种格式:命令包格式,数据包格式和接收包格式。命令包是用来控制AS608的,数据包和结束包只在导出(把模块里面的指纹导出到别的设备)和导入(把其他设备的数据导入模块)指纹数据的时候用到的。

我这里以命令包格式为例,给大家讲解一下,包头是2个字节的数据,固定为0xEF01;芯片地址4个字节,默认是0xFFFFFFFF,可以后面发送指令修改;包识别是用来区分指令的类型的,如命令包固定为0x01;包长度是指这一条指令有多少个重要的数据,包长度=包长度至校验和(指令、参数或数据)的总字节数,包含校验和,但不包含包长度本身的字节数;指令就是需要AS608执行的操作,具体的定义我后面再说;参数和具体的指令有关,不同的指令,参数的长度和数值都有所不同;校验和是为了确保串口通讯过程中出现错误,导致命令出错,校验和是从包标识至校验和之间所有字节之和。
2、功能的实现及通讯的流程
我这里只详细讲解录入指纹、识别指纹和删除指纹这三个最常用的功能的实现和操作步骤。如果你们需要用到导出和导入指纹,可以留言或私信给我,我再详细讲解。
1)录入指纹
录入指纹有以下几个步骤:
第一,录入图像。当你的手指放在光学指纹窗口的时候执行这个指令,就可以把指纹的图像拍下来。
第二,生成特征。当你的指纹图像拍下来之后,调用这个指令就可以把图像中的指纹特征记录下来。AS608里面有2个缓存区可以存这个特征,我们这里先用第1个存。
第三,再次录入图像。把同一个手指放在光学指纹窗口,然后执行这个指令,再拍一个指纹图像。
第四,再次生成特征。把第二次录入的图像的指纹特征存到第2个缓存区。
第五.精确比对两枚指纹特征。录入指纹的时候为了增加准确性,最好是记录多次指纹特征,这个指令就是对录入的两个指纹特征进行比对,如果一致就说明是同一个人的同一个指纹。
第六,合并特征(生成模板)。当录入了两个指纹特征,并且两个特征是一致的时候,就可以把两个特征合并成一个指纹模板。这个指纹模板就是我们最终要录入的指纹。
第七,储存模板。当生成一个模板的时候,我们可以把这个模板存到AS608内部的Flash里面,存储的时候需要输入一个指纹ID号,这个ID其实是Flash的地址,不同的ID号,存储的位置不同,最多好像能存两三百个指纹。
2)识别指纹
第一,录入图像。这一步和录入指纹的第一步是一样的,目的是把指纹的图像拍下来。
第二,生成特征。这一步和录入指纹的第二步是一样的。指纹特征可以存到第一个缓存区也可以存到第二个缓存区。
第三,搜索指纹。调用这个指令就会将已经存在Flash里面的指纹模板和缓存区的指纹特征一一比对,如果有搜索到,会返回这个指纹的ID。要注意的是,调用的时候需要指明比对的特征是缓存区1还是缓存区2,你要选择第二步生成的特征所存储的缓存区。
3)删除指纹
删除指纹可以选择删除个别指纹或者删除所有指纹。
删除一个或几个:调用“删除模板”指令,调用的时候需要输入要删除的起始ID号和删除个数,调用之后就会把Flash里面ID号对应位置的数据清除掉。如:起始ID号是3,删除个数是4,那么就会把3,4,5,6这四个ID号对应的指纹删掉。
删除所有:调用“清空指纹库”指令即可。
4)导出指纹模板
第一,读出模板存到缓存区。
第二,上传特征或模板。
5)导入指纹模板
第一,下载特征或模板。
第二,储存模板。
6)导出图像
第一,录入图像。
第二,上传图像。
7)导入图像
第一,下载图像。
第二,生成特征。
第三,存储模板。
3、指令讲解
所有的指令在“AS60x指纹识别SOC用户手册V10”这个文件中都有说明,我这里只给大家讲解一些常用的指令。
1) 录入图像
这个指令你只需要按照下面指令包格式用串口给AS608发送数据就可以了,建议先用电脑串口助手发,理解这个通讯的过程之后再用单片机发。注意下面的数据是十六进制表示的,所以你如果用串口助手发的话要用“hex发送”。发送成功之后模块应该会有回复,根据回复的内容可以知道指令执行的状态。
如:发送:EF 01 FF FF FF FF 01 03 01 05 回复:EF 01 FF FF FF FF 07 03 00 0A
说明图像录入成功。

2) 生成特征
这个指令的发送和接收跟上面录入图像基本一致,唯一的区别是多了一个缓存区号,缓存区有两个,是用来暂存和比较两个指纹特征的。我们可以把第一次录入的图像生成特征存在缓存区1,把第二次录入的图像生成特征存在缓存区2。

3) 精确比对两枚指纹特征
这个指令可以比对2个缓存区的指纹特征。

4) 合并特征(生成模板)
把录入的指纹特征进行合并,生成模板以便于存储,合并之后的特征分别存在缓存区1和缓存区2。

5) 储存模板
当生成一个模板的时候,我们可以把这个模板存到AS608内部的Flash里面。存储的时候要选择缓存区号和指纹ID。缓存区号1和缓存区号2分别对应你两次录入的指纹,选择其中一个保存即可。ID是模块内部Flash的存储地址,不同的ID代表存储的位置不同,同一个位置只能存一个指纹,如果录入了两个不同的指纹,但是都存到同一个ID里面,那么第二次录入的指纹就会覆盖掉第一次录入的。

6) 搜索指纹
这个指令是用来识别指纹的。调用这个指令就会将已经存在Flash里面的指纹模板和缓存区的指纹特征一一比对,如果有搜索到,会返回这个指纹的ID。要注意的是,调用的时候需要指明比对的特征是在缓存区1还是缓存区2的,你在调用这个指令之前就应该把要识别的指纹的特征存到缓存区1或缓存区2。

7) 删除模板
调用的时候需要输入要删除的起始ID号和删除个数,调用之后就会把Flash里面ID号对应位置的数据清除掉。如:起始ID号是3,删除个数是4,那么就会把3,4,5,6这四个ID号对应的指纹删掉。

四、编程讲解
#include
#include "delay.h" #include "usart2.h" #include "as608.h" u32 AS608Addr = 0XFFFFFFFF; //默认地址 //初始化PA6为下拉输入 //读摸出感应状态(触摸感应时输出高电平信号) void PS_StaGPIO_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能GPIOA时钟 //初始化读状态引脚GPIOA GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;//输入下拉模式 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHz GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO GPIO_ResetBits(GPIOA,GPIO_Pin_6); //输出低 } //串口发送一个字节 static void MYUSART_SendData(u8 data) {
while((USART2->SR&0X40)==0); USART2->DR = data; } //发送包头 static void SendHead(void) {
MYUSART_SendData(0xEF); MYUSART_SendData(0x01); } //发送地址 static void SendAddr(void) {
MYUSART_SendData(AS608Addr>>24); MYUSART_SendData(AS608Addr>>16); MYUSART_SendData(AS608Addr>>8); MYUSART_SendData(AS608Addr); } //发送包标识, static void SendFlag(u8 flag) {
MYUSART_SendData(flag); } //发送包长度 static void SendLength(int length) {
MYUSART_SendData(length>>8); MYUSART_SendData(length); } //发送指令码 static void Sendcmd(u8 cmd) {
MYUSART_SendData(cmd); } //发送校验和 static void SendCheck(u16 check) {
MYUSART_SendData(check>>8); MYUSART_SendData(check); } //判断中断接收的数组有没有应答包 //waittime为等待中断接收数据的时间(单位1ms) //返回值:数据包首地址 static u8 *JudgeStr(u16 waittime) {
char *data; u8 str[8]; str[0]=0xef;str[1]=0x01;str[2]=AS608Addr>>24; str[3]=AS608Addr>>16;str[4]=AS608Addr>>8; str[5]=AS608Addr;str[6]=0x07;str[7]='\0'; USART2_RX_STA=0; while(--waittime) {
delay_ms(1); if(USART2_RX_STA&0X8000)//接收到一次数据 {
USART2_RX_STA=0; data=strstr((const char*)USART2_RX_BUF,(const char*)str); if(data) return (u8*)data; } } return 0; } //录入图像 PS_GetImage //功能:探测手指,探测到后录入指纹图像存于ImageBuffer。 //模块返回确认字 u8 PS_GetImage(void) {
u16 temp; u8 ensure; u8 *data; SendHead(); SendAddr(); SendFlag(0x01);//命令包标识 SendLength(0x03); Sendcmd(0x01); temp = 0x01+0x03+0x01; SendCheck(temp); data=JudgeStr(1500); if(data) ensure=data[9]; else ensure=0xff; return ensure; } //生成特征 PS_GenChar //功能:将ImageBuffer中的原始图像生成指纹特征文件存于CharBuffer1或CharBuffer2 //参数:BufferID --> charBuffer1:0x01 charBuffer1:0x02 //模块返回确认字 u8 PS_GenChar(u8 BufferID) {
u16 temp; u8 ensure; u8 *data; SendHead(); SendAddr(); SendFlag(0x01);//命令包标识 SendLength(0x04); Sendcmd(0x02); MYUSART_SendData(BufferID); temp = 0x01+0x04+0x02+BufferID; SendCheck(temp); data=JudgeStr(1500); if(data) ensure=data[9]; else ensure=0xff; return ensure; } //精确比对两枚指纹特征 PS_Match //功能:精确比对CharBuffer1 与CharBuffer2 中的特征文件 //模块返回确认字 u8 PS_Match(void) {
u16 temp; u8 ensure; u8 *data; SendHead(); SendAddr(); SendFlag(0x01);//命令包标识 SendLength(0x03); Sendcmd(0x03); temp = 0x01+0x03+0x03; SendCheck(temp); data=JudgeStr(1500); if(data) ensure=data[9]; else ensure=0xff; return ensure; } //搜索指纹 PS_Search //功能:以CharBuffer1或CharBuffer2中的特征文件搜索整个或部分指纹库.若搜索到,则返回页码。 //参数: BufferID @ref CharBuffer1 CharBuffer2 //说明: 模块返回确认字,页码(相配指纹模板) u8 PS_Search(u8 BufferID,u16 StartPage,u16 PageNum,SearchResult *p) {
u16 temp; u8 ensure; u8 *data; SendHead(); SendAddr(); SendFlag(0x01);//命令包标识 SendLength(0x08); Sendcmd(0x04); MYUSART_SendData(BufferID); MYUSART_SendData(StartPage>>8); MYUSART_SendData(StartPage); MYUSART_SendData(PageNum>>8); MYUSART_SendData(PageNum); temp = 0x01+0x08+0x04+BufferID +(StartPage>>8)+(u8)StartPage +(PageNum>>8)+(u8)PageNum; SendCheck(temp); data=JudgeStr(2000); if(data) {
ensure = data[9]; p->pageID =(data[10]<<8)+data[11]; p->mathscore=(data[12]<<8)+data[13]; } else ensure = 0xff; return ensure; } //合并特征(生成模板)PS_RegModel //功能:将CharBuffer1与CharBuffer2中的特征文件合并生成 模板,结果存于CharBuffer1与CharBuffer2 //说明: 模块返回确认字 u8 PS_RegModel(void) {
u16 temp; u8 ensure; u8 *data; SendHead(); SendAddr(); SendFlag(0x01);//命令包标识 SendLength(0x03); Sendcmd(0x05); temp = 0x01+0x03+0x05; SendCheck(temp); data=JudgeStr(2000); if(data) ensure=data[9]; else ensure=0xff; return ensure; } //储存模板 PS_StoreChar //功能:将 CharBuffer1 或 CharBuffer2 中的模板文件存到 PageID 号flash数据库位置。 //参数: BufferID @ref charBuffer1:0x01 charBuffer1:0x02 // PageID(指纹库位置号) //说明: 模块返回确认字 u8 PS_StoreChar(u8 BufferID,u16 PageID) {
u16 temp; u8 ensure; u8 *data; SendHead(); SendAddr(); SendFlag(0x01);//命令包标识 SendLength(0x06); Sendcmd(0x06); MYUSART_SendData(BufferID); MYUSART_SendData(PageID>>8); MYUSART_SendData(PageID); temp = 0x01+0x06+0x06+BufferID +(PageID>>8)+(u8)PageID; SendCheck(temp); data=JudgeStr(2000); if(data) ensure=data[9]; else ensure=0xff; return ensure; } //删除模板 PS_DeletChar //功能: 删除flash数据库中指定ID号开始的N个指纹模板 //参数: PageID(指纹库模板号),N删除的模板个数。 //说明: 模块返回确认字 u8 PS_DeletChar(u16 PageID,u16 N) {
u16 temp; u8 ensure; u8 *data; SendHead(); SendAddr(); SendFlag(0x01);//命令包标识 SendLength(0x07); Sendcmd(0x0C); MYUSART_SendData(PageID>>8); MYUSART_SendData(PageID); MYUSART_SendData(N>>8); MYUSART_SendData(N); temp = 0x01+0x07+0x0C +(PageID>>8)+(u8)PageID +(N>>8)+(u8)N; SendCheck(temp); data=JudgeStr(2000); if(data) ensure=data[9]; else ensure=0xff; return ensure; } //清空指纹库 PS_Empty //功能: 删除flash数据库中所有指纹模板 //参数: 无 //说明: 模块返回确认字 u8 PS_Empty(void) {
u16 temp; u8 ensure; u8 *data; SendHead(); SendAddr(); SendFlag(0x01);//命令包标识 SendLength(0x03); Sendcmd(0x0D); temp = 0x01+0x03+0x0D; SendCheck(temp); data=JudgeStr(2000); if(data) ensure=data[9]; else ensure=0xff; return ensure; } //写系统寄存器 PS_WriteReg //功能: 写模块寄存器 //参数: 寄存器序号RegNum:4\5\6 //说明: 模块返回确认字 u8 PS_WriteReg(u8 RegNum,u8 DATA) {
u16 temp; u8 ensure; u8 *data; SendHead(); SendAddr(); SendFlag(0x01);//命令包标识 SendLength(0x05); Sendcmd(0x0E); MYUSART_SendData(RegNum); MYUSART_SendData(DATA); temp = RegNum+DATA+0x01+0x05+0x0E; SendCheck(temp); data=JudgeStr(2000); if(data) ensure=data[9]; else ensure=0xff; if(ensure==0) printf("\r\n设置参数成功!"); else printf("\r\n%s",EnsureMessage(ensure)); return ensure; } //读系统基本参数 PS_ReadSysPara //功能: 读取模块的基本参数(波特率,包大小等) //参数: 无 //说明: 模块返回确认字 + 基本参数(16bytes) u8 PS_ReadSysPara(SysPara *p) {
u16 temp; u8 ensure; u8 *data; SendHead(); SendAddr(); SendFlag(0x01);//命令包标识 SendLength(0x03); Sendcmd(0x0F); temp = 0x01+0x03+0x0F; SendCheck(temp); data=JudgeStr(2000); if(data) {
ensure = data[9]; p->PS_max = (data[14]<<8)+data[15]; p->PS_level = data[17]; p->PS_addr=(data[18]<<24)+(data[19]<<16)+(data[20]<<8)+data[21]; p->PS_size = data[23]; p->PS_N = data[25]; } else ensure=0xff; if(ensure==0x00) {
printf("\r\n模块最大指纹容量=%d",p->PS_max); printf("\r\n对比等级=%d",p->PS_level); printf("\r\n地址=%x",p->PS_addr); printf("\r\n波特率=%d",p->PS_N*9600); } else printf("\r\n%s",EnsureMessage(ensure)); return ensure; } //设置模块地址 PS_SetAddr //功能: 设置模块地址 //参数: PS_addr //说明: 模块返回确认字 u8 PS_SetAddr(u32 PS_addr) {
u16 temp; u8 ensure; u8 *data; SendHead(); SendAddr(); SendFlag(0x01);//命令包标识 SendLength(0x07); Sendcmd(0x15); MYUSART_SendData(PS_addr>>24); MYUSART_SendData(PS_addr>>16); MYUSART_SendData(PS_addr>>8); MYUSART_SendData(PS_addr); temp = 0x01+0x07+0x15 +(u8)(PS_addr>>24)+(u8)(PS_addr>>16) +(u8)(PS_addr>>8) +(u8)PS_addr; SendCheck(temp); AS608Addr=PS_addr;//发送完指令,更换地址 data=JudgeStr(2000); if(data) ensure=data[9]; else ensure=0xff; AS608Addr = PS_addr; if(ensure==0x00) printf("\r\n设置地址成功!"); else printf("\r\n%s",EnsureMessage(ensure)); return ensure; } //功能: 模块内部为用户开辟了256bytes的FLASH空间用于存用户记事本, // 该记事本逻辑上被分成 16 个页。 //参数: NotePageNum(0~15),Byte32(要写入内容,32个字节) //说明: 模块返回确认字 u8 PS_WriteNotepad(u8 NotePageNum,u8 *Byte32) {
u16 temp; u8 ensure,i; u8 *data; SendHead(); SendAddr(); SendFlag(0x01);//命令包标识 SendLength(36); Sendcmd(0x18); MYUSART_SendData(NotePageNum); for(i=0;i<32;i++) {
MYUSART_SendData(Byte32[i]); temp += Byte32[i]; } temp =0x01+36+0x18+NotePageNum+temp; SendCheck(temp); data=JudgeStr(2000); if(data) ensure=data[9]; else ensure=0xff; return ensure; } //读记事PS_ReadNotepad //功能: 读取FLASH用户区的128bytes数据 //参数: NotePageNum(0~15) //说明: 模块返回确认字+用户信息 u8 PS_ReadNotepad(u8 NotePageNum,u8 *Byte32) {
u16 temp; u8 ensure,i; u8 *data; SendHead(); SendAddr(); SendFlag(0x01);//命令包标识 SendLength(0x04); Sendcmd(0x19); MYUSART_SendData(NotePageNum); temp = 0x01+0x04+0x19+NotePageNum; SendCheck(temp); data=JudgeStr(2000); if(data) {
ensure=data[9]; for(i=0;i<32;i++) {
Byte32[i]=data[10+i]; } } else ensure=0xff; return ensure; } //高速搜索PS_HighSpeedSearch //功能:以 CharBuffer1或CharBuffer2中的特征文件高速搜索整个或部分指纹库。 // 若搜索到,则返回页码,该指令对于的确存在于指纹库中 ,且登录时质量 // 很好的指纹,会很快给出搜索结果。 //参数: BufferID, StartPage(起始页),PageNum(页数) //说明: 模块返回确认字+页码(相配指纹模板) u8 PS_HighSpeedSearch(u8 BufferID,u16 StartPage,u16 PageNum,SearchResult *p) {
u16 temp; u8 ensure; u8 *data; SendHead(); SendAddr(); SendFlag(0x01);//命令包标识 SendLength(0x08); Sendcmd(0x1b); MYUSART_SendData(BufferID); MYUSART_SendData(StartPage>>8); MYUSART_SendData(StartPage); MYUSART_SendData(PageNum>>8); MYUSART_SendData(PageNum); temp = 0x01+0x08+0x1b+BufferID +(StartPage>>8)+(u8)StartPage +(PageNum>>8)+(u8)PageNum; SendCheck(temp); data=JudgeStr(2000); if(data) {
ensure=data[9]; p->pageID =(data[10]<<8) +data[11]; p->mathscore=(data[12]<<8) +data[13]; } else ensure=0xff; return ensure; } //读有效模板个数 PS_ValidTempleteNum //功能:读有效模板个数 //参数: 无 //说明: 模块返回确认字+有效模板个数ValidN u8 PS_ValidTempleteNum(u16 *ValidN) {
u16 temp; u8 ensure; u8 *data; SendHead(); SendAddr(); SendFlag(0x01);//命令包标识 SendLength(0x03); Sendcmd(0x1d); temp = 0x01+0x03+0x1d; SendCheck(temp); data=JudgeStr(2000); if(data) {
ensure=data[9]; *ValidN = (data[10]<<8) +data[11]; } else ensure=0xff; if(ensure==0x00) {
printf("\r\n有效指纹个数=%d",(data[10]<<8)+data[11]); } else printf("\r\n%s",EnsureMessage(ensure)); return ensure; } //与AS608握手 PS_HandShake //参数: PS_Addr地址指针 //说明: 模块返新地址(正确地址) u8 PS_HandShake(u32 *PS_Addr) {
SendHead(); SendAddr(); MYUSART_SendData(0X01); MYUSART_SendData(0X00); MYUSART_SendData(0X00); delay_ms(200); if(USART2_RX_STA&0X8000)//接收到数据 {
if(//判断是不是模块返回的应答包 USART2_RX_BUF[0]==0XEF &&USART2_RX_BUF[1]==0X01 &&USART2_RX_BUF[6]==0X07 ) {
*PS_Addr=(USART2_RX_BUF[2]<<24) + (USART2_RX_BUF[3]<<16) +(USART2_RX_BUF[4]<<8) + (USART2_RX_BUF[5]); USART2_RX_STA=0; return 0; } USART2_RX_STA=0; } return 1; } //模块应答包确认码信息解析 //功能:解析确认码错误信息返回信息 //参数: ensure const char *EnsureMessage(u8 ensure) {
const char *p; switch(ensure) {
case 0x00: p="OK";break; case 0x01: p="数据包接收错误";break; case 0x02: p="传感器上没有手指";break; case 0x03: p="录入指纹图像失败";break; case 0x04: p="指纹图像太干、太淡而生不成特征";break; case 0x05: p="指纹图像太湿、太糊而生不成特征";break; case 0x06: p="指纹图像太乱而生不成特征";break; case 0x07: p="指纹图像正常,但特征点太少(或面积太小)而生不成特征";break; case 0x08: p="指纹不匹配";break; case 0x09: p="没搜索到指纹";break; case 0x0a: p="特征合并失败";break; case 0x0b: p="访问指纹库时地址序号超出指纹库范围"; case 0x10: p="删除模板失败";break; case 0x11: p="清空指纹库失败";break; case 0x15: p="缓冲区内没有有效原始图而生不成图像";break; case 0x18: p="读写 FLASH 出错";break; case 0x19: p="未定义错误";break; case 0x1a: p="无效寄存器号";break; case 0x1b: p="寄存器设定内容错误";break; case 0x1c: p="记事本页码指定错误";break; case 0x1f: p="指纹库满";break; case 0x20: p="地址错误";break; default : p="模块返回确认码有误";break; } return p; }
2、录指纹函数
//录入指纹 u16 Add_FR(u16 ID) {
u8 i=0,ensure,processnum=0; int a=1; Audio(2); //播放"开始录入指纹" delay_ms(1000); OLED_Clear(); OLED_ShowCHinese(28,0,14); OLED_ShowCHinese(48,0,15); OLED_ShowCHinese(68,0,16); OLED_ShowCHinese(88,0,17); //显示"录入指纹" while(a) {
switch (processnum) {
case 0: i++; Audio(3); OLED_ShowCHinese(28,2,18); OLED_ShowCHinese(48,2,25); OLED_ShowCHinese(68,2,26); OLED_ShowCHinese(88,2,27); //显示"请按手指" delay_ms(50); if(PS_Sta==1) {
ensure=PS_GetImage(); //录入图像 if(ensure==0x00) {
ensure=PS_GenChar(CharBuffer1); //生成特征 if(ensure==0x00) {
Audio(4); //播报"开始录入指纹" OLED_ShowCHinese(28,2,16); OLED_ShowCHinese(48,2,17); OLED_ShowCHinese(68,2,28); OLED_ShowCHinese(88,2,29); //显示"指纹正确" delay_ms(1000); i=0; processnum=1; //跳到第二步 } else {
OLED_ShowCHinese(28,2,16); OLED_ShowCHinese(48,2,17); OLED_ShowCHinese(68,2,8); OLED_ShowCHinese(88,2,9); //显示"指纹错误" } } } break; case 1: i++; Audio(5); //播报"请再按一次手指" OLED_ShowCHinese(8,2,30); OLED_ShowCHinese(28,2,25); OLED_ShowCHinese(48,2,31); OLED_ShowCHinese(68,2,32); OLED_ShowCHinese(88,2,26); OLED_ShowCHinese(108,2,27); //显示"再按一次手指" if(PS_Sta==1) {
ensure=PS_GetImage(); //录入图像 if(ensure==0x00) {
ensure=PS_GenChar(CharBuffer2); //生成特征 if(ensure==0x00) {
Audio(4); OLED_ShowString(8,2," ",16); OLED_ShowCHinese(28,2,16); OLED_ShowCHinese(48,2,17); OLED_ShowCHinese(68,2,28); OLED_ShowCHinese(88,2,29); //显示"指纹正确" i=0; processnum=2; //跳到第三步 } else {
OLED_ShowCHinese(28,2,16); OLED_ShowCHinese(48,2,17); OLED_ShowCHinese(68,2,8); OLED_ShowCHinese(88,2,9); //显示"指纹错误" } } } break; case 2: i++; ensure=PS_Match(); //对比两次指纹 if(ensure==0x00) //两次指纹一致 {
processnum=3; //跳到第四步 } else //两次指纹不一致 {
Audio(19); //播报"两次指纹不一样,请重新录入" delay_ms(50); OLED_ShowCHinese(8,2,33); OLED_ShowCHinese(28,2,32); OLED_ShowCHinese(48,2,16); OLED_ShowCHinese(68,2,17); OLED_ShowCHinese(88,2,34); OLED_ShowCHinese(108,2,35); //显示"两次指纹不同" OLED_ShowCHinese(8,4,18); OLED_ShowCHinese(28,4,36); OLED_ShowCHinese(48,4,37); OLED_ShowCHinese(68,4,14); OLED_ShowCHinese(88,4,15); //"请重新录入" delay_ms(1500); OLED_ShowString(8,2," ",16); OLED_ShowString(8,4," ",16); i=0; processnum=0; //跳回第一步 } break; case 3: ensure=PS_RegModel(); //产生一个指纹模板 if(ensure==0x00) //生成指纹模板成功 {
processnum=4; //跳到第五步 } else {
processnum=0; } break; case 4: i++; ensure=PS_StoreChar(CharBuffer2,ID); //储存模板 if(ensure==0x00) {
Audio(6); MYUSART_SendData1(0x3A); MYUSART_SendData1(0x01); MYUSART_SendData1(0x00); MYUSART_SendData1(0x01); MYUSART_SendData1(0x01); MYUSART_SendData1(0x00); MYUSART_SendData1(0x04); MYUSART_SendData1(0x3A); OLED_ShowString(8,2," ",16); OLED_ShowCHinese(28,2,14); OLED_ShowCHinese(48,2,15); OLED_ShowCHinese(68,2,6); OLED_ShowCHinese(88,2,7); //显示"录入成功" ZW_ID[0]=ID; SPI_Flash_Write((u8*)ZW_ID,FLASH_SIZE-100,1); //写入当前ID a=0; break; } else {
processnum=0; } break; } delay_ms(1000); if(i>5) {
i=0; a=0; Audio(7); //播报"录入失败" MYUSART_SendData1(0x3A); MYUSART_SendData1(0x01); MYUSART_SendData1(0x00); MYUSART_SendData1(0x01); MYUSART_SendData1(0x00); MYUSART_SendData1(0x00); MYUSART_SendData1(0x04); MYUSART_SendData1(0x3A); OLED_ShowCHinese(28,2,14); OLED_ShowCHinese(48,2,15); OLED_ShowCHinese(68,2,4); OLED_ShowCHinese(88,2,5); //显示"录入失败" delay_ms(1000); OLED_ShowString(28,2," ",16); } } }
3、刷指纹
void press_FR(void) {
SearchResult seach; u8 ensure; if(audio_flag) {
audio_flag=0; Audio(11);//播报“开始签到,请按手指” } OLED_ShowString(0,0," ",16); OLED_ShowString(104,0," ",16); OLED_ShowString(0,2," ",16); OLED_ShowString(0,4," ",16); OLED_ShowString(0,6," ",16); OLED_ShowCHinese(28,0,10); OLED_ShowCHinese(48,0,11); OLED_ShowCHinese(68,0,12); OLED_ShowCHinese(88,0,13); //显示"开始签到" // printf("开始签到\n"); if(PS_Sta==1) {
ensure=PS_GetImage(); if(ensure==0x00)//获取图像 {
OLED_ShowCHinese(28,2,69); OLED_ShowCHinese(48,2,70); OLED_ShowCHinese(68,2,71); OLED_ShowString(88,2,"...",16); //显示"比对中..." // printf("获取图像成功 \n"); ensure=PS_GenChar(CharBuffer1); if(ensure==0x00) //生成特征 {
// printf("生成特征成功 \n"); ensure=PS_HighSpeedSearch(CharBuffer1,0,300,&seach); if(ensure==0x00)//搜索成功 {
// printf("搜索指纹成功\n ");//搜索指纹成功 // delay_ms(100); // sprintf(str,"Match ID:%d Match score:%d\n",seach.pageID,seach.mathscore);//显示匹配指纹的ID和分数 // printf(" 匹配指纹的ID和分数 %s\n",str); // printf("%d",seach.pageID); // OLED_ShowNum(0,6,seach.pageID,6,16); Up_stu_num(seach.pageID); ID=seach.pageID; OLED_ShowCHinese(28,4,12); OLED_ShowCHinese(48,4,13); OLED_ShowCHinese(68,4,6); OLED_ShowCHinese(88,4,7); //显示"签到成功" Audio(12);//播报“签到成功” delay_ms(1000); } else {
Audio(13); OLED_ShowCHinese(28,4,12); OLED_ShowCHinese(48,4,13); OLED_ShowCHinese(68,4,4); OLED_ShowCHinese(88,4,5); //显示"签到失败" delay_ms(1000); // ShowErrMessage(ensure); } // delay_ms(50); } // else // ShowErrMessage(ensure); // delay_ms(50); } } }
4、清空指纹
这个函数在底层驱动里面有,直接调用即可
PS_Empty();
5、上传和下载指纹
如果没有用到这个功能可以跳过
u16 Up_FR(u16 ID) //上传指纹 {
u8 ensure; Audio(15); OLED_Clear(); OLED_ShowCHinese(28,0,60); OLED_ShowCHinese(48,0,61); OLED_ShowCHinese(68,0,16); OLED_ShowCHinese(88,0,17); //显示"上传指纹" ensure=PS_LoadChar(CharBuffer2,ID); //读出模板 if(ensure==0x00) {
PS_UpChar(CharBuffer2); //上传特征 if(ensure==0x00) {
// printf("上传指纹成功"); Audio(16); OLED_ShowCHinese(8,2,60); OLED_ShowCHinese(28,2,61); OLED_ShowCHinese(48,2,16); OLED_ShowCHinese(68,2,17); OLED_ShowCHinese(88,2,6); OLED_ShowCHinese(108,2,7); //显示"上传指纹成功" } else {
Audio(17); OLED_ShowCHinese(8,2,60); OLED_ShowCHinese(28,2,61); OLED_ShowCHinese(48,2,16); OLED_ShowCHinese(68,2,17); OLED_ShowCHinese(88,2,4); OLED_ShowCHinese(108,2,5); //显示"上传指纹失败" delay_ms(1000); } } else {
OLED_ShowCHinese(8,2,60); OLED_ShowCHinese(28,2,61); OLED_ShowCHinese(48,2,16); OLED_ShowCHinese(68,2,17); OLED_ShowCHinese(88,2,6); OLED_ShowCHinese(108,2,7); //显示"上传指纹失败" delay_ms(1000); } } u16 Down_FR(u16 ID) //下载指纹 {
u8 ensure; u16 i; Audio(8); OLED_Clear(); OLED_ShowCHinese(28,0,58); OLED_ShowCHinese(48,0,59); OLED_ShowCHinese(68,0,16); OLED_ShowCHinese(88,0,17); //显示"下载指纹" ensure=PS_DownChar(CharBuffer2); if(ensure==0x00) {
for(i=4;i<838;i++) {
while((USART2->SR&0X40)==0); USART2->DR = USART_RX_BUF[i]; } ensure=PS_StoreChar(CharBuffer2,ID); if(ensure==0x00) {
MYUSART_SendData1(0x3A); MYUSART_SendData1(0x03); MYUSART_SendData1(0x00); MYUSART_SendData1(0x01); MYUSART_SendData1(0x01); MYUSART_SendData1(0x00); MYUSART_SendData1(0x03); MYUSART_SendData1(0x3A); // printf("下载指纹成功"); ZW_ID[0]=ID; SPI_Flash_Write((u8*)ZW_ID,FLASH_SIZE-100,1); //写入当前ID OLED_ShowCHinese(8,2,58); OLED_ShowCHinese(28,2,59); OLED_ShowCHinese(48,2,16); OLED_ShowCHinese(68,2,17); OLED_ShowCHinese(88,2,6); OLED_ShowCHinese(108,2,7); //显示"下载指纹成功" delay_ms(1000); show_main_page(); } else {
Audio(10); OLED_ShowCHinese(8,2,58); OLED_ShowCHinese(28,2,59); OLED_ShowCHinese(48,2,16); OLED_ShowCHinese(68,2,17); OLED_ShowCHinese(88,2,4); OLED_ShowCHinese(108,2,5); //显示"下载指纹失败" } } }
6、main函数
我这份程序是做一个学生签到系统,上位机通过串口给单片机发送指令,单片机执行相应的操作
int main(void) {
u16 t=0; delay_init(); Audio_Init();//语音模块初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2 TIM4_Int_Init(9999,7199);//10Khz的计数频率,1s定时中断 uart_init(); //初始化串口1波特率为,用于与上位机通讯 usart2_init(57600);//初始化串口2,用于与指纹模块通讯 PS_StaGPIO_Init(); //初始化FR读状态引脚 OLED_Init(); //OLED初始化 OLED_Clear();//OLED清屏 SPI_Flash_Init(); //外接FLASH芯片W25Q64初始化,用来存学生学号(指纹是存到AS608芯片里面的) LED_Init(); while(SPI_Flash_ReadID()!=W25Q64) //检测W25Q64 {
delay_ms(100); LED0=!LED0; //DS0闪烁 } while(PS_HandShake(&AS608Addr)) //与AS608模块握手 {
OLED_ShowCHinese(8,0,0); OLED_ShowCHinese(28,0,1); OLED_ShowCHinese(48,0,2); OLED_ShowCHinese(68,0,3); OLED_ShowString(88,0,"...",16); //显示"正在连接..." } OLED_ShowCHinese(8,0,2); OLED_ShowCHinese(28,0,3); OLED_ShowCHinese(48,0,6); OLED_ShowCHinese(68,0,7); OLED_ShowString(88,0," ",16); //显示"连接成功" // printf("\n连接成功\n"); OLED_Clear(); show_main_page();//OLED显示主界面 while(1) {
command_rx();//等待串口接收指令(我这里是用上位机给单片机串口发指令的) delay_ms(100); if(command==0x01) //收到录入指纹命令 {
command=0; SPI_Flash_Write((u8*)TEXT_Buffer,FLASH_SIZE-100,1);//从倒数第100个地址处开始,写入SIZE长度的数据 SPI_Flash_Read(ZW_ID,FLASH_SIZE-100,1); //读取当前已存的最大指纹ID号 ID=ZW_ID[0]+1; Add_FR(ID); //录指纹 show_main_page(); //显示首页界面 } else if(command==0x02) //上传指纹 {
command=0; SPI_Flash_Read(ZW_ID,FLASH_SIZE-100,1); //读取当前已存的最大指纹ID号 ID=ZW_ID[0]; // MYUSART_SendData1(0x3A); // MYUSART_SendData1(0x02); // MYUSART_SendData1(0x03); // MYUSART_SendData1(0x42); Up_FR(ID); //获取指纹信息 for(t=0;t<841;t++) {
while((USART1->SR&0X40)==0) ; USART1->DR = zw_up[t]; //向上位机上传指纹信息 } // MYUSART_SendData1(0x03); // MYUSART_SendData1(0x45); // MYUSART_SendData1(0x3A); show_main_page(); } else if(command==0x03) //下载指纹 {
command=0; SPI_Flash_Read(ZW_ID,FLASH_SIZE-100,1); //读取当前已存的最大指纹ID号 ID=ZW_ID[0]+1; Down_FR(ID); //下载指纹 show_main_page(); } else if(command==0x04) //上传学号/开始签到 {
press_FR(); } else if(command==0x05) //下载学号 {
command=0; Down_stu_num(ID); show_main_page(); } else if(command==0x06) //结束签到 {
command=0; Audio(14); OLED_Clear(); OLED_ShowCHinese(28,0,12); OLED_ShowCHinese(48,0,13); OLED_ShowCHinese(68,0,62); OLED_ShowCHinese(88,0,63);//显示"结束签到" delay_ms(1500); show_main_page(); } else if(command==0x07) //清空数据 {
command=0; PS_Empty(); ZW_ID[0]=0; SPI_Flash_Write((u8*)ZW_ID,FLASH_SIZE-100,1); //写入当前ID OLED_Clear(); MYUSART_SendData1(0x3A); MYUSART_SendData1(0x07); MYUSART_SendData1(0x00); MYUSART_SendData1(0x01); MYUSART_SendData1(0x00); MYUSART_SendData1(0x04); MYUSART_SendData1(0x3A); OLED_ShowCHinese(12,4,64); OLED_ShowCHinese(30,4,65); OLED_ShowCHinese(48,4,66); OLED_ShowCHinese(66,4,67); OLED_ShowCHinese(84,4,68);//"已清空数据" Audio(18); //播放"播放已清空数据" delay_ms(1500); show_main_page(); } } }
好了,关于这个光学指纹识别模块就讲到这里,程序是以前写的,现在回看,诸多地方都不满意,也没时间一一去改了,如果你们觉得写的不好,勿怪,如果大家还有什么问题可以留言给我。
源码下载链接1:https://pan.baidu.com/s/1A2fbiTy10-2pZUxAaQdJnw ,提取码:8kdp
源码下载链接2:https://pan.baidu.com/s/1aOKyCLwdMrvzPlpIq5tMtA,提取码:abcd
如果觉得博主写的文章有用,那就点赞+关注支持一下吧,创作不易,加班狗用业余时间写博客,不容易呐,所以请尊重每一位博主的劳动,后续也会继续介绍一些适合大学生使用的模块,谢谢大家!!!
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/213718.html原文链接:https://javaforall.net
