Программирование AVR Русификация индикатора LCD на чипе Hitachi 44780 Sat, December 21 2024  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.


Русификация индикатора LCD на чипе Hitachi 44780 Печать
Добавил(а) microsin   

Подключить LCD-индикатор на основе контроллера Hitachi 44780 к микроконтроллеру сейчас не составляет проблемы, поскольку имеется множество готовых примеров кода и библиотек для разных платформ []. Однако подключить индикатор и заставить его работать это только половина решения проблемы, если Вам нужно организовать вывод русского текста, но кодировка символов индикатора не совпадает с кодировкой, которую выводит на экран Ваш код. Т. е. вместо вывода на экран русского текста Вы видите либо кракозябры, либо пустые знакоместа.

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

1. Определение символьной таблицы индикатора. Необходимо узнать, каким образом каждый код символа, записываемый в индикатор, отображается на его экране.

2. Поиск/создание русских букв. Необходимо найти способ вывода на экран русскоязычных символов.

3. Перекодировка выводимого текста. Необходимо составить таблицу перекодировки таким образом, чтобы кодировка всех символов строк в тексте программы соответствовала внешнему виду символов на экране индикатора.

[Определение символьной таблицы индикатора]

Под "кодировкой" индикатора понимают таблицу, где приведено соответствие 8-битного кода символа (код ASCII или ANSI) начертанию символов на экране индикатора. Ниже показан пример такой таблицы, которую обычно можно найти в даташите на индикатор LCD-016N001A-NFG-ET. В заголовке столбцов указана старшая тетрада байта кода символа, а в заголовке строк младшая. Код символа получается конкатенацией (склеиванием) бит тетрад, а в пересечении строки и столбца показано начертание символа.

LCD 016N001A NFG ET charmap

Рис. 1. Начертание набора символов индикатора LCD-016N001A-NFG-ET.

Очевидно, что в кодировке этого индикатора полностью отсутствуют русские буквы. Как в таком случае его можно русифицировать?

Во-первых, некоторые буквы английского алфавита совпадают по начертанию с русскими. Во-вторых, у индикатора есть специальная область пользовательской графики (CG RAM), куда можно загрузить графику русских символов, и выводить эти символы через коды 00h..0Fh.

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

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

[Character Generator RAM (CGRAM)]

В CGRAM пользователь может перезаписать символ своей программой. Для режима 5x8 точек можно определить 8 символов, и для режима 5x10 точек можно определить 4 символа.

Запишите память индикатора код символа по адресу, показанному в левом столбце таблицы 1, чтобы показать графику, сохраненную в CGRAM. Пользовательские символы остаются в памяти индикатора до выключения его питания.

Таблица 1. Как хранится графика пользовательских символов в CGRAM.

Для режима 5x8:

LCD44780 CGRAM5x8

Каждый символ LCD построен как матрица графики из 8 строк и 5 столбцов (5x8). Чтобы создать свой символ, нужно послать в индикатор массив из 8 байт. Каждый байт в нем будет представлять данные графики строки 5-ю младшими битами. Если бит установлен, то на этом месте будет отображаться точка, если не установлен, то точка отображена не будет.

Для режима 5x10:

LCD44780 CGRAM5x10

[LCD Custom Char Builder]

Вы можете использовать программу LCD Custom Char Builder Software [2], чтобы быстро и просто создать графику для своих символов для символьных LCD-индикаторов.

Стандартные алфавитно-цифровые LCD поддерживают 4 или 8 пользовательских символов (в зависимости от типа индикатора и выбранного размера знакоместа). С помощью этой программы можно создать 8 символов в с именами от Char0 до Char7. Вы можете выбрать любой из этих символов и отредактировать его графику.

С помощью левой кнопки мыши можно рисовать символ. Удерживание правой кнопки мыши стирает точку.

LCD Custom Char Builder

Нарисуйте все 8 символов. После этого кликните на кнопке Save code, чтобы получить файл custom_char.h file. Этот заголовочный файл совместим с популярной библиотекой [3]. В файле содержатся данные графики нарисованных символов, которые Вы можете загрузить в CGRAM индикатора.

Библиотека позволяет очень просто выводить пользовательские символы с помощью последовательности %n, где n - номер пользовательского символа. Пример вывода символа Char2:

LCDWriteString("I %2 AVR");

Дла рисования графики символов 5x8 можно также воспользоваться удобным онлайн-редактором [4].

[Пример загрузки в CGRAM пользовательских символов]

/////////////////////////////////////////////////////////////
// Сгенерированный файл custom_char.h:
#ifndef __CUSTOMCHAR_H
#define __CUSTOMCHAR_H
 
