Вывод русских символов на различные типы дисплеев
В данной статье мы рассмотрим как вывести русские символы на различные типы дисплеев.
Вывод русских символов на различные типы дисплеев
06.05.2024 в 12:20   2723 0
Версия для печати

Вывод русских символов на различные  типы дисплеев в ваших проектах

logo

Задача вывода русских символов на дисплеи в Arduino проектах является нетривиальной, поскольку большинство дисплеев и библиотек, с ними работающих, не поддерживает русские шрифты изначально. Это создает дополнительные препятствия для тех, кто хочет использовать русский язык в своих проектах на Arduino. В данной статье мы рассмотрим, как можно решить эту проблему и успешно вывести русские символы на различные типы дисплеев.

LCD1602 и LCD2004

Дисплеи LCD1602 и LCD2004 представляют собой жидкокристаллические дисплеи с символьной матрицей, которые могут отображать текст и несколько символов.

Данный тип дисплеев может отображать лишь ограниченный набор символов, зашитый в ПЗУ дисплея и разбитый  две страницы памяти  знакогенератора, которые состоят из различных символов и букв. И будут ли там русские буквы зависит только от производителя дисплея. . Один из вариантов страниц знакогенератора вы можете увидеть на рисунке ниже.

symbols

Как видите, таблица уже содержит некоторые русские символы. И для вывода, например, буквы "Ю" можно воспользоваться следующей функцией:

lcd.print("\xB1");

Здесь, после директивы \x указывается столбец и строка символа из таблицы знакогенератора

Но чаще всего, в знакогенераторе вместо русских символов расположены иероглифы и прочие кракозябры. Особенно актуально это для дисплеев с Aliexpress. К счастью, для данных дисплеев есть возможность добавить в знакогенератор 8 пользовательских символов, которые будут подгружаться из оперативной памяти микроконтроллера и выводится на экран во время  выполнения программы. Поэтому для вывода русского текста на экран можно использовать английские символы со схожим начертанием, а недостающие символы добавить через функцию добавления символов в знакоенератор.

Например, букву "Б" можно добавить следующим образом


byte letter_B[8] = {
 B11111,
 B10000,
 B10000,
 B11110,
 B10001,
 B10001,
 B10001,
 B11110
};

Затем можно использовать функцию lcd.createChar() для создания нового символа с индексом 0 и передать массив байт для символа "Б":

lcd.createChar(0, letter_B);

После этого символ "Б" будет доступен по индексу 0, и его можно отобразить с помощью команды lcd.write()

lcd.write(byte(0));

Способ, конечно, трудоемкий, но вполне рабочий. К счастью, с помощью сторонних библиотек всю рутину по добавлению русских символов в знакогенератор и вывода их на экран можно легко автоматизировать. Например с помощью библиотеки  LCD_1602_RUS_ALL. Достаточно лишь подключить ее к вашему проекту и просто писать в функциях вывода на дисплей русский текст. Все необходимые преобразования библиотека сделает сама.

Демонстрация работы

Например, загрузим в Arduino такой скетч

#include <lcd_1602_rus.h>

LCD_1602_RUS lcd(0x27, 16, 2);

void setup()
{
 String str;
 str = "по-русски";

 lcd.init(); // initialize the lcd
 // Print a message to the LCD.
 lcd.backlight();
 lcd.setCursor(2, 0);
 lcd.print("Теперь можно");
 lcd.setCursor(3, 1);
 lcd.print(str);

}

void loop()
{
}#include 

LCD_1602_RUS_ALL lcd(0x27, 16, 2);

void setup()
{
 String str;
 str = "по-русски";

 lcd.init(); // initialize the lcd
 // Print a message to the LCD.
 lcd.backlight();
 lcd.setCursor(2, 0);
 lcd.print("Теперь можно");
 lcd.setCursor(3, 1);
 lcd.print(str);

}

void loop()
{
}

В результате выполнения на дисплее вы увидите следующее:

lcd result

Однако, у данного метода есть существенный недостаток. Из-за того, что символы раскиданы по разным страницам памяти, при выводе больших объемов текста, со множеством различных символов, система не всегда корректно обрабатывает переключение между страницами. Поэтому иногда возможны вот такие вот артефакты как на фотографии ниже. Пример вывода русского алфавита:

