Отображение информации это один из важнейших аспектов автоматизированных систем.
В IoT системах роль терминала чаще всего выполняет смартфон или компьютер. Но иногда и в умном доме удобно иметь автономную операторскую панель
На сайте Makerfabs в разделе OpenHardware появились интеллектуальные дисплеи Sunton 4.3″, 5″ и 7″ на базе ESP32S3. Из них и герой обзора — панель ESP32-8048S070, купленная на Алиэкспресс за 3000 руб. вместе с доставкой.
Чем мне приглянулось данное устройство:
- Использование нового ESP32S3 позволило подключить дисплей по аппаратному параллельному 16-ти битному интерфейсу, что позволило достичь неплохой скорости выдачи информации на экран (по сравнению с тем же SPI)
- В отличие тех же дисплеев Nextion, обязательно подключаемых к внешнему контроллеру, данный дисплей может работать как автономное устройство
- Открытая понятная схемотехника и программирование напрямую в Arduino IDE или PlatformIO (Те же Nextion или DWIN используют для программирования свой проприоритарный софт)
- Ну и немаловажный фактор для DIY, это цена.
Ну а что там с конкурентами?
Свел в табличку доступные аналогичные дисплеи. Первые два, Nextion и DWIN, программируются своим специализированным софтом и работают только с внешним контроллером по UART интерфейсу. Вывести на них произвольную картинку из интернета не так и просто.
Дисплей от ELECROW очень близок к обозреваемому по схемотехнике и функционалу. Только при покупке на Алиэкспресс дороже почти в полтора раза.
Производитель | NEXTION | DWIN | ELECROW | MAKERFABS |
Марка | NX8048T070 | DMG80480C070 | DIS06043H | ESP32-8048S070 |
Экран |
TFT 800×600 |
|||
Интерфейс | RGB565 16бит | RGB666 18бит | RGB565 16бит | RGB565 16бит |
Сенсор | Резистивный | Емкостной | Емкостной | Емкостной |
MPU | STM32 | T5L ASIC | ESP32S3 N4R8 | ESP32S3 N16R8 |
Программирование | Nextion Editor | DWIN UI Designer | LVGL, LovyanGFX | LVGL, Arduino GFX |
Цена на Али (*) | 9137,59 | 3427,80 | 4466,73 | 3151,68 |
(*) — Цена с доставкой в Пермь на момент написания статьи
Железо
- Микроконтроллер — ESP32-S3-WROOM-1-N16R8 (16Мб flash + 8Мб PSRAM)
- Сенсорный контроллер — емкостной пятиточечный GT911 с интерфейсом I2C распаянный на шлейфе сенсорной панели
- Дисплей TFT 7.0″ 65K цветов 800×480 с драйвером EK9716 c интерфейсом RGB565 16 бит
- ЦАП с усилителем MAX98357
- USB/UART CH320C (аналог «народного» CH340G но без внешнего кварца) с USB-C
- Два импульсных стабилизатора — 3.3В для MCU и питание дисплея
- Импульсный драйвер подсветки, похожий на MP3202
Дополнительная периферия:
- Разъем UART0 (Параллельно CH340) HC 1.25 x 4
- Разъем под TF карта (SPI IO10, IO11, IO12, IO13)
- Разъем SPI (IO10, IO11, IO12, IO13) HC 1.25 x 4
- Разъем UART (IO17, IO18) + USB (IO19, IO20) HC 1.25 x 4
- Разъем I2C (IO17, IO18) HC 1.25 x 4
- Разъем I2C (IO17, IO18) SH 1.0 x 4
- Разъем на внешний динамик от ЦАП JST 1.25 x 2
Принципиальная схема
Софт
Отдельного WYSISYG редактора интерфейса, как у NEXTION, у данного дисплея нет. Хотя можно использовать Squareline Studio, генерирующий код для фреймвока LVGL. Вместо этого предлагается программирование в среде Arduino IDE. В магазине есть ссылка на папку на гугл-диске с файлами для всей линейки дисплеев данного производителя.
В данном архиве кроме руководства и схем имеются бинарники прошивки, драйвера и библиотеки с примерами, к слову, довольно старые.
- Графическая библиотека RGB Parallel 16 bit Arduino_GFX от Moononournatio (форк Adafruit Arduino_GFX).
- Библиотека для работы с емкостным дисплеем — TAMC_GT911 или GT911 Touch library
- Библиотека для работы с ЦАП MAX98357 ESP32-audioI2S
- Ну и очень мощная библиотека для разработки пользовательского интерфейса LVGL
Последние версии ставятся из менеджера библиотек Arduino IDE
В полученный дисплей загружен пример Widgets Demo из проекта LVGL
Программирование
Для программирования нужно взять последнюю ESP32 Core for Arduino IDE с поддержкой новых модулей ESP32S2, ESP32S3 и ESP32C3
Если взять библиотеки из архива, то в принципе, примеры собираются и работают. Но когда я поставил последнюю версию библиотеки Arduino_GFX от Moononournatio, выяснилось, что формат функций работы с шиной RGB 16 bit поменялся. Можно конечно было остаться на старой библиотеке, но есть вероятность рано или поздно получить несовместимость. И придется программировать в старой IDE со старым набором библиотек. Лучше разобраться.
Итак, в старой версии мы имеем такое определение шины и экземпляра GFX с пинами нашего дисплея:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
Arduino_ESP32RGBPanel *bus = new Arduino_ESP32RGBPanel( GFX_NOT_DEFINED /* CS */, GFX_NOT_DEFINED /* SCK */, GFX_NOT_DEFINED /* SDA */, 41 /* DE */, 40 /* VSYNC */, 39 /* HSYNC */, 42 /* PCLK */, 14 /* R0 */, 21 /* R1 */, 47 /* R2 */, 48 /* R3 */, 45 /* R4 */, 9 /* G0 */, 46 /* G1 */, 3 /* G2 */, 8 /* G3 */, 16 /* G4 */, 1 /* G5 */, 15 /* B0 */, 7 /* B1 */, 6 /* B2 */, 5 /* B3 */, 4 /* B4 */ ); // option 1: // 7? 50PIN 800*480 Arduino_RPi_DPI_RGBPanel *gfx = new Arduino_RPi_DPI_RGBPanel( bus, 800 /* width */, 0 /* hsync_polarity */, 210 /* hsync_front_porch */, 30 /* hsync_pulse_width */, 16 /* hsync_back_porch */, 480 /* height */, 0 /* vsync_polarity */, 22 /* vsync_front_porch */, 13 /* vsync_pulse_width */, 10 /* vsync_back_porch */, 1 /* pclk_active_neg */, 16000000 /* prefer_speed */, true /* auto_flush */); |
В документации по нашему интерфейсу видим новый формат конструктора Arduino_ESP32RGBPanel. Ну и вместо класса Arduino_RPi_DPI_RGBPanel, мипользуемого во всех примерах, нужно теперь применять Arduino_RGB_Display. Итоговое объявление получилось таким:
1 2 3 4 5 6 7 8 9 |
Arduino_ESP32RGBPanel *rgbpanel = new Arduino_ESP32RGBPanel( 41 /* DE */, 40 /* VSYNC */, 39 /* HSYNC */, 42 /* PCLK */, 14 /* R0 */, 21 /* R1 */, 47 /* R2 */, 48 /* R3 */, 45 /* R4 */, 9 /* G0 */, 46 /* G1 */, 3 /* G2 */, 8 /* G3 */, 16 /* G4 */, 1 /* G5 */, 15 /* B0 */, 7 /* B1 */, 6 /* B2 */, 5 /* B3 */, 4 /* B4 */, 0 /* hsync_polarity */, 210 /* hsync_front_porch */, 30 /* hsync_pulse_width */, 16 /* hsync_back_porch */, 0 /* vsync_polarity */, 22 /* vsync_front_porch */, 13 /* vsync_pulse_width */, 10 /* vsync_back_porch */); Arduino_RGB_Display *gfx = new Arduino_RGB_Display(800, 480, rgbpanel); |
Теперь любой пример можно собрать заменив параметры конструктора класса дисплея.
Примеры и LvglWidgets и lvgl_music_gt911_7.0 собираются только после того как папка demos библиотеки LVGL помещается внутрь src. Ну и файл lv_cinfig.h из каталога с примером нужно поместить в корневой каталог всех библиотек Arduino
Для сборки всех скетчев Arduino для данного дисплея нужно выбрать в менеджере плат ESP32S3 Dev Module, а в меню модуля выбрать Flash Size — 16MB (128Mb) и PSRAM — OPI PSRAM
Скетч отображения картинки
Для начала нужно преобразовать саму картинку в двухмерную матрицу (768000 байт на картинку 800х460 16бит/пиксел). Для этого рyководство AdafruitGFX отсылает на онлайновый сервис Image2Cpp.
Полученный результат нужно вставить в файл Img.h И положить его рядом с файлом скетча. Сам скетч предельно простой
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#include <Arduino_GFX_Library.h> #include "Img.h" //Файл с картинкой #define TFT_BL 2 Arduino_ESP32RGBPanel *rgbpanel; Arduino_RGB_Display *gfx; void setup() { Serial.begin(115200); delay(1000); // Инициализация дисплея rgbpanel = new Arduino_ESP32RGBPanel( 41 /* DE */, 40 /* VSYNC */, 39 /* HSYNC */, 42 /* PCLK */, 14 /* R0 */, 21 /* R1 */, 47 /* R2 */, 48 /* R3 */, 45 /* R4 */, 9 /* G0 */, 46 /* G1 */, 3 /* G2 */, 8 /* G3 */, 16 /* G4 */, 1 /* G5 */, 15 /* B0 */, 7 /* B1 */, 6 /* B2 */, 5 /* B3 */, 4 /* B4 */, 0 /* hsync_polarity */, 210 /* hsync_front_porch */, 30 /* hsync_pulse_width */, 16 /* hsync_back_porch */, 0 /* vsync_polarity */, 22 /* vsync_front_porch */, 13 /* vsync_pulse_width */, 10 /* vsync_back_porch */); gfx = new Arduino_RGB_Display(800, 480, rgbpanel); gfx->begin(); pinMode(TFT_BL, OUTPUT); digitalWrite(TFT_BL, HIGH); gfx->fillScreen(BLACK); // Выдача картинки с подсчетом затраченного времени uint32_t ms = millis(); gfx->draw16bitRGBBitmap(0,0,(uint16_t *)sav001,800,480); ms = millis() - ms; Serial.printf("Load IMG %ld ms\n",ms); } void loop() { delay(1000); } |
Выдача картинки записанной флэш-памяти ESP32 происходит за 61мс, что дает скорость выдачи примерно 12 кадров/сек
Скетч проверки сенсорного экрана
Данный скетч реализует пять простейших экранных кнопок с фиксацией нажатия
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
#include <Arduino_GFX_Library.h> #include <Wire.h> #include <TAMC_GT911.h> #define TFT_BL 2 #define BTN_HEIGHT 100 #define BTN_WIDTH 150 struct btn_t { int x; int y; char text[10]; bool enable; } btns[] = { {0,100,"BTN01",false}, {160,100,"BTN02",false}, {320,100,"BTN03",false}, {480,100,"BTN04",false}, {640,100,"BTN05",false} }; int btn_n = 5; Arduino_ESP32RGBPanel *rgbpanel; Arduino_RGB_Display *gfx; TAMC_GT911 tp(19, 20, -1, 38, 800, 480); void setup() { Serial.begin(115200); //Инициализация порта отладки delay(1000); tp.begin(); // Инициализация сенсорного экрана tp.setRotation(ROTATION_INVERTED); // Инициализация дисплея rgbpanel = new Arduino_ESP32RGBPanel( 41 /* DE */, 40 /* VSYNC */, 39 /* HSYNC */, 42 /* PCLK */, 14 /* R0 */, 21 /* R1 */, 47 /* R2 */, 48 /* R3 */, 45 /* R4 */, 9 /* G0 */, 46 /* G1 */, 3 /* G2 */, 8 /* G3 */, 16 /* G4 */, 1 /* G5 */, 15 /* B0 */, 7 /* B1 */, 6 /* B2 */, 5 /* B3 */, 4 /* B4 */, 0 /* hsync_polarity */, 210 /* hsync_front_porch */, 30 /* hsync_pulse_width */, 16 /* hsync_back_porch */, 0 /* vsync_polarity */, 22 /* vsync_front_porch */, 13 /* vsync_pulse_width */, 10 /* vsync_back_porch */); gfx = new Arduino_RGB_Display(800, 480, rgbpanel); gfx->begin(); pinMode(TFT_BL, OUTPUT); //Включение дисплея digitalWrite(TFT_BL, HIGH); gfx->fillScreen(BLACK); for( int i=0; i<btn_n; i++)displayBTN(i); //Начальная отрисовка кнопок } uint32_t ms0 = 0; void loop() { uint32_t ms = millis(); tp.read(); if( ms0 == 0 || ms - ms0 > 500 ){ // Убираем дребезг виртуальных кнопок (задержка 0.5 сек) if (tp.isTouched){ ms0 = ms; int x = tp.points[0].x; int y = tp.points[0].y; int n_new = -1; int n_old = -1; for( int i=0; i<btn_n; i++){ if( btns[i].enable )n_old = i; if( x > btns[i].x && x < btns[i].x+BTN_WIDTH && y > btns[i].y && y < btns[i].y+BTN_HEIGHT )n_new = i; } Serial.printf("x=%d y=%d old=%d new=%d ms=%ld\n",x,y,n_old,n_new,ms0); if( n_new >= 0 && n_old == n_new ){ //Если нажата та же кнопка, инвертируем состояние btns[n_new].enable = !btns[n_new].enable; displayBTN(n_new); } else if( n_new >=0 ){ //Фиксируем нажатую кнопку btns[n_new].enable = true; displayBTN(n_new); if( n_old >= 0 ){ //Убираем предыдущую кнопку btns[n_old].enable = false; displayBTN(n_old); } } } } } // Отображение одной кнопки из структуры void displayBTN(int i){ if( i<0 || i>= btn_n )return; struct btn_t btn = btns[i]; uint16_t color_back = BLACK, color_border = LIGHTGREY, color_text = DARKGREEN; if( btn.enable ){ color_back = DARKGREEN; color_border = LIGHTGREY; color_text = WHITE; } gfx->fillRect(btn.x,btn.y,BTN_WIDTH,BTN_HEIGHT,color_back); gfx->drawRect(btn.x,btn.y,BTN_WIDTH,BTN_HEIGHT,color_border); gfx->drawRect(btn.x+1,btn.y+1,BTN_WIDTH-2,BTN_HEIGHT-2,color_border); gfx->setCursor(btn.x+20, btn.y+30); gfx->setTextSize(4); gfx->setTextColor(color_text); gfx->print(btn.text); } |
Что-то полезное
В интернете ходит выражение «Что вы вы не делали из ESP, получится метеостанция» )))
Вот и у меня то же. Корпус на 3Д принтере:
и скетч выдающий на экран время, дату, пробки в городе, температуру в комнате, за окном и прогноз. Приводить его здесь не буду, так как все это завязано на IoT систему ThingBoard (открывается только через VPN или Proxy), на которой у меня крутится «умный дом». «Но это уже совсем другая история (C)» которая выходит за рамки обзора данной панели.
Выводы
Недостатки/недоработки
- В схемотехнике панели мне не понравилось, что подсветку можно только включать/выключать. Гораздо лучше, если бы при помощи ШИМ можно было бы регулировать яркость.
- Одноканальный ЦАП. А так хотелось бы сделать интернет радио или какой-нибудь MP3 проигрыватель
- Поддержка/коммунити довольно слабая, во всем приходится разбираться.
Но в целом панель просто огонь по соотношению возможности и цены. Пусть пока повисит в качестве метеостанции, но в дальнейшем планирую ей место пульта управления в умном доме.