Русификация библиотеки Adafruit-GFX и вывод русских букв на дисплей в кодировке UTF-8 из Arduino IDE

arduinec
Offline
Зарегистрирован: 01.09.2015

Краткие итоги предыдущих 150 постов

Для русификации библиотеки Adafruit-GFX требуется:
- скачать любой из приведённых ниже архивов;
- заменить файл glcdfont.c в Adafruit-GFX;
- добавить функцию utf8rus() в скетч;
- вставить в начале скетча команду: display.cp437(true);

Применять функцию utf8rus() можно внутри команд печати строк:
display.println(utf8rus("Тест"));

В архивах примеры и библиотеки, различающиеся по виду дисплея:

0.96" OLED 128x64
https://yadi.sk/d/dd7ULuRftVcRV

2.8" TFT Touch Shield 320x240
https://yadi.sk/d/FgUr5NPztVcRd

Nokia 5110 84x48
https://yadi.sk/d/juZ_mZbfsTpez

Более подробная информация в предыдущих постах.
Например:
В посте 27 демонстрируется скетч, с помощью которого можно редактировать шрифты (в том числе и в glcdfont.c).
В посте 40 приводится вариант utf8rus() с экономным использованием оперативной памяти.
В посте 46 показан 2.8" TFT Touch Shield для Uno и Mega, и прилагается полный набор библиотек и примеров для него.
В посте 80 описаны изменения в шрифте для проекта Transistor Tester.
 

KoJIxo3Huk
Offline
Зарегистрирован: 07.02.2017

Зарегистрировался на форуме специально только для того чтобы сказать arduinec СПАСИБО!!! Очень помогли Ваши труды!!!

None
Offline
Зарегистрирован: 15.01.2016

Присоединяюсь к посту выше.

Хотя сейчас и пишу библиотеку(пока внутри общего кода) для работы с SSD1306 заново, жаба давит отдавать полтора десятка килобайт кода и половину оперативной просто за русский язык. Да и не надо мне весь алфавит, только русский, цифры и немного символов.

arduinec
Offline
Зарегистрирован: 01.09.2015

None пишет:

отдавать полтора десятка килобайт кода и половину оперативной просто за русский язык

Половину оперативной памяти занимает буфер экрана, и от языка он не зависит. Все 256 символов шрифта (в том числе и русские) занимают во флеш-памяти 1280 байт.

KoJIxo3Huk
Offline
Зарегистрирован: 07.02.2017

Ещё один огромный плюс нашёл для себя в функции utf8rus - с этой функцией сообщения в сериал монитор пишутся тоже на русском! Супер :)

alexhr
Offline
Зарегистрирован: 16.02.2014

Здравствуйте. Я начинающий :). Помогите разобраться в скетче NokiaRusTest2. Как вывести символы на экран? Покажите пример, или направте на литературу :) 

arduinec
Offline
Зарегистрирован: 01.09.2015

alexhr пишет:

Помогите разобраться в скетче NokiaRusTest2. Как вывести символы на экран?