При выводе небольших простых текстов, подобных проблем не наблюдалось. Так что пользуйтесь с осторожностью. Возможно это одной конкретной библиотеки.

OLED дисплеи на примере SSD1306

C OLED дисплеями, в частности с SSD1306, дело обстоит несколько проще. Изображение на нем формируется массивом светодиодов размерностью 128x64, каждый из которых мы можем включать по отдельности. 
Для работы в с данным типом дисплеев в Arduino IDE используются драйвер Adafruit SSD1306 в паре с графической библиотекой Adafruit GFX. Вывод текста на экран в ней реализован посредством, так называемых, файлов шрифтов. Которые, если говорить очень упрощенно, представляют собой байтовый массив, описывающий порядок пикселей для отрисовки символа и его значение в кодировке UTF-8.

Во время выполнения программы, процессор, получив команду вывода текста на экран, ищет код этого символа в файле шрифта. Найдя его, в соответствии со значениями в байтовом  массиве для этого символа, зажигает на экране нужные пиксели в указанном месте.

В Adafruit GFX, по умолчанию используется шрифт, содержащийся в файле glcdfont.c. Как не трудно догадаться, русских символов в нем нет. Но зато есть множество энтузиастов, которых это совершенно не устраивает. Одно из решений было предложено на форуме Arduino.ru

В файл glcdfont.c со стандартным шрифтом были добавлены русские буквы. Но шрифт рассчитан на однобайтовую кодировку букв, а Arduino IDE использует (для русских символов) двухбайтовую кодировку UTF-8.

Однако оказалось, что в русской кодировке UTF-8 прослеживается определенная последовательность. И она позволяет несложным путем перекодировать из UTF-8 в однобайтовую русскую кодировку Windows-1251, которая и была выбрана для замены букв.

Функция utf8rus() получает исходную строку, символы с кодами 0x00-0xBF пропускает без изменения в выходную строку, а в оставшихся кодах отбирает русские буквы и перекодирует их.

Ниже расположен код данной функции.

String utf8rus(String source)
{
 int i,k;
 String target;
 unsigned char n;
 char m[2] = { '0', '\0' };

 k = source.length(); i = 0;

 while (i < k) {
 n = source[i]; i++;
 if (n >= 0xBF){
 switch (n) {
 case 0xD0: {
 n = source[i]; i++;
 if (n == 0x81) { n = 0xA8; break; }
 if (n >= 0x90 && n <= 0xBF) n = n + 0x2F;
 break;
 }
 case 0xD1: {
 n = source[i]; i++;
 if (n == 0x91) { n = 0xB7; break; }
 if (n >= 0x80 && n <= 0x8F) n = n + 0x6F;
 break;
 }
 }
 }
 m[0] = n; target = target + String(m);
 }
return target;
}

Скачать модифицированный glcdfont.c можно здесь.

Демонстрация работы

Для проверки отображения русского текста загрузите в ваш микроконтроллер следующий скетч

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// software SPI:
unsigned char i1,i2,c3;

Adafruit_SSD1306 display(128, 64, &Wire, -1);

void setup(){ 
 display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
 display.cp437(true);
}

void loop() {
 TEST_display_1();
 delay(10000);
 TEST_display_2();
 delay(10000);
 TEST_display_3();
 delay(8000);
 TEST_display_4();
 delay(4000);
}

void TEST_display_1()
{
 display.clearDisplay();
 display.setTextColor(WHITE);
 display.setTextSize(1);
 display.setCursor(0,0);
 
 for(i1=0; i1<8; i1++) {
 for(i2=0; i2<16; i2++) {
 c3=i1*16+i2;
 if(c3 == 0x0A || c3 == 0x0D) display.print(" ");
 else display.write(c3);
 }
 display.println("");
 }
 display.display();
}

void TEST_display_2()
{
 display.clearDisplay();
 display.setTextColor(WHITE);
 display.setTextSize(1);
 display.setCursor(0,0);
 
 for(i1=8; i1<16; i1++) {
 for(i2=0; i2<16; i2++)
 display.write(i1*16+i2);
 display.println("");
 }
 display.display();
}

