↩ All projects and sketches Deze pagina in het Nederlands
ESP8266 · SPI · ST7789

ST7789 SPI color display: NTP clock with ESP8266

ST7789 SPI color display (320x240px) connected to an ESP8266
2 inch display on Amazon — 320×240px, high refresh rate

A sharp color screen with a high refresh rate, driven with TFT_eSPI — with a WiFi status indicator and flicker-free partial updates.

What do you need for this?

SPI display ST7789 (320×240px) + ESP8266

This display has a resolution of 320 × 240 pixels, providing a very sharp image. The display has a high refresh rate, you could display — if desired — hundredths of a second. The fastest and most versatile library for such displays is TFT-eSPI (Bodmer). It includes numerous examples, analog clocks, fonts, sprites, various gauges, the game "pong", graphs and fractals.

The code contains about 10 lines more than that of the e-paper, because it provides functions for the synchronization interval and the callback of the synchronization. Because the TFT_eSPI library supports multiple displays, you need to set up a file "User_Setup.h" (or choose a predefined setup from the "User_Setups" folder of the TFT_eSPI library).

Connections:

ESP8266	|   2 inch Waveshare (ST7739V driver) | 2.4 inch Waveshare (ILI9341 driver)
===============================
GND	------- GND
3V3	------- VCC
D3	------- DC
RST	------- RST
D5	------- CLK
D7	------- DIN
D8	------- CS
        ------- BL (not connected - niet verbonden)

Sketch:

#include <WiFiManager.h>  // https://github.com/tzapu/WiFiManager/
#include <TFT_eSPI.h>     // https://github.com/Bodmer/TFT_eSPI
#include <coredecls.h>    // ESP8266 core

struct tm tInfo;  // https://cplusplus.com/reference/ctime/tm/
char days[7][10] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
byte previousHour = 24, previousMinute = 61, previousSecond;
String previousWeekDay;

TFT_eSPI tft = TFT_eSPI();
WiFiManager myWiFi;

void setup() {
  Serial.begin(115200);
  tft.init();
  tft.setRotation(1);
  tft.fillScreen(TFT_BLACK);  // clear screen from any previous session
  myWiFi.setAPCallback(showMessageNoConnection);
  myWiFi.autoConnect("ST7789_ESP");
  settimeofday_cb(esp8266NtpCallback);  // we need "#include <coredecls.h>" for this
  tft.fillScreen(TFT_BLACK);            // clear screen from "showMessageNoConnection" messages
  configTzTime(PSTR("CET-1CEST,M3.5.0,M10.5.0/3"), "be.pool.ntp.org");
  tft.setTextColor(TFT_CYAN);
  tft.setTextSize(2);
  tft.setCursor(117, 14, 7);
  tft.print(":");
}

void loop() {
  showChangesOnDisplay();
  WiFi.isConnected() ? showLogoWiFi(TFT_GREEN) : showLogoWiFi(TFT_RED);
}

void showTime(char timeChar[2], int leftS, int top, bool large) {
  tft.setCursor(leftS, top, 7);  // 7 is a built in font
  tft.setTextColor(TFT_CYAN, TFT_BLACK);
  tft.setTextSize(large + 1);
  tft.print(timeChar);
  tft.setTextSize(1);
}