Подключить библиотеки Adafruit_GFX и Adafruit_PCD8544 (прилагаются в архиве NokiaRus2.zip: https://yadi.sk/d/juZ_mZbfsTpez). В качестве примера использовать скетч NokiaRusTest2.ino.

Ksiw
Offline
Зарегистрирован: 30.08.2016

Друзья, натолкнулся на интересный аспект, в котором пока что не могу разобраться:

В повседневности использую visual micro www.visualmicro.com плагин для визуал студио. Этот плагин всего лишь позволяет задействовать средства arduino IDE в студии. Очень удобно, автозавершение кода, синтаксический анализ - не пропустишь скобку...

Представленный ниже код корректно работает при компиляции в ARDUINO IDE, но криво, если компилить в студии, выводя на экранчик кракозябры.

Никогда ранее с подобным не сталкивался, и был бы рад, если бы кто сумел прояснить ситуацию.

arduino UNO+ нокиа 5110

/*
 Name:    ArdRus.ino
 Created: 08.04.2017 12:57:46
 Author:  Ksiw
*/

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>

Adafruit_PCD8544 display(13, 11, 5, 3, 6);
String utf8rus(String source);

void setup() 
{
  display.begin();
  display.cp437(true);
  display.setContrast(50);
  display.setTextSize(1);
  display.setTextColor(BLACK);
  display.clearDisplay();
  display.setCursor(0, 0);
  display.println(utf8rus("Шрифт 1"));
  display.display();
}

void loop() 
{
  
}
String utf8rus(String source)       /* Recode russian fonts from UTF-8 to Windows-1251 */
{
  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;
}

 

arduinec
Offline
Зарегистрирован: 01.09.2015

Ksiw пишет:

Никогда ранее с подобным не сталкивался, и был бы рад, если бы кто сумел прояснить ситуацию.

А в визуал студии какая кодировка?

Ksiw
Offline
Зарегистрирован: 30.08.2016

Кодировка чего?

P.S. Вылечил, спс arduinec. Сохранил код в студии, указав кодировку текстового файла UTF-8.

Очень странно выглядит, чесс говоря. Это все равно что написать пальцем на песке 5+5 и получить в результате 10, но при этом написав это же выражение, скажем, маркером на лбу соседа, получить иной результат в итоге, что вроде как вполне закономерно, хотя формально то... 

estratos
Offline
Зарегистрирован: 23.04.2017

Я использую этот экран SSD1306 на ардуино про мини, и библиотека Adafruit GFX используя графический буфер забирает почти всю память, поэтому перешел на использование SSD1306Ascii  где нет буфера и выводится только текст. Попытался русский шрифт выводить, заменил в фонте System5x7 кусок с кодами символов. Заработал только перевод русских маленьких букв и вывод английских маленьких. Вместо больших букв как русских так и английских мусор. Как это исправить?

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Ksiw пишет:

Очень странно выглядит, чесс говоря. Это все равно что написать пальцем на песке 5+5 и получить в результате 10, но при этом написав это же выражение, скажем, маркером на лбу соседа, получить иной результат в итоге, что вроде как вполне закономерно, хотя формально то... 

А каким образом Вы запаисываете на песе число 5? Пять черточек? Римские цифры? Арабские цифры? Двоичная система?

Например: пишем 101+101=?

Чему равно? 202 или 1010?

Так что аналогия со лбьом соседа не проходит - Вы пигеие на том жепеске, только в другой системе счисления.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

estratos пишет:

Я использую этот экран SSD1306 на ардуино про мини, и библиотека Adafruit GFX используя графический буфер забирает почти всю память, поэтому перешел на использование SSD1306Ascii  где нет буфера и выводится только текст. Попытался русский шрифт выводить, заменил в фонте System5x7 кусок с кодами символов. Заработал только перевод русских маленьких букв и вывод английских маленьких. Вместо больших букв как русских так и английских мусор. Как это исправить?

Говорю сразу: как "исправить" - не знаю, да и знать не хочу. Могу посоветовать найти тему "Кириллица на дисплее или что я делаю не так?". Там как раз речь о библиотеке, которая не использует буфер, зато поддерживает кириллицу в родной для Arduiono IDE кодировке utf-8. Ссылку лучше брать на самую последнюю версию - ближе к концу обсуждения.

estratos
Offline
Зарегистрирован: 23.04.2017

благодарю за подсказку, только там i2c экран, а у меня spi

KRUTENb
Offline
Зарегистрирован: 03.05.2017

Добрый день. А каким образом можно добавить функцию, чтобы была возможность назвать кнопку по-русски? Библиотека Adafruit_GFX. Пример кода инициализации кнопок Clear  Show  Recalibration: 

void initializeButtons() {

  uint16_t x = 40;
  uint16_t y = 20;
  uint16_t w = 75;
  uint16_t h = 20;
  
  uint8_t spacing_x = 5;
  
  uint8_t textSize = 1;
 
  char buttonlabels[3][20] = {"Clear", "Show", "Recalib."};
  uint16_t buttoncolors[15] = {RED, BLUE, RED};
 
  for (uint8_t b=0; b<3; b++) {
    buttons[b].initButton(&tft,                           // TFT object
                  x+b*(w+spacing_x),  y,                  // x, y,
                  w, h, WHITE, buttoncolors[b], WHITE,    // w, h, outline, fill, 
                  buttonlabels[b], textSize);             // text
  }
 
  // Save the y position to avoid draws
  
  buttons_y = y;
  
}
KoJIxo3Huk
Offline
Зарегистрирован: 07.02.2017

Может так попробовать написать?:

char buttonlabels[3][20] = {utf8rus("Очистить"), utf8rus("Показать"), utf8rus("Перекалибр.")};

 

KRUTENb
Offline
Зарегистрирован: 03.05.2017

Ошибка:

cannot convert 'String' to 'char' in initialization

KoJIxo3Huk
Offline
Зарегистрирован: 07.02.2017

А двумерный массив из Стрингов не получится сделать? Или преобразование типа Стринг_то_Чар какое-нибудь использовать...

KRUTENb
Offline
Зарегистрирован: 03.05.2017

Да вот тоже думаю об этом. Нашел функцию string.toCharArray(buf, len).

arduinec
Offline
Зарегистрирован: 01.09.2015

KRUTENb пишет:

А каким образом можно добавить функцию, чтобы была возможность назвать кнопку по-русски?

Например так:

#define maxString 21
char target[maxString + 1] = "";

void setup()
{
  char buttonlabels[3][20];
  strcpy(buttonlabels[0], utf8rus("Очистить"));
  strcpy(buttonlabels[1], utf8rus("Показать"));
  strcpy(buttonlabels[2], utf8rus("Перекалибр."));

  Serial.begin(9600);
  Serial.println(buttonlabels[0]);
  Serial.println(buttonlabels[1]);
  Serial.println(buttonlabels[2]);
}

void loop()
{
}

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

  strcpy(target, ""); k = strlen(source); i = j = 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; strcat(target, m);
    j++; if (j >= maxString) break;
  }
  return target;
}