void TEST_display_3()
{
 display.clearDisplay(); 
 display.setTextColor(WHITE);
 display.setTextSize(1);
 display.setCursor(0,0);

 display.println(utf8rus("АБВГДЕЖЗИЙКЛМНОП"));
 display.println(utf8rus("РСТУФХЦЧШЩЪЫЬЭЮЯ"));
 display.println(utf8rus("абвгдежзийклмноп"));
 display.println(utf8rus("рстуфхцчшщъыьэюя"));
 display.println(utf8rus("Ёё123ABCabc!@#\xBC\xBD"));
 display.println(utf8rus("10\x83 10\x8A\x82 10\x81\x80 2\x85"));

 display.display(); 
}

void TEST_display_4()
{
 display.clearDisplay(); 
 display.setTextColor(WHITE);
 display.setCursor(0,0);

 display.setTextSize(1);
 display.println(utf8rus("Размер шрифта 1"));

 display.setTextSize(2);
 display.println(utf8rus("Размер 2"));

 display.setTextSize(3);
 display.println(utf8rus("Разм 3"));

 display.display(); 
}

/* Recode russian fonts from UTF-8 to Windows-1251 */
String utf8rus(String source)
{
 int i,k;
 String target;
 unsigned char n;
 char m[2] = { '0', '\0' };

 k = source.length(); i = 0;

 while (i < k) {
 n = source[i]; i++;

 if (n >= 0xC0) {
 switch (n) {
 case 0xD0: {
 n = source[i]; i++;
 if (n == 0x81) { n = 0xA8; break; }
 if (n >= 0x90 && n <= 0xBF) n = n + 0x30;
 break;
 }
 case 0xD1: {
 n = source[i]; i++;
 if (n == 0x91) { n = 0xB8; break; }
 if (n >= 0x80 && n <= 0x8F) n = n + 0x70;
 break;
 }
 }
 }
 m[0] = n; target = target + String(m);
 }
return target;
}

Если вы все сделали правильно, то на экране вы увидите следующее:

oledtest

Данный способ работает отлично и неоднократно хорошо себя зарекомендовал во многих моих проектах. Однако, если после загрузки программы в микроконтроллер русские символы на дисплее так и не появились, то попробуйте очистить кэш компилятора. Для этого достаточно полностью закрыть Arduino IDE и запустить его заново.

TFT дисплеи

Что касается TFT дисплеев, то для вывода графики и текста можно также использовать библиотеку Adafruit GFX. Способ вывода русского текста полностью аналогичен тому, что мы использовали для OLED дисплеев. Работает все также хорошо, но почему-то у меня не выводятся на экран большие буквы Р и С. Если вы знаете как это исправить, пишите в комментариях. 
Но есть в этом способе и один большой недостаток. Мы ограничены всего одним шрифтом, к тому же не очень симпатичным. К счастью, есть еще один способ добавления любых в аш проект шрифтов с произвольным набором символов с помощью библиотеки TFT_eSPI.
В ней, кстати, тоже можно использовать русифицированный шрифт glcdfont.c, но перед выводом текста на экран надо выполнить следующую команду
tft.setAttribute(UTF8_SWITCH, false);

А после вывода

tft.setAttribute(UTF8_SWITCH, true);

Русификация библиотеки TFT_eSPI

Несмотря на множество достоинств, есть у TFT_eSPI один существенный недостаток. Она совершенно не умеет выводить на экран русские шрифты. К счастью это очень легко исправить средствами самой библиотеки.

Подготовка

Для добавления собственных шрифтов в библиотеке в существует специальная утилита Create Font, расположенная по адресу TFT_eSPI\Tools\Create_Smooth_Font\Create_font. Она представляет собой скрипт на Processing - среде разработки приложений под Windows. Так что перед тем как заняться портирование собственных шрифтов переходим на официальный сайт processing.org, качаем свежую версию программы и устанавливаем её. После успешной установки, возвращаемся к папке с библиотекой TFT_eSPI и запускаем скрипт Create_font.pde, расположенный по пути TFT_eSPI\Tools\Create_Smooth_Font\Create_font. Откроется окно программы Processing c текстом скрипта. Самое время переходить к настройке.

processing

 

Настройка скрипта.

В первую очередь, ничего не меняя в коде программы, просто запускаем скрипт нажав на соответствующую кнопку в левом верхнем углу экрана.

 

compile

