1

I’m building an analog clock on an ESP32 Wrover Kit with a TFT LCD using the TFT_eSPI library. The clock displays the correct time using NTP, but I have a problem with the hands:

When the hands move, the old position remains visible (trails).

If I clear the whole screen and redraw the background and text every update, it works, but causes flicker and my static text disappears briefly.

Since my background is a colorful image, I cannot just erase the hands with a solid color.

Here is a simplified version of my code that reproduces the issue:

#include <TFT_eSPI.h> #include <time.h> #include <WiFi.h> TFT_eSPI tft = TFT_eSPI(); #define CENTER_X 50 #define CENTER_Y 60 #define RADIUS 50 #define HOUR_LENGTH 10 #define MINUTE_LENGTH 20 const char* ssid = "Dina"; const char* password = "Dd78134003Segco"; const char* ntpServer = "pool.ntp.org"; const long gmtOffset_sec = 12600; // ایران +3:30 const int daylightOffset_sec = 0; int lastMinute = -1; // draw clock hand as triangle void drawHandTriangle(int length, float angleRad, uint16_t color, int width) { float cosA = cos(angleRad); float sinA = sin(angleRad); int xTip = CENTER_X + cosA * length; int yTip = CENTER_Y + sinA * length; int xLeft = CENTER_X + cos(angleRad + 1.57) * width; int yLeft = CENTER_Y + sin(angleRad + 1.57) * width; int xRight = CENTER_X + cos(angleRad - 1.57) * width; int yRight = CENTER_Y + sin(angleRad - 1.57) * width; tft.fillTriangle(xTip, yTip, xLeft, yLeft, xRight, yRight, color); } void drawClockFace() { tft.fillScreen(TFT_BLACK); for (int h = 0; h < 12; h++) { float angle = (h * 30 - 90) * 0.0174533; int x0 = CENTER_X + cos(angle) * (RADIUS - 3); int y0 = CENTER_Y + sin(angle) * (RADIUS - 3); int x1 = CENTER_X + cos(angle) * RADIUS; int y1 = CENTER_Y + sin(angle) * RADIUS; tft.drawLine(x0, y0, x1, y1, TFT_WHITE); } for (int h = 1; h <= 12; h++) { float angle = (h * 30 - 90) * 0.0174533; int x = CENTER_X + cos(angle) * (RADIUS - 15); int y = CENTER_Y + sin(angle) * (RADIUS - 15); tft.setTextColor(TFT_WHITE); tft.setCursor(x - 5, y - 7); tft.print(h); } } void setup() { Serial.begin(115200); tft.init(); tft.setRotation(0); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); } configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); drawClockFace(); } void loop() { struct tm timeinfo; if (!getLocalTime(&timeinfo)) { delay(1000); return; } if (timeinfo.tm_min != lastMinute) { drawClockFace(); // clears and redraws everything → causes flicker lastMinute = timeinfo.tm_min; float hourAngle = ((timeinfo.tm_hour % 12) + timeinfo.tm_min / 60.0) * 30 - 90; float minuteAngle = timeinfo.tm_min * 6 - 90; drawHandTriangle(HOUR_LENGTH, hourAngle * 0.0174533, TFT_WHITE, 2); drawHandTriangle(MINUTE_LENGTH, minuteAngle * 0.0174533, TFT_WHITE, 1); } delay(1000); } 

Question: How can I update only the hands on top of a static background image and text, without leaving trails or causing flicker?

2
  • If the hands appear on a monochrome background circle they are better readable and can be easily erased. But your's an interesting question. "How to extract a small non-rectangular part of a picture to be able to restore it later". Commented Sep 12 at 8:55
  • 5
    I've not done it with ESP32 but double buffering is the usual solution - does docs.espressif.com/projects/esp-idf/en/v5.0/esp32s3/… apply? Commented Sep 12 at 9:05

1 Answer 1

0

It looks like your drawing strategy needs an update. In the loop() method, the code only checks for minute changes (if (timeinfo.tm_min != lastMinute)), so it redraws the entire screen (drawClockFace()) and the hands only once per minute.

However, even with the delay(1000), the loop runs ~once per second, and if there's any minor rendering overlap or persistence from previous frames (common on TFT LCDs due to how pixels are cleared), trails can appear, especially if the hands don't perfectly align on redraws.

TFT_eSPI on ESP32 is efficient, but to eliminate trails, you need to redraw the hands every second (for smooth second-hand simulation, even without a second hand) and erase previous positions by drawing over them in the background color (black).

Sign up to request clarification or add additional context in comments.

1 Comment

I have done that but my background is a complicated image and it can't be replaced with black color

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.