Написание русскоязычного текста на графических дисплеях с контролером ks0108 или его аналогами все еще представляет существенные трудности. Библиотека openGLCD, которую рекомендуют официальные сайты Arduino, в оригинальной комплектации последней на данный момент версии не содержит никаких кириллических шрифтов, кроме шрифта cp437font8x8. На практике он малопригоден, потому что в русскоязычной части поддерживает кодировку Win-1251. Следовательно, чтобы выводить символы таким шрифтом, их нужно либо вставлять в текст восьмеричными или шестнадцатеричными кодами (и при этом остаются неясности со строчной буквой «я», как указывает в комментарии сам создатель шрифта), либо все равно писать отдельную функцию перекодировки, как это сделал arduinec для библиотеки Adafruit-GFX.

Кроме всего прочего, cp437font8x8 крупноват для экранчиков 128х64 точки. Оптимальным размером шрифта для вспомогательных надписей на таком дисплее остается System5x7. Мы здесь сосредоточимся на русификации именно системного шрифта, хотя читатель может по этому образцу самостоятельно русифицировать и любой другой шрифт (особенно, если у него экран побольше).

А в чем проблема?


Для начала давайте вникнем в корни проблемы. Среда Arduino IDE — это обычный текстовый редактор Windows, который работает в универсальной кодировке UTF-8, как любой другой в современных версиях Windows (Блокнот, например). UTF-8 представляет собой экономичную версию многобайтовой кодировки UNICODE. В UTF-8 англоязычные символы, цифры, точки-запятые-скобки и всякие прочие значки представлены одним байтом, совпадающим со стандартной кодировкой ASCII. Поэтому их представление в коде скетча не представляет никаких трудностей: строка англоязычных символов после компиляции передается в загружаемый hex-файл без изменений и оказывается понятна 8-разрядному контролеру, как говорится, «без перевода».

В процессе этого преобразования каждый символ, как и в любой программе на любом языке программирования, представляется непосредственно в виде его кода, то есть порядкового номера в таблице шрифта, из которой программа извлекает графическое начертание соответствующего символа. В файле шрифта System5x7.h библиотеки openGLCD количество символов представлено переменной font_Char_Count типа uint8_t, то есть не может превышать величины одного байта. Поэтому кириллические символы, которые в UTF-8 занимают два байта, не могут быть переданы контроллеру обычным образом.

Предыдущие попытки решения
Заметим, что это было не всегда так. Версии Arduino 1.0.x (и, по слухам, 1.6.0) усекали двухбайтовый код до однобайтового, банально отбрасывая старший байт (который для кириллицы, как следует из таблицы UTF-8 по ссылке выше, равен либо 0xD0, либо 0xD1). Потому для доработки шрифта в этих версиях среды годится старая библиотека GLCD v3, в которой массив шрифта просто дополнялся символами кириллических букв так, чтобы их позиции совпадали с младшим байтом кодировки UTF-8 (байты с 0x80 по 0xBF). Более подробно такая модернизация описана в статье автора «Работа с текстом на графическом дисплее». Повторяю — для нее нужна одна из версий Arduino IDE 1.0.x в совокупности с библиотекой GLCD v3, а не их более современные варианты.

В новых версиях Arduino IDE стало все сложнее. Библиотека решительно отказывается понимать двухбайтовые номера символов, выводя вместо них пустое место, потому простой переделкой шрифта тут не обойдешься. Приходится дополнить его функцией перекодировки двухбайтовых символов в однобайтовые.

Решение


Автор не стал лезть в недра библиотечных функций, а написал для openGLCD надстройку в виде функции outstr(), которая перебирает все элементы входной строки, пропуская их через оператор выбора Switch. Он вылавливает из строки кириллические символы и заменяет их однобайтовыми кодами, соответствующими модернизированному файлу шрифта System5x7R.h.

Например, для заглавной русской буквы «Ф» строка замены будет такой:

case 'Ф': GLCD.PutChar(0xA4); break;

Здесь 0xA4 — младший байт кодировки буквы «Ф» в UTF-8 (см. ссылку выше). В соответствии с этой кодировкой составлен новый файл шрифта System5x7R.h. В принципе при таком подходе в шрифте можно применять любую кодировку русских символов и любых других глифов, которые вздумается вставить в шрифт. Лишь бы их общее количество не превышало 128 штук: от начала таблицы до символа 0x7F (127 — последний символ стандартной таблицы ASCII) целесообразно оставить шрифт в неприкосновенности.