Функцмя utf8rus() взята из поста 40, в котором описываются её отличия от стандартной.

KRUTENb
Offline
Зарегистрирован: 03.05.2017

Спасибо большое. Подскажите,пожалуйста, как увеличить количество символов в строке? На кнопке больше 9 букв не выводит.

arduinec
Offline
Зарегистрирован: 01.09.2015

KRUTENb пишет:

Подскажите,пожалуйста, как увеличить количество символов в строке? На кнопке больше 9 букв не выводит.

Можно уменьшить шрифт, можно увеличить размер кнопки, но это уже совсем другая история (к данной теме уже не относится).

KRUTENb
Offline
Зарегистрирован: 03.05.2017

Увеличить длину строки получилось, изменив файл Adafruit GFX. Однако я не заметил того, что функция tft.println(utf8rus("")) уже не работает, хотя кнопки  называются по-русски. В чем может быть дело?

Теперь все работает. Решил вернуть первоначальный вид utf8rus в виде функции, а не отдельной библиотеки.

Vitali-71
Offline
Зарегистрирован: 25.04.2017

Доброго всем дня! Помогите, пожалуйста руссифицировать Цветной графический TFT-экран 480×320 
вот ссылка: http://wiki.amperka.ru/продукты:tft-lcd-480x320 Спасибо!

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Графический дисплей не нуждается в русификации - на нем можно нарисовать все, что угодно.

Vitali-71
Offline
Зарегистрирован: 25.04.2017

я имею ввиду, чтобы писать написи на русском на нем! он не сенсорный

KoJIxo3Huk
Offline
Зарегистрирован: 07.02.2017

Для начала нужно прочитать всю тему с самого начала.

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

Vitali-71 пишет:

я имею ввиду, чтобы писать написи на русском на нем! он не сенсорный

Чтобы писать надписи на русском на графическом дисплее - надо русифицировать библиотеку, а не дисплей. Т.е.ь для начала надо определиться, с какой библиотекой работает дислпей, а дальше уже от этого плясать.

Vitali-71
Offline
Зарегистрирован: 25.04.2017

