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.
School Bell Timer: the finished build
UnoIndia utility

Automatic school bell timer with RTC and LCD (Arduino Uno + DS3231)

Rings every period on time, skips Sundays, and keeps time through power cuts.

Difficulty
Easy
Build time
2 h
Parts cost
₹1,530 · $18
Verified — core avr 1.8.8, RTClib 2.1.4, 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)
DS3231 RTC module + CR2032 cell1₹150Buy DS3231 RTC module + CR2032 cell
16×2 LCD with I2C backpack (PCF8574, 0x27)1₹180Buy 16×2 LCD with I2C backpack (PCF8574, 0x27)
1-channel relay module, 5 V1₹60Buy 1-channel relay module, 5 V
12 V DC electric bell or 12 V siren (≤ 1 A)1₹350Buy 12 V DC electric bell or 12 V siren (≤ 1 A)
12 V 2 A adapter (for the bell)1₹200Buy 12 V 2 A adapter (for the bell)
Push button (ring now)1₹20Buy Push button (ring now)
5 V 1 A USB adapter + cable (for the Uno)1₹120Buy 5 V 1 A USB adapter + cable (for the Uno)
Total₹1,530

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 logic12 V DC bell / siren on its own 12 V adapterDS3231 real-time clock (RTC) module16×2 LCD + I2C backpack1-channel relay module (5 V coil)Push button (6 mm tactile switch)+12VBell +5VGNDD4D7SDA · 18SCL · 1932K (not connected)SQW (not connected)SCLSDAVCCGNDGNDVCCSDASCLDC+DC−INCOMNONC (not connected)12
Every connection
Arduino Uno R3Part · pinWireNotes
5VDS3231 real-time clock (RTC) module · VCCred
GNDDS3231 real-time clock (RTC) module · GNDblack
SDADS3231 real-time clock (RTC) module · SDAblue
SCLDS3231 real-time clock (RTC) module · SCLyellow
5V16×2 LCD + I2C backpack · VCCred
GND16×2 LCD + I2C backpack · GNDblack
SDA16×2 LCD + I2C backpack · SDAblue
SCL16×2 LCD + I2C backpack · SCLyellow
D71-channel relay module (5 V coil) · INorangeActive-LOW; set HIGH before it becomes an output
5V1-channel relay module (5 V coil) · DC+red
GND1-channel relay module (5 V coil) · DC−black
12 V DC bell / siren on its own 12 V adapter · +12V1-channel relay module (5 V coil) · COMred12 V adapter + to COM
12 V DC bell / siren on its own 12 V adapter · Bell +1-channel relay module (5 V coil) · NOredNO to the bell’s +; bell − back to the adapter −
D4Push button (6 mm tactile switch) · 1purpleRing-now button, INPUT_PULLUP
GNDPush button (6 mm tactile switch) · 2black

Board quirks: This build rings a <strong>12 V DC</strong> bell or siren, so nothing on it touches 230 V. If your school already has a 230 V bell, ask an electrician to have the relay switch the coil of a small contactor that feeds the bell — never run 230 V wiring into the Uno box yourself. Set the clock once with the Serial Monitor at 115200 baud: <code>SET 2026 06 15 08 59 30</code> (year month day hour minute second). The DS3231 keeps time on its coin cell through power cuts and holidays, drifting about a minute a year. If the clock ever loses power completely, the LCD says “Set the clock!” and the bell stays silent — a wrong clock ringing at random times is worse than no bell. Many DS3231 modules charge their coin cell through a diode and resistor meant for an LIR2032. With a normal CR2032, remove that charging resistor (see the module’s notes) or use an LIR2032.

Code

school-bell-timer.inoArduino C++Open in PlaygroundOpen in PlaygroundFlash
// Automatic school bell timer — Arduino Uno + DS3231 RTC + 16x2 I2C LCD + relay module
// DS3231 and LCD share I2C (SDA/SCL). Relay module IN on D7 (active-LOW): its COM/NO switch a
// 12 V DC bell from its own 12 V adapter. Manual "ring now" push button on D4 to GND.
// Set the clock once: send "SET 2026 06 15 08 59 30" in the Serial Monitor (115200 baud).
#include <Wire.h>
#include <RTClib.h>
#include <LiquidCrystal_I2C.h>