Правда, пару вольностей с таблицей ASCII я себе разрешил. Дело в том, что в оригинальном шрифте System5x7.h значок градуса вынесен в последнюю строку таблицы, занимая символ 0x80, который у нас уже относится к кириллице. Чтобы не нарушать порядок построения кириллической таблицы в соответствии с UTF-8, эта строка выброшена из файла. А значок градуса пристроен вместо символа ASCII «~» (номер 0x7E), который в шрифте все равно не использовался по назначению. Зато такая замена позволяет вводить значок градуса в тексте скетча прямо с клавиатуры в виде символа «~».

Еще одна вольность связана с тем, что автор на дух не переносит перечеркнутый ноль — архаику времен АЦПУ и монохромных текстовых дисплеев. Потому ноль в модернизированном шрифте заменен на глиф буквы «О». Те, кто придерживается пуристических принципов, могут просто удалить в файле шрифта System5x7R.h эту вставку (старый глиф перечеркнутого нуля там оставлен закомментированным, его код 0x30).

В модернизированной библиотеке openGLCD, которую вы можете скачать по ссылке в конце статьи, внесено еще одно исправление — изменен порядок подключения выводов для дисплеев с контроллером ks0108. Почему автором библиотеки выбран такой порядок (см. таблицу по ссылке на официальном сайте Arduino), неизвестно. В модернизированном варианте подключение дисплея (для примера выбран популярный MT-12864J) осуществляется согласно вот такой схеме:

Схема подключения MT-12864J
image

Переменный резистор R1 здесь подключается согласно рекомендации производителя, а резистор R2 служит для ограничения тока подсветки, если она подключена не к напряжению 5 В, а прямо ко входному источнику питания (вывод Vin Arduino) с более высоким напряжением.

Пример вывода на дисплей MT-12864J русского алфавита вперемешку с латинским, а также цифр и значка градуса, представлен на фото:

image

Текст скетча для этого примера:

Текст скетча с выводом русского алфавита
#include <openGLCD.h> //подключим библиотеку
#include <outstr.h> //файл с функцией вывода русских букв
#include <System5x7R.h> //файл с кодами русских букв

void setup() {
      GLCD.Init(); //инициализация
      GLCD.ClearScreen();
      }

void loop()
      {
      GLCD.SelectFont(System5x7R);  //выбираем шрифт
      GLCD.CursorTo(0,0); //установим курсор в начальную позицию 
      //выводим смешанные англо-русские строки: 
      outstr("ABC АВГДЕЖЗИКЛМНОП\n");
      outstr("PRQ РСТУФХЦЧШЩЪЫЬЭЮЯ\n");
      outstr("nts абвгдежзийклмноп\n");
      outstr("xyz рстуфхцчшщъыьэюя\n");
      GLCD.println("1234567890");
      GLCD.CursorTo(19,4); //установим курсор в предпоследнюю позицию 5-й строки 
      GLCD.print("~C"); //градус С 
      GLCD.println("@;/.,|<>()=-_{}\"'");
            GLCD.CursorTo(4,7); //установим курсор в поз 4 строки 8
      GLCD.print("MT-12864J");
      }



Так как файлы с функцией outstr.h и шрифтом System5x7R.h размещены в корневом каталоге модернизированной библиотеки, то на них надо размещать отдельные ссылки в начале скетча с помощью директивы #include. Для англоязычных надписей удобно по-прежнему пользоваться стандартными функциями println/print, а вот при необходимости перевода строки в русском тексте необходимо явно указывать символ «\n».

Подправленный вариант библиотеки вы можете скачать здесь. Распакованную библиотеку (папку openGLCD) следует поместить в папку Arduino\libraries, как обычно. Пример скетча находится в том же архиве отдельно (в не в папке Examples библиотеки). Подключение дисплея с контроллером ks0108 в соответствии с этой библиотекой отражено на схеме выше. Если вам захочется дополнительно изменить порядок подключения выводов, то разыщите в папке Arduino\libraries\openGLCD\config\ks0108 файл PinConfig_ks0108-Uno.h и отредактируйте в нем строки под заголовком «Data pin definitions» и далее, ориентируясь на исправления автора.

