Arduino UNO Based Biometric Electronic Voting System with LCD Display and Fingerprint Authentication

Arduino UNO Based Biometric Electronic Voting System | Fingerprint + LCD + Buzzer
🔐 Biometric · Arduino · Embedded Systems

Arduino UNO Based
Biometric Electronic Voting System

A secure digital polling machine with fingerprint authentication, real-time LCD display, servo gate control, buzzer feedback, and EEPROM vote storage — preventing duplicate and unauthorised voting.

🔒 Fingerprint Auth 🗳️ 3-Candidate Voting 💾 EEPROM Storage 🖥️ 16×2 LCD ⚙️ Servo Gate

01 / OverviewProject Overview

The Arduino UNO Based Biometric Electronic Voting System integrates fingerprint authentication, push-button voting, real-time LCD display, and buzzer feedback into a secure and intelligent digital polling solution.

At the core of the system is the Arduino UNO microcontroller, which manages voter authentication, vote counting, and result display. An Adafruit Fingerprint Sensor verifies voter identity before allowing access to voting buttons. Once authenticated, the voter selects their preferred candidate using dedicated push buttons.

The system features a 16×2 I2C LCD display that provides on-screen instructions, voter verification status, candidate names, and real-time vote counts. A buzzer gives audible confirmation after successful fingerprint verification and vote submission. A servo motor acts as a physical gate that opens only for authenticated voters. Vote counts are stored in EEPROM, so data is retained even after power loss.

This project demonstrates advanced embedded system concepts including serial communication with fingerprint modules, digital signal processing, real-time display management, and secure access control — all in a low-cost, practical prototype.

02 / WorkflowFunctional Workflow

  1. 1
    System Initialisation

    Arduino initialises the LCD, fingerprint module, servo, and reads stored vote counts from EEPROM addresses 0, 1, and 2.

  2. 2
    Welcome Screen

    LCD displays "Voting System by Finger Print" then transitions to the "Press Start to begin voting" prompt.

  3. 3
    Voter Presses Start

    The start button (Pin 6) triggers the fingerprint scan sequence. LCD shows "Place Finger".

  4. 4
    Fingerprint Authentication

    getFingerprintIDez() captures the image, converts it to a template, and performs a fast search against stored templates.

  5. 5
    Authentication Result

    On success: buzzer beeps, LCD shows "Allowed / Vote Now", servo opens the gate (0°). On failure: LCD shows "Fingerprint Not Found", buzzer beeps error pattern.

  6. 6
    Candidate Selection

    Voter presses one of three candidate buttons (C1/C2/C3). Arduino increments the corresponding vote counter and writes it to EEPROM.

  7. 7
    Vote Confirmation & Gate Close

    LCD confirms "Voted: Candidate X". Servo holds gate open for 5 seconds then closes (180°). LCD shows "Gate Closed".

03 / ComponentsKey Components

🧠
Arduino UNO
ATmega328P — main controller
🔐
Fingerprint Sensor
Adafruit R307 / R305 UART
🖥️
16×2 I2C LCD
LiquidCrystal_I2C @ 0x27
⚙️
Servo Motor
SG90 — physical gate, Pin 5
🔔
Buzzer
Active buzzer — Pin 8
🔘
Push Buttons ×7
Start, C1, C2, C3, Enroll, Del, Result
💾
EEPROM (internal)
ATmega328P built-in, 1 KB
🔌
Breadboard + Wires
Hardware prototyping

04 / CircuitCircuit Diagram

The diagram below shows all connections between components. Scroll horizontally on small screens. Colour-coded wires show signal type.

