Dołącz do naszej grupy Telegram — tam osobiście odpowiadam na pytania, dzielę się poradami, schematami, kodem i trikami dotyczącymi montażu i konfiguracji.
Перейти в Telegram

NEWS

Podłączenie wyświetlacza GC9A01 do ESP32 S3

 Dzielę się działającym przykładem podłączenia okrągłego wyświetlacza GC9A01 (240×240 px) do mikrokontrolera ESP32-S3 WROOM (30 pinów). Początkowo chciałem użyć mojego ulubionego ESP32-S2 Mini, ponieważ ma wiele wyprowadzeń, ale z tym układem mi się nie udało (prawdopodobnie nie wgrywał się z podłączonym wyświetlaczem), więc przeszedłem na ESP32-S3 — i wszystko od razu zadziałało jak należy.

 Zakładam, że masz już zainstalowane Arduino IDE. Do pracy z wyświetlaczem potrzebna będzie biblioteka TFT_eSPI. Po jej zainstalowaniu otwórz plik konfiguracyjny User_Setup.h, który znajduje się w ścieżce:

C:\Users\You\Documents\Arduino\libraries\TFT_eSPI

W tym pliku ustaw następujące parametry:

#define GC9A01_DRIVER

#define TFT_WIDTH  240
#define TFT_HEIGHT 240

#define TFT_CS     15  // Chip Select
#define TFT_DC     23  // Data/Command
#define TFT_RST    4   // Reset
#define TFT_MOSI   12  // SPI Data
#define TFT_SCLK   14  // SPI Clock

#define LOAD_GLCD
#define LOAD_FONT2
#define LOAD_FONT4
#define LOAD_FONT6
#define LOAD_FONT7
#define LOAD_FONT8
#define LOAD_GFXFF

#define SPI_FREQUENCY  27000000

#define USER_SETUP_ID 931

 Próbowałem wgrać obraz tarczy zegara jako tablicę, ale jakość była zbyt pikselowa. Ostatecznie zdecydowałem się rysować grafikę bezpośrednio w kodzie projektu — wyszło elastycznie i schludnie.

 Poniżej — schemat podłączenia:

Schemat podłączenia GC9A01 do ESP32-S3

 Podaję również kod podłączenia mikrokontrolera do Twojej sieci Wi-Fi i pobierania czasu z internetu. W kodzie należy podać swój SSID i hasło, a w razie potrzeby zmienić strefę czasową.

 Do GPIO 22 można podłączyć przycisk — po podaniu niskiego poziomu na ten pin wyświetlanie czasu przełącza się między wersją analogową a cyfrową.



#include <wifi.h>
#include <time.h>
#include <tft_espi.h>

TFT_eSPI tft = TFT_eSPI();

// Настройки часов
#define CENTER_X 120
#define CENTER_Y 120
#define RADIUS 100
#define DOT_RADIUS 3
#define TRACK_RADIUS 110

// Пины
#define PIN_BUTTON 22
#define DEBOUNCE_DELAY 200

// Wi-Fi настройки
const char* ssid = "YouWiFi";
const char* password = "YouPASS";
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 3 * 3600;
const int daylightOffset_sec = 0;

// Переменные времени
struct tm timeinfo;
uint8_t last_second = 61;
bool showAnalogClock = true;

// Позиции стрелок
int16_t last_hx, last_hy, last_mx, last_my;

// Прототипы функций
void drawClockFace();
void updateAnalogClock(uint8_t prevSecond);
void drawDotAtSecond(uint8_t sec, uint16_t color);
void displayDigitalTime();

void setup() {
  Serial.begin(115200);
  pinMode(PIN_BUTTON, INPUT_PULLUP);

  tft.init();
  tft.setRotation(2);
  tft.fillScreen(TFT_BLACK);

  tft.setTextColor(TFT_WHITE, TFT_BLACK);
  tft.setTextDatum(MC_DATUM);
  tft.setTextSize(2);
  tft.drawString("CONNECTING...", CENTER_X, CENTER_Y);

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  tft.fillRect(CENTER_X - 80, CENTER_Y - 10, 160, 20, TFT_BLACK);
  tft.drawString("CONNECTED!", CENTER_X, CENTER_Y);
  delay(1000);

  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  while (!getLocalTime(&timeinfo)) {
    Serial.println("Waiting for time...");
    delay(500);
  }

  drawClockFace();
}

