1.7 TFT Digital Clock
Display a ticking digital clock on the TFT LCD screen with the TFT_eSPI library.
Overview
This example brings the onboard TFT LCD to life by rendering a watch-style digital clock. It draws a static bezel background once at startup, then updates the time display every second using a software clock.
What You’ll Learn
Initializing the TFT display with
TFT_eSPIDrawing rectangles, rounded rectangles, and decorative lines
Using custom 7-segment fonts for digital clock displays
Simple software timekeeping with
millis()
Before You Begin
Complete the setup steps in Preparation before continuing.
Note
Use the recommended Arduino IDE settings in Recommended Board Settings unless this lesson says otherwise.
Important
The TFT_eSPI library must be configured for this board’s display pins before this example will compile. A matching User_Setup.h is provided in the library ZIP.
Open the example sketch from the code package:
LAFVIN-ESP32-S3-Multimedia-Kit-main/1.Arduino/7.TFT_Watch/7.TFT_Watch.ino
This example uses the onboard TFT LCD. No external wiring is required.
Upload and Test
Connect the board with a USB Type-C data cable.
Open
7.TFT_Watch.inoin Arduino IDE.In the Tools menu, select
ESP32S3 Dev Moduleas the board and choose the correct serial port.Click Upload.
After uploading, the TFT screen shows a watch face with hours, minutes, and seconds. The time starts from the sketch’s compile time and advances every second.
The display layout:
White outer background
Dark grey rounded bezel frame
Light grey LCD face with decorative lines
HH:MMin large 7-segment font near the centreSSin smaller size below“LAFVIN” branding at the bottom
How the Code Works
Display Initialization
#include <TFT_eSPI.h>
TFT_eSPI tft = TFT_eSPI();
tft.init();
tft.setRotation(0); // Portrait orientation
tft.invertDisplay(true); // Correct colours for this panel
Drawing the Watch Face
The watch face is drawn once in setup() using filled rectangles, horizontal lines, and text labels. A dark bezel frame sits on a white background, with a lighter LCD face area inside.
tft.fillScreen(TFT_WHITE);
tft.fillRect(5, 40, 230, 220, WATCH_FRAME);
tft.fillRect(15, 50, 210, 200, LCD_BACK_LIGHT);
tft.drawFastHLine(20, 80, 200, TFT_BLUE);
tft.drawFastHLine(20, 220, 200, TFT_BLUE);
tft.setTextColor(LCD_TEXT_BLACK, LCD_BACK_LIGHT);
tft.setTextDatum(TL_DATUM);
tft.drawString("ALARM CHRONO", 20, 55, 2);
tft.setTextDatum(TR_DATUM);
tft.drawString("LIGHT", 220, 55, 2);
tft.setTextDatum(MC_DATUM);
tft.setTextColor(TFT_DARKGREY, TFT_WHITE);
tft.drawString("LAFVIN", 120, 280, 4);
Software Clock
The initial time is parsed from the __TIME__ compile-time macro using a conv2d() helper that extracts two-digit numbers from the "HH:MM:SS" string. The loop() increments seconds, minutes, and hours with carry, then redraws only the changed digits using font 7 (a 7-segment display font).
static uint8_t conv2d(const char* p) {
uint8_t v = 0;
if ('0' <= *p && *p <= '9')
v = *p - '0';
return 10 * v + *++p - '0';
}
uint8_t hh = conv2d(__TIME__), mm = conv2d(__TIME__ + 3), ss = conv2d(__TIME__ + 6);
void loop() {
if (targetTime < millis()) {
targetTime += 1000;
ss++;
if (ss == 60) { ss = 0; mm++; }
if (mm > 59) { mm = 0; hh++; }
if (hh > 23) { hh = 0; }
String mainTime = hourStr + ":" + minStr;
tft.setTextDatum(MC_DATUM);
tft.drawString(mainTime, 120, 130, 7);
tft.drawString(secStr, 120, 190, 7);
}
}
In the provided sketch:
The watch face is drawn once in
setup()and not redrawnOnly the changing time digits are updated in
loop()A 7-segment font (font 7) gives the clock an authentic digital-watch look
setTextDatum(MC_DATUM)centres the text horizontally and vertically at the given coordinate
Try This Next
Change
tft.setRotation(0)totft.setRotation(1)for a landscape clockAdd the date below the time using a smaller font
Replace
__TIME__with an NTP-synced clock for real internet time (see 2.13 WiFi Connection Manager for a Wi-Fi example)