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

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

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

Для русификации библиотеки 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 (http://arduino.ru/forum/proekty/transistor-tester-arduino).
В посте 379 дополнительно приведён скетч для демонстрации динамических эффектов из символов, содержащихся в шрифте.
В посте 399 приводится скетч с функцией utf8rus2hex(), которая перекодирует русские буквы и преобразует их в строчные HEX-символы.

killspika
Offline
Зарегистрирован: 04.02.2019

arduinec Спасибо большое работает на ура)

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

Топик, по моему, заслужил что-бы его приклеели!

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

xDriver пишет:

Топик, по моему, заслужил что-бы его приклеели!

В разделе "Программирование" половина первой страницы в приклееных темах. Лучше бы отдельный раздел создали и туда наиболее популярные темы переместили.

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

Используя собственный код из поста #40 научил функцию utf8rus() работать со строками, размещёнными в PROGMEM.
Для сохранения перекодированной строки нужно создать в глобальных переменных массив char. Длина массива определяется исходя из максимального размера строки, выводимой на дисплей.
В исходном варианте дисплей OLED 0.96 имеет ширину 128 пикселей. Ширина каждой буквы составляет 5 пикселей плюс интервал между буквами (6-й пиксель). В итоге, поделив 128 на 6, получаем, что максимальная длина выводимой строки составляет 21 символ плюс ещё один знак для нулевого символа конца строки.
Чтобы не выскочить за пределы массива в функцию встроена проверка на превышение максимального размера строки (более длинная строка просто отсекается).
По аналогии с PROGMEM-функциями к utf8rus тоже была добавлена буква _P.

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

char *utf8rus_P(const char *source)
{
  char m[2] = { '0', '\0' };
  int j = 0;
  unsigned char n = 1;

  strcpy(target, "");

  while (1) {
    n = pgm_read_byte(source); source++;

    if (n >= 0xC0) {
      switch (n) {
        case 0xD0: {
          n = pgm_read_byte(source); source++;

          if (n == 0x81) { n = 0xA8; break; }
          if (n >= 0x90 && n <= 0xBF) n = n + 0x30;
          break;
        }
        case 0xD1: {
          n = pgm_read_byte(source); source++;

          if (n == 0x91) { n = 0xB8; break; }
          if (n >= 0x80 && n <= 0x8F) n = n + 0x70;
          break;
        }
      }
    }
    if (n == 0) break;

    m[0] = n; strcat(target, m);
    j++; if (j >= maxString) break;
  }
  return target;
}

Демонстрационный код для дисплея OLED 0.96:

#include <avr/pgmspace.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// software SPI:
#define OLED_CLK   13 // D0
#define OLED_MOSI  12 // D1
#define OLED_RESET 11 // RES
#define OLED_DC    10 // DC
#define OLED_CS    9  // CS

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

const char Stroka31[] PROGMEM = "АБВГДЕЖЗИЙКЛМНОП";
const char Stroka32[] PROGMEM = "РСТУФХЦЧШЩЪЫЬЭЮЯ";
const char Stroka33[] PROGMEM = "абвгдежзийклмноп";
const char Stroka34[] PROGMEM = "рстуфхцчшщъыьэюя";
const char Stroka35[] PROGMEM = "Ёё123ABCabc!@#\xBC\xBD";
const char Stroka36[] PROGMEM = "10\x83 10\x8A\x82 10\x81\x80 2\x85";
const char Stroka41[] PROGMEM = "Размер шрифта 1";
const char Stroka42[] PROGMEM = "Размер 2";
const char Stroka43[] PROGMEM = "Разм 3";
const char Stroka51[] PROGMEM = "Строка более 21 символа длиной";
const char Stroka52[] PROGMEM = "Stroka bolee 21 simvola dlinoj";

unsigned char i1,i2,c3;

Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);

void setup(){                 
  display.begin(SSD1306_SWITCHCAPVCC);
  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);
  TEST_display_5();
  delay(6000);
}

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_P(Stroka31));
  display.println(utf8rus_P(Stroka32));
  display.println(utf8rus_P(Stroka33));
  display.println(utf8rus_P(Stroka34));
  display.println(utf8rus_P(Stroka35));
  display.println(utf8rus_P(Stroka36));

  display.display();  
}

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

  display.setTextSize(1);
  display.println(utf8rus_P(Stroka41));

  display.setTextSize(2);
  display.println(utf8rus_P(Stroka42));

  display.setTextSize(3);
  display.println(utf8rus_P(Stroka43));

  display.display();  
}

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

  display.println(utf8rus_P(Stroka51));
  display.println(utf8rus_P(Stroka52));

  display.display();  
}

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

  strcpy(target, "");

  while (1) {
    n = pgm_read_byte(source); source++;

    if (n >= 0xC0) {
      switch (n) {
        case 0xD0: {
          n = pgm_read_byte(source); source++;

          if (n == 0x81) { n = 0xA8; break; }
          if (n >= 0x90 && n <= 0xBF) n = n + 0x30;
          break;
        }
        case 0xD1: {
          n = pgm_read_byte(source); source++;

          if (n == 0x91) { n = 0xB8; break; }
          if (n >= 0x80 && n <= 0x8F) n = n + 0x70;
          break;
        }
      }
    }
    if (n == 0) break;

    m[0] = n; strcat(target, m);
    j++; if (j >= maxString) break;
  }
  return target;
}