TX(D2)·RX(D3) SDA·SCL (I2C) Pin 5 PWM Pin 8 C1,C2,C3,Start… 5V · GND ARDUINO UNO D2·D3(FP) D5(Servo) D6(Start) D8(Buzzer) A0–A6(Btns) I2C(LCD) ATmega328P @ 16MHz — EEPROM 1KB FINGERPRINT Adafruit R307 — UART VCC TX RX GND 16×2 I2C LCD LiquidCrystal_I2C @ 0x27 VCC GND SDA SCL SERVO SG90 Gate Control — Pin 5 VCC SIG GND BUZZER Active — Pin 8 + – START C1 C2 C3 ENROLL DEL RESULT PUSH BUTTONS (×7) All INPUT_PULLUP — GND on press Pin 6 · A1 · A5 · A6 A1 · A0 · A4 💾 EEPROM Storage Addr 0 → voteCount1 Addr 1 → voteCount2 Addr 2 → voteCount3 Retained on power loss ⚙️ Servo Gate Logic Auth OK → 0° (open) 5s After vote → 180° (closed) Arduino UNO — Biometric Electronic Voting System Fingerprint Sensor · Arduino UNO · 16×2 LCD · Servo · Buzzer · Push Buttons · EEPROM
UART (Fingerprint)
I2C (LCD)
PWM (Servo)
Digital (Buzzer)
Digital IN (Buttons)
Power (5V/GND)

📋 Wiring Notes

  • Fingerprint sensor VCC → 5V; TX → Arduino D2; RX → Arduino D3
  • LCD: SDA → A4; SCL → A5 (hardware I2C on UNO)
  • Servo signal → D5 (PWM); Servo VCC → 5V; Servo GND → GND
  • Buzzer + → D8; Buzzer − → GND
  • All buttons wired with INPUT_PULLUP — connect one leg to the pin, other to GND
  • Use SoftwareSerial(2,3) for fingerprint sensor to free hardware UART for debugging

Rendered from JSON — Components

Rendered from JSON — Connections

FromToSignalWire

06 / TutorialStep-by-Step Tutorial

Follow these steps to build and program your biometric voting machine from scratch. Click each step to expand.

1
Gather Components & Install Libraries

Collect all components: Arduino UNO, Adafruit fingerprint sensor (R307/R305), 16×2 I2C LCD, SG90 servo, active buzzer, 7 push buttons, breadboard, and jumper wires.

Open Arduino IDE and install these libraries via Sketch → Include Library → Manage Libraries:

  • Adafruit_Fingerprint by Adafruit
  • LiquidCrystal_I2C by Frank de Brabander
  • Servo (built-in)
  • EEPROM (built-in)
  • SoftwareSerial (built-in)

Verify library versions — use Adafruit_Fingerprint v2.x or higher for fingerFastSearch() support.

2
Connect the Fingerprint Sensor

The fingerprint sensor communicates via UART. Since we use SoftwareSerial to keep the hardware serial available for debugging:

  • Fingerprint VCC → Arduino 5V
  • Fingerprint GND → Arduino GND
  • Fingerprint TX → Arduino D2 (SoftwareSerial RX)
  • Fingerprint RX → Arduino D3 (SoftwareSerial TX)

In the code: SoftwareSerial fingerPrint(2, 3); — the first argument is RX, second is TX from Arduino's perspective.

Note: Some sensors require 3.3V — check your module's datasheet before connecting to 5V.

3
Connect the 16×2 I2C LCD

The I2C LCD reduces wiring significantly — only 4 wires needed:

  • LCD VCC → 5V
  • LCD GND → GND
  • LCD SDA → Arduino A4
  • LCD SCL → Arduino A5

Default I2C address is 0x27. If the display doesn't work, try 0x3F. Use an I2C scanner sketch to find the correct address.

In the code: LiquidCrystal_I2C lcd(0x27, 16, 2); followed by lcd.begin(16,2); — note this library uses begin() not init() in some versions.

4
Connect Servo Motor, Buzzer & Buttons

Servo (SG90):

  • Red wire → 5V  |  Brown wire → GND  |  Orange (signal) → D5
  • Closed position = 180°, Open = 0°. Initialise with myServo.write(180); in setup.

Buzzer:

  • Positive (+) → D8  |  Negative (−) → GND
  • Active buzzer sounds when D8 goes HIGH. No additional resistor needed.

