Fingerprint Sensor (R305 / AS608)
The R305 (and its variants ZFM-20, AS608, GT-511C3) is an optical fingerprint module with an onboard DSP that handles fingerprint enrollment, image capture, feature extraction, and matching — no complex image processing on the host microcontroller is needed. Communication is via UART (serial) at 57600 baud (default). The module stores up to 300–1000 fingerprints in its onboard flash memory and returns a confidence score for each match. It is widely used for biometric access control, door locks, and attendance systems.
For this interfacing you need the following components:
- Arduino board (Uno, Nano, Mega, etc.)
- R305 / ZFM-20 / AS608 optical fingerprint sensor module
- Breadboard and jumper wires
- USB cable to connect Arduino to your computer
Schematic
The fingerprint sensor uses UART serial communication. Connect it to the Arduino’s hardware serial (or SoftwareSerial on Uno/Nano).
Fingerprint Sensor Arduino
----------------- -------
VCC (red) --> 5V
GND (black) --> GND
TX (white) --> Digital Pin 2 (Arduino RX via SoftwareSerial)
RX (green) --> Digital Pin 3 (Arduino TX via SoftwareSerial)
Touch (blue) --> Digital Pin 4 (optional — wakes the sensor)
On an Arduino Mega, use Serial1 (pins 19 RX1 / 18 TX1) instead of SoftwareSerial:
Mega Pin 19 (RX1) --> Sensor TX
Mega Pin 18 (TX1) --> Sensor RX
Voltage level
The sensor operates at 3.3V logic but includes an onboard regulator that accepts 5V supply. The UART TX of the sensor outputs 3.3V — this is safe for the Arduino’s 5V RX pin (ATmega328P treats ≥ 3V as HIGH). The Arduino’s 5V TX signal goes to the sensor’s RX, which is also 5V tolerant. No level shifting is needed.
Pin Map
| Module Pin | Colour | Name | Arduino Connection |
|---|---|---|---|
| VCC | Red | Power | 5V |
| GND | Black | Ground | GND |
| TX | White | Sensor Transmit | Pin 2 (SoftwareSerial RX) |
| RX | Green | Sensor Receive | Pin 3 (SoftwareSerial TX) |
| Touch | Blue | Wake / Touch detect | Pin 4 (optional) |
Install necessary Library
Install the Adafruit Fingerprint library by Adafruit via the Library Manager (Tools > Manage Libraries).
Alternatively, using arduino-cli:
arduino-cli lib install "Adafruit Fingerprint Sensor Library"
This library handles the serial packet protocol for the R305/ZFM-20 family.
Code with complete explanation
This sketch allows enrolling a new fingerprint (ID #1) and then continuously scanning for a match, printing results to the Serial Monitor.
#include <SoftwareSerial.h>
#include <Adafruit_Fingerprint.h>
// SoftwareSerial for the fingerprint sensor
SoftwareSerial fingerSerial(2, 3); // RX = pin 2, TX = pin 3
Adafruit_Fingerprint finger = Adafruit_Fingerprint(&fingerSerial);
void setup()
{
Serial.begin(9600);
finger.begin(57600);
if (finger.verifyPassword())
{
Serial.println("Fingerprint sensor found.");
}
else
{
Serial.println("Fingerprint sensor NOT found. Check wiring.");
Serial.println("Entering loop — check Serial Monitor for errors.");
while (1) { delay(1); }
}
// Read sensor parameters
finger.getParameters();
Serial.print("Capacity: ");
Serial.print(finger.capacity);
Serial.print(" Security level: ");
Serial.println(finger.security_level);
Serial.println();
Serial.println("Commands:");
Serial.println(" E — Enroll a new fingerprint (ID #1)");
Serial.println(" S — Scan finger to match");
Serial.println();
}
void loop()
{
if (Serial.available())
{
char cmd = Serial.read();
switch (cmd)
{
case 'E':
case 'e':
enrollFingerprint(1);
break;
case 'S':
case 's':
scanFingerprint();
break;
}
}
}
uint8_t enrollFingerprint(uint8_t id)
{
Serial.print("Waiting for finger to enroll ID #");
Serial.println(id);
// Step 1: Capture first image
int p = finger.getImage();
if (p != FINGERPRINT_OK)
{
Serial.println("No finger detected.");
return p;
}
// Step 2: Convert image to feature template
p = finger.image2Tz(1);
if (p != FINGERPRINT_OK)
{
Serial.println("Image conversion failed.");
return p;
}
Serial.println("Remove finger.");
delay(2000);
// Step 3: Capture second image
p = 0;
while (p != FINGERPRINT_NOFINGER)
{
p = finger.getImage();
}
Serial.print("Place same finger again.");
delay(2000);
p = finger.getImage();
if (p != FINGERPRINT_OK)
{
Serial.println("No finger detected.");
return p;
}
// Step 4: Convert second image to template
p = finger.image2Tz(2);
if (p != FINGERPRINT_OK)
{
Serial.println("Image conversion failed.");
return p;
}
// Step 5: Create model from both templates
p = finger.createModel();
if (p != FINGERPRINT_OK)
{
Serial.println("Templates don't match.");
return p;
}
// Step 6: Store model in flash
p = finger.storeModel(id);
if (p == FINGERPRINT_OK)
{
Serial.print("Fingerprint enrolled as ID #");
Serial.println(id);
}
else
{
Serial.println("Storage failed.");
}
return p;
}
uint8_t scanFingerprint()
{
Serial.println("Place finger to scan...");
// Capture image
int p = finger.getImage();
if (p != FINGERPRINT_OK)
{
Serial.println("No finger detected.");
return p;
}
// Convert to template
p = finger.image2Tz();
if (p != FINGERPRINT_OK)
{
Serial.println("Image conversion failed.");
return p;
}
// Search the database
p = finger.fingerFastSearch();
if (p == FINGERPRINT_OK)
{
Serial.print("Match found! ID #");
Serial.print(finger.fingerID);
Serial.print(" Confidence: ");
Serial.println(finger.confidence);
}
else
{
Serial.println("No match found.");
}
return p;
}
Code breakdown
Adafruit_Fingerprint finger(&serial)— creates a fingerprint object on the given serial port (SoftwareSerial or hardware UART).finger.begin(baud)— sets the serial baud rate (default 57600).finger.verifyPassword()— sends the default password (0x00000000) to authenticate with the sensor. Returnsfalseif the sensor is not responding.finger.getParameters()— reads and populatesfinger.capacity(max stored fingerprints) andfinger.security_level(1–5, higher = stricter matching).finger.getImage()— captures a fingerprint from the optical sensor. ReturnsFINGERPRINT_OK(0x00) on success,FINGERPRINT_NOFINGER(0x02) if no finger is present.finger.image2Tz(slot)— processes the captured image into a 512-byte feature template stored in slot 1 or 2 of the sensor’s RAM.finger.createModel()— combines two templates (slot 1 and slot 2) into one model. Returns error if the two captures are too different.finger.storeModel(id)— stores the model in flash memory at the given ID number (0–capacity-1).finger.fingerFastSearch()— searches all stored templates for a match. Setsfinger.fingerIDandfinger.confidenceon success. Confidence is 0–255 (≥ 60 is generally a reliable match).finger.deleteModel(id)— removes a stored fingerprint model.
Using hardware serial (Mega)
// For Arduino Mega — use Serial1
Adafruit_Fingerprint finger = Adafruit_Fingerprint(&Serial1);
void setup()
{
Serial.begin(9600);
Serial1.begin(57600);
finger.begin(57600);
}
Deleting and listing fingerprints
void deleteFingerprint(uint8_t id)
{
int p = finger.deleteModel(id);
if (p == FINGERPRINT_OK)
{
Serial.print("Deleted ID #");
Serial.println(id);
}
else
{
Serial.println("Delete failed.");
}
}
void listFingerprints()
{
uint8_t id = 0;
int p = finger.loadModel(id);
while (p == FINGERPRINT_OK)
{
Serial.print("Found ID #");
Serial.println(id);
id++;
p = finger.loadModel(id);
}
}
Security level
// Set matching strictness (1 = least strict, 5 = most strict)
// Higher levels reduce false positives but may increase false negatives
finger.setSecurityLevel(3); // Default
Steps to perform this interfacing
- Connect the fingerprint sensor to the Arduino as shown in the schematic.
- Install the Adafruit Fingerprint library via the Library Manager.
- Copy the code into the Arduino IDE.
- Select the correct board and port (
Tools > BoardandTools > Port). - Upload the sketch to the Arduino.
- Open the Serial Monitor (
Tools > Serial Monitor, set baud rate to 9600). - The monitor will print the sensor’s capacity and security level, then a menu.
- Type E and press Enter to enroll a fingerprint.
- Place your finger on the sensor when prompted, hold until the first capture succeeds.
- Remove your finger, wait for the prompt, then place the same finger again.
- The sensor will store the fingerprint and assign it ID #1.
- Type S and press Enter to scan. Place any enrolled finger on the sensor.
- The matched ID and confidence score will be printed.
Tips for reliable enrollment
- Clean the sensor window with a soft, lint-free cloth before use.
- Place the same finger twice in a similar orientation during enrollment.
- Dry or very oily fingers may fail to enroll — try different fingers.
- The sensor stores the template internally — it persists even after power-off.
Caution
- Baud rate mismatch: The sensor defaults to 57600 baud. Some clones use 9600. If
verifyPassword()fails, try changingfinger.begin(57600)tofinger.begin(9600). The baud rate of certain modules can also be changed withfinger.setBaudRate(newRate)but some modules lock after the change until power-cycled. - UART voltage: The sensor’s TX pin outputs 3.3V logic. This is safely recognised as HIGH by an Arduino Uno/Nano (5V ATmega with VIH minimum of 0.6 VCC ≈ 3.0V). The Arduino’s 5V TX is within the sensor’s 5V-tolerant RX. However, for 3.3V-only boards (Due, Zero, MKR), use a voltage divider on the Arduino TX or a level shifter.
- SoftwareSerial limitations: On Uno/Nano,
SoftwareSerialcannot send and receive simultaneously at 57600 baud reliably on all pin pairs. Use pins 2 and 3 (the defaultSoftwareSerialexample). If you experience garbled data, switch to hardware serial by using an Arduino Mega or temporarily disconnecting the sensor’s TX during upload to avoid data collision. - Upload interference: The R305’s TX pin sends data continuously when powered. During Arduino sketch upload, this data on pin 2 (RX via SoftwareSerial) can interfere with USB communication. Disconnect the sensor’s TX wire from pin 2 during upload, or power the sensor separately. On Mega using Serial1, this is not an issue.
- Power consumption: The sensor draws 30–50 mA during idle and 80–120 mA during fingerprint capture/LED illumination (the bright blue LED). Do not power from the Arduino’s 3.3V pin. Use the 5V pin, which is powered from the USB 5V rail (500 mA max).
- Sensor blank (no response): The sensor requires 5V supply and the UART pins connected correctly. If
verifyPassword()fails every time: check that RX/TX are not swapped, the baud rate is correct, and the sensor is powered (its blue LED should glow during capture). If still failing, serial data may be corrupted — a logic analyser can verify. - Template storage endurance: The sensor’s onboard flash is rated for approximately 100,000 erase/write cycles per fingerprint slot. This is adequate for frequent re-enrollment in hobby projects but may be a concern for industrial door-lock applications. Each fingerprint model occupies ≈ 512 bytes of the sensor’s internal flash.
- Finger condition: Wet, excessively dry, scarred, or dirty fingers may fail to enroll or match reliably. The sensor’s security level adjusts the false-rejection/false-acceptance trade-off. Level 3 (default) balances both. Level 5 reduces false accepts but increases false rejects. Level 1 is the opposite. Adjust via
finger.setSecurityLevel(n). - Touch pin (WAKE): The blue wire (Touch/Wake) on the R305 can be used to detect finger presence without serial communication. When wired to a digital input with a pull-up, it goes LOW when a finger is touched. This allows the Arduino to wake from sleep or power up the sensor only when needed. Some R305 clones do not expose this pin.