AS608指纹模块高级功能实现(一):底层数据传输——指纹特征库上传给上位机

一、写在前面

最近突发其想,想利用两个AS608模块实现数据共享,也就是利用其中一个录入指纹,另外一个也能够读取到录入的指纹。但是笔者找遍全网,也只有实现了基本的录入、删除、验证功能的例程,以及一个具有全功能的上位机,如果要实现数据共享,那么必须要实现文件底层数据的传输,而上位机根本无法看到内部的具体实现。于是,笔者还是决定通过串口调试、翻阅手册,探究AS608数据传输的实现方法。

AS608作为一款比较成熟的指纹芯片,SoC已经封装好了各种指令,我们只要发送我们所需的指令包,便可完成一系列的操作。笔者使用了STC15系列单片机进行试验,加入了LCD辅助显示程序运行情况,本文主要目的还是在于探讨,对于一些交互并没有十分重视,对于AS608的基本操作也没有过多的介绍,希望大家理解。

二、实现目标、主要难点

目标

使用串口调试助手,获得芯片一份完整指纹特征模板,并生成.mb文件

难点

滤除包头包尾,UART串口通讯

三、芯片通讯方式

1、通讯方法

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

在这里插入图片描述
上图介绍了芯片三种包的格式,其中数据包和结束包是本文重点用到的,也是最容易被大家忽略掉的。

四、实验流程

一、芯片配置

9600波特率,数据包大小64字节
也可以自行设置,涉及到串口通信问题,笔者串口1连接上位机,串口2连接AS608模块。

二、指纹录入,生成出该指纹的特征模板存放于Buffer1

在这里插入图片描述
emmm自己画的,忽视水印

两次按指纹完成一次指纹录入。

三、模板保存于缓冲区并通过串口发送至上位机

在这里插入图片描述
关键在于滤除包头包尾,包头使用逐层判断,判断包头后开始接收数据,包头后面跟64字节有效+2字节校验和,所以我们只需要for循环接收64字节,后面2字节不管,完成后存放特征寄存数组,随后进入下一次数据包头判断。

五、主要实现代码

串口2:UART2.h

#ifndef __UART2_H
#include <string.h>
#include "uart.h"
#define __UART2_H

#define uchar unsigned char 
#define uint unsigned int



#define S2RI 0x01           //串口2接收中断请求标志位
#define S2TI 0x02           //串口2发送中断请求标志位
#define S2RB8 0x04
#define S2TB8 0x08
       
#define UART2_MAX_RECV_LEN		768					//最大接收缓存字节数
#define UART2_MAX_SEND_LEN		1028					//最大发送缓存字节数

//串口接收缓存区 	
uchar  xdata UART2_RX_BUF[24]; 				//命令接收缓冲,不需要太大
uchar  xdata UART2_TX_BUF[UART2_MAX_SEND_LEN]; //发送缓冲,最大USART3_MAX_SEND_LEN字节
uchar  xdata CHAR_TEMP_BUF[64];
uchar  xdata CHARBUF[800];
uint   UART2_RX_STA = 0;             //命令接收缓冲指针
uint   CHAR_TEMP_STA = 0;            //数据包缓冲区临时指针
uint   CHARBUF_STA = 0;              //特征模板存储指针
uchar  Head_Flag = 0;                //数据包包头检测标志


//串口2初始化
void UART2_Init()
{
	
	TMOD |= 0x20;	// 0010 0000 定时器2工作于方式2(8位自动重装方式)
	T2H  = 0xfd;	// 波特率:37600 /22.1184MHZ
	T2L  = 0xc0;	// 波特率:37600 /22.1184MHZ
	AUXR = 0x14;    // 使用定时器2作为波特率发生器
	S2CON = 0x50; 	
	// 设置中断
	IE2 =0x01;     
	EA   = 1;
}