void loop() {
  static uint32_t lastUpdate = 0;

  if (digitalRead(PIN_BUTTON) == LOW) {
    delay(DEBOUNCE_DELAY);
    if (digitalRead(PIN_BUTTON) == LOW) {
      showAnalogClock = !showAnalogClock;
      tft.fillScreen(TFT_BLACK);
      if (showAnalogClock) drawClockFace();
      while (digitalRead(PIN_BUTTON) == LOW) delay(10);
    }
  }

  if (millis() - lastUpdate >= 1000) {
    lastUpdate = millis();

    if (getLocalTime(&timeinfo)) {
      if (timeinfo.tm_sec != last_second) {
        uint8_t prev_second = last_second;
        last_second = timeinfo.tm_sec;

        if (showAnalogClock) {
          updateAnalogClock(prev_second);
        } else {
          displayDigitalTime();
        }
      }
    }
  }
}

void drawClockFace() {
  tft.fillScreen(TFT_BLACK);
  tft.drawCircle(CENTER_X, CENTER_Y, RADIUS, TFT_WHITE);

  // Цифры 12, 3, 6, 9
  const char* labels[] = {"12", "3", "6", "9"};
  int angles[] = {270, 0, 90, 180};  // поправлено

  tft.setTextSize(2);
  tft.setTextColor(TFT_WHITE, TFT_BLACK);
  tft.setTextDatum(MC_DATUM);

  for (int i = 0; i < 4; i++) {
    float angle = angles[i] * PI / 180.0;
    int x = CENTER_X + (RADIUS - 25) * cos(angle);
    int y = CENTER_Y + (RADIUS - 25) * sin(angle);
    tft.drawString(labels[i], x, y);
  }

  // Минутные метки
  for (int i = 0; i < 60; i++) {
    float angle = i * 6 * PI / 180;
    int length = (i % 5 == 0) ? 12 : 6;
    int x1 = CENTER_X + (RADIUS - length) * cos(angle);
    int y1 = CENTER_Y + (RADIUS - length) * sin(angle);
    int x2 = CENTER_X + RADIUS * cos(angle);
    int y2 = CENTER_Y + RADIUS * sin(angle);
    tft.drawLine(x1, y1, x2, y2, (i % 5 == 0) ? TFT_WHITE : TFT_DARKGREY);
  }
}

void updateAnalogClock(uint8_t prevSecond) {
  // Стираем старые стрелки и точку
  tft.drawLine(CENTER_X, CENTER_Y, last_hx, last_hy, TFT_BLACK);
  tft.drawLine(CENTER_X, CENTER_Y, last_mx, last_my, TFT_BLACK);
  drawDotAtSecond(prevSecond, TFT_BLACK);

  // Часовая стрелка
  float hourAngle = (timeinfo.tm_hour % 12 + timeinfo.tm_min / 60.0) * PI / 6;
  last_hx = CENTER_X + RADIUS * 0.5 * sin(hourAngle);
  last_hy = CENTER_Y - RADIUS * 0.5 * cos(hourAngle);

  // Минутная стрелка
  float minAngle = timeinfo.tm_min * PI / 30;
  last_mx = CENTER_X + RADIUS * 0.7 * sin(minAngle);
  last_my = CENTER_Y - RADIUS * 0.7 * cos(minAngle);

  // Рисуем часовую и минутную стрелки
  tft.drawLine(CENTER_X, CENTER_Y, last_hx, last_hy, TFT_WHITE);
  tft.drawLine(CENTER_X, CENTER_Y, last_mx, last_my, TFT_WHITE);

  // Рисуем текущую точку-секунду
  drawDotAtSecond(timeinfo.tm_sec, TFT_RED);
}

void drawDotAtSecond(uint8_t sec, uint16_t color) {
  float angle = sec * PI / 30;
  int x = CENTER_X + TRACK_RADIUS * sin(angle);
  int y = CENTER_Y - TRACK_RADIUS * cos(angle);
  tft.fillCircle(x, y, DOT_RADIUS, color);
}

void displayDigitalTime() {
  static char timeStr[9];
  sprintf(timeStr, "%02d:%02d:%02d", timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);

  tft.setTextSize(3);
  tft.setTextColor(TFT_WHITE, TFT_BLACK);
  tft.setTextDatum(MC_DATUM);
  tft.drawString(timeStr, CENTER_X, CENTER_Y);
}