Preview build — page text is a draft awaiting human review. Code badges come from real compiles. The flasher is real but not yet hardware-tested; the Playground is still a preview.
Classroom Voting Machine: the finished build
UnoStudent projects

Classroom voting machine for class elections — an EVM model (Arduino Uno + 16x2 LCD)

One BALLOT press, one vote, one long beep — a class-election model of an EVM.

Difficulty
Easy
Build time
2 h
Parts cost
₹951 · $11
Verified — core avr 1.8.8, LiquidCrystal I2C 1.1.2, 3 Nov 2026Compile-only

Community draft — report a mistake

Parts list

PartQtyApprox.Buy
Arduino Uno R3 (CH340 clone)1₹450Buy Arduino Uno R3 (CH340 clone)
16x2 LCD with I2C backpack (PCF8574, 0x27)1₹180Buy 16x2 LCD with I2C backpack (PCF8574, 0x27)
Push button 12 mm with cap (candidates)4₹60Buy Push button 12 mm with cap (candidates)
Tactile push button (BALLOT, RESULT)2₹6Buy Tactile push button (BALLOT, RESULT)
Active buzzer module1₹25Buy Active buzzer module
6-core cable between the voting box and the officer’s box (2 m)1₹80Buy 6-core cable between the voting box and the officer’s box (2 m)
Two small project boxes or cardboard boxes2₹120Buy Two small project boxes or cardboard boxes
Jumper wires1₹30Buy Jumper wires
Total₹951

Affiliate disclosure: “Buy” links may earn FlashReady a small commission at no extra cost to you. Prices are indicative.

Wiring

Arduino Uno R3Only the pins used are shown · 5 V logicPush button (6 mm tactile switch)Push button (6 mm tactile switch) #2Push button (6 mm tactile switch) #3Push button (6 mm tactile switch) #4Push button (6 mm tactile switch) #5Push button (6 mm tactile switch) #616×2 LCD + I2C backpackActive buzzer module (high-level trigger)5VGNDA4A5D2D3D4D5D6D7D8121212121212GNDVCCSDASCLI/OVCCGND
Every connection
Arduino Uno R3Part · pinWireNotes
D2Push button (6 mm tactile switch) · 1orangeCandidate 1 — internal pull-up
GNDPush button (6 mm tactile switch) · 2black
D3Push button (6 mm tactile switch) #2 · 1orangeCandidate 2
GNDPush button (6 mm tactile switch) #2 · 2black
D4Push button (6 mm tactile switch) #3 · 1orangeCandidate 3
GNDPush button (6 mm tactile switch) #3 · 2black
D5Push button (6 mm tactile switch) #4 · 1orangeCandidate 4 (NOTA)
GNDPush button (6 mm tactile switch) #4 · 2black
D6Push button (6 mm tactile switch) #5 · 1purpleBALLOT — on the officer’s control box
GNDPush button (6 mm tactile switch) #5 · 2black
D7Push button (6 mm tactile switch) #6 · 1brownRESULT — on the officer’s control box
GNDPush button (6 mm tactile switch) #6 · 2black
A416×2 LCD + I2C backpack · SDAblue
A516×2 LCD + I2C backpack · SCLyellow
5V16×2 LCD + I2C backpack · VCCred
GND16×2 LCD + I2C backpack · GNDblack
D8Active buzzer module (high-level trigger) · I/Ogreen
5VActive buzzer module (high-level trigger) · VCCred
GNDActive buzzer module (high-level trigger) · GNDblack

Board quirks: This is a classroom demonstration of how an electronic voting machine works — for class-monitor or house-captain elections in school. It is not, and must never be presented as, a real election device. Change the names in the NAME[] list before the election (up to 9 letters each). The fourth button is NOTA, as on the real machine’s ballot unit. Votes live in the Uno’s EEPROM (bytes 0–8), so unplugging it or a power cut never loses them. Re-uploading the sketch keeps them too; only BALLOT + RESULT held for 5 s clears them. The sketch never prints which candidate received a vote — only the running total — so a laptop watching the Serial Monitor can’t break the secret ballot. If your LCD stays blank but lights up, its backpack may be at 0x3F instead of 0x27: change the address in the sketch. Turn the blue contrast pot on the backpack if you see only blocks.

Code

classroom-voting-machine.inoArduino C++Open in PlaygroundOpen in PlaygroundFlash
// Classroom voting machine (a model of an EVM for class elections) — Arduino Uno + 16x2 I2C LCD.
// Like the real thing, the presiding officer enables ONE vote at a time with the BALLOT button;
// the voter then presses one candidate button and a long beep confirms it. Votes are kept in
// EEPROM, so a power cut doesn't lose them. Hold RESULT for 3 s to show the count.
// Hold BALLOT + RESULT together for 5 s to clear all votes (new election).
// Candidates D2–D5 (to GND), BALLOT D6, RESULT D7, buzzer module I/O D8, LCD on SDA/SCL (A4/A5).
// A classroom demonstration only — not a real election device.
#include <Wire.h>
#include <EEPROM.h>
#include <LiquidCrystal_I2C.h>