unsigned char __cgram[]=
{
0x1F, 0x10, 0x10, 0x1E, 0x11, 0x11, 0x1E, 0x00, //Char0 'Б'
0x1F, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, //Char1 'Г'
0x07, 0x09, 0x09, 0x09, 0x09, 0x11, 0x1F, 0x11, //Char2 'Д'
0x15, 0x15, 0x15, 0x0E, 0x15, 0x15, 0x15, 0x00, //Char3 'Ж'
0x11, 0x11, 0x13, 0x15, 0x19, 0x11, 0x11, 0x00, //Char4 'И'
0x07, 0x09, 0x09, 0x09, 0x09, 0x09, 0x11, 0x00, //Char5 'Л'
0x1F, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00, //Char6 'П'
0x0E, 0x15, 0x15, 0x15, 0x15, 0x0E, 0x04, 0x00, //Char7 'Ф'
};
 
#endif
 
/////////////////////////////////////////////////////////////
// Тест-программа для вывода пользовательских символов
// из массива __cgram[] файла custom_char.h.
/////////////////////////////////////////////////////////////
#include < stdlib.h >
#include < string.h >
#include < stdio.h >
#include < avr/io.h >
#include < util/delay.h >
 
#include "lcd.h"
#include "custom_char.h"
 
int main(void)
{
   /* Инициализация LCD BC1601A1 */
   lcd_init();
 
   /* Запись пользовательских символов в память индикатора */
   for (u8 i=0; i < 8; i++)
   {
      lcd_create_char(i, &__cgram[i*8]);
   }
   lcd_on();                  // Включение индикатора.
   lcd_clear();               // Очистка дисплея.
   lcd_disable_cursor();      // Выключить курсор.
 
   /* Вывод пользовательских символов на экран */
   lcd_set_cursor(0, 0);
   char tmpstr[9];
   for (u8 i=0; i < 8; i++)
   {
      tmpstr[i] = i+8;
   }
   tmpstr[8] = 0;
   //На экран выведутся символы "БГДЖИЛРФ":
   lcd_printf("%s", tmpstr);
   while (1)
   {
   }
}

Обратите внимание, что символы "БГДЖИЛРФ" записываются в строку tmpstr как коды от 8 до 15. Дело в том, что в памяти CGRAM графика для кодов символов 0..7 и 8..15 дублируется, однако символ с кодом 0 всегда выводится как пробел. Поэтому пользовательские символы следует выводить как коды от 8 до 15.

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

#include < stdlib.h >
#include < string.h >
#include < stdio.h >
 
#include < avr/io.h >
 
#include "encoder.h"
#include "lcd.h"
 
int main (void)
{
   initialize();
   lcd_on();
   lcd_clear();
   lcd_disable_cursor();
 
   static u8 sym = 0;
   static bool showsym = true;
   u8 encstate;
   
   while (true)
   {
      encstate = ENC_GetStateEncoder();
      if (LEFT_SPIN == encstate)
      {
         sym--;
         showsym = true;
      }
      else if (RIGHT_SPIN == encstate)
      {
         sym++;
         showsym = true;
      }
      if (showsym)
      {
         lcd_clear();
         lcd_printf("%02X %i %c", sym, sym, sym);
         showsym = false;
      }
   }
} 

Ниже на фото показан пример вывода на экран символа с кодом A2h (162 десятичное).

LCD1601 hd44780 sym test

Рис. 2. Пример работы тест-программы для анализа знакогенератора индикатора.

После этого нужно просмотреть вывод кодов всех символов, и составить таблицу знакогенератора индикатора.

[Поиск русских букв]

Мне нужно было определить кодировку индикатора BC1601AGPLCWs, и с помощью этой тест-программы мне удалось составить вот такую таблицу:

BC1601AGPLCWs charmap

Рис. 3. Начертание набора символов индикатора BC1601AGPLCWs.

Символы русских букв тут присутствуют, но кодировка символов не совпадает ни с ASCII, ни с ANSI, поэтому для нормального отображения текста требуется таблица перекодировки.

[Создание таблицы перекодировки]

Если Вы создаете текст программы с помощью обычного текстового редактора, например в среде Atmel Studio, то наверняка для текста используется 8-битная кодировка ANSI CP1251 [1], в которой имеются русские буквы.

Для простой перекодировки нужно создать таблицу только для символов с кодами 0xC0..0xFF. Для расширенной перекодировки, если есть свободная память, можно сделать таблицу перекодировки для символов с кодами 0xA0..0xFF, или даже 0x80..0xFF.

Вот таблица перекодировки ANSI CP1251 для диапазона кодов 0xC0..0xFF, если используется знакогенератор примера на рис. 3:

char ANSI1251_CO_FF [] =
{
   0x41,       //код 0xC0, символ 'А'
   0xA0,       //код 0xC1, символ 'Б'
   0x42,       //код 0xC2, символ 'В'
   0xA1,       //код 0xC3, символ 'Г'
   0xE0,       //код 0xC4, символ 'Д'
   0x45,       //код 0xC5, символ 'Е'
   0xA3,       //код 0xC6, символ 'Ж'
   0xA4,       //код 0xC7, символ 'З'
   0xA5,       //код 0xC8, символ 'И'
   0xA6,       //код 0xC9, символ 'Й'
   0x4B,       //код 0xCA, символ 'К'
   0xA7,       //код 0xCB, символ 'Л'
   0x4D,       //код 0xCC, символ 'М'
   0x48,       //код 0xCD, символ 'Н'
   0x4F,       //код 0xCE, символ 'О'
   0xA8,       //код 0xCF, символ 'П'
   0x50,       //код 0xD0, символ 'Р'
   0x43,       //код 0xD1, символ 'С'
   0x54,       //код 0xD2, символ 'Т'
   0xA9,       //код 0xD3, символ 'У'
   0xAA,       //код 0xD4, символ 'Ф'
   0x58,       //код 0xD5, символ 'Х'
   0xE1,       //код 0xD6, символ 'Ц'
   0xAB,       //код 0xD7, символ 'Ч'
   0xAC,       //код 0xD8, символ 'Ш'
   0xE2,       //код 0xD9, символ 'Щ'
   0xAD,       //код 0xDA, символ 'Ъ'
   0xAE,       //код 0xDB, символ 'Ы'
   0x62,       //код 0xDC, символ 'Ь'
   0xAF,       //код 0xDD, символ 'Э'
   0xB0,       //код 0xDE, символ 'Ю'
   0xB1,       //код 0xDF, символ 'Я'
   0x61,       //код 0xE0, символ 'а'
   0xB2,       //код 0xE1, символ 'б'
   0xB3,       //код 0xE2, символ 'в'
   0xB4,       //код 0xE3, символ 'г'
   0xE3,       //код 0xE4, символ 'д'
   0x65,       //код 0xE5, символ 'е'
   0xB6,       //код 0xE6, символ 'ж'
   0xB7,       //код 0xE7, символ 'з'
   0xB8,       //код 0xE8, символ 'и'
   0xB9,       //код 0xE9, символ 'й'
   0xBA,       //код 0xEA, символ 'к'
   0xBB,       //код 0xEB, символ 'л'
   0xBC,       //код 0xEC, символ 'м'
   0xBD,       //код 0xED, символ 'н'
   0x6F,       //код 0xEE, символ 'о'
   0xBE,       //код 0xEF, символ 'п'
   0x70,       //код 0xF0, символ 'р'
   0x63,       //код 0xF1, символ 'с'
   0xBF,       //код 0xF2, символ 'т'
   0x79,       //код 0xF3, символ 'у'
   0xE4,       //код 0xF4, символ 'ф'
   0x78,       //код 0xF5, символ 'х'
   0xE5,       //код 0xF6, символ 'ц'
   0xC0,       //код 0xF7, символ 'ч'
   0xC1,       //код 0xF8, символ 'ш'
   0xE6,       //код 0xF9, символ 'щ'
   0xC2,       //код 0xFA, символ 'ъ'
   0xC3,       //код 0xFB, символ 'ы'
   0xC4,       //код 0xFC, символ 'ь'
   0xC5,       //код 0xFD, символ 'э'
   0xC6,       //код 0xFE, символ 'ю'
   0xC7        //код 0xFF, символ 'я'
};

Модифицированная подпрограмма lcd_puts, исползующая таблицу перекодировки ANSI1251_C0_FF:

void lcd_puts(char *string)
{
   for (char *it = string; *it; it++)
   {
      //Старый код, вывод без перекодировки:
      //lcd_write(*it);
      //Вывод с перекодировкой:
      if (*it < 0xC0)
      {
         lcd_write(*it);
      }
      else
      {
         lcd_write(ANSI1251_CO_FF[(unsigned char)(*it)-0xC0]);
      }
   }
}

[Ссылки]

1. Таблица символов ANSI.
2. Displaying Custom Characters on Alphanumeric LCDs site:extremeelectronics.co.in.
3. Using LCD Module with AVRs site:extremeelectronics.co.in.
4. Онлайн-генератор графики для LCD-индикаторов.

 

Комментарии  

 
0 #2 Михаил 26.10.2021 09:53
Взял Вашу функцию и массив и кириллица не выводится, а латиница выводится. Проверил таблицу на LCD на позиции знакогенератора , она такая как в статье. Если я меняю условие на if (*it > 0xC0) то появляются русские но вместо английских кракозябры. В чем может быть проблема?

microsin: вероятно другая версия прошивки индикатора. Нужно опытным путем проверять, какие символы он отображает в ответ на какой код символа, и уже после этого исправлять таблицу и программу перекодировки.
Цитировать
 
 
+1 #1 Dmitry 31.07.2020 11:14
Спасибо огромное за статью! :D
Цитировать
 

Добавить комментарий


Защитный код
Обновить

Top of Page