На предыдущем уроке мы разобрались с выводом на TFT дисплей русского текста стандартным шрифтом GLCD. Это растровый шрифт с очень низким разрешением — всего 5*8 точек. Его целесообразно использовать только для вывода служебных сообщений и отладки. А что делать, если нужен приличный сглаженный шрифт, как на экране монитора?
Благо, библиотека TFT_eSPI позволяет работать со сглаженными шрифтами TrueType и OpenType. Но нельзя просто так взять и загрузить файл шрифта .ttf на ESP и использовать его. Потребуется предварительная растеризация шрифта заданного размера.
На этом уроке мы как раз этим и займёмся: подготовим шрифт, загрузим его в память контроллера и выведем какой-нибудь текст на TFT дисплей.
Для экспериментов используем контроллер Графит-32S и 2-дюймовый дисплей с IPS матрицей. Всё это есть в интернет-магазине RobotClass.
Подключение
Дисплей подключается к контроллеру по 4-контактной шине SPI.
Графит-32S (ESP32-S) | 3V3 | Gnd | 14 | 22 | 23 | 5 | 18 | — |
Дисплей IPS 2.0 | VCC | G | CS | RST | RS | SCK | MO | BK |
Контакт BK отвечает за подсветку матрицу. Для выключения подсветки этот контакт можно соединить с землёй, но мы его оставим в покое.
Программа
Для правильной работы библиотеки TFT_eSPI сначала необходимо настроить файл конфигурации. Это нужно сделать вручную, открыв в текстовом редакторе файл:
путь_к_библиотекам\Arduino\libraries\TFT_eSPI-master\User_Setup.h
Можно удалить всё содержимое этого файла и оставить только следующие строки:
#define USER_SETUP_INFO "User_Setup"
#define ST7789_2_DRIVER
#define TFT_RGB_ORDER TFT_RGB
#define TFT_WIDTH 240
#define TFT_HEIGHT 320
#define TFT_INVERSION_ON
#define TFT_MOSI 18
#define TFT_SCLK 5
#define TFT_CS 15
#define TFT_DC 27
#define TFT_RST 33
#define SMOOTH_FONT
#define SPI_FREQUENCY 27000000
#define SPI_READ_FREQUENCY 20000000
#define SPI_TOUCH_FREQUENCY 2500000
Единственное отличие от настроек для предыдущего урока со шрифтом GLCD — это строчка:
#define SMOOTH_FONT
которая означает подключение TrueType шрифтов. Если работа с GLCD не планируется, то директиву #define LOAD_GLCD можно убрать.
Растеризация шрифта
В папке с библиотекой TFT_eSPI имеется программа, которая осуществляет растеризацию ttf и otf шрифтов с заданным размером. Однако, запустить её можно только в среде Processing. Поэтому, сначала потребуется установить среду на компьютер (скачать архив можно с официального сайта по ссылке в конце урока).
Запускаем Processing, открываем скетч Create_font. Путь до него:
...\TFT_eSPI\Tools\Create_Smooth_Font\Create_font
Теперь изменим некоторые параметры в коде скетча.
String fontName = "nasalization";
Этот параметр указывает на имя файла шрифта (регистр важен!), который мы будем готовить. Имя записывается без расширения. При этом, сам файл должен лежать в папке data, внутри папки скетча:
...\TFT_eSPI\Tools\Create_Smooth_Font\Create_font\data\nasalization.otf
Следующий параметр — тип файла: ttf или otf.
String fontType = ".otf";
Далее — размер шрифта:
int fontSize = 48;
После генерации растрового шрифта, на экране появится форма с демонстрацией полученных символов. Размер текста в этой демонстрации также же можно указать, но на результат это не повлияет.
int displayFontSize = 24;
Наконец, укажем какие символы мы хотим растеризовать. Нас интересует кириллица, поэтому уберём символ комментария перед этой строчкой:
0x0400, 0x04FF, //Cyrillic, 256, 256, Cyrillic (254 characters), Inherited (2 characters)
С параметрами на этом всё. Жмём кнопку «Запустить». В результате, в папке скетча появится нужный нам файл с расширением vlw:
...\TFT_eSPI\Tools\Create_Smooth_Font\Create_font\FontFiles\nasalization24.vlw
Загрузка шрифта в память контроллера
Полученный на предыдущем шаге шрифт необходимо загрузить в SPIFFS память контроллера. Копируем его в папку data внутри папки со скетчем и используем плагин ESP32 Sketch Data Upload.
После завершения этой процедуры можем, наконец, написать программу для работы с этим шрифтом.
Программа
Пусть программа выводит в центре дисплея текст: ВНИМАНИЕ! Используем шрифт nasalization размером 24, который мы ранее подготовили.
Для работы со шрифтом нам пригодятся две функции. Первая — загружает шрифт из SPIFFS в оперативную память контроллера:
ttf.loadFont("nasalization24")
В качестве единственного аргумента — имя файла шрифта, без расширения. Вторая функция освобождает память.
ttf.unloadFont()
Таким образом, шрифты нельзя использовать параллельно! Загрузив один шрифт, мы пользуемся им до вызова функции unloadFont, после которого можно загрузить уже другой, например, с другим размером.
Итак, программа.
#include <TFT_eSPI.h>
TFT_eSPI tft = TFT_eSPI();
void setup() {
tft.init();
tft.setRotation(2);
tft.fillScreen(TFT_BLACK);
// инициализация SPIFFS
if (!SPIFFS.begin()) {
while (1) yield();
}
tft.loadFont("nasalization24"); // загрузка в память шрифта
tft.setCursor(40, 150);
tft.setTextColor(TFT_ORANGE, TFT_BLACK);
tft.println("ВНИМАНИЕ!");
tft.unloadFont(); // выгрузка шрифта из памяти
}
void loop() {
}
Загружаем программу на контроллер и наблюдаем результат.
Отлично, следующий шаг — добавим шрифт другого размера и немного динамики.
Обратный отсчет
Пусть на дисплее будет написан текст шрифтом nasalization с размером 24. Ниже основного текста разместим счётчик обратного отсчёта шрифтом 48-го размера. Для этого подготовим и загрузим в SPIFFS файл nasalization48.vlw.
Когда счётчик достигнет значения 03, цвет текста изменится на красный.
#include <TFT_eSPI.h>
TFT_eSPI tft = TFT_eSPI();
uint8_t counter = 20;
uint16_t text_width = 0;
void setup() {
tft.init();
tft.setRotation(2);
tft.fillScreen(TFT_BLACK);
if (!SPIFFS.begin()) {
while (1) yield();
}
tft.loadFont("nasalization24");
tft.setCursor(40, 100);
tft.setTextColor(TFT_ORANGE, TFT_BLACK);
tft.println("ВНИМАНИЕ!");
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.setCursor(47, 140);
tft.println("до запуска");
tft.setCursor(59, 165);
tft.println("осталось");
tft.setCursor(74, 255);
tft.println("секунд");
tft.unloadFont();
tft.loadFont("nasalization48");
}
void loop() {
if( counter > 0 ){
counter--;
char text[5];
sprintf(text, "%02d", counter);
tft.fillRect((tft.width() - text_width)/2, 200, text_width, 48, TFT_BLACK);
text_width = tft.textWidth(text);
tft.setCursor((tft.width() - text_width)/2, 200);
if( counter <4 ){
tft.setTextColor(TFT_RED, TFT_BLACK);
} else {
tft.setTextColor(TFT_WHITE, TFT_BLACK);
}
tft.println(text);
delay(1000);
}
}
Основная загвоздка — как стирать старый текст? Ведь если мы будем выводить текст по одним и тем же координатам, то получится символьное месиво.
Решить это можно стиранием предыдущей надписи, перед тем как мы будем выводить новую. А стирать проще всего закрашивая старый текст прямоугольник цветом фона. Именно для этого в коде есть такой участок:
char text[5];
sprintf(text, "%02d", counter);
tft.fillRect((tft.width() - text_width)/2, 200, text_width, 48, TFT_BLACK);
Размеры прямоугольника должны совпадать с размерам области, которую занимает текст. Для этого мы вычисляем ширину текста функцией textWidth (чуть ниже в коде), и используем это значение для вычисления ширины прямоугольника.
Загружаем программу и наблюдаем за обратным отсчётом.
Полезные ссылки
Среда разработки Processing:
https://processing.org/download
Спасибо, работает. Но! Текст на кириллице выводятся долго, построчно, как будто кто-то очень быстро набирает текст на экране )
Если заменяю на латиницу, текст выводится моментально. Как-то можно ускорить?
Похоже, что SPIFFS тормозит. Если есть рвение, можно модифицировать библиотеку TFT_eSPI и заменить SPIFFS на LittleFS. Будет работать значительно быстрее.
Что можно сделать или как модифицировать tft_espi что бы работало через LittleFS. SPIFFS выводит текст хорошо а вот LittleFS никак.