//串口2发送一个字节
void UART2_SendData(uchar c)
{
    S2BUF = c;
    while(!(S2CON&S2TI));  //若S2TI=0,在此等待
    S2CON&=~S2TI;          //S2TI=0
}

void show_rx_buff(void)
{
	uint i=0;
	for(i;i<UART2_MAX_RECV_LEN;i++)
	{
			UART_Send_Byte(CHARBUF[i]);
	}
}

/************串行口2中断处理函数*************/
void UART2_Interrupt(void) interrupt 8
{
	uchar Res;
	if(S2CON&S2RI)
	{
		S2CON&=~S2RI;
		Res=S2BUF;
		UART_Send_Byte(Res);
			if(UART2_RX_STA<24)
			{
				UART2_RX_BUF[UART2_RX_STA++]=Res;       //命令存储
			}else{}
			if(Head_Flag == 0)       //包头检测,采用了最传统的判断算法
			{  
				if(Res == 0xEF)  
					Head_Flag++;  
				else  
					Head_Flag = 0;  
			}  
			else if(Head_Flag == 1)  
			{  
					if(Res == 0x01)  
							Head_Flag++;  
					else  
							Head_Flag = 0;  
			}  
			else if(Head_Flag == 2)  
			{  
					if(Res == 0xFF)  
							Head_Flag++;  
					else  
							Head_Flag = 0;  
			}  
			else if(Head_Flag == 3)  
			{  
					if(Res == 0xFF)  
							Head_Flag++;  
					else  
							Head_Flag = 0;  
			}  
			else if(Head_Flag == 4)  
			{  
					if(Res == 0xFF)  
							Head_Flag++;  
					else  
							Head_Flag = 0;  
			}  
			else if(Head_Flag == 5)  
			{  
					if(Res == 0xFF)  
							Head_Flag++;  
					else  
							Head_Flag = 0;  
			}
			else if(Head_Flag == 6)  
			{  
					if(Res == 0x02||Res == 0x08)    //包括了结束包
			  		Head_Flag++;
					else
							Head_Flag = 0;  
			}
			else if(Head_Flag == 7)  
			{  
					if(Res == 0x00)  
							Head_Flag++;  
					else  
							Head_Flag = 0;  
			}
			else if(Head_Flag == 8)  
			{  
					if(Res == 0x42)  
							Head_Flag++;  
					else  
							Head_Flag = 0;  
			}

			else if(Head_Flag == 9)
			{
				if(CHAR_TEMP_STA<64)
				CHAR_TEMP_BUF[CHAR_TEMP_STA++]=Res;
				else if(CHAR_TEMP_STA==64)
				{
					for(CHAR_TEMP_STA=0;CHAR_TEMP_STA<64;CHAR_TEMP_STA++)
					{
						CHARBUF[CHARBUF_STA++]=CHAR_TEMP_BUF[CHAR_TEMP_STA];
					}
					CHAR_TEMP_STA=0;
					Head_Flag=0;
				}
			}		
	}
}
#endif

AS608.h

#ifndef __AS608_H
#define __AS608_H
#include <string.h>
#include "UART.h"
#include "UART2.h"
#include "lcd.h"

#define uchar unsigned char 
#define uint unsigned int
#define ulong unsigned long


#define CharBuffer1 0x01
#define CharBuffer2 0x02

ulong AS608Addr = 0XFFFFFFFF; //??????

char str2[6]={0};

void Delay_Ms(uint ms)               
{
	uint a,b,c;
	for(a=ms;a>0;a--)
		for(b=10;b>0;b--)
			for(c=85;c>0;c--);
}

//发送包头
static void SendHead(void)
{
	UART2_SendData(0xEF);
	UART2_SendData(0x01);
}

//发送地址
static void SendAddr(void)
{
	UART2_SendData(AS608Addr>>24);
	UART2_SendData(AS608Addr>>16);
	UART2_SendData(AS608Addr>>8);
	UART2_SendData(AS608Addr);
}

//发送包标识
static void SendFlag(uchar flag)
{
	UART2_SendData(flag);
}