constexpr uint8_t CANDIDATES = 4;
constexpr uint8_t CAND_PIN[CANDIDATES] = {2, 3, 4, 5};
constexpr uint8_t BALLOT_PIN = 6, RESULT_PIN = 7, BUZZER_PIN = 8;
// Up to 9 characters each so "name 123" fits a 16-character line twice.
const char* const NAME[CANDIDATES] = {"Aarav", "Diya", "Kabir", "NOTA"};
constexpr uint8_t MAGIC = 0xE7;  // EEPROM byte 0: marks the vote store as initialised

LiquidCrystal_I2C lcd(0x27, 16, 2);
uint16_t votes[CANDIDATES];
bool ballotOpen = false;

bool down(uint8_t pin) { return digitalRead(pin) == LOW; }

void beep(unsigned int ms) {
  digitalWrite(BUZZER_PIN, HIGH);
  delay(ms);
  digitalWrite(BUZZER_PIN, LOW);
}

void show(const __FlashStringHelper* a, const __FlashStringHelper* b) {
  lcd.clear();
  lcd.print(a);
  lcd.setCursor(0, 1);
  lcd.print(b);
}

void saveVotes() {
  EEPROM.update(0, MAGIC);
  EEPROM.put(1, votes);
}

uint16_t total() {
  uint16_t t = 0;
  for (uint8_t i = 0; i < CANDIDATES; i++) t += votes[i];
  return t;
}

void idleScreen() {
  lcd.clear();
  lcd.print(F("Votes cast: "));
  lcd.print(total());
  lcd.setCursor(0, 1);
  lcd.print(F("Officer: BALLOT"));
}

// Wait until every button is released, so one press never counts twice.
void waitRelease() {
  for (;;) {
    bool any = down(BALLOT_PIN) || down(RESULT_PIN);
    for (uint8_t i = 0; i < CANDIDATES; i++) any |= down(CAND_PIN[i]);
    if (!any) break;
  }
  delay(40);
}

// True if `pin` (and `also`, when given) stay pressed for `ms`.
bool held(uint8_t pin, uint8_t also, unsigned long ms) {
  unsigned long t0 = millis();
  while (down(pin) && (also == 0xFF || down(also))) {
    if (millis() - t0 >= ms) return true;
  }
  return false;
}

void showResult() {
  Serial.println(F("--- Result ---"));
  uint8_t lead = 0;
  bool tie = false;
  for (uint8_t i = 0; i < CANDIDATES; i++) {
    Serial.print(NAME[i]);
    Serial.print(F(": "));
    Serial.println(votes[i]);
    if (i && votes[i] > votes[lead]) lead = i, tie = false;
    else if (i && votes[i] == votes[lead]) tie = true;
  }
  // Two candidates per screen, 3 s each, then the outcome.
  for (uint8_t i = 0; i < CANDIDATES; i += 2) {
    lcd.clear();
    for (uint8_t r = 0; r < 2 && i + r < CANDIDATES; r++) {
      lcd.setCursor(0, r);
      lcd.print(NAME[i + r]);
      lcd.setCursor(11, r);
      lcd.print(votes[i + r]);
    }
    delay(3000);
  }
  lcd.clear();
  if (total() == 0) lcd.print(F("No votes yet"));
  else if (tie) lcd.print(F("Result: TIE"));
  else {
    lcd.print(F("Leading:"));
    lcd.setCursor(0, 1);
    lcd.print(NAME[lead]);
  }
  Serial.println(total() == 0 ? F("No votes yet") : tie ? F("Tie at the top") : F("Leader shown on the LCD"));
  delay(3000);
  idleScreen();
}

void setup() {
  for (uint8_t i = 0; i < CANDIDATES; i++) pinMode(CAND_PIN[i], INPUT_PULLUP);
  pinMode(BALLOT_PIN, INPUT_PULLUP);
  pinMode(RESULT_PIN, INPUT_PULLUP);
  pinMode(BUZZER_PIN, OUTPUT);
  Serial.begin(115200);
  Serial.println(F("Classroom voting machine (demo model)"));
  lcd.init();
  lcd.backlight();
  if (EEPROM.read(0) == MAGIC) EEPROM.get(1, votes);
  else {
    memset(votes, 0, sizeof votes);
    saveVotes();
  }
  show(F("Class election"), F("Voting machine"));
  delay(1500);
  Serial.print(F("Votes stored: "));
  Serial.println(total());
  idleScreen();
}

