物联网项目开发:AS608+ ESP32S3 构建指纹识别系统(一)

目录

一、前言

二、AS608指纹模块简介

三、初步测试AS608模块

(一)硬件信息(详细信息请查看模块使用手册)

1、特性参数

2、接口说明

(二)硬件连接

(三)驱动程序 

 1、下载相关库文件

​编辑

 2、根据需求修改代码

四、获取AS608的指纹特征库数据

(一)理论依据

        指令格式(重点):​编辑

(二)录入指纹获取相应的指纹特征数据库 

(三)获取指纹特征数据

五、最终获取指纹特征库

六、总结 


一、前言

        最近在做一个物联网的项目,主体构思是根据AS608模块来采集指纹并生成对应的指纹库,然后通过一个主控芯片ESP32S3来链接,再加上一个4G模块用来上传数据到云端平台,这样就可以实现线上平台统一管理,多台指纹识别设备互相协同构成系统。

二、AS608指纹模块简介

        AS608 指纹识别模块主要是指采用了杭州晟元芯片技术有限公司(Synochip)的 AS608 指纹识别芯片而做成的指纹模块,模块厂商只是基于该芯片设计外围电路,集成一个可供2次开发的指纹模块;所以只要是基于AS608芯片的指纹模块,其控制电路及控制协议几乎是一样的,只是厂家和性能不同而已。

 资料链接:(包含上位机、模块使用说明、Arduino测试程序等本文涉及的相关资料)

通过网盘分享的文件:CSDN-AS608.rar

链接: https://pan.baidu.com/s/1SzOkoVvrtSNGuyuNM1S56Q?pwd=1234

提取码: 1234

三、初步测试AS608模块

(一)硬件信息(详细信息请查看模块使用手册)

1、特性参数

2、接口说明

(二)硬件连接

  1. 电源线,连接ESP32S3上的3.3V和GND就行了,注意别接反了,听说容易烧坏。
  2. 通信线,需要根据自己设定的串口进行连接。例如:我设定的ESP32S3串口引脚是 RX_PIN = 16,TX_PIN = 17,那么它们分别就跟AS608上的TX和RX相连即可。
#define ESP_RX  16      //Connect with TXpin of AS608
#define ESP_TX  17      //Connect with RXpin of AS608

(三)驱动程序 

 1、下载相关库文件及示例

可以直接访问以下链接:

adafruit/Adafruit-Fingerprint-Sensor-Library: Arduino library for interfacing to the fingerprint sensor in the Adafruit shop (github.com)

也可以在Aduino IDE里面直接搜索下载:

 2、根据需求修改代码

        代码中串口设定需要我们去进行调整。如下图,修改前:

修改后:

 

        再阐述一遍修改原因:由于不同型号的主控芯片对应的可用于UART串口通信的引脚也不同,所以需要根据自己所使用的串口引脚。

修改了串口之后就可以运行示例进行一些简单的尝试:
        

         当然这些示例都是一些非常简单的功能,和我们想设计的系统复杂度差别较大。这里其实也是我写篇文章的原因:网上搜到的关于AS608的文章都是讲的比较简单(可以直接搜索其他文章进行操作,如有需要也可留言我进行编写发布),但没涉及到怎么去提取存储在模块内的指纹库内的数据(真正用来校验指纹的数据)。

四、获取AS608的指纹特征库数据

(一)理论依据

        指令格式(重点):

        为了获取指纹特征库的数据,我们需要重点关注数据包和结束包,并且在串口通信过程中,获取数据之后把包头包尾等部分去除(详见后文)。 

        为了获取指纹特征数据库,可以先了解一下AS608的应答过程:

        

(二)录入指纹获取相应的指纹特征数据库 

        这一过程是必须的,也是为了后续验证我们通过代码所截取到的数据是否准确。我们使用上位机来完成这一步(上文的资料里面有)

        使用一个USB转UART的小模块,然后把AS608链接上电脑(注意调整模块的电压为3.3V),之后打开上位机(具体步骤参照资料里面的软件使用说明)

选择正确的串口号(如图所示为COM7):

成功连接之后应该会如下显示: 

        之后再按照界面的提示,或者软件使用说明,可以先尝试一下模块的具体功能,录入几个指纹数据。

然后再获取指纹库:

 会生成一个.mb后缀的数据文件。这种后缀的文件可以用EmEditor 中的十六进制试图二进制打开方式查看:(这个打开方式我找了好久,啊啊啊……)