Программа просканирует установленные в системе шрифты и сохранит их в файле TFT_eSPI\Tools\Create_Smooth_Font\Create_font\FontFiles\System_Font_List.txt
Откройте полученный файл, найдите интересующий вас шрифт и запомните его порядковый номер написанных в квадратных скобках.

Для примера возьмем системный шрифт Windows 10 Calibri. В списке он обозначен как [41] Calibri. Запоминаем цифру 41 и возвращаемся в Processing. 

Пролистываем код программы до следующего текста

// >>>>>>>>>> USER CONFIGURED PARAMETERS START HERE <<<<<<<<<<

// Use font number or name, -1 for fontNumber means use fontName below, a value >=0 means use system font number from list.
// When the sketch is run it will generate a file called "systemFontList.txt" in the sketch folder, press Ctrl+K to see it.
// Open the "systemFontList.txt" in a text editor to view the font files and reference numbers for your system.

int fontNumber = 41; // << Use [Number] in brackets from the fonts listed.

// OR use font name for ttf files placed in the "Data" folder or the font number seen in IDE Console for system fonts
// the font numbers are listed when the sketch is run.
// | 1 2 | Maximum filename size for SPIFFS is 31 including leading /
// 1234567890123456789012345 and added point size and .vlw extension, so max is 25
String fontName = "Calibri"; // Manually crop the filename length later after creation if needed
 // Note: SPIFFS does NOT accept underscore in a filename!
String fontType = ".ttf";
//String fontType = ".otf";


// Define the font size in points for the TFT_eSPI font file
int fontSize = 10;

int fontNumber = 41; - меняем на номер нужного нам шрифта

String fontName = "Calibri"; - в кавычках пишем под каким именем сохранить новый шрифт

String fontType = ".ttf"; - тип исходного шрифта .otf или .ttf

int  fontSize = 10; - размер шрифта

Пролистываем ниже и раскомментируем следующие 2 строки

0x0400, 0x04FF, //Cyrillic, 256, 256, Cyrillic (254 characters), Inherited (2 characters)
 0x0500, 0x052F, //Cyrillic Supplement, 48, 48, Cyrillic

На этом настройка завершена! Запускаем скрипт еще раз и в появившемся окне проверяем правильность отображения нашего нового шрифта

font view

Если результат вас полностью устраивает, то можно либо закрыть Processing и перейти к следующему шагу, либо продолжить редактирование.

Добавление русского шрифта в ваш проект

Конвертированные вами шрифты хранятся в папке TFT_eSPI\Tools\Create_Smooth_Font\Create_font\FontFiles. Для того чтобы добавить их в ваш проект необходимо скопировать файлы шрифтов в файловую систему ESP8266. Как это сделать я подробно рассказывал здесь. После копирования всех необходимых файлов следует подключить шрифты и в самой программе. Как это сделать мы подробно разберем в небольшом примере.

Пример программы вывода русского текста на экран.

Откройте Arduino IDE и скопируйте в нее следующий текст программы


#define FONT_10 "Arial10"
#define FONT_11 "Arial11"
#define FONT_12 "Arial12"
#define FONT_14 "Arial14"
#define FONT_16 "Arial16"
#define FONT_18 "Arial18"
#define FONT_20 "Arial20"
#define FONT_22 "Arial22"
#define FONT_25 "Arial25"
#define FONT_30 "Arial30"

#include <FS.h>// Файлы шрифтов хранятся в SPIFFS, поэтому загрузите библиотеку
#include <SPI.h>
#include <TFT_eSPI.h> // Библиотека для конкретного оборудования

TFT_eSPI tft = TFT_eSPI();


void setup(void) {

 Serial.begin(250000);
 tft.begin();
 tft.setRotation(1);

//****** проверка загрузки шрифтов
 if (!SPIFFS.begin()) {
 Serial.println("Ошибка инициализации SPIFFS!");
 while (1) yield(); // Оставайся здесь, бездельничая, ожидая
 } 
}