В следующей публикации мы попытаемся разобраться с русификацией строчных дисплеев. Как вы увидите, с ними все одновременно и проще и сложнее.
Поделиться с друзьями
-->

Комментарии (13)


  1. Alex_ME
    13.01.2017 22:08
    +1

    Среда Arduino IDE — это обычный текстовый редактор Windows, который работает в универсальной кодировке UTF-8, как любой другой в современных версиях Windows (Блокнот, например)

    Неправда, блокнот сохраняет в CHCP 1261


    1. barkalov
      14.01.2017 02:42


      1. Alex_ME
        14.01.2017 02:46

        Черт, за столько лет и не заметил. Спасибо. Правда, не слишком часто пользуюсь блокнотом.


    1. SGordon123
      14.01.2017 08:16

      ANSI это же 1251 для русского?


  1. fundorin
    13.01.2017 22:46

    Библиотека u8g2 поддерживает несколько русских шрифтов из коробки и импорт сторонних шрифтов любых. Можно как с гитхаба скачать, так и из менеджера библиотек самой Arduino IDE. Автор активно развивает библиотеку и добавляет поддержку новых устройств.


    1. YRevich
      14.01.2017 10:29

      Я смотрел все альтернативы, разумеется. Библиотека u8g2 чересчур сложна в применении и, кроме того, дело не в том, чтобы поддерживать шрифт. В любой библиотеке можно создать любой шрифт, это вопрос максимум полдня работы. Дело в удобстве вывода русских надписей — я стремился к тому, чтобы прямо с клавы получать читаемый код скетча. Иначе получишь трудновылавливаемые ошибки — например, когда названия месяцев в календаре по русски, ошибку в написании можно обнаружить через полгода. Я поэтому и значок градуса переместил.


      1. fundorin
        15.01.2017 00:56

        Честно говоря, не увидел никаких сложностей с этой библиотекой. Русский вводится и отображается без проблем.

        Три русских шрифта зашиты в библиотеку из коробки:
        Unifont — https://github.com/olikraus/u8g2/wiki/fntgrpunifont
        CU12 — https://github.com/olikraus/u8g2/wiki/fntgrpcu12
        PX11 — https://github.com/olikraus/u8g2/wiki/fntgrpx11

        Сторонние добавляются очень легко и отнюдь не за полдня. UTF8 отображает отлично.

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


        1. YRevich
          15.01.2017 10:15

          fundorin, я же совершенно не возражаю. Вполне вероятно, u8g2 — наилучшее решение, а я чего-то не увидел (в первую очередь, наверное, внятной документации, позволяющей с ходу оценить преимущества и недостатки). Но так или иначе, GLCD распространена больше, примеры для нее на каждом углу, и потому мое решение ориентируется на нее.


  1. znsoft
    14.01.2017 10:44

    case 'Ф': GLCD.PutChar(0xA4); break;

    а разве не проще было написать что то вроде?:
    String charMap = "рстуфхцшщ....";
    ....
      int cyrChar = charMap.indexOf(str[nn]);
    if(cyrChar>=0)GLCD.PutChar(0x80+cyrChar); else GLCD.PutChar(str[nn]); 
    ...
    


    www.arduino.cc/en/Reference/StringIndexOf


    1. YRevich
      14.01.2017 11:08

      Может, сработает, но скорее всего нет. Я пробовал сократить алгоритм по-всякому, естественно (см. ссылку на arduinec'а в начале статьи). Простая замена кода элемента строки — напрашивается. Но никаким путем это не работало — именно из-за того, что исходные символы двухбайтовые. Строки типа String я, честно говоря, не пробовал, но уверен, что там будет то же самое: нигде не написано, что String поддерживает двухбайтовые символы (то есть наверняка не поддерживает — его элементы имеют тип char). Потому я плюнул на изыски, на которые ушла куча времени, и сделал тупую замену символов напрямую — пусть компилятор сам разбирается. Еще и потому, кстати, что сокращения времени работы все равно не получится, будет только сокращение исходного кода.


  1. mitrich
    14.01.2017 16:49

    "0" и "О" различимы?


    1. YRevich
      14.01.2017 17:15

      В шрифте 5х7 они абсолютно идентичны (если не считать перечеркивания нуля по умолчанию). Не путайте компьютерные TTF-шрифты с матричными при дефиците точек.


  1. mitrich
    14.01.2017 16:49

    Это ноль и заглавная О соответственно