библиотека UTFT

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

Эта тема про библиотеку Adafruit-GFX. 

Спрашиваем у гугла utft русский шрифт и получаем кучу ссылок:

https://github.com/twsdwf/UTFT-rus

https://грибовы.рф/?p=2240

http://devicter.ru/news/UTFT-part-1

http://devicter.blogspot.ru/2013/03/rusUTFT-SmallFont.html

http://devicter.blogspot.com/2013/11/utft-2-bigfont.html

 

Vitali-71
Offline
Зарегистрирован: 25.04.2017

Jeka_M пишет:

Эта тема про библиотеку Adafruit-GFX.

Все, понял! Ну дурак я, что поделать!!!

obuhus
Offline
Зарегистрирован: 26.05.2017

Дброго дня всем.

Большое спасибо уважаемому arduinec за информацию по русификации. Очень помогло, работает ))

Я новичок в программировании ардуино. Сечас возник вопрос: возможно, чтобы выводимый на экран текст, выравнивался по правому краю, а не по левому, как сейчас?

Заранее спасибо.

KoJIxo3Huk
Offline
Зарегистрирован: 07.02.2017

Нужно высчитывать длину строки. У меня, например, для выравнивания по центру экрана высчитывается позиция курсора так:

pos_x = 320 / 2 - utf8rus("любой Ваш текст").length() * 12 / 2

 

obuhus
Offline
Зарегистрирован: 26.05.2017

Вроде получается) Спасибо!!!

obuhus
Offline
Зарегистрирован: 26.05.2017

KoJIxo3Huk пишет:

Нужно высчитывать длину строки. У меня, например, для выравнивания по центру экрана высчитывается позиция курсора так:

pos_x = 320 / 2 - utf8rus("любой Ваш текст").length() * 12 / 2

 

Теперь новая проблема. "любой Ваш текст" у меня не текст, а числовая переменная. Как вычислить количество цифр в числе?

Прошу прощения, что отвлекаю по пустякам.

KoJIxo3Huk
Offline
Зарегистрирован: 07.02.2017

Ну почему пустяки? Меня эта задача тоже первоначально в ступор поставила :)

Можно преобразовать число в строку, а дальше задача сводится к тривиальной )) Вот, например: http://forum.amperka.ru/threads/%D0%9F%D1%80%D0%B5%D0%BE%D0%B1%D1%80%D0%B0%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F-%D1%87%D0%B8%D1%81%D0%BB%D0%B0-%D0%B2-%D1%81%D1%82%D1%80%D0%BE%D0%BA%D1%83.740/

А вот другие методы: https://habrahabr.ru/post/269237/

obuhus
Offline
Зарегистрирован: 26.05.2017

KoJIxo3Huk пишет:

Ну почему пустяки? Меня эта задача тоже первоначально в ступор поставила :)

Можно преобразовать число в строку, а дальше задача сводится к тривиальной )) Вот, например: http://forum.amperka.ru/threads/%D0%9F%D1%80%D0%B5%D0%BE%D0%B1%D1%80%D0%B0%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F-%D1%87%D0%B8%D1%81%D0%BB%D0%B0-%D0%B2-%D1%81%D1%82%D1%80%D0%BE%D0%BA%D1%83.740/

А вот другие методы: https://habrahabr.ru/post/269237/

Огромное спасибо!!! Не сразу, но разобрался. Работает! )))

Вот такая конструкция получилась: tft.setCursor (240 - String(ProFile).length() * 24, 215); 

ProFile - как раз переменная, количество цифр в которой я и вычисляю.

Один странный момент, только: цифры 0123... нормально прижимаются к правому краю, а 10 почему-то выводится с отступом от правого края пикселей на 5-8. В чем подвох может быть?

KoJIxo3Huk
Offline
Зарегистрирован: 07.02.2017

Может быть ширина единицы меньше, чем у других символов?

Попробовать вывести сначала одну единицу, затем 11, 111 и т.д. и смотреть - будет ли увеличиваться расстояние от правого края. Если это так - то придётся ещё учитывать меньшую ширину единицы в расчётах.

