Biometric Access System with Dual Authentication using Arduino
Build a powerful dual-authentication security system using Arduino Uno,
R307 Fingerprint Sensor, 4×4 keypad, I2C LCD, and ILI9341 TFT display. Combines
biometric fingerprint verification with PIN entry backup — ideal for door locks, banking
kiosks, locker systems, and secure access control. Full diagram.json,
complete Arduino C++ code, and live Wokwi simulation included.
What This Project Builds
This system simulates a mini banking authentication terminal using Arduino. Unlike simple password locks, it features a graphical TFT fingerprint scan animation, transaction validation logic, account scrolling menu, failure mode simulation, real-time LED indicators, and a touchscreen PIN pattern entry — all in one project.
Two authentication methods work in tandem, increasing security, reliability, and usability:
🟢 Method 1: Fingerprint
- Place finger on R307 sensor
- Compare against stored templates
- Match → Green LED + access granted
- No match → Red LED + access denied
- LCD displays result message
🔵 Method 2: PIN Entry
- Enter 4-digit PIN via 4×4 keypad
- System validates entered PIN
- Correct PIN → access granted
- Wrong PIN → access denied
- Backup if fingerprint unavailable
Key Features
Components Required
All components are simulated in Wokwi — no physical hardware needed to try this project.
Libraries Required
| Library | Purpose | Install via |
|---|---|---|
| Wire.h | I2C communication | Built-in Arduino |
| LiquidCrystal_I2C.h | I2C LCD control | Library Manager |
| Keypad.h | Matrix keypad input | Library Manager |
| Adafruit_GFX.h | Graphics primitives | Library Manager |
| Adafruit_ILI9341.h | TFT display driver | Library Manager |
| Adafruit_FT6206.h | Capacitive touch | Library Manager |
Wiring Guide
Fingerprint Sensor (R307) → Arduino
| R307 Pin | Arduino Pin | Wire Color |
|---|---|---|
| VCC | 5V | Red |
| GND | GND | Black |
| TX | RX (via SoftwareSerial) | Yellow |
| RX | TX (via SoftwareSerial) | Green |
I2C LCD (16×2) → Arduino
| LCD Pin | Arduino Pin | Wire Color |
|---|---|---|
| VCC | 5V (via j5 junction) | Red |
| GND | GND (via j3 junction) | Black |
| SDA | A4 (via j6 junction) | Green |
| SCL | A5 (via j4 junction) | Yellow |
ILI9341 TFT Display → Arduino
| TFT Pin | Arduino Pin | Wire Color | Protocol |
|---|---|---|---|
| SCK (SCLK) | 13 | Blue | SPI |
| MISO | 12 | Blue | SPI |
| MOSI | 11 | Blue | SPI |
| CS | 10 | Blue | Chip Select |
| D/C | A2 | Blue | Data/Command |
| RST | A3 | Blue | Reset |
| SDA (Touch) | A4 (shared I2C) | Green | I2C |
| SCL (Touch) | A5 (shared I2C) | Yellow | I2C |
| VCC | 5V | Red | Power |
| GND | GND | Black | Ground |
4×4 Keypad → Arduino
| Keypad Pin | Arduino Pin | Wire Color |
|---|---|---|
| R1 (Row 1) | 9 | Green |
| R2 (Row 2) | 8 | Green |
| R3 (Row 3) | 7 | Green |
| R4 (Row 4) | 6 | Green |
| C1 (Col 1) | 5 | Green |
| C2 (Col 2) | 4 | Green |
| C3 (Col 3) | 3 | Green |
| C4 (Col 4) | 2 | Green |
LED Indicators → Arduino
| LED | Anode (+) | Cathode (−) |
|---|---|---|
| 🟢 Green LED | A0 (via 220Ω resistor) | GND |
| 🔴 Red LED | A1 (via 220Ω resistor) | GND |
Shared I2C bus: The I2C LCD and FT6206 touch controller share SDA (A4) and SCL (A5). Ensure both have different I2C addresses. The LCD uses 0x27 and the FT6206 uses its own default address.
How It Works — State Machine
The system uses state machine programming for clean transitions between phases. There are four distinct states, each handling specific user interactions:
Step-by-Step System Flow
-
1
System Startup — Amount Entry
LCD displays "Enter Amount: Rs.". The user types the transaction amount using the keypad (digits 0–9). Press 'A' to clear, '#' to confirm. If amount exceeds ₹2000, the system rejects it with a limit exceeded message and Red LED.
-
2
Fingerprint Verification Phase
LCD shows "Place Finger on Scanner..." and the TFT displays a cyan ellipse outline. The user touches the TFT screen to simulate placing a finger. The system runs a concentric oval scan animation.
If failMode = 2 (hold 'A' key), it returns red animation + "Unknown Finger" + Red LED. Otherwise, green animation + "WELCOME: [Username]" + transitions to account selection.
-
3
Account Selection Menu
The LCD shows the user's linked bank accounts (e.g., "SBI 4894", "PNB 7930"). Press 'D' to scroll down, 'C' to scroll up through 5 accounts. Press a number key (1–5) to select an account. Two users with different bank sets are supported.
-
4
PIN Tap Pattern Entry
LCD shows "Tap Pattern Now". User taps the TFT screen 4 times — each tap shows a '*' on the LCD. After 4 taps, the system validates. If failMode = 1 (hold 'B' key), it fails. Otherwise it shows "PAYMENT SUCCESS" + Green LED + reference number.
✅SOS Mode: Press '*' anytime to activate SOS. On successful payment, the LCD shows "SOS ALERT SENT!" instead of the reference number.
diagram.json — Complete Circuit
Paste this into the diagram.json tab in your Wokwi project to instantly load the full circuit — Arduino Uno, TFT display, I2C LCD, 4×4 keypad, two LEDs, and all junctions pre-wired.
{
"version": 1,
"author": "Tapish Chahera",
"editor": "wokwi",
"parts": [
{
"type": "wokwi-arduino-uno", "id": "uno",
"top": 152.6, "left": -33.4, "rotate": 180, "attrs": {}
},
{ "type": "wokwi-membrane-keypad", "id": "keypad",
"top": 55.6, "left": 245.6, "attrs": {} },
{
"type": "wokwi-led", "id": "led-green",
"top": 44.4, "left": 195.8,
"attrs": { "color": "green", "flip": "" }
},
{
"type": "wokwi-led", "id": "led-red",
"top": 44.4, "left": 138.2,
"attrs": { "color": "red", "flip": "" }
},
{
"type": "wokwi-lcd1602", "id": "lcd1",
"top": -89.6, "left": -23.2,
"attrs": { "pins": "i2c" }
},
{
"type": "board-ili9341-cap-touch", "id": "lcd2",
"top": -47.24, "left": -288.38, "attrs": {}
},
{ "type": "wokwi-junction", "id": "j1", "top": 91.2, "left": 62.4, "attrs": {} },
{ "type": "wokwi-junction", "id": "j2", "top": 91.2, "left": 148.8, "attrs": {} },
{ "type": "wokwi-junction", "id": "j3", "top": 91.2, "left": -52.8, "attrs": {} },
{ "type": "wokwi-junction", "id": "j4", "top": 158.4, "left": -100.8, "attrs": {} },
{ "type": "wokwi-junction", "id": "j5", "top": 72, "left": -43.2, "attrs": {} },
{ "type": "wokwi-junction", "id": "j6", "top": 139.2, "left": -110.4, "attrs": {} }
],
"connections": [
// ── LED ground connections ──────────────────
[ "led-green:C", "uno:GND", "black", [ "v0" ] ],
[ "led-red:C", "uno:GND", "black", [ "v0" ] ],
// ── Keypad → Arduino digital pins ───────────
[ "uno:9", "keypad:R1", "green", [ "v57.6", "h325.6" ] ],
[ "uno:8", "keypad:R2", "green", [ "v67.2", "h345.6" ] ],
[ "uno:7", "keypad:R3", "green", [ "v76.8", "h371.1" ] ],
[ "uno:6", "keypad:R4", "green", [ "v86.4", "h390.1" ] ],
[ "uno:5", "keypad:C1", "green", [ "v96", "h409.1" ] ],
[ "uno:4", "keypad:C2", "green", [ "v105.6", "h428.1" ] ],
[ "uno:3", "keypad:C3", "green", [ "v115.2", "h447.35" ] ],
[ "uno:2", "keypad:C4", "green", [ "v124.8", "h466.6" ] ],
// ── TFT SPI connections ─────────────────────
[ "lcd2:SCK", "uno:13", "blue", [ "v134.4", "h307.6" ] ],
[ "lcd2:MISO", "uno:12", "blue", [ "v124.8", "h278.9" ] ],
[ "lcd2:MOSI", "uno:11", "blue", [ "v144", "h298.2" ] ],
[ "lcd2:CS", "uno:10", "blue", [ "v153.6", "h317.5" ] ],
// ── GND junction network ────────────────────
[ "uno:GND.2", "j1:J", "black", [ "h-3.9", "v-38.3" ] ],
[ "j1:J", "j2:J", "black", [ "v0" ] ],
[ "j2:J", "led-green:C", "black", [ "v0", "h67.2" ] ],
[ "j2:J", "led-red:C", "black", [ "v0" ] ],
[ "j1:J", "j3:J", "black", [ "v0" ] ],
[ "j3:J", "lcd1:GND", "black", [ "v0" ] ],
[ "j3:J", "lcd2:GND", "black", [ "v230.4", "h-192" ] ],
// ── I2C SCL (A5) ────────────────────────────
[ "uno:A5", "j4:J", "yellow", [ "v0" ] ],
[ "j4:J", "lcd1:SCL", "yellow", [ "v0" ] ],
[ "j4:J", "lcd2:SCL", "yellow", [ "v105.6", "h-67.2" ] ],
// ── 5V power junction ───────────────────────
[ "uno:5V", "j5:J", "red", [ "v-86.3", "h-119" ] ],
[ "j5:J", "lcd1:VCC", "red", [ "v0" ] ],
[ "j5:J", "lcd2:VCC", "red", [ "v259.2", "h-211.2" ] ],
// ── I2C SDA (A4) ────────────────────────────
[ "uno:A4", "j6:J", "green", [ "v0" ] ],
[ "j6:J", "lcd1:SDA", "green", [ "v0" ] ],
[ "j6:J", "lcd2:SDA", "green", [ "v115.2", "h-48" ] ],
// ── LED anode → Arduino analog pins ─────────
[ "uno:A0", "led-green:A", "green", [ "v-28.7", "h188.2" ] ],
[ "uno:A1", "led-red:A", "green", [ "v-38.3", "h140.1" ] ],
// ── TFT control pins ────────────────────────
[ "uno:A3", "lcd2:RST", "blue",
[ "v-28.7", "h-71.3", "v163.2", "h-153.6" ] ],
[ "uno:A2", "lcd2:D/C", "blue",
[ "v-38.3", "h-90.4", "v163.2", "h-134.4" ] ]
],
"dependencies": {}
}
How to use: In Wokwi, click the diagram.json tab, select all existing text, and paste. The full wired circuit loads instantly including all junction nodes.
Arduino C++ — Complete Program
Full state-machine implementation with fingerprint simulation via touch, PIN tap pattern, multi-user bank data, sales tracking, and SOS mode.
#include <Wire.h> #include <LiquidCrystal_I2C.h> #include <Keypad.h> #include <Adafruit_GFX.h> #include <Adafruit_ILI9341.h> #include <Adafruit_FT6206.h> #define TFT_CS 10 #define TFT_DC A2 #define TFT_RST A3 #define LED_GRN A0 #define LED_RED A1 const byte ROWS = 4, COLS = 4; char keys[ROWS][COLS] = { {'1','2','3','A'}, {'4','5','6','B'}, {'7','8','9','C'}, {'*','0','#','D'} }; byte rowPins[ROWS] = {9, 8, 7, 6}; byte colPins[COLS] = {5, 4, 3, 2}; Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS); LiquidCrystal_I2C lcd(0x27, 16, 2); Adafruit_ILI9341 tft(TFT_CS, TFT_DC, TFT_RST); Adafruit_FT6206 ctp = Adafruit_FT6206(); enum State { MERCHANT_ENTRY, ID_PHASE, ACCOUNT_SEL, PIN_PHASE }; State currentState = MERCHANT_ENTRY; int currentUser = 0; String userNames[] = {"Tapish Chahera", "Simran Chawla"}; String userBanks[2][5] = { {"SBI 4894", "PNB 7930", "HDFC 4689", "ICICI 1122", "AXIS 9901"}, {"KOTAK 2210", "INDUS 5543", "YES 9090", "BOB 3321", "UCO 1199"} }; const int totalBanks = 5; int scrollIndex = 0; String amount = ""; String selectedBank = ""; int pinTaps = 0; int failMode = 0; float totalSales = 0; bool sosActive = false; unsigned long lastTouch = 0; void scanFingerEffect(uint16_t color) { for (int r = 0; r <= 50; r += 3) { int ry = (r * 8) / 5; tft.drawEllipse(120, 160, r, ry, color); tft.drawEllipse(120, 160, r+1, ry+1, color); } } void updateBankList() { lcd.clear(); lcd.setCursor(0, 0); lcd.print(String(scrollIndex + 1) + "." + userBanks[currentUser][scrollIndex]); if (scrollIndex + 1 < totalBanks) { lcd.setCursor(0, 1); lcd.print(String(scrollIndex + 2) + "." + userBanks[currentUser][scrollIndex + 1]); } } void resetSystem() { currentState = MERCHANT_ENTRY; amount = ""; pinTaps = 0; failMode = 0; selectedBank = ""; scrollIndex = 0; sosActive = false; digitalWrite(LED_GRN, LOW); digitalWrite(LED_RED, LOW); lcd.clear(); lcd.print("Enter Amount:"); lcd.setCursor(0, 1); lcd.print("Rs. "); tft.fillScreen(ILI9341_BLACK); tft.drawEllipse(120, 160, 50, 80, 0x5AEB); tft.drawEllipse(120, 160, 49, 79, 0x5AEB); } void setup() { pinMode(LED_GRN, OUTPUT); pinMode(LED_RED, OUTPUT); lcd.init(); lcd.backlight(); tft.begin(); tft.setRotation(0); ctp.begin(10); // Low threshold for Wokwi touch sensitivity resetSystem(); } void loop() { KeyState kstate = keypad.getState(); char key = keypad.getKey(); if (kstate == HOLD) { char lastKey = keypad.key[0].kchar; if (lastKey == 'A') failMode = 2; if (lastKey == 'B') failMode = 1; if (lastKey == 'D' && currentState == MERCHANT_ENTRY) { lcd.clear(); lcd.print("TOTAL SALES:"); lcd.setCursor(0,1); lcd.print("Rs. " + String(totalSales, 2)); delay(3000); resetSystem(); } } if (key == '*') sosActive = true; if (key == 'B' && currentState == MERCHANT_ENTRY) currentUser = !currentUser; // ── State: MERCHANT_ENTRY ────────────────── if (currentState == MERCHANT_ENTRY) { if (key >= '0' && key <= '9') { amount += key; lcd.setCursor(4, 1); lcd.print(amount); } else if (key == 'A') { amount = ""; lcd.setCursor(4, 1); lcd.print(" "); } else if (key == '#') { if (amount.toFloat() > 2000) { lcd.clear(); lcd.print("LIMIT EXCEEDED!"); lcd.setCursor(0,1); lcd.print("Max Rs. 2000"); digitalWrite(LED_RED, HIGH); delay(3000); resetSystem(); } else if (amount != "") { currentState = ID_PHASE; lcd.clear(); lcd.print("Place Finger on"); lcd.setCursor(0, 1); lcd.print("Scanner..."); tft.fillScreen(ILI9341_BLACK); tft.drawEllipse(120, 160, 50, 80, ILI9341_CYAN); tft.drawEllipse(120, 160, 49, 79, ILI9341_CYAN); } } } // ── State: ACCOUNT_SEL ──────────────────── else if (currentState == ACCOUNT_SEL) { if (key == 'D' && scrollIndex < totalBanks - 2) { scrollIndex++; updateBankList(); } if (key == 'C' && scrollIndex > 0) { scrollIndex--; updateBankList(); } if (key >= '1' && key <= '9') { int choice = (key - '0') - 1; if (choice < totalBanks) { selectedBank = userBanks[currentUser][choice]; currentState = PIN_PHASE; lcd.clear(); lcd.print("Selected: " + selectedBank.substring(0,6)); lcd.setCursor(0, 1); lcd.print("Tap Pattern Now"); tft.fillScreen(ILI9341_BLACK); tft.drawEllipse(120, 160, 50, 80, ILI9341_YELLOW); tft.drawEllipse(120, 160, 49, 79, ILI9341_YELLOW); } } } // ── Touch input with debouncing ─────────── if (ctp.touched()) { TS_Point p = ctp.getPoint(); if (millis() - lastTouch > 250) { lastTouch = millis(); if (currentState == ID_PHASE) { scanFingerEffect(ILI9341_CYAN); if (failMode == 2) { lcd.clear(); lcd.print("ACCESS DENIED"); lcd.setCursor(0,1); lcd.print("Unknown Finger"); digitalWrite(LED_RED, HIGH); scanFingerEffect(ILI9341_RED); delay(3000); resetSystem(); } else { lcd.clear(); lcd.print("WELCOME:"); lcd.setCursor(0, 1); lcd.print(userNames[currentUser]); scanFingerEffect(ILI9341_GREEN); delay(1500); currentState = ACCOUNT_SEL; updateBankList(); tft.fillScreen(ILI9341_BLACK); tft.drawEllipse(120, 160, 50, 80, ILI9341_WHITE); } } else if (currentState == PIN_PHASE) { pinTaps++; lcd.setCursor(0, 1); lcd.print("PIN: "); for(int i=0; i<pinTaps; i++) lcd.print("*"); scanFingerEffect(ILI9341_WHITE); tft.fillScreen(ILI9341_BLACK); tft.drawEllipse(120, 160, 50, 80, ILI9341_YELLOW); if (pinTaps == 4) { lcd.clear(); if (failMode == 1) { lcd.print("TXN FAILED"); lcd.setCursor(0,1); lcd.print("Wrong Pattern"); digitalWrite(LED_RED, HIGH); scanFingerEffect(ILI9341_RED); } else { lcd.print("PAYMENT SUCCESS"); totalSales += amount.toFloat(); digitalWrite(LED_GRN, HIGH); scanFingerEffect(ILI9341_GREEN); lcd.setCursor(0,1); if (sosActive) lcd.print("SOS ALERT SENT!"); else lcd.print("Ref: " + String(random(1000,9999))); } delay(4000); resetSystem(); } } } } }
Fail mode testing: Hold 'A' on the keypad to simulate fingerprint rejection, or hold 'B' to simulate wrong PIN pattern. These keys must be held during the respective authentication phase.
SOS Mode: Press the '*' key at any point during the transaction. On success, the LCD will display "SOS ALERT SENT!" instead of the reference number — simulating a distress signal feature.
Applications
Learning Outcomes
Perfect for STEM projects, final-year engineering demos, robotics exhibitions, and IoT security prototypes. This project demonstrates real-world authentication architecture on a microcontroller.
Comments
Post a Comment