constexpr uint8_t RELAY_PIN = 7;
constexpr uint8_t BUTTON_PIN = 4;
constexpr bool RELAY_ACTIVE_LOW = true;
constexpr bool SKIP_SUNDAY = true;

struct Bell { uint8_t h, m, seconds; const char* label; };
// Edit to your timetable (24-hour clock). Longer rings mark assembly, breaks and home time.
const Bell BELLS[] = {
  {9, 0, 8, "Assembly"}, {9, 20, 4, "Period 1"}, {10, 0, 4, "Period 2"}, {10, 40, 4, "Period 3"},
  {11, 20, 6, "Short break"}, {11, 35, 4, "Period 4"}, {12, 15, 4, "Period 5"}, {12, 55, 6, "Lunch"},
  {13, 35, 4, "Period 6"}, {14, 15, 4, "Period 7"}, {14, 55, 4, "Period 8"}, {15, 35, 10, "Home time"},
};
constexpr uint8_t N_BELLS = sizeof(BELLS) / sizeof(BELLS[0]);

RTC_DS3231 rtc;
LiquidCrystal_I2C lcd(0x27, 16, 2);
unsigned long ringUntil = 0;
int lastRungMinute = -1;
bool rtcOk = false;

void relay(bool on) {
  digitalWrite(RELAY_PIN, (on != RELAY_ACTIVE_LOW) ? HIGH : LOW);
}

void ring(uint8_t seconds, const char* why) {
  ringUntil = millis() + seconds * 1000UL;
  relay(true);
  Serial.print(F("Ring "));
  Serial.print(seconds);
  Serial.print(F(" s: "));
  Serial.println(why);
}

void serialCommands() {
  if (!Serial.available()) return;
  String cmd = Serial.readStringUntil('\n');
  int y, mo, d, h, mi, s;
  if (sscanf(cmd.c_str(), "SET %d %d %d %d %d %d", &y, &mo, &d, &h, &mi, &s) == 6) {
    rtc.adjust(DateTime(y, mo, d, h, mi, s));
    Serial.println(F("Clock set"));
  }
}

void setup() {
  digitalWrite(RELAY_PIN, RELAY_ACTIVE_LOW ? HIGH : LOW);  // bell off before the pin becomes an output
  pinMode(RELAY_PIN, OUTPUT);
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  Serial.begin(115200);
  lcd.init();
  lcd.backlight();
  rtcOk = rtc.begin();
  if (!rtcOk) {
    lcd.print(F("RTC not found"));
    Serial.println(F("DS3231 not found - check SDA/SCL and power"));
  } else if (rtc.lostPower()) {
    Serial.println(F("RTC lost power - set the time with SET YYYY MM DD hh mm ss"));
  }
}

