How to Build One ESP32 Split-Flap Clock Digit

A 3D-printed mechanical digit with stepper motion and magnetic homing

ESP32CNC & MakingIntermediate2–3 hours5 components

Updated

How to Build One ESP32 Split-Flap Clock Digit
For illustrative purposes only
On this page

What you'll build

Build one working split-flap digit module: the mechanical unit that flips through numbers in a retro clock. The electronics are deliberately simple: an ESP32 sends four step signals to a ULN2003 driver, the driver moves a 28BYJ-48 geared stepper, and a KY-035 Hall sensor plus a small magnet gives the wheel a repeatable home position after boot.

Keep the first build to one digit. A split-flap clock only feels simple once one module can home reliably, move exactly one flap at a time, and recover after power loss. After that, duplicating the digit is mostly more drivers, more Hall inputs, and a clean power layout.

Watch the original build inspiration here on YouTube.

What you are building

This guide covers one numeric digit, not a complete multi-digit clock. The module has four jobs:

  1. spin the 28BYJ-48 through a ULN2003 driver,
  2. detect a known zero position with a magnet and Hall sensor,
  3. advance by a calibrated number of steps per flap,
  4. expose Serial Monitor commands so you can test digits before scaling up.

That boundary is intentional. If one digit misses steps, rubs mechanically, or homes unreliably, a four-digit clock will multiply the problem.

Upload and calibrate

Install the AccelStepper library, flash the starter sketch, and open Serial Monitor at 115200 baud.

Useful commands:

  • ? prints available commands.
  • r prints the current Hall sensor reading.
  • h homes the wheel using the magnet.
  • 09 moves directly to a digit.
  • n advances to the next digit.
  • d toggles demo mode; manual digit commands automatically pause the demo cycle.

Start by sending r with the magnet away from the sensor, then again with the magnet near the sensor. Set HOME_THRESHOLD between those two readings. Most KY-035 boards read lower near the magnet; if yours reads higher, flip the comparison inside magnetDetected().

After homing works, send 0 through 9. If every move lands a little short or a little long, tune STEPS_PER_FLAP. The default 205 is a practical starting point for a 2048-step 28BYJ-48 and ten flaps, but printed tolerances and gear alignment can shift the real value.

Troubleshooting

  • Motor buzzes but does not turn: check 5 V motor power, shared ground, and the coil order. The sketch uses IN1, IN3, IN2, IN4, which matches many 28BYJ-48 + ULN2003 kits.
  • ESP32 resets during a move: use a separate 5 V supply for the motor and keep grounds common.
  • Homing never finishes: print the Hall reading with r, reduce the magnet gap, and tune HOME_THRESHOLD.
  • Digit lands between flaps: adjust STEPS_PER_FLAP, then test a full 0-9 cycle.
  • One flap works but later flaps drift: fix mechanical drag first, then lower speed or acceleration.

Scaling to a full clock

Once one digit is reliable, duplicate the motor driver and Hall sensor per digit. Keep motor power separate from ESP32 logic power, share grounds, and avoid reusing GPIO 34 for every Hall sensor; each digit needs its own input. A full clock also needs timekeeping logic, but the mechanical calibration should stay per digit.

Wiring diagram

Loading diagram…
Interactive wiring diagram

Components needed

Supplier links, prices, and availability are shown as a guide and may change. Schematik may earn a commission from purchases made through affiliate links.

Assembly

1

Assemble the printed flap wheel

Press the wheel parts onto the shaft, clamp the digit flaps in order, and fit the right-side cap and small gear. Use the M2 inserts and 8 mm M2 screws so the wheel stays square but can still rotate freely.

2

Mount the sensor and stepper

Install the KY-035 Hall sensor with the short M2 screws, then mount the 28BYJ-48 stepper motor with M3 screws. Place the 10 x 3 mm magnet so it passes close to the Hall sensor once per revolution.

3

Wire the driver and Hall sensor

Connect ESP32 GPIO 16, 17, 18 and 19 to ULN2003 IN1-IN4. Power the ULN2003 motor side from 5 V, share GND with the ESP32, and connect the Hall sensor AO pin to GPIO 34 with VCC on 3V3.

4

Upload and calibrate one digit

Upload the sketch, open Serial Monitor at 115200 baud, and let the wheel home against the Hall sensor. If the displayed digit lands between flaps, adjust STEPS_PER_FLAP slightly until each move centres the next number.

Pin assignments

PinConnectionType
GPIO 16uln2003-stepper-driver-1 IN1DIGITAL
GPIO 17uln2003-stepper-driver-1 IN2DIGITAL
GPIO 18uln2003-stepper-driver-1 IN3DIGITAL
GPIO 19uln2003-stepper-driver-1 IN4DIGITAL
5Vuln2003-stepper-driver-1 5VPOWER
GNDuln2003-stepper-driver-1 GNDGROUND
3V3ky-035-hall-sensor-1 VCCPOWER
GNDky-035-hall-sensor-1 GNDGROUND
GPIO 34ky-035-hall-sensor-1 AOANALOG

Code

Arduino C++
#include <Arduino.h>
#include <Stepper.h>

#define STEPS_PER_REV 2048
#define MOTOR_IN1 16
#define MOTOR_IN2 17
#define MOTOR_IN3 18
#define MOTOR_IN4 19
#define HALL_PIN 34
#define HOME_THRESHOLD 1800
#define FLAP_COUNT 10
#define STEPS_PER_FLAP 205

Stepper flapMotor(STEPS_PER_REV, MOTOR_IN1, MOTOR_IN3, MOTOR_IN2, MOTOR_IN4);
int currentDigit = 0;

bool magnetDetected() {
  return analogRead(HALL_PIN) < HOME_THRESHOLD;
}

void stepForward(int steps) {
  flapMotor.step(steps);
  delay(80);
}

void homeWheel() {
  Serial.println("Homing split-flap wheel...");
  for (int i = 0; i < STEPS_PER_REV + 300; i += 4) {
    if (magnetDetected()) {
      currentDigit = 0;
      Serial.println("Home magnet found");
      return;
    }
    stepForward(4);
  }
  Serial.println("Home magnet not found. Check sensor alignment.");
}

void showDigit(int targetDigit) {
  targetDigit = constrain(targetDigit, 0, FLAP_COUNT - 1);
  int delta = (targetDigit - currentDigit + FLAP_COUNT) % FLAP_COUNT;
  stepForward(delta * STEPS_PER_FLAP);
  currentDigit = targetDigit;
  Serial.printf("Showing digit %d\n", currentDigit);
}

void setup() {
  Serial.begin(115200);
  analogReadResolution(12);
  pinMode(HALL_PIN, INPUT);
  flapMotor.setSpeed(12);
  delay(500);
  homeWheel();
}

void loop() {
  for (int digit = 0; digit < FLAP_COUNT; digit++) {
    showDigit(digit);
    delay(1200);
  }
}

// Run this and build other cool things at schematik.io
Libraries: Stepper

Ready to build this?

Open this project in Schematik to get the full wiring diagram, pin assignments, and deployable code for the Split-Flap Clock Digit.

Open in Schematik →

Related guides