void showChangesOnDisplay() {                             // this function divides the screen changes
  char hourChar[3], minChar[3], secChar[3], theDate[11];  // into chunks to prevent flicker
  getLocalTime(&tInfo);
  if (tInfo.tm_sec != previousSecond) {
    sprintf(secChar, "%02d", tInfo.tm_sec);  // format 2 digits decimal
    showTime(secChar, 256, 61, false);
    previousSecond = tInfo.tm_sec;
  }
  if (tInfo.tm_min != previousMinute) {
    sprintf(minChar, "%02d", tInfo.tm_min);
    showTime(minChar, 131, 14, true);
    previousMinute = tInfo.tm_min;
  }
  if (previousHour != tInfo.tm_hour) {
    sprintf(hourChar, "%02d", tInfo.tm_hour);
    showTime(hourChar, -2, 14, true);
    previousHour = tInfo.tm_hour;
     if (previousWeekDay != days[tInfo.tm_wday]) {
      tft.fillRect(0, 134, 320, 106, TFT_BLACK);
      tft.setTextColor(TFT_YELLOW);
      tft.setFreeFont(&FreeSansBold24pt7b);  // custom font. &FreeMonoBold24pt7b is possible too
      tft.drawCentreString(days[tInfo.tm_wday], 160, 136, 1);
      tft.drawRoundRect(0, 124, 320, 70, 3, TFT_WHITE);
      tft.setTextColor(TFT_GREEN);
      strftime(theDate, sizeof(theDate), "%d-%m-%G", &tInfo);
      tft.drawCentreString(theDate, 160, 202, 1);
      tft.setTextFont(7);
      previousWeekDay = days[tInfo.tm_wday];
    }
  }
}

void showLogoWiFi(int myColor) {
  tft.fillCircle(294, 30, 6, myColor);
  for (byte tel = 0; tel < 3; tel++) {
    tft.drawSmoothArc(294, 32, 30 - tel * 7, 28 - tel * 7, 135, 225, myColor, myColor, true);
  }
}

void showMessageNoConnection(WiFiManager* myWiFi) {
  tft.setCursor(0, 0, 4);
  tft.setTextColor(TFT_GREEN, TFT_BLACK);
  tft.print(F("\nWiFi: no connection\nConnect to hotspot:\n"));
  tft.print(F("ST7789_ESP and open\na browser at address \n192.168.4.1\n"));
  tft.print(F("to enter network name\nand password"));
}

void esp8266NtpCallback(bool from_sntp) {  // in setup: "settimeofday_cb(esp8266NtpCallback)";
  if (from_sntp) Serial.printf("\n*** NTP Sync ***\n%s \n", getenv("TZ"));
}

uint32_t sntp_update_delay_MS_rfc_not_less_than_15000() {  // declare only, unnecessary to call this function
  return 4 * 60 * 60 * 1000UL;                             // SNTP sync every 4 hr
}

You'll find among the predefined "User_Setups" the most common configurations. For example the "Setup18_ST7789.h" in this folder can be used for this project. Should the displayed colors not be correct (red and green swapped), you can set the 3rd line active and comment out the 4th line:

//            ST7789
#define USER_SETUP_INFO "User_Setup"
#define ST7789_DRIVER 
// #define TFT_RGB_ORDER TFT_RGB  // Colour order Red-Green-Blue
#define TFT_RGB_ORDER TFT_BGR  // Colour order Blue-Green-Red
#define TFT_HEIGHT 320 // ST7789 240 x 320
#define TFT_CS   PIN_D8  // Chip select control pin D8
#define TFT_DC   PIN_D3  // Data Command control pin
#define TFT_RST  -1    // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V
// fonts die je niet gebruikt best uitcommenten om FLASH te besparen
#define LOAD_GLCD   // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
#define LOAD_FONT2  // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
#define LOAD_FONT4  // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
#define LOAD_FONT6  // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
#define LOAD_FONT7  // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-.
#define LOAD_FONT8  // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT
#define LOAD_GFXFF  // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts

#define SPI_FREQUENCY  27000000
#define SPI_READ_FREQUENCY  20000000
#define SPI_TOUCH_FREQUENCY  2500000
TFT_eSPI — attention For easy overview, we modify the content of the file "User_Setup.h" directly. This is a quick and dirty solution if you want to get one display working and see quick results.

If you use multiple displays and/or don't want to lose data when installing a new copy of this library, you'd better follow the tip from the designer of the library: github.com/Bodmer/TFT_eSPI/#tips.

You can comment out the entire contents of "User_Setup.h" if you work this way.

More displays with the ESP8266 / ESP32

Curious about other displays? Check out the full overview, including TM1637, SSD1306, SH1106, ST7735, e-paper and integrated displays like the Lilygo T-Display and the Waveshare ESP32-S3.