就可以看到如下内容:
 暂时先不去管里面的数据怎么划分。

OK,到这步你已经拥有了一个存储了指纹数据的AS608模块,接下来就是尝试通过ESP32S3链接AS608模块来获取指纹特征库(这也是真正与系统交互的关键)。

(三)获取指纹特征数据

首先我们通过上位机看一下我们的数据包大小是多少:

注意看其实此时的大小指的是我们数据包中数据那一部分有多大,其实还有数据前(包头2 bytes+地址 4 bytes+标识 1 byte+长度 2 bytes)总共9 bytes,结尾的校验码2 bytes。

所以总共一个数据包的实际长度是:128+9+2 = 139 bytes。

根据前面提到的模块应答流程可以知道,一个数据包后面会跟一个结束包,所以我们至少一口气读两个包也就是:139*2=278 bytes。

如果再去除掉包头包尾那些没有用的数据,就可以得到我们想要的指纹特征库了。

OK,理论分析完毕,开始实践。

最终实验代码如下:(对于fingerID = 0 的指纹特征数据,连续读取了三个包,总共是417 bytes,未去除掉包头包尾)

#include <Adafruit_Fingerprint.h>

#define ESP_RX  16      //Connect with TXpin of AS608
#define ESP_TX  17      //Connect with RXpin of AS608

HardwareSerial mySerial(2);

Adafruit_Fingerprint finger = Adafruit_Fingerprint(&mySerial);

int getFingerprintIDez();

void setup()
{
 
  Serial.begin(9600);
  while (!Serial);
  delay(100);
  Serial.println("TEST begin!");

  mySerial.begin(57600, SERIAL_8N1, ESP_RX, ESP_TX);
  // set the data rate for the sensor serial port
  finger.begin(57600);
  delay(5);

  if (finger.verifyPassword()) {
    Serial.println("Found fingerprint sensor!");
      Serial.println(F("Reading sensor parameters"));
      finger.getParameters();
      Serial.print(F("Status: 0x")); Serial.println(finger.status_reg, HEX);
      Serial.print(F("Sys ID: 0x")); Serial.println(finger.system_id, HEX);
      Serial.print(F("Capacity: ")); Serial.println(finger.capacity);
      Serial.print(F("Security level: ")); Serial.println(finger.security_level);
      Serial.print(F("Device address: ")); Serial.println(finger.device_addr, HEX);
      Serial.print(F("Packet len: ")); Serial.println(finger.packet_len);
      Serial.print(F("Baud rate: ")); Serial.println(finger.baud_rate);
  } else {
    Serial.println("Did not find fingerprint sensor :(");
    while (1);
  }


/*
  // Try to get the templates for fingers 1 through 10
  for (int finger = 0; finger < 10; finger++) {
    downloadFingerprintTemplate(finger);
  }
*/

  int finger = 0 ;
  downloadFingerprintTemplate(finger);

}

