← До всіх проєктів
Дисплеї Середній

Метеостанція на кольоровому TFT: ILI9341, TFT_eSPI і DHT22

Кольоровий дисплей 2.8″ 320×240 по SPI перетворює ESP32 на гарну панель. Налаштовуємо TFT_eSPI через User_Setup.h, малюємо рамки й шкали, вирівнюємо текст через datum і оновлюємо цифри без мерехтіння завдяки padding.

Складність
Середній
Час
1 h
Категорія
Дисплеї
Оновлено

Про проєкт

Монохромний OLED гарний, але кольоровий TFT 2.8″ на ILI9341 (320×240, 65 тисяч кольорів) — зовсім інший рівень: панелі приладів, графіки, міні-інтерфейси. На ESP32 для нього найкраща бібліотека — TFT_eSPI від Bodmer, вона вміє апаратний SPI й DMA. Робимо метеостанцію: температура й вологість із DHT22, кольорові цифри та шкали.

Що знадобиться

  • ESP32 DevKit
  • TFT-модуль 2.8″ ILI9341 SPI (червона плата; сенсорна версія теж підійде)
  • Датчик DHT22
  • Бібліотеки TFT_eSPI і DHT sensor library

Схема

TFT ESP32
VCC 3V3
GND GND
CS GPIO15
RESET GPIO4
DC (D/C, RS) GPIO2
MOSI (SDI) GPIO23
SCK GPIO18
LED (підсвітка) 3V3 (або GPIO з ШІМ для яскравості)
MISO (SDO) не обов'язково

DHT22: VCC → 3V3, GND → GND, DATA → GPIO27.

MOSI 23 і SCK 18 — апаратна шина VSPI. Саме вони дають швидкість 40 МГц, а на інших виводах буде програмний SPI, у рази повільніший.

Налаштування TFT_eSPI

TFT_eSPI бере виводи й драйвер не зі скетча, а з файлу User_Setup.h у папці бібліотеки (або з User_Setup_Select.h). Для цієї схеми в ньому мають бути розкоментовані:

#define ILI9341_DRIVER
#define TFT_MOSI 23
#define TFT_SCLK 18
#define TFT_CS   15
#define TFT_DC    2
#define TFT_RST   4
#define LOAD_GLCD
#define LOAD_FONT2
#define LOAD_FONT4
#define SPI_FREQUENCY  40000000

Після оновлення бібліотеки файл перезаписується, тому збережіть свою копію.

Прийоми, які варто знати

  • Datum визначає точку прив'язки тексту: MC_DATUM — центр, TC_DATUM — центр верхнього краю, ML_DATUM — лівий край посередині. Центрувати заголовок у рамці — один рядок коду.
  • Padding. Фоновий колір у setTextColor(колір, фон) затирає старий текст, але коротше число («9.5» після «10.5») залишає «хвіст». setTextPadding(ширина) заповнює фоном всю задану ширину.
  • Не очищайте весь екран щоразу: fillScreen() на 320×240 триває ~30–40 мс і мерехтить. Намалюйте статичну рамку один раз у setup(), а в loop() перемальовуйте тільки змінні частини.
  • Кольори — 16-бітні RGB565: готові TFT_RED, TFT_SKYBLUE тощо або tft.color565(r, g, b).

Код

// Метеостанція: ILI9341 2.8" з TFT_eSPI + DHT22
#include <TFT_eSPI.h>
#include <DHT.h>

TFT_eSPI tft = TFT_eSPI();   // виводи задає User_Setup.h: MOSI 23, SCLK 18, CS 15, DC 2, RST 4
DHT dht(27, DHT22);

// статична частина екрана: малюється один раз
void drawFrame() {
  tft.fillScreen(TFT_BLACK);
  tft.fillRect(0, 0, 320, 34, TFT_NAVY);
  tft.setTextColor(TFT_WHITE, TFT_NAVY);
  tft.setTextDatum(ML_DATUM);
  tft.drawString("ESP32 weather", 10, 17, 2);
  tft.drawRoundRect(8, 44, 148, 150, 10, TFT_DARKGREY);
  tft.drawRoundRect(164, 44, 148, 150, 10, TFT_DARKGREY);
  tft.setTextDatum(TC_DATUM);
  tft.setTextColor(TFT_LIGHTGREY, TFT_BLACK);
  tft.drawString("Temperature", 82, 54, 2);
  tft.drawString("Humidity", 238, 54, 2);
}

// колір цифр залежно від температури
uint16_t tempColor(float t) {
  if (t < 10) return TFT_CYAN;
  if (t < 25) return TFT_GREEN;
  if (t < 30) return TFT_ORANGE;
  return TFT_RED;
}

void drawBar(int x, int y, int w, int h, float frac, uint16_t color) {
  frac = constrain(frac, 0.0, 1.0);
  int filled = (int)(w * frac);
  tft.fillRoundRect(x, y, w, h, 4, TFT_DARKGREY);
  if (filled > 8) tft.fillRoundRect(x, y, filled, h, 4, color);
}

void setup() {
  Serial.begin(115200);
  dht.begin();
  tft.init();
  tft.setRotation(3);   // альбомна орієнтація 320×240, виводи зліва
  drawFrame();
}

void loop() {
  float t = dht.readTemperature();
  float h = dht.readHumidity();
  if (isnan(t) || isnan(h)) {
    tft.setTextColor(TFT_RED, TFT_BLACK);
    tft.setTextDatum(MC_DATUM);
    tft.drawString("Sensor error", 160, 215, 2);
    delay(2000);
    return;
  }
  tft.setTextDatum(MC_DATUM);
  tft.setTextPadding(tft.textWidth("-88.8", 4));   // padding затирає попереднє значення
  tft.setTextColor(tempColor(t), TFT_BLACK);
  tft.drawFloat(t, 1, 82, 108, 4);
  tft.setTextColor(TFT_SKYBLUE, TFT_BLACK);
  tft.drawFloat(h, 0, 238, 108, 4);
  tft.setTextPadding(0);
  tft.setTextColor(TFT_LIGHTGREY, TFT_BLACK);
  tft.drawString("C", 82, 138, 2);
  tft.drawString("%", 238, 138, 2);
  drawBar(20, 165, 124, 14, (t + 10) / 50.0, tempColor(t));   // шкала −10…+40 °C
  drawBar(176, 165, 124, 14, h / 100.0, TFT_SKYBLUE);
  Serial.printf("%.1f C  %.0f %%\n", t, h);
  delay(2000);
}

Типові проблеми

  • Білий екран. Не збігаються виводи в User_Setup.h зі схемою, або обрано не той драйвер (ST7789 замість ILI9341).
  • Дзеркальне чи зсунуте зображення. Спробуйте інший setRotation(). Для «дзеркальних» клонів у User_Setup є TFT_INVERSION_ON/OFF і TFT_RGB_ORDER.
  • Нічого не видно, хоча код працює. Не підключено LED (підсвітку).
  • Кирилиця. Вбудовані шрифти лише латинські. Для української потрібні згенеровані smooth-шрифти (loadFont()) із потрібними символами.