Push Buttons (all 7):

  • One leg of each button → designated Arduino pin (see Pin Map above)
  • Other leg → GND on breadboard
  • Use INPUT_PULLUP mode — button reads LOW when pressed
  • Pins: Start→D6, C1→D4, C2→A5, C3→A6, Enroll→A1, Delete→A0, Result→A4, Up→A2, Down→A3
5
Upload & Test the Code

Copy the full code from Section 07 below. Before uploading:

  • Select Board: Arduino UNO and correct Port in Tools menu
  • Click Upload (Ctrl+U)
  • Open Serial Monitor at 9600 baud to see debug output

On power-up, LCD should show "Voting System / by Finger Print" then transition to "Finding Module". If it shows "Module Not Found", recheck fingerprint sensor wiring.

Troubleshooting:

  • LCD blank: adjust contrast pot on the I2C backpack module
  • Sensor not found: check TX/RX swap — they often need reversing
  • Servo jitter: add a 100µF capacitor across the servo power lines
6
Enroll Voter Fingerprints

Before voting can begin, register voter fingerprints:

  1. Press the ENROLL button (A1) from the main screen
  2. LCD shows "Enroll Finger / Location: 0"
  3. Use UP (A2) / DOWN (A3) buttons to select the storage ID (0–24)
  4. Press DEL (A0) to confirm the selected location and begin capture
  5. LCD prompts "Place Finger" — place the finger firmly on the sensor
  6. After first scan: LCD shows "Remove Finger" — lift your finger
  7. Sensor captures a second scan and creates a combined template
  8. Template is stored in sensor memory at the selected ID

Repeat for each authorised voter. The sensor supports up to 127 fingerprints.

To delete a fingerprint: press DEL button from the main screen, select the ID, and confirm.

7
Conduct Voting & View Results

Voting Process:

  1. Voter presses START (D6) — LCD shows "Place Finger"
  2. Voter places finger on the sensor
  3. If matched: buzzer beeps once, LCD shows "Allowed / Vote Now", servo opens gate
  4. Voter presses C1, C2, or C3 button within 5 seconds
  5. LCD confirms "Voted: Candidate X", vote saved to EEPROM
  6. Servo closes automatically after 5 seconds

View Results:

  • Press the RESULT button (A4) at any time
  • LCD displays "Results: C1:X C2:Y C3:Z" for 5 seconds
  • Counts are loaded from EEPROM on each boot — data is never lost

Reset votes: clear EEPROM addresses 0, 1, 2 manually with a separate sketch using EEPROM.write(addr, 0).

07 / CodeArduino Code

Upload the full sketch below via Arduino IDE. All five required libraries must be installed before compilation.

BiometricVotingSystem.ino
#include <Adafruit_Fingerprint.h>
#include <LiquidCrystal_I2C.h>  // I2C LCD library
#include <SoftwareSerial.h>
#include <Servo.h>
#include <EEPROM.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);   // LCD I2C address 0x27
SoftwareSerial fingerPrint(2, 3);        // RX=2, TX=3
Servo myServo;

Adafruit_Fingerprint finger = Adafruit_Fingerprint(&fingerPrint);

// ── Button & pin definitions ────────────────────────────
#define enroll        A1
#define del           A0
#define up            A2
#define down          A3
#define startButton   6   // Start fingerprint scan
#define resultbutton  A4
#define candidate1    4
#define candidate2    A5
#define candidate3    A6
#define servoPin      5
#define buzzer        8

uint8_t id;
int voteCount1, voteCount2, voteCount3;