void loop() {
  serialCommands();
  if (ringUntil && (long)(millis() - ringUntil) >= 0) {
    relay(false);
    ringUntil = 0;
  }
  if (digitalRead(BUTTON_PIN) == LOW && !ringUntil) {
    ring(3, "manual");
    while (digitalRead(BUTTON_PIN) == LOW) delay(10);
  }
  if (!rtcOk) return;

  DateTime now = rtc.now();
  bool lost = rtc.lostPower();
  bool holiday = SKIP_SUNDAY && now.dayOfTheWeek() == 0;
  int minuteOfDay = now.hour() * 60 + now.minute();

  // Ring once at second 0 of each bell's minute (never on a clock that lost its time).
  if (!lost && !holiday && now.second() < 2 && minuteOfDay != lastRungMinute) {
    for (uint8_t i = 0; i < N_BELLS; i++) {
      if (BELLS[i].h == now.hour() && BELLS[i].m == now.minute()) {
        ring(BELLS[i].seconds, BELLS[i].label);
        lastRungMinute = minuteOfDay;
      }
    }
  }

  // Line 1: time and day. Line 2: the next bell.
  static int shownSecond = -1;
  if (now.second() == shownSecond) return;
  shownSecond = now.second();
  char line[17];
  const char* days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
  snprintf(line, sizeof line, "%02d:%02d:%02d %s   ", now.hour(), now.minute(), now.second(), days[now.dayOfTheWeek()]);
  lcd.setCursor(0, 0);
  lcd.print(line);
  lcd.setCursor(0, 1);
  if (lost) {
    lcd.print(F("Set the clock!  "));
  } else if (holiday) {
    lcd.print(F("Sunday: no bells"));
  } else if (ringUntil) {
    lcd.print(F("RINGING...      "));
  } else {
    const Bell* next = nullptr;
    for (uint8_t i = 0; i < N_BELLS && !next; i++)
      if (BELLS[i].h * 60 + BELLS[i].m > minuteOfDay) next = &BELLS[i];
    if (next) snprintf(line, sizeof line, "Next %02d:%02d %-5.5s", next->h, next->m, next->label);
    else snprintf(line, sizeof line, "Done for today  ");
    lcd.print(line);
  }
}

Compiled for uno on avr 1.8.8 with RTClib 2.1.4 · 3 Nov 2026

How it works

In most Indian schools the peon watches the clock and rings the bell by hand for every period — and the bell is late whenever he is busy. Small factories and coaching centres have the same problem with shift and lunch bells. This timer rings it on time, every time, from a timetable you type into the sketch.

How it works

The DS3231 is a real-time clock with a temperature-compensated crystal and its own coin cell. The Uno reads the time once a loop over I2C. The 16×2 LCD (on the same two I2C wires) shows the time, the day and the next bell, for example Next 11:20 Short.

The timetable is the BELLS list: hour, minute, how many seconds to ring, and a label. When the clock reaches a bell’s minute, the sketch closes the relay for that many seconds — 8 s for assembly, 4 s between periods, 10 s for home time. Each bell rings only once per minute, and Sundays are skipped. A push button rings for 3 seconds whenever someone presses it.

The relay pin is set HIGH (relay off) before it becomes an output, so the bell never chirps when the Uno restarts after a power cut.

Why these parts

  • DS3231 instead of the Uno’s millis() — the Uno’s crystal drifts minutes a day and forgets everything in a power cut; the DS3231 drifts about a minute a year.
  • A 12 V bell — loud, cheap, and low voltage, so the whole box is safe to build on a desk.
  • I2C LCD — four wires shared with the clock.

Setting the timetable

Edit BELLS in 24-hour time. Keep the entries in order through the day — the “next bell” display looks for the first one after the current minute. Change SKIP_SUNDAY if your school works on Sundays.

India notes

Schools have long power cuts in summer. Run the Uno and the 12 V bell adapter from an inverter-backed socket, or use a 12 V battery with a charger and a small buck converter for the Uno, so the bells keep going through the cut.

Troubleshooting

The LCD lights up but shows no text

Turn the contrast trimmer on the back of the I2C backpack. Still blank? Run the I2C scanner — some backpacks are at 0x3F; change it in LiquidCrystal_I2C lcd(0x27, 16, 2).

The bell rings at the wrong times

Check the time on the LCD and set it again with SET. The timetable uses the 24-hour clock, so 2 pm is 14:00.

The relay clicks but the bell is silent

Check the bell’s 12 V circuit: adapter + → COM, NO → bell +, bell − → adapter −. Measure 12 V across the bell while the relay is on.

Upgrades

  • Add a second timetable for Saturdays (half day) and exam days, picked with a switch.
  • Keep a holiday list (dates) so the bell skips festivals and vacations.
  • Play a recorded prayer or the national anthem through a DFPlayer Mini for assembly.

↑↓ to move · Enter to open