Графический IPS дисплей с драйвером Sitronix ST7789
Разрешение | 240*240 пикселей |
Глубина цвета | 18 бит (262 144 цвета)* |
Диагональ | 1,3 дюйма |
Размер активной области (матрица) | 23,4*23,4 мм |
Количество выведенных контактов | 24 (под разъем) или 12 (под пайку) |
Шина передачи данных | Intel8080 (параллельный 8 бит), SPI (одноканальный) |
Подсветка | 2 белых светодиода |
Особенности:
- Драйвер TFT дисплеев ST7789 позволяет выводить 262 тысячи цветов, используя 18 бит для кодирования цвета каждого пикселя, используя 6-6-6 бит на цвета R-G-B. 18-битные изображения хранятся и отправляются в виде 24-битных. Из-за увеличенного объема каждого пикселя, изображения хранятся в виде массивов 32-битных чисел, занимают больше памяти и дольше передаются, поэтому часто используется дополнительный режим работы драйвера с глубиной 16 бит и кодированием 5-6-5.
- Дисплей имеет два типа подключения к микроконтроллеру: параллельный (i8080) или последовательный (SPI). В теории параллельный интерфейс должен ускорить передачу данных более чем в 8 раз, по сравнению с SPI. В таком режиме работы оправдано использование 18 бит для цвета. Обратите внимание на отсутствие выводов для параллельного интерфейса в версии дисплея "под пайку".
Чертеж дисплея "под пайку"
Чертеж дисплея "под разъем"
Распиновка дисплея "под пайку"
Распиновка дисплея "под разъем"
Покупка
На Aliexpress продаются дисплеи обоих типов без платы, а также готовые модули дисплея двух видов: с параллельным интерфейсом и без него.
Используемая библиотека
Для ESP32, ESP32-S2, ESP32-S3, ESP32-C3 рекомендуется использовать библиотеку LovyanGFX. Данная библиотека предоставляет очень широкий функционал для работы с графикой и вывода изображений на дисплей. По проведенным тестам LovyanGFX имеет скорость передачи данных на дисплей до 3 раз выше, чем у Adafruit ST7789. LovyanGFX позволяет использовать многие аппаратные интерфейсы периферии в микроконтроллерах Espressif, например Direct Memory Access (DMA), благодаря которому вероятно и достигается прирост производительности в режиме SPI. Также библиотека позволяет взаимодействовать с дисплеем через параллельный интерфейс.
Библиотека доступна в Arduino IDE, ESP-IDF, PlatformIO.
#include <Arduino.h> // Подключение библиотеки Arduino необходмо в PldtformIO
#include <LovyanGFX.hpp> // Подключение Библиотеки Lovyan GFX
#include <SPI.h> // Подключение Библиотеки SPI
#define SCK 7
#define MOSI 5
#define DC 3
#define CS 9
#define RST 11
class LGFX : public lgfx::LGFX_Device
{
lgfx::Panel_ST7789 _panel_instance; // Предлагается выбрать контроллер дисплея
lgfx::Bus_SPI _bus_instance; // Выбрать тип шины
public:
LGFX(void)
{
{
auto cfg = _bus_instance.config();
cfg.spi_host = SPI2_HOST; // Выбор номера шины SPI в микроконтроллере
cfg.freq_write = 80000000; // Частота передачи данных
cfg.dma_channel = SPI_DMA_CH_AUTO; // Канал DirectMemoryAccess
cfg.pin_sclk = SCK;
cfg.pin_mosi = MOSI;
cfg.pin_dc = DC;
_bus_instance.config(cfg);
_panel_instance.setBus(&_bus_instance);
}
{
auto cfg = _panel_instance.config();
cfg.pin_cs = CS;
cfg.pin_rst = RST;
cfg.panel_width = 240;
cfg.panel_height = 240;
cfg.invert = true; // Инвертирование цвета (необходимо при неправильном отображении цвета)
_panel_instance.config(cfg);
}
setPanel(&_panel_instance);
}
};
LGFX display;
void setup() {
display.init();
display.setRotation(2); // Поворот изображения на 180 градусов
uint32_t timer = micros(); // Таймер для измерения скорости работы
display.clear(TFT_BLUE);
timer = micros()-timer;
// Время за которое дисплей залит цветом равно времени передачи цвета для каждого пикселя на дисплее
display.setTextColor(TFT_WHITE, TFT_BLUE); // Первое значение - цвет текста, второе - цвет фона
display.println("Hello, world!");
display.printf("Display clear (fill) takes: %f ms", timer / 1000.0); // Поддерживается Printf
}
void loop() {
}
Пример 1 текст
#include <Arduino.h> #include <LovyanGFX.hpp> #include <SPI.h> #include <WiFi.h> class LGFX : public lgfx::LGFX_Device { lgfx::Panel_ST7789 _panel_instance; lgfx::Bus_SPI _bus_instance; public: LGFX(void) { { auto cfg = _bus_instance.config(); cfg.spi_host = SPI2_HOST; cfg.freq_write = 80000000; cfg.dma_channel = SPI_DMA_CH_AUTO; cfg.pin_sclk = 7; cfg.pin_mosi = 5; cfg.pin_dc = 3; _bus_instance.config(cfg); _panel_instance.setBus(&_bus_instance); } { auto cfg = _panel_instance.config(); cfg.pin_cs = 9; cfg.pin_rst = 11; cfg.panel_width = 240; cfg.panel_height = 240; cfg.invert = true; _panel_instance.config(cfg); } setPanel(&_panel_instance); } }; #include "USB.h" USBCDC USBSerial; #include <GyverNTP.h> GyverNTP ntp(3); LGFX display; static LGFX_Sprite canvas(&display); uint16_t* frameBuffer; void drawClock(); void setup() { USB.begin(); USBSerial.begin(); display.setColorDepth(18); display.init(); canvas.setPsram(false); canvas.createSprite(240,240); display.setRotation(2); uint32_t timer = micros(); display.clear(TFT_BLUE); timer = micros()-timer; display.setTextColor(TFT_WHITE, TFT_BLUE); display.printf("Color Depth: %d Timer: %f\n", display.getColorDepth(), timer/1000.0); display.printf("Display clear (fill) takes: %f ms\n", timer / 1000.0); display.print("Connecting to WiFi"); WiFi.begin("SSID", "PASSWORD"); while (WiFi.status() != WL_CONNECTED) { delay(100); display.print("."); } display.println(); display.println("Connected!"); ntp.setHost("ntp.msk-ix.ru"); ntp.begin(); ntp.tick(); ntp.updateNow(); delay(500); display.clear(TFT_BLACK); canvas.setTextColor(TFT_GREEN, TFT_BLACK); canvas.setFont(&fonts::Orbitron_Light_24); canvas.setTextSize(1); } void loop() { ntp.tick(); canvas.clear(TFT_BLACK); drawClock(); } void drawClock() { canvas.setColor(TFT_CYAN); int halfScreen = display.width() >> 1; int clockRad = halfScreen - 40; canvas.drawCircle(halfScreen, halfScreen, clockRad); canvas.drawCircle(halfScreen, halfScreen, clockRad+1); for(int i = 0; i < 12; i++) { float angle = (i / 12.0) * PI * 2.0 + HALF_PI; int x1 = halfScreen - cos(angle) * clockRad; int y1 = halfScreen - sin(angle) * clockRad; int x2 = halfScreen - cos(angle) * (clockRad - 20); int y2 = halfScreen - sin(angle) * (clockRad - 20); canvas.setColor(TFT_CYAN); canvas.drawWideLine(x1, y1, x2, y2, 1, TFT_CYAN); x1 = halfScreen - cos(angle) * (clockRad+25) - (canvas.textWidth(String(i)) >> 1); y1 = halfScreen - sin(angle) * (clockRad+25) - (canvas.fontHeight()>>1); canvas.setCursor(x1, y1); USBSerial.printf("num: %d len: %d\n", i, canvas.textWidth(String(i))); canvas.print(String(i)); } for(int i = 0; i < 60; i++) { float angle = (i / 60.0) * PI * 2.0 + HALF_PI; int x1 = halfScreen - cos(angle) * (clockRad - 1); int y1 = halfScreen - sin(angle) * (clockRad - 1); int x2 = halfScreen - cos(angle) * (clockRad - 10); int y2 = halfScreen - sin(angle) * (clockRad - 10); canvas.setColor(TFT_CYAN); canvas.drawWideLine(x1, y1, x2, y2, 1, TFT_CYAN); } int hour = ntp.hour(); int minute = ntp.minute(); int ms = ntp.second()*1000+ntp.ms(); canvas.setColor(TFT_RED); float angle = (ms / 60000.0) * PI * 2.0 + HALF_PI; int x1 = halfScreen - cos(angle) * (clockRad-5); int y1 = halfScreen - sin(angle) * (clockRad-5); canvas.drawWideLine(x1, y1, halfScreen, halfScreen, 1.2, TFT_RED); canvas.setColor(TFT_GREEN); angle = (minute / 60.0) * PI * 2.0 + HALF_PI; x1 = halfScreen - cos(angle) * (clockRad-30); y1 = halfScreen - sin(angle) * (clockRad-30); canvas.drawLine(halfScreen, halfScreen, x1, y1); canvas.drawWideLine(x1, y1, halfScreen, halfScreen, 2, TFT_GREEN); canvas.setColor(TFT_MAGENTA); angle = (hour / 12.0) * PI * 2.0 + HALF_PI; x1 = halfScreen - cos(angle) * (clockRad-50); y1 = halfScreen - sin(angle) * (clockRad-50); canvas.drawWideLine(x1, y1, halfScreen, halfScreen, 2, TFT_MAGENTA); canvas.pushRotatedWithAA(0, -1); }
пример 2 часы