ZW111 capacitive fingerprint sensor test
ZW111 pinout:
Note: make sure your connector follows same color sequence as this.
Datasheet: Download ZW111 datasheet
ZW111 to Classic ESP32 Connection:
Note: you must you 3.3v only. 5v may kill the module.
For this setup, we are powering both the touch sensor and the fingerprint sensor with 3.3V.
| Pin | Wire Color | Function | ESP32 Pin |
|---|---|---|---|
| 1 | White | V_SENSOR (Touch Power) | 3.3V |
| 2 | Blue | TOUCH_OUT (Wake-up) | GPIO 4 |
| 3 | Green | VCC (Module Power) | 3.3V |
| 4 | Yellow | UART_TX (Data Out) | GPIO 16 (RX2) |
| 5 | Black | UART_RX (Data In) | GPIO 17 (TX2) |
| 6 | Red | GND | GND |
ZW111 ESP32 Test Code:
Boot button single click: add new fingerprint id.
Boot button 3s press: erase all fingerprint id.
#include <Arduino.h>
#include <Adafruit_Fingerprint.h>
// Hardware Serial 2 for ESP32
#define RX_PIN 16
#define TX_PIN 17
#define TOUCH_PIN 4
#define BOOT_BUTTON 0
HardwareSerial mySerial(2);
Adafruit_Fingerprint finger(&mySerial);
int get_next_id() {
for (int i = 1; i <= 40; i++) { // ZW111 supports 40 IDs
if (finger.loadModel(i) != FINGERPRINT_OK) {
return i;
}
}
return -1;
}
void enroll_finger() {
int slot = get_next_id();
if (slot == -1) {
Serial.println("Storage full (40 IDs reached)!");
return;
}
Serial.print("ENROLLING ID #");
Serial.println(slot);
Serial.println("Place finger...");
while (finger.getImage() != FINGERPRINT_OK) { delay(50); }
if (finger.image2Tz(1) != FINGERPRINT_OK) {
Serial.println("Error: Image messy.");
return;
}
Serial.println("Remove finger");
delay(1000);
while (finger.getImage() != FINGERPRINT_NOFINGER) { delay(50); }
Serial.println("Place same finger again...");
while (finger.getImage() != FINGERPRINT_OK) { delay(50); }
if (finger.image2Tz(2) != FINGERPRINT_OK) {
Serial.println("Error: Image messy.");
return;
}
if (finger.createModel() == FINGERPRINT_OK) {
if (finger.storeModel(slot) == FINGERPRINT_OK) {
Serial.print("SUCCESS! Stored in ID ");
Serial.println(slot);
}
} else {
Serial.println("FAILED: Prints did not match.");
}
}
void setup() {
Serial.begin(115200);
pinMode(TOUCH_PIN, INPUT_PULLDOWN);
pinMode(BOOT_BUTTON, INPUT_PULLUP);
// Baud rate 57600 is default for ZW111
mySerial.begin(57600, SERIAL_8N1, RX_PIN, TX_PIN);
if (finger.verifyPassword()) {
Serial.println("Found ZW111 Fingerprint sensor!");
} else {
Serial.println("Did not find fingerprint sensor :(");
while (1) { delay(1); }
}
}
void loop() {
// Scan when touch sensor is triggered
if (digitalRead(TOUCH_PIN) == HIGH) {
if (finger.getImage() == FINGERPRINT_OK) {
if (finger.image2Tz(1) == FINGERPRINT_OK) {
if (finger.fingerSearch() == FINGERPRINT_OK) {
Serial.print("MATCH ID: ");
Serial.print(finger.fingerID);
Serial.print(" | Confidence: ");
Serial.println(finger.confidence);
} else {
Serial.println("NOT RECOGNIZED");
}
}
}
while (digitalRead(TOUCH_PIN) == HIGH) { delay(50); }
}
// Use Boot button to enroll
if (digitalRead(BOOT_BUTTON) == LOW) {
delay(500); // debounce
enroll_finger();
}
}
Here is a test connection for ESP32 S3:
| Pin | Wire Color | Function | ESP32 S3 Pin |
|---|---|---|---|
| 1 | White | V_SENSOR (Touch Power) | 3.3V |
| 2 | Blue | TOUCH_OUT (Wake-up) | GPIO 4 |
| 3 | Green | VCC (Module Power) | 3.3V |
| 4 | Yellow | UART_TX (Data Out) | GPIO 6 |
| 5 | Black | UART_RX (Data In) | GPIO 7 |
| 6 | Red | GND | GND |
Now, here is the test code for ESP32 S3:
Boot button single click: add new fingerprint id.
Boot button 3s press: erase all fingerprint id.
S3 RGB:
BLUE = sensor connected successfully.
GREEN = fingerprint matched.
RED = fingerprint did not match .
PURPLE = all fingerprint id erased.
CYAN/LIGHT BLUE = first fingerprint capture take successful.
#include <Arduino.h>
#include <Adafruit_Fingerprint.h>
#define RX_PIN 6
#define TX_PIN 7
#define TOUCH_PIN 4
#define BOOT_BUTTON 0
#define RGB_BRIGHT 26 // 10% Brightness
HardwareSerial mySerial(2);
Adafruit_Fingerprint finger(&mySerial);
void setRGB(uint8_t r, uint8_t g, uint8_t b) {
rgbLedWrite(RGB_BUILTIN, r, g, b);
}
void enroll_finger() {
int slot = -1;
for (int i = 1; i <= 40; i++) {
if (finger.loadModel(i) != FINGERPRINT_OK) {
slot = i;
break;
}
}
if (slot == -1) return;
// First Take
while (finger.getImage() != FINGERPRINT_OK) { delay(50); }
if (finger.image2Tz(1) != FINGERPRINT_OK) return;
setRGB(0, RGB_BRIGHT, RGB_BRIGHT); // Cyan: 1st Take Success
Serial.println("Remove finger");
delay(1000);
while (finger.getImage() != FINGERPRINT_NOFINGER) { delay(50); }
// Second Take
while (finger.getImage() != FINGERPRINT_OK) { delay(50); }
if (finger.image2Tz(2) != FINGERPRINT_OK) return;
if (finger.createModel() == FINGERPRINT_OK && finger.storeModel(slot) == FINGERPRINT_OK) {
setRGB(0, RGB_BRIGHT, 0); // Green: Full Success
delay(1000);
} else {
setRGB(RGB_BRIGHT, 0, 0); // Red: Fail
delay(1000);
}
setRGB(0, 0, RGB_BRIGHT);
}
void erase_database() {
if (finger.emptyDatabase() == FINGERPRINT_OK) {
setRGB(RGB_BRIGHT, 0, RGB_BRIGHT); // Purple: Erase Success
delay(2000);
} else {
setRGB(RGB_BRIGHT, 0, 0);
delay(1000);
}
setRGB(0, 0, RGB_BRIGHT);
}
void setup() {
Serial.begin(115200);
pinMode(TOUCH_PIN, INPUT_PULLDOWN);
pinMode(BOOT_BUTTON, INPUT_PULLUP);
mySerial.begin(57600, SERIAL_8N1, RX_PIN, TX_PIN);
if (finger.verifyPassword()) {
setRGB(0, 0, RGB_BRIGHT); // Blue: Ready
} else {
while (1) {
setRGB(RGB_BRIGHT, 0, 0);
delay(200); setRGB(0, 0, 0); delay(200);
}
}
}
void loop() {
if (digitalRead(TOUCH_PIN) == HIGH) {
if (finger.getImage() == FINGERPRINT_OK && finger.image2Tz(1) == FINGERPRINT_OK) {
if (finger.fingerSearch() == FINGERPRINT_OK) {
setRGB(0, RGB_BRIGHT, 0); // Green
} else {
setRGB(RGB_BRIGHT, 0, 0); // Red
}
}
delay(1000);
setRGB(0, 0, RGB_BRIGHT);
while (digitalRead(TOUCH_PIN) == HIGH) { delay(10); }
}
if (digitalRead(BOOT_BUTTON) == LOW) {
unsigned long pressTime = millis();
while (digitalRead(BOOT_BUTTON) == LOW) {
if (millis() - pressTime > 3000) {
erase_database();
while (digitalRead(BOOT_BUTTON) == LOW);
return;
}
delay(10);
}
enroll_finger();
}
}

Comments
Post a Comment