// ── Setup ───────────────────────────────────────────────
void setup() {
    delay(1000);
    myServo.attach(servoPin);
    myServo.write(180);  // Gate closed initially

    pinMode(enroll,      INPUT_PULLUP);
    pinMode(up,          INPUT_PULLUP);
    pinMode(down,        INPUT_PULLUP);
    pinMode(del,         INPUT_PULLUP);
    pinMode(buzzer,      OUTPUT);
    pinMode(candidate1,  INPUT_PULLUP);
    pinMode(candidate2,  INPUT_PULLUP);
    pinMode(candidate3,  INPUT_PULLUP);
    pinMode(resultbutton,INPUT_PULLUP);
    pinMode(startButton, INPUT_PULLUP);

    lcd.begin(16, 2);
    lcd.print("Voting system");
    lcd.setCursor(0, 1);
    lcd.print("by Finger Print");
    delay(2000);
    lcd.clear();

    finger.begin(57600);
    Serial.begin(9600);

    lcd.print("Finding Module");
    delay(1000);
    if (finger.verifyPassword()) {
        Serial.println("Found fingerprint sensor!");
        lcd.clear();
        lcd.print("Module Found");
        delay(1000);
    } else {
        lcd.clear();
        lcd.print("Module Not Found");
        lcd.setCursor(0, 1);
        lcd.print("Check Connections");
        while (1);  // Halt
    }

    // Load stored vote counts from EEPROM
    voteCount1 = EEPROM.read(0);
    voteCount2 = EEPROM.read(1);
    voteCount3 = EEPROM.read(2);
}

// ── Main Loop ───────────────────────────────────────────
void loop() {
    lcd.setCursor(0, 0);
    lcd.print("Press Start ");
    lcd.setCursor(0, 1);
    lcd.print("to begin voting");

    if (digitalRead(startButton) == LOW) {
        lcd.clear();
        lcd.print("Place Finger");
        delay(2000);

        if (getFingerprintIDez() >= 0) {
            digitalWrite(buzzer, HIGH);
            delay(500);
            digitalWrite(buzzer, LOW);

            lcd.clear();
            lcd.print("Allowed");
            lcd.setCursor(0, 1);
            lcd.print("Vote Now");

            handleVoting();

            myServo.write(0);   // Open gate
            delay(5000);
            myServo.write(180); // Close gate

            lcd.clear();
            lcd.print("Gate Closed");
        }
        delay(1000);
    }

    checkKeys();
    delay(500);  // Debounce delay
}

// ── Handle Voting ───────────────────────────────────────
void handleVoting() {
    lcd.clear();
    lcd.print("Vote: C1 C2 C3");

    while (true) {
        if (digitalRead(candidate1) == LOW) {
            voteCount1++;
            EEPROM.update(0, voteCount1);
            lcd.clear(); lcd.print("Voted: Candidate 1");
            delay(2000); break;
        } else if (digitalRead(candidate2) == LOW) {
            voteCount2++;
            EEPROM.update(1, voteCount2);
            lcd.clear(); lcd.print("Voted: Candidate 2");
            delay(2000); break;
        } else if (digitalRead(candidate3) == LOW) {
            voteCount3++;
            EEPROM.update(2, voteCount3);
            lcd.clear(); lcd.print("Voted: Candidate 3");
            delay(2000); break;
        }
    }
}

// ── Show Results ────────────────────────────────────────
void showResults() {
    lcd.clear();
    lcd.print("Results:");
    lcd.setCursor(0, 1);
    lcd.print("C1:"); lcd.print(voteCount1);
    lcd.setCursor(6, 1);
    lcd.print("C2:"); lcd.print(voteCount2);
    lcd.setCursor(12, 1);
    lcd.print("C3:"); lcd.print(voteCount3);
    delay(5000);
}

// ── Check Admin Keys ────────────────────────────────────
void checkKeys() {
    if (digitalRead(enroll) == LOW) {
        lcd.clear(); lcd.print("Please Wait");
        delay(1000); Enroll();
    } else if (digitalRead(del) == LOW) {
        lcd.clear(); lcd.print("Please Wait");
        delay(1000); delet();
    } else if (digitalRead(resultbutton) == LOW) {
        showResults();
    }
}

// ── Enroll Fingerprint ──────────────────────────────────
void Enroll() {
    int count = 0;
    lcd.clear(); lcd.print("Enroll Finger");
    lcd.setCursor(0, 1); lcd.print("Location:");

    while (true) {
        lcd.setCursor(9, 1); lcd.print(count);
        if (digitalRead(up) == LOW)   { count = (count + 1) % 25; delay(500); }
        else if (digitalRead(down) == LOW) { count = (count > 0) ? count - 1 : 24; delay(500); }
        else if (digitalRead(del) == LOW)  { id = count; getFingerprintEnroll(); return; }
        else if (digitalRead(enroll) == LOW) { return; }
    }
}

