In this project, we build a digital dice roller using an ESP32 board with a 1.9″ TFT LCD and a tilt sensor. When you shake the device, a random number between 1 and 6 appears on the screen as a traditional red-dot dice face — all displayed inside a stylish 3D-looking square.
Hardware Components
| Component | Quantity | Description |
|---|---|---|
| ESP32 with built-in 1.9″ ST7789 LCD | 1 | Main microcontroller with LCD (e.g. this one) |
| Tilt Sensor (Ball Switch) | 1 | Detects motion to simulate a dice roll |
| Breadboard or jumper wires | 1 set | For prototyping the connections |
| (Optional) 10kΩ Resistor | 1 | For additional pull-up if needed (not required here) |
Schematic

Wiring / Connections
| Tilt Sensor Pin | ESP32 Pin |
|---|---|
| Ground (-) | GND |
| VCC (+) | 3V3 |
| Signal (S) | GPIO 33 |
Arduino Code
#include <Adafruit_GFX.h>
#include <Adafruit_ST7789.h>
#include <SPI.h>
#define TFT_CS 15
#define TFT_DC 2
#define TFT_RST 4
#define TILT_PIN 33 // Connected to tilt sensor
Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);
// Dice layout [3x3 grid]
const uint8_t diceDots[6][9] = {
{0,0,0, 0,1,0, 0,0,0}, // 1
{1,0,0, 0,0,0, 0,0,1}, // 2
{1,0,0, 0,1,0, 0,0,1}, // 3
{1,0,1, 0,0,0, 1,0,1}, // 4
{1,0,1, 0,1,0, 1,0,1}, // 5
{1,0,1, 1,0,1, 1,0,1} // 6
};
unsigned long lastShakeTime = 0;
const unsigned long debounceDelay = 200;
bool wasTilted = false;
void setup() {
pinMode(TILT_PIN, INPUT_PULLUP);
Serial.begin(115200);
tft.init(170, 320);
tft.setRotation(1);
tft.fillScreen(ST77XX_BLACK);
showCenterText("Shake to Roll Dice", 2, ST77XX_WHITE);
}
void loop() {
bool tilt = digitalRead(TILT_PIN) == LOW;
if (tilt && !wasTilted && (millis() - lastShakeTime > debounceDelay)) {
lastShakeTime = millis();
wasTilted = true;
int value = random(1, 7);
Serial.println("Rolled: " + String(value));
displayDice(value);
}
else if (!tilt) {
wasTilted = false;
}
}
void showCenterText(const char* msg, uint8_t textSize, uint16_t color) {
tft.fillScreen(ST77XX_BLACK);
tft.setTextSize(textSize);
int16_t x1, y1;
uint16_t w, h;
tft.getTextBounds(msg, 0, 0, &x1, &y1, &w, &h);
int x = (tft.width() - w) / 2;
int y = 10; // Move closer to top
tft.setCursor(x, y);
tft.setTextColor(color);
tft.println(msg);
}
void displayDice(int num) {
int diceSize = 120;
int diceX = (tft.width() - diceSize) / 2;
int diceY = 60; // Moved up to avoid cropping
// Draw white square dice with black border
tft.fillRect(diceX, diceY, diceSize, diceSize, ST77XX_WHITE);
tft.drawRect(diceX, diceY, diceSize, diceSize, ST77XX_BLACK);
// 3D shadow effect (within screen bounds)
if (diceY + diceSize + 1 < tft.height())
tft.drawLine(diceX, diceY + diceSize, diceX + diceSize, diceY + diceSize, ST77XX_BLACK);
if (diceX + diceSize + 1 < tft.width())
tft.drawLine(diceX + diceSize, diceY, diceX + diceSize, diceY + diceSize, ST77XX_BLACK);
int dotSize = 10;
int spacing = diceSize / 4;
int x0 = diceX + spacing;
int y0 = diceY + spacing;
const uint8_t* layout = diceDots[num - 1];
for (int i = 0; i < 9; i++) {
if (layout[i]) {
int row = i / 3;
int col = i % 3;
int cx = x0 + col * spacing;
int cy = y0 + row * spacing;
tft.fillCircle(cx, cy, dotSize, ST77XX_RED);
}
}
}
Tilt Detection:digitalRead(TILT_PIN) checks if the ball switch is closed (i.e. tilted). A LOW means the device was shaken.
Debouncing Logic:
Ensures that only one roll is triggered per physical shake using wasTilted and millis() timing.
Random Roll:random(1, 7) generates values from 1 to 6 inclusively.
Dice Display:
A perfect square is centered on the screen. The layout uses a 3×3 grid of red circles based on a binary layout.
UI Styling:
Basic 3D shadow lines and a fillRect + drawRect combo make the dice look crisp and modern.
Conclusion
This digital dice roller is a fantastic mini-project combining fun and function. It turns the ESP32 and a tilt sensor into a playful gadget that mimics real dice in both appearance and behavior. Whether you’re learning, teaching, or just exploring, this is a great step into microcontroller displays and sensors.
If you liked this project, follow more on circuit-diy.com for tutorials, projects, and practical circuits for makers like you!