Архив с кодом и библиотеками:
https://yadi.sk/d/Tay6fBw-Qoo45w

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

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

kc_duke
Offline
Зарегистрирован: 23.04.2019

Добрый день,

использую код из 401 поста. И возникли проблемы. Если вызывать utf8rus из loop все прекрасно работает. Если же я вызывают utf8rus из другой функции, а затем эту фукнцию из loop. То вместо русских букв ничего нет. Причем не кракозябры, а именно ничего нет.

#include <Adafruit_CCS811.h>
#include "HDC1080JS.h"
#include "Wire.h"
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
//#include <Fonts/rus5x7.h>
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);
Adafruit_CCS811 ccs;


HDC1080JS tempsensor;


void setup() {
  display.cp437(true);
  Serial.begin(9600);
  Wire.begin();
  Wire.setClock(400000); //set clock speed for I2C bus to maximum allowed for HDC1080
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  Serial.println("CCS811 test");
  pinMode(2, INPUT);




  tempsensor = HDC1080JS();
  tempsensor.config();

  if (!ccs.begin()) {
    Serial.println("Failed to start sensor! Please check your wiring.");
    while (1);
  }

  //calibrate temperature sensor
  while (!ccs.available());
  float temp = ccs.calculateTemperature();
  ccs.setTempOffset(temp - 25.0);
}
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;
}


void loop() {
  if (digitalRead(2) == HIGH)
    edin();
  if (digitalRead(2) == LOW)
    chered();
}
void chered()
{
  display.clearDisplay();
  tempsensor.readTempHumid();
  float temp = tempsensor.getTemp();
  float humid = tempsensor.getRelativeHumidity();
  display.setTextColor(WHITE);
  display.setTextSize(2);
  display.setCursor(20, 0);
  display.print(utf8rus("ТЕМПЕРАТУРА"));
  display.setCursor(0, 16);
  display.print(temp);
  display.print("\xB0");
  display.print("C");
  display.display();
  delay(5000);
  display.clearDisplay();
  display.setCursor(20, 0);
  display.setTextSize(2);
  display.println(utf8rus("ВЛАЖНОСТЬ"));
  display.setCursor(0, 16);
  display.setTextSize(3);
  display.print(humid);
  display.print("%");
  display.display();
  delay(5000);
  if (ccs.available()) {
    if (!ccs.readData()) {
      display.clearDisplay();
      display.setCursor(20, 0);
      display.setTextSize(2);
      display.println(utf8rus("СОДЕРЖАНИЕ CO2"));
      display.setTextSize(3);
      display.print(ccs.geteCO2());
      display.print("ppm");
      display.display();
      delay(5000);
      display.clearDisplay();
      display.setCursor(20, 0);
      display.setTextSize(1);
      display.println(utf8rus("СОДЕРЖАНИЕ ЛОВ"));
      display.setCursor(0, 16);
      display.setTextSize(3);
      display.print(ccs.getTVOC());
      display.print("ppb");
      display.display();
      delay(5000);
    }
    else {
      display.setTextSize(2);
      display.setCursor(0, 0);
      display.print(utf8rus("css error"));
      while (1);
    }
  }
}

void edin()
{
  display.clearDisplay();
  tempsensor.readTempHumid();
  float temp = tempsensor.getTemp();
  float humid = tempsensor.getRelativeHumidity();
  display.setTextColor(WHITE);
  display.drawFastHLine(0, 31, 128, 1);
  display.drawFastVLine(63, 0, 64, 1);
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.print(utf8rus("Темп., "));
  display.print("\xB0");
  display.print("C");
  display.setCursor(0, 10);
  display.setTextSize(2);

  display.print(temp);
  display.setCursor(73, 0);
  display.setTextSize(1);
  display.print(utf8rus("Влажн., %"));
  display.setTextSize(2);
  display.setCursor(68, 10);
  display.print(humid);
  if (ccs.available()) {
    //   float temp = ccs.calculateTemperature();
    if (!ccs.readData()) {
      display.setCursor(0, 56);
      display.setTextSize(1);
      display.print(utf8rus("CO2, ppm"));
      display.setTextSize(2);
      display.setCursor(10, 39);
      display.print(ccs.geteCO2());
      display.setCursor(73, 56);
      display.setTextSize(1);
      display.print(utf8rus("TVOC, ppb"));
      display.setTextSize(2);
      display.setCursor(75, 39);
      display.print(ccs.getTVOC());
      display.display();
    }
    else {
      //Serial.println("ERROR!");
      display.setTextSize(2);
      display.setCursor(0, 0);
      display.print(utf8rus("css error"));
      while (1);
    }
  }

  delay(5000);
}

 

kc_duke
Offline
Зарегистрирован: 23.04.2019

Выяснил в чем глюк. Перекодировщик так реагивет на пробел между русскими буквами. То есть после :


display.print(utf8rus("Влажн., %"));