// ── Delete Fingerprint ──────────────────────────────────
void delet() {
    int count = 0;
    lcd.clear(); lcd.print("Delete Finger");
    lcd.setCursor(0, 1); lcd.print("Location:");

    while (true) {
        lcd.setCursor(9, 1); lcd.print(count);
        if (digitalRead(up) == LOW)   { count = (count + 1) % 25; delay(500); }
        else if (digitalRead(down) == LOW) { count = (count > 0) ? count - 1 : 24; delay(500); }
        else if (digitalRead(del) == LOW)  { id = count; finger.deleteModel(id); return; }
        else if (digitalRead(enroll) == LOW) { return; }
    }
}

// ── Capture & Store Fingerprint Template ────────────────
uint8_t getFingerprintEnroll() {
    int p;
    lcd.clear(); lcd.print("Finger ID:"); lcd.print(id);
    lcd.setCursor(0, 1); lcd.print("Place Finger");

    while ((p = finger.getImage()) != FINGERPRINT_OK) { handleFingerprintErrors(p); }

    finger.image2Tz(1);
    lcd.clear(); lcd.print("Remove Finger");
    delay(2000);
    p = finger.image2Tz(2);
    if (p == FINGERPRINT_OK && finger.createModel() == FINGERPRINT_OK) {
        finger.storeModel(id);
    }
    return p;
}

// ── Fast Fingerprint Match ──────────────────────────────
int getFingerprintIDez() {
    if (finger.getImage() != FINGERPRINT_OK ||
        finger.image2Tz() != FINGERPRINT_OK ||
        finger.fingerFastSearch() != FINGERPRINT_OK) {
        lcd.clear(); lcd.print("Fingerprint Not Found");
        digitalWrite(buzzer, HIGH); delay(1000); digitalWrite(buzzer, LOW);
        delay(2000);
        return -1;
    }
    return finger.fingerID;
}

// ── Fingerprint Error Handler ───────────────────────────
void handleFingerprintErrors(int errorCode) {
    lcd.clear();
    if (errorCode == FINGERPRINT_NOFINGER)
        lcd.print("No Finger Detected");
    else if (errorCode == FINGERPRINT_PACKETRECIEVEERR)
        lcd.print("Communication Error");
    else if (errorCode == FINGERPRINT_IMAGEFAIL)
        lcd.print("Imaging Error");
    delay(1000);
}

08 / FeaturesTechnical Features

🔐

Biometric Authentication

Adafruit fingerprint sensor stores up to 127 unique templates. Fast search mode matches in under 1 second.

💾

EEPROM Vote Persistence

Vote counts written to EEPROM with update() to minimise write cycles. Data survives power loss indefinitely.

🖥️

16×2 I2C LCD Display

Provides real-time voter guidance, authentication status, and results display over just 2 wires (SDA/SCL).

⚙️

Servo Gate Control

Physical access gate opens only for authenticated voters, held open for 5 seconds then auto-closes.

🔔

Dual-Mode Buzzer

Single beep confirms successful authentication. Extended beep signals fingerprint failure or error states.

🔘

Input Debouncing

Hardware INPUT_PULLUP with 500ms software debounce delay prevents false button triggers.

🔒

Anti-Duplicate Voting

Each voter must pass fingerprint authentication — the sensor rejects unregistered and repeat rapid attempts.

👨‍💼

Admin Enroll & Delete

Dedicated enroll/delete buttons allow administrators to manage voter fingerprints without re-uploading code.

09 / ApplicationsApplications

College and university student election demonstrations
Secure polling prototype systems for engineering labs
Embedded systems academic final-year projects
Biometric authentication and access control learning projects
Science exhibitions and technology expos
Low-cost EVM (Electronic Voting Machine) proof-of-concept

This project demonstrates advanced embedded system concepts including serial communication with fingerprint modules, digital signal processing, real-time display management, and secure access control implementation — providing a scalable, practical prototype for biometric electronic voting.