Interface Fingerprint Sensor Using M5Stack Core ESP32 Development Kit

This tutorial shows how to matching, add new and remove fingerprint using M5Stack.

Introduction

This is a highly integrated rectangle-shaped all-in-one capacitive fingerprint sensor module, which is designed in small form factor. The module is controlled via UART commands, fairly easy to use. This sensor features functionalities like fingerprint enrolling, image acquisition, feature finding, fingerprint matching, and so on. Without any knowledge about the complicate fingerprinting algorithm, all you need to do is just sending some UART commands, to quickly integrate it into fingerprint verification applications which require small size and high precision.

Video

This video shows how to interface fingerprint sensor using M5Stack Core ESP32 Development Kit.

Hardware Preparation

This is the list of items used in the video.

Sample Program

Since the code is quite long, I divide into 3 files. 2 files with a named “Fingerprint” are the library and “M5StackFingerprint” is the main file. You can refer to the video tutorial on how to use the code.

#include <M5Stack.h>
#include "Fingerprint.h"
Fingerprint::Fingerprint(void)
{
Serial1.begin(19200, SERIAL_8N1, FINGER_TX, FINGER_RX);
}
uint8_t Fingerprint::TxAndRxCmd(uint8_t Scnt, uint8_t Rcnt, uint16_t Delay_ms)
{
uint8_t i, j, CheckSum;
uint32_t before_tick;
uint32_t after_tick;
uint8_t overflow_Flag = 0;
//Serial.print("TX: ");
Serial1.write(CMD_HEAD); //Serial.print(CMD_HEAD, HEX); Serial.print(" ");
CheckSum = 0;
for (i = 0; i < Scnt; i++) {
Serial1.write(finger_TxBuf[i]); //Serial.print(finger_TxBuf[i], HEX); Serial.print(" ");
CheckSum ^= finger_TxBuf[i];
}
Serial1.write(CheckSum); //Serial.print(CheckSum, HEX); Serial.print(" ");
Serial1.write(CMD_TAIL); //Serial.println(CMD_TAIL, HEX);
fingerPrevMillis = millis();
while (millis() – fingerPrevMillis < Delay_ms) {
if (Serial1.available()) break;
}
//Serial.print("RX: ");
i = 0;
while (Serial1.available()) {
finger_RxBuf[i] = Serial1.read();
//Serial.print(finger_RxBuf[i], HEX); Serial.print(" ");
i++;
}
//Serial.println();
if (i != Rcnt) {
return ACK_TIMEOUT;
}
else if (finger_RxBuf[0] != CMD_HEAD) {
return ACK_FAIL;
}
else if (finger_RxBuf[Rcnt – 1] != CMD_TAIL) {
return ACK_FAIL;
}
else if (finger_RxBuf[1] != finger_TxBuf[0]) {
return ACK_FAIL;
}
CheckSum = 0;
for (j = 1; j < Rcnt – 1; j++) {
CheckSum ^= finger_RxBuf[j];
}
if (CheckSum != 0) {
return ACK_FAIL;
}
return ACK_SUCCESS;
}
uint8_t Fingerprint::GetUserCount(void)
{
uint8_t m;
finger_TxBuf[0] = CMD_USER_CNT;
finger_TxBuf[1] = 0;
finger_TxBuf[2] = 0;
finger_TxBuf[3] = 0;
finger_TxBuf[4] = 0;
m = TxAndRxCmd(5, 8, 100);
if (m == ACK_SUCCESS && finger_RxBuf[4] == ACK_SUCCESS) {
return finger_RxBuf[3];
}
else {
return 0xFF;
}
}
uint8_t Fingerprint::GetcompareLevel(void)
{
uint8_t m;
finger_TxBuf[0] = CMD_COM_LEV;
finger_TxBuf[1] = 0;
finger_TxBuf[2] = 0;
finger_TxBuf[3] = 1;
finger_TxBuf[4] = 0;
m = TxAndRxCmd(5, 8, 100);
if (m == ACK_SUCCESS && finger_RxBuf[4] == ACK_SUCCESS) {
return finger_RxBuf[3];
}
else {
return 0xFF;
}
}
uint8_t Fingerprint::SetcompareLevel(uint8_t temp)
{
uint8_t m;
finger_TxBuf[0] = CMD_COM_LEV;
finger_TxBuf[1] = 0;
finger_TxBuf[2] = temp;
finger_TxBuf[3] = 0;
finger_TxBuf[4] = 0;
m = TxAndRxCmd(5, 8, 100);
if (m == ACK_SUCCESS && finger_RxBuf[4] == ACK_SUCCESS) {
return finger_RxBuf[3];
}
else {
return 0xFF;
}
}
uint8_t Fingerprint::GetTimeOut(void)
{
uint8_t m;
finger_TxBuf[0] = CMD_TIMEOUT;
finger_TxBuf[1] = 0;
finger_TxBuf[2] = 0;
finger_TxBuf[3] = 1;
finger_TxBuf[4] = 0;
m = TxAndRxCmd(5, 8, 100);
if (m == ACK_SUCCESS && finger_RxBuf[4] == ACK_SUCCESS) {
return finger_RxBuf[3];
}
else {
return 0xFF;
}
}
uint8_t Fingerprint::AddUser(void)
{
uint8_t m;
m = GetUserCount();
if (m >= USER_MAX_CNT) {
return ACK_FULL;
}
finger_TxBuf[0] = CMD_ADD_1;
finger_TxBuf[1] = 0;
finger_TxBuf[2] = m + 1;
finger_TxBuf[3] = 3;
finger_TxBuf[4] = 0;
m = TxAndRxCmd(5, 8, 5000);
if (m == ACK_SUCCESS && finger_RxBuf[4] == ACK_SUCCESS) {
finger_TxBuf[0] = CMD_ADD_3;
m = TxAndRxCmd(5, 8, 5000);
if (m == ACK_SUCCESS && finger_RxBuf[4] == ACK_SUCCESS) {
return ACK_SUCCESS;
}
else {
return ACK_FAIL;
}
}
else {
return ACK_GO_OUT;
}
}
uint8_t Fingerprint::ClearAllUser(void)
{
uint8_t m;
finger_TxBuf[0] = CMD_DEL_ALL;
finger_TxBuf[1] = 0;
finger_TxBuf[2] = 0;
finger_TxBuf[3] = 0;
finger_TxBuf[4] = 0;
m = TxAndRxCmd(5, 8, 500);
if (m == ACK_SUCCESS && finger_RxBuf[4] == ACK_SUCCESS) {
return ACK_SUCCESS;
}
else {
return ACK_FAIL;
}
}
uint8_t Fingerprint::IsMasterUser(uint8_t UserID)
{
if ((UserID == 1) || (UserID == 2) || (UserID == 3)) {
return true;
}
else {
return false;
}
}
uint8_t Fingerprint::VerifyUser(void)
{
uint8_t m;
finger_TxBuf[0] = CMD_MATCH;
finger_TxBuf[1] = 0;
finger_TxBuf[2] = 0;
finger_TxBuf[3] = 0;
finger_TxBuf[4] = 0;
m = TxAndRxCmd(5, 8, 1000);
if ((m == ACK_SUCCESS) && (IsMasterUser(finger_RxBuf[4]) == true)) {
return ACK_SUCCESS;
}
else if(finger_RxBuf[4] == ACK_NO_USER) {
return ACK_NO_USER;
}
else if(finger_RxBuf[4] == ACK_TIMEOUT) {
return ACK_TIMEOUT;
}
else {
return ACK_FAIL;
}
}

