Русификация библиотеки Adafruit-GFX и вывод русских букв на дисплей в кодировке UTF-8 из Arduino IDE
- Войдите на сайт для отправки комментариев
Русификация библиотеки Adafruit-GFX и вывод русских букв на дисплей в кодировке UTF-8 из Arduino IDE
При этом русские буквы вводятся стандартным способом через русскую клавиатуру и отображаются в Arduino IDE как русские символы.
Мне понравились библиотеки Adafruit-GFX и Adafruit-SSD1306 (https://github.com/adafruit) для OLED Display 0.96 128x64 (http://arduino-project.net/oled-l2c-arduino-uno/).
Но (как и следовало ожидать) в них не оказалось русского шрифта. Добавить его оказалось несложно: нужно лишь заменить в файле glcdfont.c из Adafruit-GFX некоторые символы на русские буквы (в нужной кодировке).
Но шрифт рассчитан на однобайтовую кодировку букв, а 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 >= 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; }
Применять ее можно внутри команд печати строк:
display.println(utf8rus("Тест"));
Саму функцию можно добавить в скетч, либо в виде отдельного файла положить в каталог скетча (как и сделано в примере).
В архиве utf8rus.zip прилагаются:
- файл glcdfont.c с русскими буквами для замены в Adafruit-GFX;
- пример OledRusTest для демонстрации русских (и других) символов и работы функции utf8rus();
- пример OledSymbolTest для демонстрации использования динамических символов.
Обращаю внимание в примерах на то, что мой дисплей подключается через SPI.
https://yadi.sk/d/FWO6Y1NwiqLVu
В примере OledRusTest первые два экрана отображают все символы, которые заложены в glcdfont.c
На первом экране стандартная ASCII-кодировка. Не отображаются символы 0x0A (воспринимается как перевод строки) и 0x0D (игнорируется), поэтому вместо них выводятся пробелы.
На втором экране русские буквы, другие символы из кодировки Windows-1251 и дополнительные символы для дисплея.
Так как в glcdfont.c нашлись свободные места, добавил туда цифры для указания степени числа и некоторые символы для динамических эффектов.
Третий и четвертый экраны отображаются с использованием utf8rus()
При выборе динамических символов для примера OledSymbolTest руководствовался картинкой экрана MP3-плеера.
Получилось 7 динамических объектов и несколько статичных картинок.
Разумеется, все символы можно нарисовать на дисплее графическим путем, но буквенные символы должны занимать меньше памяти в контроллере.
Ещё в примере для библиотеки Adafruit-SSD1306 заменил звезду на снежинку:
Падающие снежинки выглядят намного лучше, чем падающие звезды.
А можно как то переделать шрифт для библиотек Adafruit_ST7735 и Adafruit-GFX. Хотелось писать на русском в проекте. Дисплей 1.8 TFT. Подключение к Nano Pro Mini по SPI.
Спасибо!
А можно как то переделать шрифт для библиотек Adafruit_ST7735 и Adafruit-GFX. Хотелось писать на русском в проекте. Дисплей 1.8 TFT. Подключение к Nano Pro Mini по SPI.
Спасибо!
Библиотека Adafruit_ST7735 для вывода шрифта использует библиотеку Adafruit-GFX, а в ней для вывода русских букв нужно заменить файл glcdfont.c, который (с примерами) прилагается выше.
Пробовал, но как только в программе вводишь русские символы, на экране они занимают 2 знакоместа или 2 байта, не знаю как правильно объяснить...
Во второй строчке экрана, набраны буквы "АБВГД". Вот что он отображает, перед каждой буквой какой то значок. Букву "А" перерисовал в редакторе, отображается правильно. Остальные не трогал.
Для того, чтобы русские буквы нормально выводились, нужно использовать функцию utf8rus(). Она есть в архиве и в примере показано как она работает.
Судя по фотографии, файл glcdfont.c не заменён, то есть русских букв в Adafruit-GFX нет.
Я вставлял ваш файл glcdfont.c, но вот воспользоваться функцией utf8rus() не получается, при компиляции скетча выдается ошибка на эту строчку. Возможно я что то не так делаю...
tft.println(utf8rus("АБВГД")); пытался вот так ее использовать
Я вставлял ваш файл glcdfont.c, но вот воспользоваться функцией utf8rus() не получается, при компиляции скетча выдается ошибка на эту строчку. Возможно я что то не так делаю...
Какую ошибку выдаёт компилятор?
Если на отсутствие функции, то скорее всего функция не добавлена к скетчу. Как добавить функцию описано в первом посте данной темы.
Саму функцию можно добавить в скетч, либо в виде отдельного файла положить в каталог скетча (как и сделано в примере).
preproc.substitute_unicode=false в преференсах IDE, добавить win1251 шрифты в glcdfont.c и везде по русски, проверял на 5110 экране.
Ну что ж... Спасибо, разобрался через несколько часов проб и ошибок. Все получилось, только пришлось немного переписать код. Отличия минимальны, поменял пару адресов:
Ну и соответственно сделал ее библиотекой. Русифицированный файл glcdfont.c оставил от arduinec
Ну что ж... Спасибо, разобрался через несколько часов проб и ошибок. Все получилось, только пришлось немного переписать код. Отличия минимальны, поменял пару адресов:
Ну и соответственно сделал ее библиотекой. Русифицированный файл glcdfont.c оставил от arduinec
Отличия, вероятнее всего, связаны с тем, что в старой библиотеке Adafruit-GFX в шрифте файла glcdfont.c было 255 символов - отсутствовал символ B0 (=176). В новой же библиотеке и моём файле glcdfont.c там 256 символов.
Arduinec, я вот только так и не понял, куда в знакогенераторе спряталась маленькая "я". Получилось как в том анекдоте: "Ты суслика видишь?...")))
Небольшие изменения для новой версии библиотеки Adafruit-GFX
В старой версии библиотеки Adafruit-GFX в файле со шрифтами glcdfont.c было 255 символов - отсутствовал символ 0xB0 (=176). В новой версии библиотеки (https://github.com/adafruit/Adafruit-GFX-Library) данный символ добавили, но для совместимости со старыми версиями в код добавили пропуск данного символа по умолчанию. При этом была добавлена и функция cp437(), которая при аргументе true позволяет выводить указанный символ.
В моём файле glcdfont.c с русскими шрифтами изначально были все 256 символов, и в старой библиотеке всё отображалось.
Для того, чтобы в новой библиотеке символ 0xB0 (=176) отображался (в кодировке Windows-1251 ему соответствует символ градуса) нужно в начале скетча (после инициализации дисплея) применить функцию cp437() с аргументом true:
display.cp437(true);
Функция utf8rus() для перекодирования русского шрифта остаётся без изменения.
Применять функцию можно внутри команд печати строк:
display.println(utf8rus("Тест"));
Инструкция по русификации Adafruit-GFX остаётся прежней:
- скачиваем архив utf8rus2.zip по приведённой ниже ссылке;
- заменяем файл glcdfont.c в Adafruit-GFX;
- функцию utf8rus() добавляем в скетч, или в виде отдельного файла utf8rus.ino копируем в каталог скетча (как и сделано в примере);
- смотрим примеры OledRusTest и OledSymbolTest (фотографии к ним остались прежними).
https://yadi.sk/d/kdjXv7-ziwFL5
P.S. Для старой версии библиотеки Adafruit-GFX нормально работает вариант из первого поста данной темы.
Arduinec, я вот только так и не понял, куда в знакогенераторе спряталась маленькая "я". Получилось как в том анекдоте: "Ты суслика видишь?...")))
Надеюсь вышеприведенные изменения решат все проблемы с отображением русских букв и других символов.
Маленькая "я" в кодировке Windows-1251 (и у меня в файле) имеет код 0xFF (=255).
повторяться не буду. есть вопрос по этой библиотеке. уже создал тему. как написать личное сообщение топикстартеру не нашел.
http://arduino.ru/forum/obshchii/adafruit-biblioteka-dlya-raboty-s-oled-...
А у меня та же проблема на таком же 1.8 дисплее маленькая "з" нету
Вернее не нету, а вместо нее маленькая "х"
А у меня та же проблема на таком же 1.8 дисплее маленькая "з" нету
Вернее не нету, а вместо нее маленькая "х"
Выполнено всё, что в пункте #15 описано?
Сделал все кроме
display.cp437(true);
выдавала ошибку изменил tft.cp437(true);
начали крокозяблы вместо слов писать, потом убрал эту строку и о чудо маленькая з появилась сама по себе о_О ниче не понятно) мож я сам в начале протупил
Ну что ж... Спасибо, разобрался через несколько часов проб и ошибок. Все получилось, только пришлось немного переписать код. Отличия минимальны, поменял пару адресов:
Ну и соответственно сделал ее библиотекой. Русифицированный файл glcdfont.c оставил от arduinec
Спасибо без Вас пришлось бы писать латиницей!!!
А можно по подробней? Я как вставил это в начале скетча перед setup все отлично заработало. А вы пишите что вы сделали из этого библиотеку, т.е. убрали кучу строк кода в одну строку #include ????
Volfram, сохранил этот код в файл с именем utf8rus.h, и потом вставил как библиотеку #include <utf8rus.h>
Здравствуйте, arduinec.
Спасибо за ваши труды.
Ваша последняя модификация utf8rus2 работает, но с символом "°" - "B0" у меня есть проблема.
Если его скопировать из Word, то на экране от всегда отображается как "В°".
как единственный символ "°" получилось вставить как "/xB0".
Ваша последняя модификация utf8rus2 работает, но с символом "°" - "B0" у меня есть проблема.
Если его скопировать из Word, то на экране от всегда отображается как "В°".
как единственный символ "°" получилось вставить как "/xB0".
В Word этот символ возможно имеет другой код (не проверял).
В Си для нестандартных символов можно использовать комбинацию "\xNN", где NN - шестнадцатиричный код символа. При этом их можно комбинировать с обычными символами.
Например: 19 градусов Цельсия = "19\xB0C".
arduinec, хочу поблагодарить за тему, все получилось с дисплеем 2.2 дюйма на LI9341, и даже символ градуса )) со второй попытки, да )
но, если можно, объясните на пальцах, или отправьте что почитать, о том как вы создавали русские символы, и дополнительные тоже, как помещали и вместо чего в файл glcdfont.c
необходимы свои спец символы
я понимаю, что нужно, грубо, символ зарисовать на поле определенного размера попиксельно, потом высчитать строки и поместить в файл, верно? но как это делать не представляю, сам не программист, увлекся контроллерами недавно
но, если можно, объясните на пальцах, или отправьте что почитать, о том как вы создавали русские символы, и дополнительные тоже, как помещали и вместо чего в файл glcdfont.c
необходимы свои спец символы
Прошу прощения за задержку с ответом (проходил обследование в больнице).
Есть какие-то программы, которые позволяют шрифты рисовать. Мне было проще написать программку на Си, которая позволила изменить шрифты.
Ниже скетч, который преобразует коды символа Й в визуальный формат и обратно:
Для изменения шрифтов я использовал программу FontEditor. С ее помощью открываешь файл glcdfont.c и можно его подредактировать
спасибо за ответ, по скетчу понятно, только не понятно куда именно в файл glcdfont.c полученый кусок в хексе поместить, подозреваю, что можно просто бегло просмотрев найти именно свой символ и его заменить ))
но в проекте решил не заморачиваться с этим, просто научился выводить рисунок на дисплей, создавать символ какого либо процесса и на нужное место помещать, так наверное будет даже лучше.
но все равно спасибо, возможно и передумаю и вернусь обратно к символам в самом фонте..
и еще, выздоравливайте )
Skayl ,я не смог найти редактор о котором вы говорили )
и еще по картинке можно догадаться что я тут пытаюсь построить ))
очередной огород на кухню ))
первый вариант честно отработал пол года, использовал ардуино уно и дисплей на примере которого в этой теме показана руссификация библиотеки. теперь хотелось бы добавить немного информативности, русский язык, изменить немного досветку (увеличить количество света), сам полив..
в общем пока бодаюсь с новым оборудованием, сейчас уперся в картридер sd карты, который на платке дисплея бонусом, не получается запустить пока, пытаюсь разобраться с интерфейсом SPI
извиняюсь за кривую фотку, на форуме только зарегистрировался
только не понятно куда именно в файл glcdfont.c полученый кусок в хексе поместить, подозреваю, что можно просто бегло просмотрев найти именно свой символ и его заменить
Для примера используем ту же букву Й:
В кодировке Windows-1251 код символа Й = 0xC9, в десятичной системе = 201. В файле glcdfont.c (из архива utf8rus2.zip) массив символов начинается со строки 16. Сложив 16 и 201 получаем, что символ Й находится в строке 217.
.. Сложив 16 и 201 получаем, что символ Й находится в строке 217.
вот теперь понял )
Был бы премного благодарен за FontEditor. перекачал сотню, ни у одного нет импорта или они на столько крутячие, что разбираться в них не стоит вовсем
но в проекте решил не заморачиваться с этим, просто научился выводить рисунок на дисплей, создавать символ какого либо процесса и на нужное место помещать, так наверное будет даже лучше.
И как же?
И как же?
вот здесь человек показал как, правда для другого дисплея http://robotclass.ru/tutorials/graphics-lcd-nokia-5110/
в общем создаем в Paint графический файл нужного размера, обязательно сохраняем как 256-цветный рисунок с расширением bmp, затем нам нужно его конвертировать в hex формат, для этого можно использовать программы (их есть в сети, но я не надыбал простой и без установки), поэтому воспользовался ссылкой в статье, http://robotclass.ru/tutorials/graphics-lcd-nokia-5110/ работает. выбираем наш шестнадцатиричный формат (хотя можно и в двоичной системе), указываем путь к нашему файлу bmp, и получаем код картинки.
затем копируем в массив, прописываем свое имя, а потом и выводим на экран, не забывая указывать реальный размер картинки.
вот скетч для примера
Ну уж если использовать картинки вместо букв, то у меня недавно появился дисплей TFT SPI (http://ru.aliexpress.com/item/Free-Shipping-1-8-Serial-SPI-TFT-LCD-Modul...). Там уже приделан слот для SD-карты, с которой выводятся на дисплей картинки в формате bmp. Таким образом можно создать любой набор картинок с буквами и символами и выводить их в нужном порядке в любое место дисплея.
И как же?
вот здесь человек показал как, правда для другого дисплея http://robotclass.ru/tutorials/graphics-lcd-nokia-5110/
Спасибо большое! Так и буду делать. И символы все на месте и картинки вроде быстро рисует.
Ну уж если использовать картинки вместо букв, то у меня недавно появился дисплей TFT SPI (http://ru.aliexpress.com/item/Free-Shipping-1-8-Serial-SPI-TFT-LCD-Module-Display-PCB-Adapter-Power-IC-SD-Socket/1906735103.html). Там уже приделан слот для SD-карты, с которой выводятся на дисплей картинки в формате bmp. Таким образом можно создать любой набор картинок с буквами и символами и выводить их в нужном порядке в любое место дисплея.
У меня почти тоже самое, только не SPI как я понял. У меня там есть слот, так же можно читать и т.д. Но мне грубо говоря в проект добавить 6 картинок 32*32 максимум и все.
Таким образом можно создать любой набор картинок с буквами и символами и выводить их в нужном порядке в любое место дисплея.
)) ну перебор конечно, а вот типа иконок парочку можно, мне кажется.
кстати я с этим слотом для SD карты помучался немного (скорее просто отсутствие опыта) но таки запустил. Думаю использовать его для хранения данных с датчиков, допустим массив кольцевой в месяц, и построение графиков, с возможностью прокрутки вправо влево.
Еще раз спасибо за руссификацию библиотеки, и за пояснения по замене символов, какие то спецсимволы таки буду использовать, ибо так намного удобнее.
В последнее время на форуме было несколько крупных публикаций по поводу экономного расходования оперативной памяти. Класс String был забракован из-за излишнего потребления ресурсов. Более экономным для работы со строками является использование массивов char. Настала пора модифицировать функцию для перекодирования русского шрифта utf8rus().
Для сохранения перекодированной строки требуется массив char. Чтобы его не определять при каждом вызове функции, создадим его один раз в глобальных переменных. Длину массива определим исходя из максимального размера строки, выводимой на дисплей.
В исходном варианте дисплей имеет ширину 128 пикселей. Ширина каждой буквы составляет 5 пикселей плюс интервал между буквами (6-й пиксель). В итоге, поделив 128 на 6, получаем, что максимальная длина выводимой строки составляет 21 символ плюс ещё один знак для нулевого символа конца строки.
Надо сказать, что библиотеки Adafruit позволяют разбивать длинные строки на несколько строк дисплея, но на маленьких экранчиках это редко нужно, поэтому данный вариант не рассматривается.
Чтобы не выскочить за пределы массива в функцию utf8rus() теперь встроена проверка на превышение максимального размера строки (более длинная строка просто отсекается).
Вызов функции utf8rus() для перекодирования русского шрифта остаётся без изменения:
display.println(utf8rus("Тест"));
Инструкция по русификации Adafruit-GFX остаётся прежней:
- скачиваем архив utf8rus3.zip по приведённой ниже ссылке;
- заменяем файл glcdfont.c в Adafruit-GFX;
- функцию utf8rus() добавляем в скетч, или в виде отдельного файла utf8rus.ino копируем в каталог скетча;
- смотрим примеры OledRusTest и OledSymbolTest (фотографии к ним остались прежними).
https://yadi.sk/d/-eYXcQ1KnqEZt
arduinec, Я бы добавил только пару моментов :
1. определение массива все таки внес в функцию.
2. Его размер сделал бы так:
char
target[sizeof(
source)]
;
3. Функцию
utf8rus внес бы в класс AdafruitGFX и вызов был бы так: tft.println(tft.utf8rus("ТЕКСТ"));По пункту 3: Код открытый и каждый может делать с ним всё что угодно. Я же старался модифицировать библиотеку минимально, чтобы при изменении версии библиотеки не пришлось много менять.
Кстати, в последних версиях библиотеки Adafruit-GFX-Library появились разноразмерные шрифты (кириллицы там разумеется нет).
По пунктам 1 и 2: Если мы на вход utf8rus() подаем строку из 30 русских букв (60 символов), то следовательно target тоже определится размером в 60 символов. На выходе же мы получим строку из 21 символа.
Кроме того, я не знаю точно, что вернёт return target (если target будет определен в стеке), так как при завершении функции стек должен быть очищен. Я предполагаю, что в этом случае return target вернёт указатель на массив символов за пределами указателя стека и вызов любой другой функции может затереть эту строку.
Если же target определяется в куче, то кто (или что) его там чистит (удаляет). Мы же за экономию оперативной памяти боремся :)
arduinec, я то давно переписал себе на array of char, но выложить как-то забыл. А потом сильно столкнулся с обработкой текстовых строк (2 устройства обмениваются информацией), и я долго старался строки массивами соимволов ставить, но потом понял что слишком много лишней потуги и перешел на string. И занимаемое место проекта с 89% упало до 70%, при том удалось еще скинуть 10% глобальных переменных. Пока в Protues проблем вроде нет. ПРобовал отладочно на пол часа запускать в железе, работает, вылетов нет. И вышло так что стринг позволил мне разместить функцию контроля входной строки, функцию ожидания ответа и повторной отправки, и еще много чего ) Еще и место осталось ) Так что конечно все зависит от обстоятельств. Скажем если до этого я только в одном месте использовал string (эта функция), то подгрузка этого класса и его методов конечно норм съедали памяти (всей) и игра не стоила свеч, но скажем если я уже где-то пользуюсь стринг и он легче и быстрее в работе чем char[], то разницы уже грубо говоря и нет )
И длину строки я считал отдельной функцией, она пробегала по массиву и если встречался символ из кирилицы уменьшара размерность target на 1.
Здравствуйте,вот хочу русифицыровать дисплей tft 2.4 на контроллере SPFD5408,но не совсем получается,буквы русские он пишет но вместо тех что я пишу в скетче он мне пишет совсем другое,все делал как описано в первом посте,в чем может быть косяк?
Здравствуйте,вот хочу русифицыровать дисплей tft 2.4 на контроллере SPFD5408,но не совсем получается,буквы русские он пишет но вместо тех что я пишу в скетче он мне пишет совсем другое,все делал как описано в первом посте,в чем может быть косяк?
Возможно решение описано в посте 15.
Появился у меня недавно 2.8" TFT Touch Shield для Uno и Mega
Сначала пришлось поискать к нему библиотеки с примерами. Когда же всё нашлось и заработало, то легко решился вопрос с его русификацией, так как библиотеки основаны на Adafruit-GFX.
Вызов функции utf8rus() для перекодирования русского шрифта остаётся без изменения:
display.println(utf8rus("Тест"));
Инструкция по русификации Adafruit-GFX остаётся прежней:
- скачиваем архив TTFrus.zip по приведённой ниже ссылке;
- заменяем файл glcdfont.c в Adafruit-GFX;
- функцию utf8rus() добавляем в скетч, или в виде отдельного файла utf8rus.ino копируем в каталог скетча;
- далее смотрим пример TTFRusTest.
Обращаю внимание на то, что при использовании новых версий библиотеки Adafruit-GFX (описано в посте 15) в начале скетча нужно выполнять команду:
display.cp437(true);
TTFrus.zip
https://yadi.sk/d/Li8N0FDUoRH3z
На всякий случай выкладываю полный набор библиотек и примеров для указанного TFT Touch Shield:
https://yadi.sk/d/xNv6ovluoJVU9
Спасибо помогло,что то я пропустил этот пост.
Пробую руссифицировать дисплей 5110,при компиляции ошибка:
exit status 1
'class Adafruit_PCD8544' has no member named 'cp437'
Как победить?
Пробую руссифицировать дисплей 5110,при компиляции ошибка:
exit status 1
'class Adafruit_PCD8544' has no member named 'cp437'
Как победить?
У меня ни на что не ругается. Немного переделал скетч (прилагается с библиотеками) из примера к библиотеке Adafruit-PCD8544: добавил функцию utf8rus, заменил падающие звёздочки на снежинки, вставил переход goto к отображению русских шрифтов, а также добавил display.cp437(true).
NokiaRus.zip
https://yadi.sk/d/yJOAk50yoTxF4
arduinec огромное спасибо Вам за проделанную работу.
Я пытаюсь научить "великому и могучему" lcd панель 32х16. Получается с трудом.
В моем случае происходит сдвиг на один символ т.е. вместо строки "абвгд" выдает строку "бвгде".
Причем только на саму панель. В serial.print(utf8rus(str)); - при этом все корректно выводит.
P.S. все разобрался почитал пост №15 сделал matrix.cp437(true);