uint8_t downloadFingerprintTemplate(uint16_t id)
{
  Serial.println("------------------------------------");
  Serial.print("Attempting to load #"); Serial.println(id);
  uint8_t p = finger.loadModel(id);
  switch (p) 
  {
    case FINGERPRINT_OK:
      Serial.print("Template "); Serial.print(id); Serial.println(" loaded");
      break;
    case FINGERPRINT_PACKETRECIEVEERR:
      Serial.println("Communication error");
      return p;
    default:
      Serial.print("Unknown error "); Serial.println(p);
      return p;
  }

  // OK success!

  Serial.print("Attempting to get #"); Serial.println(id);
  p = finger.getModel();
  switch (p) {
    case FINGERPRINT_OK:
      Serial.print("Template "); Serial.print(id); Serial.println(" transferring:");
      break;
    default:
      Serial.print("Unknown error "); Serial.println(p);
      return p;
  }

    ///*
    int Length = 417;
    uint8_t templateBuffer[Length];
    memset(templateBuffer, 0xff, Length);  //zero out template buffer
    int index=0;
    uint32_t starttime = millis();
    while ((index < Length) && ((millis() - starttime) < 1000))
    {
      if (mySerial.available())
      {
        templateBuffer[index] = mySerial.read();
        index++;
      }
    }
    Serial.print(index); Serial.println(" bytes read");

    // // filtering only the data packets
    // int uindx = 9, index = 0;
    // memcpy(fingerTemplate + index, bytesReceived + uindx, 256);   // first 256 bytes
    // uindx += 256;       // skip data
    // uindx += 2;         // skip checksum
    // uindx += 9;         // skip next header
    // index += 256;       // advance pointer
    // memcpy(fingerTemplate + index, bytesReceived + uindx, 256);   // second 256 bytes

    for(int i = 0 ; i < Length ; i ++){
      if(i % 29 == 0 && i != 0){
        Serial.print("0x");
        printHex(templateBuffer[i], 2);
        Serial.println(", ");
      }
      else{
        Serial.print("0x");
        printHex(templateBuffer[i], 2);
        Serial.print(", ");
      }
    }

  Serial.println("done.");
  //*/

  /*
    // one data packet is 267 bytes. in one data packet, 11 bytes are 'usesless' :D
    uint8_t bytesReceived[534]; // 2 data packets
    memset(bytesReceived, 0xff, 534);

    uint32_t starttime = millis();
    int i = 0;
    while (i < 534 && (millis() - starttime) < 20000) {
      if (mySerial.available()) {
        bytesReceived[i++] = mySerial.read();
      }
    }

    for (int count= 0; count < 34; count++)
      {
        for (int i = 0; i < 16; i++)
        {
          Serial.print("0x");
          Serial.print(bytesReceived[count*16+i], HEX);
          Serial.print(", ");
        }
        Serial.println();
      }

    Serial.print(i); Serial.println(" bytes read.");
    Serial.println("Decoding packet...");

    uint8_t fingerTemplate[512]; // the real template
    memset(fingerTemplate, 0xff, 512);

    // filtering only the data packets
    int uindx = 9, index = 0;
    memcpy(fingerTemplate + index, bytesReceived + uindx, 256);   // first 256 bytes
    uindx += 256;       // skip data
    uindx += 2;         // skip checksum
    uindx += 9;         // skip next header
    index += 256;       // advance pointer
    memcpy(fingerTemplate + index, bytesReceived + uindx, 256);   // second 256 bytes

    for (int i = 0; i < 512; ++i)
    {
      Serial.print("0x");
      printHex(fingerTemplate[i], 2);
      
      if(i%20 == 0){
        Serial.println();
      }
      else
      Serial.print("\t");
    }
  */    
  
  return p;

}

void printHex(int num, int precision) {
  char tmp[16];
  char format[128];

  sprintf(format, "%%.%dX", precision);

  sprintf(tmp, format, num);
  Serial.print(tmp);
}

void loop()
{}

 运行结果如下:

值得一提的是,包长:0x82 = 130(Dec),和我们用上位机读到的是一致的。在图中我把数据包前的包头和末尾的包尾都做了一定的标注。

手动去除掉包头包尾部分与之前获得的标准指纹特征库进行对比,手动去除包头包尾之后:

可以和前文的EmEditor展示出来的指纹特征数据进行对比,也可以说是完全一致的。

为了保证普适性,我还验证了fingerID = 1 时,数据也是一致的。如果获取其他未使用的ID,那么程序就会报错,显示无法获取指纹特征库。

那么接下来就只需要通过程序去让他自动去除包头包尾。

五、最终获取指纹特征库

代码如下:(获取三个数据包的内的数据)

#include <Adafruit_Fingerprint.h>

#define ESP_RX  16      //Connect with TXpin of AS608
#define ESP_TX  17      //Connect with RXpin of AS608

HardwareSerial mySerial(2);

Adafruit_Fingerprint finger = Adafruit_Fingerprint(&mySerial);

int getFingerprintIDez();

void setup()
{
 
  Serial.begin(9600);
  while (!Serial);
  delay(100);
  Serial.println("TEST begin!");

  mySerial.begin(57600, SERIAL_8N1, ESP_RX, ESP_TX);
  // set the data rate for the sensor serial port
  finger.begin(57600);
  delay(5);

  if (finger.verifyPassword()) {
    Serial.println("Found fingerprint sensor!");
      Serial.println(F("Reading sensor parameters"));
      finger.getParameters();
      Serial.print(F("Status: 0x")); Serial.println(finger.status_reg, HEX);
      Serial.print(F("Sys ID: 0x")); Serial.println(finger.system_id, HEX);
      Serial.print(F("Capacity: ")); Serial.println(finger.capacity);
      Serial.print(F("Security level: ")); Serial.println(finger.security_level);
      Serial.print(F("Device address: ")); Serial.println(finger.device_addr, HEX);
      Serial.print(F("Packet len: ")); Serial.println(finger.packet_len);
      Serial.print(F("Baud rate: ")); Serial.println(finger.baud_rate);
  } else {
    Serial.println("Did not find fingerprint sensor :(");
    while (1);
  }


/*
  // Try to get the templates for fingers 1 through 10
  for (int finger = 0; finger < 10; finger++) {
    downloadFingerprintTemplate(finger);
  }
*/

  int finger = 0 ;
  downloadFingerprintTemplate(finger);

}