view raw
Fingerprint.cpp
hosted with ❤ by GitHub

#ifndef _FINGERPRINT_H
#define _FINGERPRINT_H
// Basic response message definition
#define ACK_SUCCESS 0x00
#define ACK_FAIL 0x01
#define ACK_FULL 0x04
#define ACK_NO_USER 0x05
#define ACK_TIMEOUT 0x08
#define ACK_GO_OUT 0x0F // The center of the fingerprint is out of alignment with sensor
// User information definition
#define ACK_ALL_USER 0x00
#define ACK_GUEST_USER 0x01
#define ACK_NORMAL_USER 0x02
#define ACK_MASTER_USER 0x03
#define USER_MAX_CNT 1000 // Maximum fingerprint number
// Command definition
#define CMD_HEAD 0xF5
#define CMD_TAIL 0xF5
#define CMD_ADD_1 0x01
#define CMD_ADD_2 0x02
#define CMD_ADD_3 0x03
#define CMD_MATCH 0x0C
#define CMD_DEL 0x04
#define CMD_DEL_ALL 0x05
#define CMD_USER_CNT 0x09
#define CMD_COM_LEV 0x28
#define CMD_LP_MODE 0x2C
#define CMD_TIMEOUT 0x2E
#define CMD_FINGER_DETECTED 0x14
#define FINGER_WAKE 26
#define FINGER_RST 5
#define FINGER_RX 17
#define FINGER_TX 16
class Fingerprint
{
public:
Fingerprint(void);
uint8_t TxAndRxCmd(uint8_t Scnt, uint8_t Rcnt, uint16_t Delay_ms);
uint8_t GetUserCount(void);
uint8_t GetcompareLevel(void);
uint8_t SetcompareLevel(uint8_t temp);
uint8_t GetTimeOut(void);
uint8_t AddUser(void);
uint8_t ClearAllUser(void);
uint8_t IsMasterUser(uint8_t UserID);
uint8_t VerifyUser(void);
public:
uint8_t finger_TxBuf[9];
uint8_t finger_RxBuf[9];
long fingerPrevMillis = 0;
private:
private:
};
#endif

