Built-in project · ESP32-C3-DevKitM-1
Binary clock on an ESP32-C3
An ESP32-C3 writes the hours, minutes and seconds as three rows of binary lamps on a 128x64 OLED. The whole build, an ESP32-C3 and 1 more part, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.
IntermediateRuns in your browser. Free, and no account needed.
Click to open it in the editor
The circuit itself, running here on the simulator. Press what can be pressed; click anything else to open it in the editor.
The code
The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.
sketch.ino · ESP32-C3-DevKitM-1
// Binary clock: the time in ones and zeros on a 128x64 OLED.
//
// Wiring, module to board:
// SCL -> GPIO 5 SDA -> GPIO 4 VCC -> 3V3 GND -> GND
//
// Three rows of lamps: five bits of hours, six of minutes, six of seconds,
// most significant on the left. A filled circle is a one. Read a row as a
// binary number and that is the number under it, which the sketch also prints
// in decimal so the reading can be checked.
//
// The time comes from millis() and nothing else. There is no clock chip here,
// so the board starts at the time set below and counts from there; a real one
// would read a DS3231 over the same two wires this display is on.
//
// A whole second is a long time for a board, so the loop sleeps in 50 ms steps
// and only repaints when the second changes. The driver sends the
// eight-column blocks that changed rather than the whole kilobyte, so a tick
// that moves three lamps costs a few dozen bytes on the bus.
#include "mokxi_i2c.h"
#include "mokxi_ssd1306.h"
const uint8_t SCL_PIN = 5;
const uint8_t SDA_PIN = 4;
SoftI2c bus(SCL_PIN, SDA_PIN, 400);
Ssd1306 oled(bus, SSD1306_ADDRESS);
// Where the clock starts, since nothing here keeps time across a reset.
const uint32_t START_HOUR = 9;
const uint32_t START_MINUTE = 41;
const uint32_t START_SECOND = 0;
const int16_t ROW_Y[3] = {22, 38, 54};
const uint8_t ROW_BITS[3] = {5, 6, 6};
const char *const ROW_NAME[3] = {"H", "M", "S"};
const int16_t DOT_R = 5;
const int16_t DOT_STEP = 16;
const int16_t DOT_RIGHT = 118;
uint32_t shown = 0xffffffffu;
static void furniture() {
oled.clear();
oled.text(0, 2, "MOKXI", 1);
oled.hLine(0, 12, 128);
for (int r = 0; r < 3; r++) {
oled.text(0, (int16_t)(ROW_Y[r] - 3), ROW_NAME[r], 1);
}
}
// One row of lamps, most significant bit on the left.
static void row(int r, uint32_t value) {
uint8_t bits = ROW_BITS[r];
for (uint8_t i = 0; i < bits; i++) {
int16_t cx = (int16_t)(DOT_RIGHT - i * DOT_STEP);
bool on = ((value >> i) & 1u) != 0u;
oled.fillCircle(cx, ROW_Y[r], DOT_R, false);
if (on) {
oled.fillCircle(cx, ROW_Y[r], DOT_R, true);
} else {
oled.circle(cx, ROW_Y[r], DOT_R, true);
}
}
}
static void twoDigits(int16_t x, int16_t y, uint32_t value) {
oled.number(x, y, (long)(value / 10u), 1, true, true);
oled.number((int16_t)(x + 6), y, (long)(value % 10u), 1, true, true);
}
void setup() {
Serial.begin(115200);
Serial.println("Mokxi ESP32-C3: binary clock on an SSD1306");
if (!oled.begin()) {
Serial.println("no ACK from the display: check SCL, SDA and the supply");
return;
}
furniture();
oled.display();
}
void loop() {
uint32_t elapsed = millis() / 1000u;
uint32_t total =
(START_HOUR * 3600u + START_MINUTE * 60u + START_SECOND + elapsed) % 86400u;
if (total == shown) {
delay(50);
return;
}
shown = total;
uint32_t hours = total / 3600u;
uint32_t minutes = (total / 60u) % 60u;
uint32_t seconds = total % 60u;
row(0, hours);
row(1, minutes);
row(2, seconds);
twoDigits(72, 2, hours);
oled.text(84, 2, ":", 1, true, true);
twoDigits(90, 2, minutes);
oled.text(102, 2, ":", 1, true, true);
twoDigits(108, 2, seconds);
oled.display();
if (seconds == 0u) {
Serial.print("tick ");
Serial.print(hours);
Serial.print(":");
Serial.println(minutes);
}
}
Parts list
3 parts, plus the jumper wires. Every one is in the editor's parts bin.
How it is wired
4 connections, pin by pin, read from the circuit itself. Each line is one set of pins joined together, by a jumper wire or a breadboard strip.
- ESP32-C3-DevKitM-1 pin 3V3; OLED display, 128x64 pin VCC
- Ground: ESP32-C3-DevKitM-1 pin GND; OLED display, 128x64 pin GND
- ESP32-C3-DevKitM-1 pin 4; OLED display, 128x64 pin SDA
- ESP32-C3-DevKitM-1 pin 5; OLED display, 128x64 pin SCL
Change it and keep it
Open it in the editor, change the circuit or the code, and keep your version in a free account.