//发送包长度
static void SendLength(int length)
{
	UART2_SendData(length>>8);
	UART2_SendData(length);
}
//发送指令码
static void Sendcmd(uchar cmd)
{
	UART2_SendData(cmd);
}

//发送BuffID
static void SendBuffID(uchar BuffID)
{
	UART2_SendData(BuffID);
}

//发送校验和
static void SendCheck(uint check)
{
	UART2_SendData(check>>8);
	UART2_SendData(check);
}

//判断中断接收数组有没有应答包
//waittime为等待中断接收数组等待时间
//返回值:数据包首地址
static uchar *JudgeStr(uint waittime)
{
//	uint temp;
	char *rdata;
	uchar str[8];
	str[0]=0xef;str[1]=0x01;str[2]=0xFF;
	str[3]=0xFF;str[4]=0xFF;
	str[5]=0xFF;str[6]=0x07;str[7]='\0';   
	UART2_RX_STA=0;
	while(--waittime)
	{
		Delay_Ms(1000);
		if(1)
		{
			UART2_RX_STA=0;
			rdata=strstr((const char*)UART2_RX_BUF,(const char*)str);
			if(rdata)
				return (uchar*)rdata;	
		}		
	}
	return 0;
}

//按指纹,指令号:01
uchar PS_GetImage(void)
{
  uint temp;
  uchar  ensure;
	uchar  *rdata;
	SendHead();
	SendAddr();
	SendFlag(0x01);
	SendLength(0x03);
	Sendcmd(0x01);
  temp =  0x01+0x03+0x01;
	SendCheck(temp);
	rdata=JudgeStr(8000);
	if(rdata)
		ensure=rdata[9];
	else
		ensure=0xff;
	return ensure;
}

//生成特征,指令号:02
uchar PS_GenChar(uchar BufferID)
{
	uint temp;
  uchar  ensure;
	uchar  *rdata;
	SendHead();
	SendAddr();
	SendFlag(0x01);
	SendLength(0x04);
	Sendcmd(0x02);
	UART2_SendData(BufferID);
	temp = 0x01+0x04+0x02+BufferID;
	SendCheck(temp);
	rdata=JudgeStr(8000);
	if(rdata)
		ensure=rdata[9];
	else
		ensure=0xff;
	return ensure;
}

//合成buffer1和buffer2中的特征,指令号:05
uchar PS_RegModel(void)
{
	uint temp;
  uchar  ensure;
	uchar  *rdata;
	SendHead();
	SendAddr();
	SendFlag(0x01);
	SendLength(0x03);
	Sendcmd(0x05);
	temp = 0x01+0x03+0x05;
	SendCheck(temp);
	rdata=JudgeStr(8000);
	if(rdata)
		ensure=rdata[9];
	else
		ensure=0xff;
	return ensure;		
}

//上传特征函数,指令号:08
void PS_Upchar()
{
	uint temp;
  //uchar  ensure;
	//uchar  *rdata;
	SendHead();
	SendAddr();
	SendFlag(0x01);
	SendLength(0x04);
	Sendcmd(0x08);
	UART2_SendData(0x01);
  temp = 0x01+0x04+0x08+0x01;
	SendCheck(temp);
	/*rdata=JudgeStr(8000);
	if(rdata)
		ensure=rdata[9];
	else
		ensure=0xff;
	return ensure;*/
}