view raw
Fingerprint.h
hosted with ❤ by GitHub

/*
Project: Interface Fingerprint Sensor Using M5Stack
Board: M5Stack-Core-ESP32
Connections:
M5Stack | Fingerprint
3.3V – VIN
GND – GND
IO17 – RX
IO16 – TX
IO5 – RST
IO26 – WAKE
External libraries:
– M5Stack by M5Stack V0.3.0 (Manager)
*/
#include <M5Stack.h>
#include "Fingerprint.h"
Fingerprint fp;
char inChar;
int count = 0;
uint8_t fingerResponse;
long prevMillis = 0;
void setup()
{
pinMode(FINGER_WAKE, INPUT);
pinMode(FINGER_RST, OUTPUT);
digitalWrite(FINGER_RST, HIGH);
M5.begin();
M5.Power.begin();
Serial.begin(115200);
Serial.println();
Serial.println();
if (fp.SetcompareLevel(5) != 5) {
Serial.println("***ERROR***");
Serial.println("Please ensure that the module power supply is 3.3V or 5V,");
Serial.println("the serial line connection is correct.");
Serial.println();
}
Serial.println("********** WaveShare Capacitive Fingerprint Reader Test **********");
Serial.println("Compare Level: 5 (can be set to 0-9, the bigger, the stricter)");
Serial.print("Number of fingerprints already available: ");
Serial.println(fp.GetUserCount());
Serial.println("Send commands to operate the module: ");
Serial.println(" 1 : Query the number of existing fingerprints");
Serial.println(" 2 : Registered fingerprint (Put your finger on the sensor until successfully/failed information returned)");
Serial.println(" 3 : Clear fingerprints");
M5.Lcd.clear(BLACK);
M5.Lcd.setTextSize(2);
M5.Lcd.setTextColor(RED);
M5.Lcd.setCursor(0, 10);
M5.Lcd.println("**** Fingerprint Demo ****");
M5.Lcd.setTextColor(WHITE);
M5.Lcd.setCursor(0, 40);
M5.Lcd.println("SW1: No of fingerprint");
M5.Lcd.setTextColor(YELLOW);
M5.Lcd.println("No of existing fingerprint");
M5.Lcd.setTextColor(WHITE);
M5.Lcd.setCursor(0, 85);
M5.Lcd.println("SW2: Register fingerprint");
M5.Lcd.setTextColor(YELLOW);
M5.Lcd.println("Put your finger on sensor");
M5.Lcd.setTextColor(WHITE);
M5.Lcd.setCursor(0, 130);
M5.Lcd.println("SW3: Clear fingerprints");
M5.Lcd.setTextColor(GREEN);
M5.Lcd.setCursor(0, 160);
M5.Lcd.println("Status:");
digitalWrite(FINGER_RST, LOW);
M5.Speaker.beep();
}
void loop()
{
if (M5.BtnA.wasReleased()) {
inChar = '1';
}
else if (M5.BtnB.wasReleased()) {
inChar = '2';
}
else if (M5.BtnC.wasReleased()) {
inChar = '3';
}
if (digitalRead(FINGER_WAKE) == HIGH) {
while (digitalRead(FINGER_WAKE) != LOW) {
digitalWrite(FINGER_RST, HIGH);
delay(300);
Serial.println("Waiting Finger… Please try to place the center of the fingerprint flat to sensor!");
M5.Lcd.fillRect(0, 180, 320, 60, BLACK);
M5.Lcd.setTextColor(WHITE);
M5.Lcd.setCursor(0, 180);
M5.Lcd.println("Fingerprint is detected");
M5.Lcd.print("scanning…");
for (count = 0; count < 3; count++) {
fingerResponse = fp.VerifyUser();
if (fingerResponse == ACK_SUCCESS) break;
}
M5.Lcd.fillRect(0, 180, 320, 60, BLACK);
M5.Lcd.setTextColor(WHITE);
M5.Lcd.setCursor(0, 180);
switch (fingerResponse) {
case ACK_SUCCESS:
Serial.println("Matching successful!");
M5.Lcd.print("Matching successful!");
M5.Speaker.beep();
break;
case ACK_NO_USER:
Serial.println("Failed: This fingerprint was not found in the library!");
M5.Lcd.println("This fingerprint was not");
M5.Lcd.print("found in the library!");
break;
case ACK_TIMEOUT:
Serial.println("Failed: Time out!");
M5.Lcd.print("Time out!");
break;
case ACK_GO_OUT:
Serial.println("Failed: Please try to place the center of the fingerprint flat to sensor!");
M5.Lcd.print("Please try again!");
break;
}
}
digitalWrite(FINGER_RST, LOW);
prevMillis = millis();
}
if (Serial.available()) {
while (Serial.available()) {
inChar = (char)Serial.read();
}
}
if (inChar) {
switch (inChar) {
case '1':
digitalWrite(FINGER_RST, HIGH);
delay(300);
for (count = 0; count < 3; count++) {
fingerResponse = fp.GetUserCount();
if (fingerResponse != 0xFF) break;
}
Serial.print("Number of fingerprints already available: ");
Serial.println(fingerResponse);
M5.Lcd.fillRect(0, 180, 320, 60, BLACK);
M5.Lcd.setTextColor(WHITE);
M5.Lcd.setCursor(0, 180);
M5.Lcd.print("No of fingerprint = ");
M5.Lcd.print(fingerResponse);
digitalWrite(FINGER_RST, LOW);
break;
case '2':
digitalWrite(FINGER_RST, HIGH);
delay(300);
Serial.println("Add fingerprint (Put your finger on sensor until successfully/failed information returned.");
M5.Lcd.fillRect(0, 180, 320, 60, BLACK);
M5.Lcd.setTextColor(WHITE);
M5.Lcd.setCursor(0, 180);
M5.Lcd.println("Add new fingerprint");
M5.Lcd.print("Put your finger on sensor");
for (count = 0; count < 3; count++) {
fingerResponse = fp.AddUser();
if (fingerResponse == ACK_SUCCESS) break;
}
M5.Lcd.fillRect(0, 180, 320, 60, BLACK);
M5.Lcd.setTextColor(WHITE);
M5.Lcd.setCursor(0, 180);
switch (fingerResponse) {
case ACK_SUCCESS:
Serial.println("Fingerprint added successfully!");
M5.Lcd.println("Fingerprint added");
M5.Lcd.print("successfully!");
break;
case ACK_GO_OUT:
Serial.println("Failed: Please try to place the center of the fingerprint flat to sensor, or this fingerprint already exists!");
M5.Lcd.println("Please try again /");
M5.Lcd.print("fingerprint already exist!");
break;
case ACK_FAIL:
Serial.println("Failed: The fingerprint library is full!");
M5.Lcd.println("The fingerprint library");
M5.Lcd.print("is full!");
break;
default:
Serial.println("Error!");
M5.Lcd.print("Error!");
break;
}
digitalWrite(FINGER_RST, LOW);
delay(100);
while (digitalRead(FINGER_WAKE) == HIGH);
break;
case '3':
digitalWrite(FINGER_RST, HIGH);
delay(300);
for (count = 0; count < 3; count++) {
fingerResponse = fp.ClearAllUser();
if (fingerResponse == ACK_SUCCESS) break;
}
Serial.println("All fingerprints have been cleared!");
M5.Lcd.fillRect(0, 180, 320, 60, BLACK);
M5.Lcd.setTextColor(WHITE);
M5.Lcd.setCursor(0, 180);
M5.Lcd.println("All fingerprints have");
M5.Lcd.print("been cleared!");
digitalWrite(FINGER_RST, LOW);
break;
default:
break;
}
prevMillis = millis();
inChar = 0;
}
if (millis() – prevMillis > 5000) {
M5.Lcd.fillRect(0, 180, 320, 60, BLACK);
prevMillis = millis();
}
M5.update();
}

Thank You

References:

Thanks for reading this tutorial. If you have any technical inquiries, please post at Cytron Technical Forum.

Please be reminded, this tutorial is prepared for you to try and learn.
You are encouraged to improve the code for better application.

Leave a Comment

Your email address will not be published.

Share this Tutorial

Share on facebook
Share on whatsapp
Share on email
Share on print
Share on twitter
Share on pinterest
Share on facebook
Share on whatsapp
Share on email
Share on print
Share on twitter
Share on pinterest

Latest Tutorial

Send Data to Firebase Using Arduino Uno WiFi Rev2
Simple Alarm System Using Maker Nano
Program Cucumber ESP32-S2 Using CircuitPython
Face Recognition Using OpenCV on Raspberry Pi 400
Turned Your Tablet as a Display for the Raspberry Pi 400
Scroll to Top