uint8_t downloadFingerprintTemplate(uint16_t id)
{
  Serial.println("------------------------------------");
  Serial.print("Attempting to load #"); Serial.println(id);
  uint8_t p = finger.loadModel(id);
  switch (p) 
  {
    case FINGERPRINT_OK:
      Serial.print("Template "); Serial.print(id); Serial.println(" loaded");
      break;
    case FINGERPRINT_PACKETRECIEVEERR:
      Serial.println("Communication error");
      return p;
    default:
      Serial.print("Unknown error "); Serial.println(p);
      return p;
  }

  // OK success!

  Serial.print("Attempting to get #"); Serial.println(id);
  p = finger.getModel();
  switch (p) {
    case FINGERPRINT_OK:
      Serial.print("Template "); Serial.print(id); Serial.println(" transferring:");
      break;
    default:
      Serial.print("Unknown error "); Serial.println(p);
      return p;
  }

    ///*
    int Length = 417;
    uint8_t templateBuffer[Length];
    memset(templateBuffer, 0xff, Length); 
    int index=0;
    uint32_t starttime = millis();
    while ((index < Length) && ((millis() - starttime) < 1000))
    {
      if (mySerial.available())
      {
        templateBuffer[index] = mySerial.read();
        index++;
      }
    }
    Serial.print(index); Serial.println(" bytes read");

    Length = Length - 33;
    uint8_t fingerTemplate[Length]; // the real template
    memset(fingerTemplate, 0xff, Length);

    // filtering only the data packets
    int uindx = 9;
    index = 0;
    memcpy(fingerTemplate + index, templateBuffer + uindx, 128);   // first 128 bytes
    uindx += 128;       // skip data
    uindx += 2;         // skip checksum
    uindx += 9;         // skip next header
    index += 128;       // advance pointer
    memcpy(fingerTemplate + index, templateBuffer + uindx, 128);   // second 128 bytes
    uindx += 128;       // skip data
    uindx += 2;         // skip checksum
    uindx += 9;         // skip next header
    index += 128;       // advance pointer
    memcpy(fingerTemplate + index, templateBuffer + uindx, 128);   // third 128 bytes

    for(int i = 0 ; i < Length ; i ++){
      if(i % 29 == 0 && i != 0){
        Serial.print("0x");
        printHex(fingerTemplate[i], 2);
        Serial.println(", ");
      }
      else{
        Serial.print("0x");
        printHex(fingerTemplate[i], 2);
        Serial.print(", ");
      }
    }

  Serial.println("done.");
  //*/
  
  return p;

}

void printHex(int num, int precision) {
  char tmp[16];
  char format[128];

  sprintf(format, "%%.%dX", precision);

  sprintf(tmp, format, num);
  Serial.print(tmp);
}

void loop()
{}

运行结果如下:(成功去除了包头包尾部分)

六、总结 

        在本文介绍了如何调试AS608模块,并通过它获取指纹特征库数据;基于此结果,有 个方向:通过再给ESP32S3搭载外设(SIM7600X模块)使硬件部分具备联网的功能,实现对系统的实时管理,再配合搭建一个云平台就可以搭建起整个框架,适合与其他管理系统进行协同;或者搭载一个储存模块,平时把指纹数据库拷贝下来,周期性的把数据进行上传同步,单纯用于门禁指纹锁之类的还是很便利的。

        挖坑:接下来将对数据库的建立,PC端程序的编写进行记录分享,如果感兴趣的话欢迎持续关注。

        如果对本文的内容有任何改进的建议也欢迎评论\私信告诉我!如果本文对你有帮助的话,不妨点个赞。欢迎留言讨论问题,一起讨论问题、解决问题。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值