//函数功能:完成两次录入指纹并生成特征模板存于Buffer1和Buffer2
void Create_FR_Char(void)
{
	uchar i,ensure ,processnum=0;
	uint ID_NUM=0;
	while(1)
	{
		switch (processnum)
		{
			case 0:
				i++;
				LCD_show(0x00,"please press1");
				ensure=PS_GetImage();
				if(ensure==0x00) 
				{
					ensure=PS_GenChar(CharBuffer1);
					if(ensure==0x00)
					{
						Delay_Ms(1);
						LCD_show(0x00,"Press1 Finish");
						Delay_Ms(100);
						i=0;
						processnum=1;//跳到第二步
					}else {};
				}else {};
			break;
					
			case 1:
				i++;
			  LCD_show(0x00,"try again");
				Delay_Ms(100);
				ensure=PS_GetImage();
				if(ensure==0x00) 
				{
					ensure=PS_GenChar(CharBuffer2);//????
					if(ensure==0x00)
					{
						Delay_Ms(1);
						LCD_show(0x00,"Press2 Finish");
						Delay_Ms(100);
						i=0;
						processnum=2;//跳往第三步
					}else {};	
					}else {};		
				break;
						
				case 2:
				LCD_show(0x00,"Creating Press");
				Delay_Ms(500);
				ensure=PS_RegModel();
				if(ensure==0x00) 
				{
					LCD_show(0x00,"Creat Success");
					return ;
				}
				else
					{
						LCD_show(0x00,"Cmp defeat");
						LCD_show(0x40,"Try again");
						processnum=0;//返回第一步
					}
				Delay_Ms(1000);
				break;
					}
		Delay_Ms(400);
		if(i==10)//超过5次未按手指退出
			break;
	}		
}
#endif

main.c

#include "STC15W4k.h"
#include "UART.h"
#include "UART2.h"
#include "AS608.h"
#include "lcd.h"

sbit key1 = P2^4;
sbit key2 = P2^3;

void port_mode()            //STC15系列引口有三种模式,此为设置成开漏模式
{
	P0M1=0x00; P0M0=0x00;P1M1=0x00; P1M0=0x00;P2M1=0x00; P2M0=0x00;P3M1=0x00; P3M0=0x00;
	P4M1=0x00; P4M0=0x00;P5M1=0x00; P5M0=0x00;P6M1=0x00; P6M0=0x00;P7M1=0x00; P7M0=0x00; 
}


void main()
{
	port_mode();
	Init_LCD();
	UART_Init();
	UART2_Init();
	UART_Send_Str("初始化完毕");
	LCD_show(0x00,"Init Success");
	while(1)
	{
		if(key1==0)
		{
			Delay_Ms(5);
			if(key1==0)
			{
			Create_FR_Char();
			PS_Upchar();
			}
		}
		if(key2==0)
		{
			Delay_Ms(5);
			if(key2==0)
			{
				LCD_show(0x00,"Sending");
				show_rx_buff();
			}
		}
	}
}

六、实验结果

为操作方便,加入了按键,按键1完成录入,显示Creat Success,在完成第一步后按下按键2,给串口调试助手发送特征模板数据。实验结果以及对比如图:
在这里插入图片描述
这是未剔除包头包尾的数据,可以看到包头结尾的0x42表示后面有64字节有效数据+2字节的校验和数据。
在这里插入图片描述
剔除后的串口数据。
为了更直观看到对比,笔者将原数据剔除包头包尾后进行对比,看一看到是完全一样的。
在这里插入图片描述
真的真的是一个个手动删除!(加鸡腿)

最后,对数据进行打包成.mb文件,使用上位机上传指纹特征到芯片,同时进行指纹验证。
在这里插入图片描述
对比通过,大功告成!

七、后记

本实验换言之就是把数据拎了出来又放回去,但是我们实现了在底层进行了数据操作,这样的操作对于我们进行文件转移、数据共享是非常有意义的。同时也加深了对文件组成原理、通信原理的理解。

本实验的代码也有不足的地方,算法有待优化,也有部分bug,希望借此抛砖引玉,欢迎大家提供意见。

最后还要感谢几位在本实验过程中给予过帮助的朋友。

源代码下载:https://pan.baidu.com/s/1hfwgWqE66ruNBTlR7FC3EQ
提取码:8fb7

原创文章 1 获赞 5 访问量 160

猜你喜欢

转载自blog.csdn.net/health_/article/details/105905963
今日推荐