void loop() {

 tft.fillScreen(TFT_BLACK);
 tft.setTextColor(TFT_WHITE, TFT_BLACK); // Set the font colour AND the background colour
 // so the anti-aliasing works

 tft.setCursor(0, 0); // Set cursor at top left of screen


 tft.loadFont(FONT_10); // загружаем шрифт
 tft.print(FONT_10); // Выводим название шрифта
 tft.println(" - Потрогай Еще Эти Французские Булочки"); // Натпись про БУЛКИ
 tft.unloadFont(); // выгрузить шрифт 
 
 // tft.setCursor(0, 22); // Set cursor at top left of screen
 tft.loadFont(FONT_11); // Загружаем шрифт 
 tft.print(FONT_11); // Выводим название шрифта
 tft.println(" - Потрогай Еще Эти Французские Булочки"); // Натпись про БУЛКИ
 tft.unloadFont(); // выгрузить шрифт
 

 tft.loadFont(FONT_12); // загружаем шрифт
 tft.print(FONT_12); // Выводим название шрифта
 tft.println(" - Потрогай Еще Эти Французские Булочки"); // Натпись про БУЛКИ
 tft.unloadFont(); // выгрузить шрифт 
 

 tft.loadFont(FONT_14); // Загружаем шрифт 
 tft.print(FONT_14); // Выводим название шрифта
 tft.println(" - Потрогай Еще Эти Французские Булочки"); // Натпись про БУЛКИ
 tft.unloadFont(); // выгрузить шрифт
 

 tft.loadFont(FONT_16); // Загружаем шрифт 
 tft.print(FONT_16); // Выводим название шрифта
 // tft.println(" - Потрогай Еще Эти Французские Бу"); // Натпись про БУЛКИ
 tft.println(" - Потрогай Еще Эти Французские Бу"); // Натпись про БУЛКИ
 tft.unloadFont(); // выгрузить шрифт
 

 tft.loadFont(FONT_18); // Загружаем шрифт 
 tft.print(FONT_18); // Выводим название шрифта
 tft.println(" - Потрогай Еще Эти Французск"); // Натпись про БУЛКИ
 tft.unloadFont(); // выгрузить шрифт
 

 tft.loadFont(FONT_20); // Загружаем шрифт 
 tft.print(FONT_20); // Выводим название шрифта
 tft.println(" - Потрогай Еще Эти Францу"); // Натпись про БУЛКИ
 tft.unloadFont(); // выгрузить шрифт
 
 tft.loadFont(FONT_22); // Загружаем шрифт 
 tft.print(FONT_22); // Выводим название шрифта
 tft.println(" - Потрогай Еще Эти Фра"); // Натпись про БУЛКИ
 tft.unloadFont(); // выгрузить шрифт
 


 tft.loadFont(FONT_25); // Загружаем шрифт 
 tft.print(FONT_25); // Выводим название шрифта
 tft.println(" - Потрогай Еще Эти"); // Натпись про БУЛКИ
 tft.unloadFont(); // выгрузить шрифт
 
 
 
 tft.loadFont(FONT_30); // Загружаем шрифт 
 tft.print(FONT_30); // Выводим название шрифта
 tft.println(" - Потрогай Еще Эти"); // Натпись про БУЛКИ
 tft.unloadFont(); // выгрузить шрифт
 delay(200000);
}

В папке с проектом создайте папку data и скопируйте в нее файлы из архива с русскими шрифтами. Загрузите шрифты в файловую систему ESP*266 через меню Инструменты > ESP8266 Sketch Data Upload (Tools > ESP8266 Sketch Data Upload). Когда загрузка будет завершена, статусная панель IDE Arduino покажет сообщение «SPIFFS Image Uploaded», что значит «образ SPIFFS загружен».

Далее загрузите скетч в ваш ESP8266. Если все прошло без ошибок, то на дисплее вы увидите следующее

result

Заключение

В данной статье были рассмотрены основные методы вывода русских символов на различные типы дисплеев, а также приведены рекомендации по выбору наиболее подходящего способа для конкретной задачи. Вывод русских символов на дисплеи является сложным процессом, который требует тщательного подхода и тестирования на разных устройствах. Однако с помощью правильного выбора метода  можно достичь отображения русского текста на любых устройствах.
Материал также доступен на моем канале: Яндекс Дзен и в группе ВК
Категория: Программирование | Добавил: :, (19.03.2023)
Просмотров: 2723 | Теги: Arduino IDE, LCD, TFT_eSPI, Adafruit GFX, OLED, TFT | Рейтинг: 0.0/0
Поделиться:
Всего комментариев: 0
avatar