Все нормально.

А вот после:

display.println(utf8rus("СОДЕРЖАНИЕ ЛОВ"));

Пропадают русские буквы везде.

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

kc_duke пишет:

использую код из 401 поста. И возникли проблемы. Если вызывать utf8rus из loop все прекрасно работает. Если же я вызывают utf8rus из другой функции, а затем эту фукнцию из loop. То вместо русских букв ничего нет. Причем не кракозябры, а именно ничего нет.

Вероятнее всего String что-то портит в памяти. Лучше использовать utf8rus() из поста #40.
Немного преобразовал код и всё стало отображаться.

//#include <Adafruit_CCS811.h>
//#include "HDC1080JS.h"

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

#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

//Adafruit_CCS811 ccs;
//HDC1080JS tempsensor;
 
#define maxString 21
char target[maxString + 1] = "";

void setup() {
  display.cp437(true);
  Serial.begin(9600);
  Wire.begin();
//  Wire.setClock(400000); //set clock speed for I2C bus to maximum allowed for HDC1080
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  Serial.println("CCS811 test");
  pinMode(2, INPUT);
 
//  tempsensor = HDC1080JS();
//  tempsensor.config();
 
//  if (!ccs.begin()) {
//    Serial.println("Failed to start sensor! Please check your wiring.");
//    while (1);
//  }
 
  //calibrate temperature sensor
//  while (!ccs.available());
//  float temp = ccs.calculateTemperature();
//  ccs.setTempOffset(temp - 25.0);
}

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;
}

void loop() {
//  if (digitalRead(2) == HIGH)
    edin();
    delay(5000); // test
//  if (digitalRead(2) == LOW)
    chered();
    delay(5000); // test
}

void chered()
{
  display.clearDisplay();
//  tempsensor.readTempHumid();
//  float temp = tempsensor.getTemp();
//  float humid = tempsensor.getRelativeHumidity();
  float temp = 12;
  float humid = 34;

  display.setTextColor(WHITE);
  display.setTextSize(2);
  display.setCursor(20, 0);
  display.print(utf8rus("ТЕМПЕРАТУРА"));
  display.setCursor(0, 16);
  display.print(temp);
  display.print("\xB0");
  display.print("C");
  display.display();
  delay(5000);

  display.clearDisplay();
  display.setCursor(20, 0);
  display.setTextSize(2);
  display.println(utf8rus("ВЛАЖНОСТЬ"));
  display.setCursor(0, 16);
  display.setTextSize(3);
  display.print(humid);
  display.print("%");
  display.display();
  delay(5000);

//  if (ccs.available()) {
//    if (!ccs.readData()) {

      display.clearDisplay();
      display.setCursor(20, 0);
      display.setTextSize(2);
      display.println(utf8rus("СОДЕРЖАНИЕ CO2"));
      display.setTextSize(3);
//      display.print(ccs.geteCO2());
      display.print(56);
      display.print("ppm");
      display.display();
      delay(5000);

      display.clearDisplay();
      display.setCursor(20, 0);
      display.setTextSize(1);
      display.println(utf8rus("СОДЕРЖАНИЕ ЛОВ"));
      display.setCursor(0, 16);
      display.setTextSize(3);
//      display.print(ccs.getTVOC());
      display.print(78);
      display.print("ppb");
      display.display();
      delay(5000);
//    }
//    else {
//      display.setTextSize(2);
//      display.setCursor(0, 0);
//      display.print(utf8rus("css error"));
//      while (1);
//    }
//  }
}
 
void edin()
{
  display.clearDisplay();
//  tempsensor.readTempHumid();
//  float temp = tempsensor.getTemp();
//  float humid = tempsensor.getRelativeHumidity();
  float temp = 12;
  float humid = 34;

  display.setTextColor(WHITE);
  display.drawFastHLine(0, 31, 128, 1);
  display.drawFastVLine(63, 0, 64, 1);
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.print(utf8rus("Темп., "));
  display.print("\xB0");
  display.print("C");
  display.setCursor(0, 10);
  display.setTextSize(2);
  display.print(temp);
  display.setCursor(73, 0);
  display.setTextSize(1);
  display.print(utf8rus("Влажн., %"));
  display.setTextSize(2);
  display.setCursor(68, 10);
  display.print(humid);

//  if (ccs.available()) {
    //   float temp = ccs.calculateTemperature();
//    if (!ccs.readData()) {
      display.setCursor(0, 56);
      display.setTextSize(1);
      display.print(utf8rus("CO2, ppm"));
      display.setTextSize(2);
      display.setCursor(10, 39);
//      display.print(ccs.geteCO2());
      display.print(56);
      display.setCursor(73, 56);
      display.setTextSize(1);
      display.print(utf8rus("TVOC, ppb"));
      display.setTextSize(2);
      display.setCursor(75, 39);
//      display.print(ccs.getTVOC());
      display.print(78);
      display.display();
//    }
//    else {
      //Serial.println("ERROR!");
//      display.setTextSize(2);
//      display.setCursor(0, 0);
//      display.print(utf8rus("css error"));
//      while (1);
//    }
//  }
 
  delay(5000);
}