Подключение TFT дисплея к ESP8266
Во многих проектах для esp8266 для вывода какой либо информации используется внешний дисплей. В зависимости от целей разработчика проекта это может быть как самый обычный 2-х или 4-х строчный LCD дисплей для отображения простого текста, так и более продвинутый OLED дисплей, который помимо текста может выводить еще графику. Способы их подключения к вашим проектам я уже рассматривал ранее в статьях Подключение LCD дисплея к Arduino и ESP и Подключение OLED дисплея к Arduino и ESP8266. Чаще всего их возможности полностью перекрывают потребности разработчика.
Но если вашему проекту необходим сложный GUI, с несколькими экранами, графическими кнопками разных цветов строками ввода текста и даже виртуальной клавиатурой, то тут без TFT экрана не обойтись.
В этой статье хочу поделиться опытом, как можно подключить TFT экран к esp8266 и реализовать графический интерфейс в среде Arduino, а также организовать взаимодействие с пользователем при помощи тачскрина, если ваш дисплей его поддерживает.
Вводная часть
Для начала определимся, что из себя представляет TFT дисплей. Согласно Википедии,TFT дисплей – это экран, созданный на основе жидких кристаллов и под управлением тонкопленочных транзисторов.
Конструкция TFT дисплея
Конструкция ЖК-дисплея представлена следующим образом. Слои накладываются друг на друга, поэтому его часто сравнивают с сэндвичем. Его основная часть состоит из:
- тонкопленочного транзистора;
- цветного фильтра;
- слоя жидких кристаллов.
Сама жидкокристаллическая матрица включает в себя:
- поляризаторы;
- электроды;
- рассеиватель света;
- стекло;
- слой с жидкими кристаллами.
Свет в ЖК-дисплеях обеспечивается светодиодами или флуоресцентными лампами.
Основные модели TFT дисплеев для использования в ваших проектах
Сейчас на на aliexpress, продается огромное количество моделей TFT экранов — разных размеров, с разными разрешениями, с тачскрином или без.
TFT экраны отличаются способом подключения — есть экраны, которые подключаются по шине SPI, а другие по параллельной шине.
Минимально, для подключения по шине SPI, требуется всего 4 сигнальных вывода (GPIO), а для подключения по параллельной шине — минимум 10 (и это без учета контроллера тачскрина). Подключение по параллельной шине дает большую скорость, т.к. за один такт передается сразу 8 бит информации, а у SPI — только 1 бит.
Однако, у подключения по SPI, есть другое преимущество — меньшее количество задействованных выводов. У esp8266 количество требуемых выводов является решающим фактором: количество свободных GPIO ограничено.
Наиболее популярные модули TFT экранов с SPI интерфейсом:
- ili9341, 320x240, 2.4", с контроллером тачскрина
- ili9225, 176x220, 2.2, без тачскрина
- st7735, 160x128, 1.8", без тачскрина
Подключение TFT экрана к ESP8266.
У большинства SPI экранов похожие аппаратные интерфейсы, и поэтому, они подключаются к процессору по одинаковой схеме
Выводы RESET и LED+ можно подключить к шине питания +3.3 вольта, однако, при желании их можно подключить к GPIO esp8266, и получить возможность программного управления сбросом и подсветкой экрана.
Выводы CS и A0 можно подключить к любым удобным GPIO esp8266.
Самая важная часть — выводы SCLK и SDA. Они отвечают за передачу данных по шине SPI. Их нужно подключить к соответствующим выводам контроллера SPI ESP8266. Это GPIO14 и GPIO13 соответственно.
Если у экрана есть тачскрин контроллер, его так же следует подключить к шине SPI
Необходимые библиотеки для работы с дисплеем
После того как мы определились с экраном и схемой подключения самое время перейти к программной части. И начнем мы с установки необходимых библиотек.
Вообще для работы с практически любым дисплеем в Arduino IDE требуется как минимум 3 различные библиотеки.
Библиотека драйвер
Необходима для упрощения работы с аппаратной частью дисплея. Подбирается в зависимости от используемого чипа, управляющего дисплеем. Для установки достаточно в менеджере Библиотек Arduino IDE ввести Adafruit и название чипа. Например Adafruit ST7735 или Adafruit ILI9341
Библиотека интерфейс
Служит для взаимодействия микроконтроллера и дисплея друг с другом. Для SPI интерфейса это библиотека SPI, для I2C это Wire. Обе библиотеки входят в стандартную поставку Arduino IDE и установки не требуют. Достаточно лишь не забыть добавить их вызов в заголовке программы.
Графическая библиотека
Библиотека драйвер для дисплея обеспечивает лишь базовый набор функций. Вывод текста, заливка экрана различным цветом, включение/отключение подсветки и т.п. Для полноценного использования дисплея требуется, так называемая, графическая библиотека. Она позволяет использовать различные шрифты для текста, рисовать простые графические примитивы, отображать рисунки и анимацию. Подобных библиотек существует великое множество. Самая популярная из них это Adafruit GFX. Подробный гайд по работе с нею вы сможете прочесть в этой статье - Подключение OLED дисплея к Arduino и ESP8266.
Также очень популярная библиотека TFT eSPI. Работает даже несколько быстрее и потребляет меньше памяти чем вышеупомянутая Adafruit GFX, но несколько сложна в настройке и может вызвать ступор у неподготовленного пользователя.
И, несомненно, необходимо упомянуть uGFX. Богатая функциональность сочетается с модульностью и в проект включаются только требуемые компоненты. Библиотека open source и бесплатна для не коммерческого использования. У библиотеки есть качественная документация, доступная на сайте проекта.
Большим недостатком этой библиотеки является то, что она использует свою систему сборки, которая "из коробки" не поддерживается системой сборки Arduino. Но это ограничение рядом манипуляций можно обойти.
Так что для начинающих, пожалуй, лучший выбор это библиотека Adafruit GFX из-за простоты использования и обилия гайдов по ее настройке в интернете.
Библиотека для работы с сенсорным экраном
Если ваш дисплей оснащен сенсорным экраном, то вам понадобится еще и библиотека для работы с ним. Чаще всего для тачскрина используется драйвер XPT2046. В менеджере библиотек Arduino IDE вы можете выбрать любую библиотеку на ваш вкус. Различия между ними не слишком существенные. И все они выполняют по сути лишь одно действие определяют место касания экрана и преобразуют его в XY координаты дисплея.
Примеры использования
Теперь разберем на практике как же использовать TFT дисплей в ваших проектах
Пример 1. Тест дисплея
Данный пример из стандартной поставки библиотеки Adafruit ST7735. Наглядно демонстрирует практически все возможности графического дисплея
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library for ST7735
#include <Adafruit_ST7789.h> // Hardware-specific library for ST7789
#include <SPI.h>
#if defined(ARDUINO_FEATHER_ESP32) // Feather Huzzah32
#define TFT_CS 14
#define TFT_RST 15
#define TFT_DC 32
#elif defined(ESP8266)
#define TFT_CS 4
#define TFT_RST 16
#define TFT_DC 5
#else
// For the breakout board, you can use any 2 or 3 pins.
// These pins will also work for the 1.8" TFT shield.
#define TFT_CS 10
#define TFT_RST 9 // Or set to -1 and connect to Arduino RESET pin
#define TFT_DC 8
#endif
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
float p = 3.1415926;
void setup(void) {
Serial.begin(9600);
Serial.print(F("Hello! ST77xx TFT Test"));
// Use this initializer if using a 1.8" TFT screen:
tft.initR(INITR_BLACKTAB); // Init ST7735S chip, black tab
// OR use this initializer if using a 1.8" TFT screen with offset such as WaveShare:
// tft.initR(INITR_GREENTAB); // Init ST7735S chip, green tab
// OR use this initializer (uncomment) if using a 1.44" TFT:
//tft.initR(INITR_144GREENTAB); // Init ST7735R chip, green tab
// OR use this initializer (uncomment) if using a 0.96" 160x80 TFT:
//tft.initR(INITR_MINI160x80); // Init ST7735S mini display
// OR use this initializer (uncomment) if using a 1.3" or 1.54" 240x240 TFT:
//tft.init(240, 240); // Init ST7789 240x240
// OR use this initializer (uncomment) if using a 1.69" 280x240 TFT:
//tft.init(240, 280); // Init ST7789 280x240
// OR use this initializer (uncomment) if using a 2.0" 320x240 TFT:
//tft.init(240, 320); // Init ST7789 320x240
// OR use this initializer (uncomment) if using a 1.14" 240x135 TFT:
//tft.init(135, 240); // Init ST7789 240x135
// OR use this initializer (uncomment) if using a 1.47" 172x320 TFT:
//tft.init(172, 320); // Init ST7789 172x320
Serial.println(F("Initialized"));
uint16_t time = millis();
tft.fillScreen(ST77XX_BLACK);
time = millis() - time;
Serial.println(time, DEC);
delay(500);
// large block of text
tft.fillScreen(ST77XX_BLACK);
testdrawtext("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur adipiscing ante sed nibh tincidunt feugiat. Maecenas enim massa, fringilla sed malesuada et, malesuada sit amet turpis. Sed porttitor neque ut ante pretium vitae malesuada nunc bibendum. Nullam aliquet ultrices massa eu hendrerit. Ut sed nisi lorem. In vestibulum purus a tortor imperdiet posuere. ", ST77XX_WHITE);
delay(1000);
// tft print function!
tftPrintTest();
delay(4000);
// a single pixel
tft.drawPixel(tft.width()/2, tft.height()/2, ST77XX_GREEN);
delay(500);
// line draw test
testlines(ST77XX_YELLOW);
delay(500);
// optimized lines
testfastlines(ST77XX_RED, ST77XX_BLUE);
delay(500);
testdrawrects(ST77XX_GREEN);
delay(500);
testfillrects(ST77XX_YELLOW, ST77XX_MAGENTA);
delay(500);
tft.fillScreen(ST77XX_BLACK);
testfillcircles(10, ST77XX_BLUE);
testdrawcircles(10, ST77XX_WHITE);
delay(500);
testroundrects();
delay(500);
testtriangles();
delay(500);
mediabuttons();
delay(500);
Serial.println("done");
delay(1000);
}
void loop() {
tft.invertDisplay(true);
delay(500);
tft.invertDisplay(false);
delay(500);
}
void testlines(uint16_t color) {
tft.fillScreen(ST77XX_BLACK);
for (int16_t x=0; x < tft.width(); x+=6) {
tft.drawLine(0, 0, x, tft.height()-1, color);
delay(0);
}
for (int16_t y=0; y < tft.height(); y+=6) {
tft.drawLine(0, 0, tft.width()-1, y, color);
delay(0);
}
tft.fillScreen(ST77XX_BLACK);
for (int16_t x=0; x < tft.width(); x+=6) {
tft.drawLine(tft.width()-1, 0, x, tft.height()-1, color);
delay(0);
}
for (int16_t y=0; y < tft.height(); y+=6) {
tft.drawLine(tft.width()-1, 0, 0, y, color);
delay(0);
}
tft.fillScreen(ST77XX_BLACK);
for (int16_t x=0; x < tft.width(); x+=6) {
tft.drawLine(0, tft.height()-1, x, 0, color);
delay(0);
}
for (int16_t y=0; y < tft.height(); y+=6) {
tft.drawLine(0, tft.height()-1, tft.width()-1, y, color);
delay(0);
}
tft.fillScreen(ST77XX_BLACK);
for (int16_t x=0; x < tft.width(); x+=6) {
tft.drawLine(tft.width()-1, tft.height()-1, x, 0, color);
delay(0);
}
for (int16_t y=0; y < tft.height(); y+=6) {
tft.drawLine(tft.width()-1, tft.height()-1, 0, y, color);
delay(0);
}
}
void testdrawtext(char *text, uint16_t color) {
tft.setCursor(0, 0);
tft.setTextColor(color);
tft.setTextWrap(true);
tft.print(text);
}
void testfastlines(uint16_t color1, uint16_t color2) {
tft.fillScreen(ST77XX_BLACK);
for (int16_t y=0; y < tft.height(); y+=5) {
tft.drawFastHLine(0, y, tft.width(), color1);
}
for (int16_t x=0; x < tft.width(); x+=5) {
tft.drawFastVLine(x, 0, tft.height(), color2);
}
}
void testdrawrects(uint16_t color) {
tft.fillScreen(ST77XX_BLACK);
for (int16_t x=0; x < tft.width(); x+=6) {
tft.drawRect(tft.width()/2 -x/2, tft.height()/2 -x/2 , x, x, color);
}
}
void testfillrects(uint16_t color1, uint16_t color2) {
tft.fillScreen(ST77XX_BLACK);
for (int16_t x=tft.width()-1; x > 6; x-=6) {
tft.fillRect(tft.width()/2 -x/2, tft.height()/2 -x/2 , x, x, color1);
tft.drawRect(tft.width()/2 -x/2, tft.height()/2 -x/2 , x, x, color2);
}
}
void testfillcircles(uint8_t radius, uint16_t color) {
for (int16_t x=radius; x < tft.width(); x+=radius*2) {
for (int16_t y=radius; y < tft.height(); y+=radius*2) {
tft.fillCircle(x, y, radius, color);
}
}
}
void testdrawcircles(uint8_t radius, uint16_t color) {
for (int16_t x=0; x < tft.width()+radius; x+=radius*2) {
for (int16_t y=0; y < tft.height()+radius; y+=radius*2) {
tft.drawCircle(x, y, radius, color);
}
}
}
void testtriangles() {
tft.fillScreen(ST77XX_BLACK);
uint16_t color = 0xF800;
int t;
int w = tft.width()/2;
int x = tft.height()-1;
int y = 0;
int z = tft.width();
for(t = 0 ; t <= 15; t++) {
tft.drawTriangle(w, y, y, x, z, x, color);
x-=4;
y+=4;
z-=4;
color+=100;
}
}
void testroundrects() {
tft.fillScreen(ST77XX_BLACK);
uint16_t color = 100;
int i;
int t;
for(t = 0 ; t <= 4; t+=1) {
int x = 0;
int y = 0;
int w = tft.width()-2;
int h = tft.height()-2;
for(i = 0 ; i <= 16; i+=1) {
tft.drawRoundRect(x, y, w, h, 5, color);
x+=2;
y+=3;
w-=4;
h-=6;
color+=1100;
}
color+=100;
}
}
void tftPrintTest() {
tft.setTextWrap(false);
tft.fillScreen(ST77XX_BLACK);
tft.setCursor(0, 30);
tft.setTextColor(ST77XX_RED);
tft.setTextSize(1);
tft.println("Hello World!");
tft.setTextColor(ST77XX_YELLOW);
tft.setTextSize(2);
tft.println("Hello World!");
tft.setTextColor(ST77XX_GREEN);
tft.setTextSize(3);
tft.println("Hello World!");
tft.setTextColor(ST77XX_BLUE);
tft.setTextSize(4);
tft.print(1234.567);
delay(1500);
tft.setCursor(0, 0);
tft.fillScreen(ST77XX_BLACK);
tft.setTextColor(ST77XX_WHITE);
tft.setTextSize(0);
tft.println("Hello World!");
tft.setTextSize(1);
tft.setTextColor(ST77XX_GREEN);
tft.print(p, 6);
tft.println(" Want pi?");
tft.println(" ");
tft.print(8675309, HEX); // print 8,675,309 out in HEX!
tft.println(" Print HEX!");
tft.println(" ");
tft.setTextColor(ST77XX_WHITE);
tft.println("Sketch has been");
tft.println("running for: ");
tft.setTextColor(ST77XX_MAGENTA);
tft.print(millis() / 1000);
tft.setTextColor(ST77XX_WHITE);
tft.print(" seconds.");
}
void mediabuttons() {
// play
tft.fillScreen(ST77XX_BLACK);
tft.fillRoundRect(25, 10, 78, 60, 8, ST77XX_WHITE);
tft.fillTriangle(42, 20, 42, 60, 90, 40, ST77XX_RED);
delay(500);
// pause
tft.fillRoundRect(25, 90, 78, 60, 8, ST77XX_WHITE);
tft.fillRoundRect(39, 98, 20, 45, 5, ST77XX_GREEN);
tft.fillRoundRect(69, 98, 20, 45, 5, ST77XX_GREEN);
delay(500);
// play color
tft.fillTriangle(42, 20, 42, 60, 90, 40, ST77XX_BLUE);
delay(50);
// pause color
tft.fillRoundRect(39, 98, 20, 45, 5, ST77XX_RED);
tft.fillRoundRect(69, 98, 20, 45, 5, ST77XX_RED);
// play color
tft.fillTriangle(42, 20, 42, 60, 90, 40, ST77XX_GREEN);
}
Скетч довольно простой и полностю использует возможности библиотеки Adafruit GFX, которую мы разбирали в статье Подключение OLED дисплея к Arduino и ESP8266. Так что подробно останаливаться на этом примере не будем. Проясню лишь основные моменты
Здесь указываются пины для подключения по SPI интерфейсу. Сверьтесь со схемой подключения и измените их при необходимости. Обратите внимание, что нумерация пинов идет в GPIO формате и не соответствует шелкографии нанесенной на самой плате!
#define TFT_CS 4
#define TFT_RST 16
#define TFT_DC 5
Далее идет инициализация драйвера дисплея
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
Здесь мы по сути сопоставляем класс Adafruit_ST7735 переменной tft, для последующего обращения к ней
Далее идет строка инициализации самого дисплея
// Use this initializer if using a 1.8" TFT screen:
tft.initR(INITR_BLACKTAB); // Init ST7735S chip, black tab
// OR use this initializer if using a 1.8" TFT screen with offset such as WaveShare:
// tft.initR(INITR_GREENTAB); // Init ST7735S chip, green tab
// OR use this initializer (uncomment) if using a 1.44" TFT:
//tft.initR(INITR_144GREENTAB); // Init ST7735R chip, green tab
// OR use this initializer (uncomment) if using a 0.96" 160x80 TFT:
//tft.initR(INITR_MINI160x80); // Init ST7735S mini display
// OR use this initializer (uncomment) if using a 1.3" or 1.54" 240x240 TFT:
//tft.init(240, 240); // Init ST7789 240x240
// OR use this initializer (uncomment) if using a 1.69" 280x240 TFT:
//tft.init(240, 280); // Init ST7789 280x240
// OR use this initializer (uncomment) if using a 2.0" 320x240 TFT:
//tft.init(240, 320); // Init ST7789 320x240
// OR use this initializer (uncomment) if using a 1.14" 240x135 TFT:
//tft.init(135, 240); // Init ST7789 240x135
// OR use this initializer (uncomment) if using a 1.47" 172x320 TFT:
//tft.init(172, 320); // Init ST7789 172x320
Здесь все несколько сложнее. Поскольку китайцы наклепали великое множество вариантов данного дисплея внешних очень похожих, но работающих на разных модификациях и версиях одно и того же чипа, имеющих весьма посредственную совместимость друг с другом, нам необходимо явно указать библиотеке с какой из версий дисплея мы будем работать. К сожалению простого способа узнать это нет. Так что приходится делать это методом подбора или опираясь на разрешение экрана и цвет ярлычка на защитной пленке дисплея. В большинстве случаев это будет tft.initR(INITR_GREENTAB) или tft.initR(INITR_BLACKTAB), но возможны и другие варианты. Часть комбинаций указаны в комментариях к данной строке инициализации, но если дисплей все же ничего не отображает или картинка идет с артефактами пробуйте другой вариант
Работа с тачскрином
Для компиляции и загрузки двух следующих двух примеров. Вам необходимо установить дополнительные библиотеки в Arduino IDE. Для этого скачайте архив по ссылке Вам нужно будет скопировать папки из архива Adafuit_ILI9341esp и XPT2046 в папку библиотек Arduino (C:\Users\имя пользователя\Documents\Arduino\libraries или C:\Program Files (x86)\Arduino\libraries), после чего перезапустить Arduino IDE
Пример 2. Калибровка тачскрина
Для точного распознавания нажатий и верного соотношения из с координатами экрана ваш дисплей нужно предварительно откалибровать. Для этого либо загрузите скетч XPTCalibrate из папки с проектом, либо скопируйте текст программы, приведенный ниже в Arduino IDE и загрузите его в ваш ESP8266.#include <Arduino.h>
#include <SPI.h>
#include <Adafruit_ILI9341esp.h>
#include <Adafruit_GFX.h>
#include <XPT2046.h>
// For the Esp connection of touch
#define TFT_DC 2
#define TFT_CS 15
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
XPT2046 touch(/*cs=*/ 4, /*irq=*/ 5);
static void calibratePoint(uint16_t x, uint16_t y, uint16_t &vi, uint16_t &vj) {
// Draw cross
tft.drawFastHLine(x - 8, y, 16,0xff);
tft.drawFastVLine(x, y - 8, 16,0xff);
while (!touch.isTouching()) {
delay(10);
}
touch.getRaw(vi, vj);
// Erase by overwriting with black
tft.drawFastHLine(x - 8, y, 16, 0);
tft.drawFastVLine(x, y - 8, 16, 0);
}
void calibrate() {
uint16_t x1, y1, x2, y2;
uint16_t vi1, vj1, vi2, vj2;
touch.getCalibrationPoints(x1, y1, x2, y2);
calibratePoint(x1, y1, vi1, vj1);
delay(1000);
calibratePoint(x2, y2, vi2, vj2);
touch.setCalibration(vi1, vj1, vi2, vj2);
tft.setTextColor(ILI9341_CYAN);
tft.setTextSize(2);
tft.println("Calibration Params");
tft.println("");
tft.setTextSize(3);
tft.println(vi1);
tft.println(vj1);
tft.println(vi2);
tft.println(vj2);
}
void setup() {
delay(1000);
SPI.setFrequency(ESP_SPI_FREQ);
tft.begin();
touch.begin(tft.width(), tft.height()); // Must be done before setting rotation
tft.fillScreen(ILI9341_BLACK);
calibrate(); // No rotation!!
}
void loop() {
// Do nothing
delay(1000);
}
Данный скетч последовательно выводит на экран 2 точки с заданными координатами, которых вы должны коснуться стилусом. После чего вычисляет насколько эти координаты отличаются от тех, что определил драйвер тачскрина и выводит полученные значения на экран, для использования в последующих программах
Реализовано это следующей функцией
touch.getCalibrationPoints(x1, y1, x2, y2);
calibratePoint(x1, y1, vi1, vj1);
delay(1000);
calibratePoint(x2, y2, vi2, vj2);
touch.setCalibration(vi1, vj1, vi2, vj2);
touch.getCalibrationPoints(x1, y1, x2, y2); - задает 2 точки эталона с реальными координатами экрана. calibratePoint(x1, y1, vi1, vj1); и calibratePoint(x2, y2, vi2, vj2); обрабатывают нажатия по этим точками и заносят в переменные vi1,vj1,vi2,vj2 насколько они отличаются от распознанных контроллером. Далее touch.setCalibration(vi1, vj1, vi2, vj2); сохраняет поправки. Теперь каждое нажатие на тачскрин будет обрабатываться с учетом этих поправок
Пример 3. Простая кнопка и рисование на экране
В данном примере мы научимся обрабатывать нажатие тач кнопки и рисовать стилусом прямо по экрану
#include <Arduino.h>
#include <SPI.h>
#include <Adafruit_ILI9341esp.h>
#include <Adafruit_GFX.h>
#include <XPT2046.h>
// Modify the following two lines to match your hardware
// Also, update calibration parameters below, as necessary
// For the esp shield, these are the default.
#define TFT_DC 2
#define TFT_CS 15
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
XPT2046 touch(/*cs=*/ 4, /*irq=*/ 5);
Adafruit_GFX_Button button;
void setup() {
delay(1000);
Serial.begin(115200);
SPI.setFrequency(ESP_SPI_FREQ);
tft.begin();
touch.begin(tft.width(), tft.height()); // Must be done before setting rotation
Serial.print("tftx ="); Serial.print(tft.width()); Serial.print(" tfty ="); Serial.println(tft.height());
tft.fillScreen(ILI9341_BLACK);
// Replace these for your screen module
touch.setCalibration(209, 1759, 1775, 273);
button.initButton(&tft, 100, 100, 70, 40, ILI9341_DARKCYAN, ILI9341_BLUE, ILI9341_GREENYELLOW, "Clear", 2);
button.drawButton();
}
static uint16_t prev_x = 0xffff, prev_y = 0xffff;
void loop() {
uint16_t x, y;
if (touch.isTouching()) {
touch.getPosition(x, y);
// Serial.print("x ="); Serial.print(x); Serial.print(" y ="); Serial.println(y);
if (prev_x == 0xffff) {
tft.drawPixel(x, y,ILI9341_BLUE);
} else {
tft.drawLine(prev_x, prev_y, x, y,ILI9341_BLUE);
}
prev_x = x;
prev_y = y;
} else {
prev_x = prev_y = 0xffff;
}
button.press(button.contains(x, y)); // tell the button it is pressed
// now we can ask the buttons if their state has changed
if (button.justReleased()) {
tft.fillScreen(ILI9341_BLACK);
button.drawButton(); // draw normal
}
if (button.justPressed()) {
button.drawButton(true); // draw invert!
}
delay(20);
}
Для начала разберемся с настройками тачскрина. Инициализируется он следующим образом
XPT2046 touch(/*cs=*/ 4, /*irq=*/ 5);
Просто указываем в скобках пины ESP8266 к которым подключены cs и irq выводы тачскрина
Далее указываем ширину и высоту сенсорного дисплея в пикселях. Так как они соответствуют аналогичным параметрам экрана, то можно взять их значения из библиотеки драйвера
touch.begin(tft.width(), tft.height());
Далее указываем паараметры для калибровки экрана полученные в предыдущем примере
touch.setCalibration(209, 1759, 1775, 273);
Касание тачскрина определяем следующим образом
if (touch.isTouching()) {
touch.getPosition(x, y);
// Serial.print("x ="); Serial.print(x); Serial.print(" y ="); Serial.println(y);
if (prev_x == 0xffff) {
tft.drawPixel(x, y,ILI9341_BLUE);
} else {
tft.drawLine(prev_x, prev_y, x, y,ILI9341_BLUE);
}
prev_x = x;
prev_y = y;
} else {
prev_x = prev_y = 0xffff;
}
Функция touch.isTouching() возвращает TRUE если было касание. Далее с помощью touch.getPosition(x, y) узнаем координаты касания и рисуем в данном месте пиксель. Если касания было 2 то рисуем линию между ними
Для рисования кнопок в Adafruit GFX есть специальный инструмент виртуальная кнопка. Инициализируется она следующим образом
Adafruit_GFX_Button button;
button.initButton(&tft, 100, 100, 70, 40, ILI9341_DARKCYAN, ILI9341_BLUE, ILI9341_GREENYELLOW, "Clear", 2);
button.drawButton();
Записав данных код мы сделали следующее. Соотнесли переменную button с классом Adafruit_GFX_Button. Далее инициализировали кнопку задав ее координаты, ширину и высоту, цвет контура, цвет самой кнопки, цвет текста в ней, надпись на кнопке и радиус закругления углов. После чего использовали метод drawButton() для вывода ее на экран
Нажатие на кнопку определяется следующим образом
button.press(button.contains(x, y))
При нажатии на экран определяются координаты x и y и если они совпадают с координатами кнопки, то функция возвращает TRUE и мы определяем, что кнопка была нажата
Чтобы понять удерживаем ли мы кнопку нажатой или уже отпустили используется еще 2 функции
button.justReleased()
button.justPressed()
Эти функции возвращают TRUE когда кнопка была отпущена или нажата соответственно
И, напоследок? фото работы устройства
Это все что я вам хотел рассказать о подключении TFT дисплея к ESP8266