void loop() {
  // Clear all votes: BALLOT + RESULT held together for 5 s.
  if (down(BALLOT_PIN) && down(RESULT_PIN)) {
    show(F("Keep holding to"), F("CLEAR all votes"));
    if (held(BALLOT_PIN, RESULT_PIN, 5000)) {
      memset(votes, 0, sizeof votes);
      saveVotes();
      ballotOpen = false;
      show(F("All votes"), F("cleared"));
      Serial.println(F("All votes cleared — new election"));
      beep(600);
      delay(1500);
    }
    waitRelease();
    idleScreen();
    return;
  }

  if (down(RESULT_PIN)) {
    if (held(RESULT_PIN, 0xFF, 3000) && !ballotOpen) {
      waitRelease();
      showResult();
    } else waitRelease();
    return;
  }

  if (down(BALLOT_PIN) && !ballotOpen) {
    delay(60);
    if (down(BALLOT_PIN) && !down(RESULT_PIN)) {
      ballotOpen = true;
      show(F("BALLOT ready"), F("Press one button"));
      beep(80);
      waitRelease();
    }
    return;
  }

  for (uint8_t i = 0; i < CANDIDATES; i++) {
    if (!down(CAND_PIN[i])) continue;
    if (!ballotOpen) {
      show(F("Wait for the"), F("officer (BALLOT)"));
      waitRelease();
      delay(1000);
      idleScreen();
      return;
    }
    ballotOpen = false;  // one vote per BALLOT press
    votes[i]++;
    saveVotes();
    show(F("Vote recorded"), F("Thank you"));
    beep(1000);  // the long beep voters know from the real EVM
    // Secret ballot: only the running total is printed, never who got this vote.
    Serial.print(F("Vote recorded. Total: "));
    Serial.println(total());
    waitRelease();
    delay(800);
    idleScreen();
    return;
  }
}

Compiled for uno on avr 1.8.8 with LiquidCrystal I2C 1.1.2 · 3 Nov 2026

How it works

India votes on electronic voting machines, and a working model is one of the most popular school exhibition projects — and genuinely useful for class-monitor and house-captain elections. This one copies the real machine’s most important rule: the presiding officer enables one vote at a time.

How it works

The build has two boxes, like a real EVM: a ballot unit with four candidate buttons (the fourth is NOTA), and the officer’s control unit with BALLOT, RESULT, the LCD and the buzzer.

  1. The LCD shows the number of votes cast and “Officer: BALLOT”.
  2. The officer presses BALLOT. The LCD says “BALLOT ready”.
  3. The voter presses one candidate button. The Uno adds one to that candidate, saves the counts to EEPROM, and sounds a one-second beep — the same confirmation voters hear in a real polling booth.
  4. Any further presses are ignored until the officer presses BALLOT again.

Holding RESULT for 3 seconds shows each candidate’s count, two per screen, then the leader (or “TIE”). Holding BALLOT and RESULT together for 5 seconds clears everything for a new election.

What to show at the exhibition

Run a mini election with visitors: one of you is the officer, a visitor votes behind a cardboard screen, everyone hears the beep. Show that pressing twice doesn’t add two votes, and that pulling the USB cable out and back in keeps every vote. End with RESULT.

Questions the examiner may ask

  • How do you stop someone voting twice? Each BALLOT press allows exactly one vote; the sketch closes the ballot at the first candidate press and waits for all buttons to be released.
  • Where are votes stored, and why there? In EEPROM — non-volatile memory inside the ATmega328P that keeps data without power. EEPROM.update() only writes bytes that changed, which spares its 100,000-write life.
  • How is the vote kept secret? Nothing that identifies the chosen candidate is printed or displayed at the moment of voting — only the total.
  • How is this different from a real EVM? Real machines use one-time-programmable chips, sealed hardware, a VVPAT printer and strict procedures. This model shows the idea, not the security.

Cost in India

About ₹900 with cardboard boxes. The LCD with its I2C backpack is the largest item (₹150–220); buying it with the backpack already soldered saves 12 wires.

Troubleshooting

Pressing a candidate says “Wait for the officer”

That is correct behaviour: each vote must be enabled with BALLOT first, exactly like the control unit of a real EVM.

One press counted two votes

It can’t: BALLOT is cleared at the first candidate press and the sketch waits for every button to be released. If counts still jump, a candidate button is wired to the wrong pair of legs and is always closed.

RESULT does nothing

Hold it for a full 3 seconds, and not while a ballot is open (cast the vote or reset the board first).

Upgrades

  • Add an LED next to each candidate button that lights while their vote is being recorded, like the real ballot unit.
  • Print a paper slip for each vote on a small thermal printer — a model of VVPAT.
  • Add a CLOSE button so results can only be shown after polling ends, and lock further votes.
  • Use a 4x4 keypad for up to 15 candidates and a 20x4 LCD for longer names.

↑↓ to move · Enter to open