obuhus
Offline
Зарегистрирован: 26.05.2017

KoJIxo3Huk пишет:

Может быть ширина единицы меньше, чем у других символов?

Попробовать вывести сначала одну единицу, затем 11, 111 и т.д. и смотреть - будет ли увеличиваться расстояние от правого края. Если это так - то придётся ещё учитывать меньшую ширину единицы в расчётах.

Вообще, шрифт моноширинный. Не думаю, что дело в единице. Взят вот здесь http://arduino.ru/forum/programmirovanie/rusifikatsiya-biblioteki-adafruit-gfx-i-vyvod-russkikh-bukv-na-displei-v-kodi

Попробовал. 0-9 - в самый край. 10-50 с отступом. 100-150 с двойным отступом. О как! Чего делать? Где рыть?

Может есть какая-то зависимость от разрядности числа?

KoJIxo3Huk
Offline
Зарегистрирован: 07.02.2017

В общем, я считал так: шрифт у нас размером 5*7, но нужно ещё учесть расстояние между знаками, итого я считал ширину знака = 5+1 = 6 знаков. Если размер шрифта равен двум, то, соответственно, ширина увеличивается до 12 пикселей. У Вас, видимо, размер шрифта = 4, раз ширина символов = 24. Я бы прямо по пикселям посчитал - сколько пикселей между знаками и внёс соответствующую поправку.

По идее шрифт должен при увеличении и расстояние между знаками пропорционально увеличивать, но я большие тексты не проверял.

obuhus
Offline
Зарегистрирован: 26.05.2017

Шрифт №3. 12 я практически от фонаря написал, пока экспериментировал. Сейчас вообще 24 поставил - без изменений...

KoJIxo3Huk
Offline
Зарегистрирован: 07.02.2017

Если размер шрифта = 3 - то надо умножать кол-во символов на 18. Иначе либо не все символы влезут, или не от края будут расположены.

obuhus
Offline
Зарегистрирован: 26.05.2017

Думаю, не учтено именно расстояние между символами. Надо формулу расчета длины числа доработать. Добавить расчет количества расстояний между символами... Только как? Пока не соображу...

KoJIxo3Huk
Offline
Зарегистрирован: 07.02.2017
tft.setCursor (240 - String(ProFile).length() * 18, 215); 

 

obuhus
Offline
Зарегистрирован: 26.05.2017

СУПЕР!!! Отлично всё работает! Спасибо большое))) 

В чем математический подвох? Почему с 12 или 24 не работало?

KoJIxo3Huk
Offline
Зарегистрирован: 07.02.2017

Ширина символа = 5 пикселей + 1 пиксель на пробел. Если размер шрифта = 2, то ширину 6 умножаешь на 2, если размер шрифта = 3 - то умножаешь 6 на 3. Элементарно, Ватсон )))

obuhus
Offline
Зарегистрирован: 26.05.2017

ЭЭЭххх... Учусь, учусь... А помирать, похоже, всёравно дураком... ))) Спасибо!

obuhus
Offline
Зарегистрирован: 26.05.2017

Новый вопрос к уважаемому KoJIxo3Huk. 

Надеюсь, модераторы не забанят...  У меня новый вопрос. Есть таблица 3 колонки, 2 строки. Если вибираю для редактирования ячейку 1 строки 1 колонки - надо блокировать возожность редактирования других ячеек. Ручками прописать можно, но не правильньно, как кажется. Подозреваю, что есть способ делать это в цикле. Но как - не соображу... Есть решения? Может пошлете куда? )))

arduinec
Offline
Зарегистрирован: 01.09.2015

obuhus пишет:

Может пошлете куда?

Так как вопрос не относится к руссификации, то разумнее создать свою тему. Там привести свой скетч и правильно сформулировать вопрос.

arduinec
Offline
Зарегистрирован: 01.09.2015

arduinec пишет:

правильно сформулировать вопрос

http://arduino.ru/forum/otvlechennye-temy/robert-shekli-vernyi-vopros

"Чтобы правильно задать вопрос, нужно знать большую часть ответа".