Pull to refresh

О подключении и работе с текстовыми OLED-дисплеями Winstar

Reading time9 min
Views43K
Строчные (или текстовые) дисплеи предназначены для выдачи текстовой информации в виде строк. Они бывают нескольких типов (прежде всего, ЖК или самосветящиеся OLED), и обычно в их маркировке присутствуют цифры 1202, 1602, 1204 или похожие, указывающие на количество строк (в примерах 2 или 4) и знаков в каждой строке (12 и 16). Есть и однострочные дисплеи такого типа, но мы в дальнейшем изложении ориентируемся на более употребляемые двухстрочные.

Определяющая часть таких дисплеев совместима по управлению с контроллером HD44780 (фирма Hitachi). Самые популярные (по крайней мере, в нашей стране) дисплеи этой разновидности выпускает фирма Winstar. Причем ЖК-разновидности (название начинается с букв WH, например, WH1602) один в один совместимы с системой команд HD44780, а OLED-типы (название начинается с WEH, например, WEH001602) имеют усовершенствованный контроллер WS0010. К сожалению, или к счастью — сейчас будем разбираться.

В отличие от разобранных нами ранее графических дисплеев на основе контроллера ks0108, знакогенератор в строчных дисплеях встроенный. При этом для нас главным отличием WS0010 от стандартного HD44780 является наличие нескольких (четырех) кодовых таблиц для вывода разноязычного текста. У HD44780 такая таблица всего одна, отчего фирмам приходится в каждый регион продавать отдельную разновидность дисплея. OLED-дисплеи на основе WS0010 разбивки по регионам не требуют, что гораздо удобнее. Но только не пользователю: по умолчанию в WEH-дисплеях включена таблица ENGLISH_JAPANESE, и для включения русских символов нужно ее переключить на ENGLISH_RUSSIAN.

Подробнее о таблице ENGLISH_RUSSIAN
Никакая стандартная кодировка там не действует: в таблице шрифта (см. документацию по ссылкам ниже) вообще наличествуют только кириллические символы, отличные по начертанию от латинских. Сама идея сэкономить на кириллических глифах, идентичных латинским по начертанию, не нова — когда-то существовала кодировка ДКОИ-8, которая с большим опозданием даже была введена в стандарт (см. ГОСТ 19768-93). Но она была придумана в рамках ЕС-программы, и, соответственно, основана на айбиэмовской кодировке EBCDIC, потому не совпадает ни с какими современными, в которых за основу (первые 127 символов) всегда принимается таблица ASCII. Оттого в текстовых дисплеях, подобных рассматриваемым, придуманы свои проприетарные кодировки, совместимость которых с ASCII в части английского алфавита строго соблюдается.

Стандартная (прилагаемая к Arduino IDE) библиотека LiquidCrystal, естественно, про четыре таблицы ничего не знает, и потому требует рихтовки, как минимум, в этом отношении. Но не только: можно, в конце концов, было бы обойтись английским языком. Однако, у WS0010 заметно отличается процедура инициализации, и если ее не подправить, то дисплей будет выдавать невесть что при каждом запуске.

Другие возможности
Заметим заодно, что OLED-дисплеи Winstar обладают аппаратными возможностями, которые не отражены в официальной документации (или отражены, но не слишком внятно). Перепайкой перемычек, имеющихся на дисплеях, можно сделать довольно много интересного. Например, о том, как работать с дисплеями WEH через интерфейс SPI (точнее, «типа SPI»), вы можете прочесть здесь, а о том, как включить поддержку регулировки яркости (через вывод 3) — здесь. Но не кидайтесь сломя голову на возможность подключения через последовательный интерфейс: количество соединений уменьшается незначительно в сравнении с четырехпроводным включением, а готовую библиотеку на эту тему еще поискать надо. Если уж очень надо сократить число проводов, то отличный вариант предоставляет подключение через I2C с промежуточным контроллером (см. например, в конце этой статьи).

Почему-то на дисплеи Winstar большой дефицит в плане внятной документации (как вы могли заметить, это вообще характерная черта китайских продуктов). Стоит указать, где можно скачать более-менее полную документацию без особых ошибок: здесь на ЖК-дисплей (WH1602) с контролером HD44780, здесь на дисплеи OLED-типа (WEH1602), здесь отдельно на контроллер WS0010 (на нее мы будем ссылаться далее). А вот здесь, если кому интересно, лежит подробное описание контроллера HD44780 на русском.

Рихтовка библиотеки LiquidCrystal


Для управления строчными дисплеями на HD44780 и его аналогах вполне годится стандартная библиотека LiquidCrystal, которая традиционно входит в поставку Arduino IDE всех версий. Для вывода русского текста имеется ее версия LiquidCrystalRus, которая на удивление неплохо работает во всех современных версиях Arduino IDE (сказывается, что автор корректно подошел к преобразованию UTF-8-символов). Но для приспособления под OLED-дисплеи на контроллере WS0010 правку внести все-таки потребуется. Мы в дальнейшем будем издеваться именно над этой библиотекой и потому переименуем ее в LiquidCrystalRus_OLED, чтобы не путать с обычной. Для упрощения задачи функции переименовывать не будем, потому инициализация будет такой же, как для оригинальной LiquidCrystalRus.

Изменения следующие:

1. Так как русско-английская таблица в WS0010 (см. стр. 9 даташита на WS0010 по ссылке выше) имеет номер 2, то для переключения на нее нужно два младших бита FT1 и FT0 в команде FUNCTION SET установить в состояние 10 (0x02). (В ЖК-дисплеях с одной кодовой таблицей эти биты, кстати, никак не используются). Для этого в файле LiquidCrystalRus_OLED.cpp разыщите место (строка 96 файла), где устанавливается значение переменной _displayfunction. В обоих строках ее инициализации (строки 97 и 99) добавьте довесок «|= 0x02».

2. Далее нужно исправить задержку инициализации после включения питания. Для HD44780 она должна быть не более 40 мс (см. документацию по ссылкам выше). В библиотеке для этого используется функция delayMicroseconds(50000) (строка 120 файла LiquidCrystalRus_OLED.cpp). Для контроллера WS0010 нужно иметь задержку в десять раз больше — не менее 500 мс (см. последнюю страницу даташита по указанной выше ссылке). Требование это так тщательно спрятано (файлы с англоязычной документацией по дисплеям Winstar «потеряли шрифт» в как раз в этой части), что о нем, кажется, до сих пор мало кто задумывался. Поэтому мы заменяем эту строку на 32 повтора задержек по 16 мс каждая:

for (int i = 0; i <=31; i++) delayMicroseconds(16000);

3. Кроме этого (см. также эту последнюю страницу даташита) после этой задержки при четырехпроводном включении нужно пять раз подряд подать пустую команду (0х00). Так как Arduino существенно быстрее контроллера дисплея, команды следует подавать с промежуточной задержкой. Их необходимо вставить чуть дальше по тексту функции begin, там, где идет речь именно о 4-битном включении (строка 147 файла LiquidCrystalRus_OLED.cpp).

4. Но и это еще не конец. В оригинальной таблице ENGLISH_RUSSIAN имеется значок градуса (код 0xEF). Вариант крайне неудачно выполнен графически (слишком велик), потому вместо него я предпочитаю использовать жирную верхнюю точку (код 0xDF) — она куда больше напоминает градус в привычном начертании. Ее можно было бы вводить в виде кода (лучше восьмеричного «\337»), но вот беда — стремясь упростить функцию замены кодов русских букв на коды в таблице знакогенератора, автор библиотеки, исходя из кодировки UTF-8 (см. предыдущую статью), ввел условие замены любого кода, большего 0x80 (функция LiquidCrystalRus::write). Так как наше 0xDF явно больше 0x80, то при указании в строке кода символа «\337» вместо него выведется пустое место, ибо никакой русской букве он не соответствует.

К сожалению, штатная функция createChar() при попытке с ее помощью создать собственный значок градуса у меня вводила дисплей в полный ступор, из которого вывести его можно было только перезагрузкой программы. С чем надо разбираться дополнительно и буду благодарен, если кто-нибудь укажет мне, в чем тут дело. Так что знакогенератор править не в наших возможностях, но мы можем исключить нужный нам символ 0xDF из условия. Для этого нужно заменить имеющееся (см. текст функции write) условие на следующее:

if ((value>=0x80)&&(value!=0xdf))

5. Наконец, перечеркнутый ноль на этом дисплее не так бросается в глаза, как на графических ЖК-экранах. Тем не менее, в эту же функцию write мной введена замена кода нуля (0x30) на код буквы «O» (0x4f). Желающие могут вернуть перечеркнутый ноль обратно, просто удалив или закомментировав строку замены (строка 308 измененного файла LiquidCrystalRus_OLED.cpp).
Подправленную библиотеку можно скачать по ссылке в конце статьи.

Подключение


Вот теперь вроде бы все подправили, можно подключать. Подключение дисплея WEH001602BG (16 символов, длина экрана 100 мм) к Arduino показано на следующем рисунке:

image

Выводы Arduino, к которым подключены контакты дисплея RS, E, DB4-DB7 должны указываться при инициализации дисплея:

// RS, E, DB4, DB5, DB6, DB7
LiquidCrystalRus OLED1(3, 5, 7, 8, 9, 10);

При желании можно подключить два и даже более дисплеев в любом варианте интерфейса (восьми- или четырехпроводном). Линии данных и RS при этом можно сделать общими. Выбор между дисплеями в этом случае производится через вывод E, который для разных дисплеев подключается к разным выводам Arduino (линии подключения второго дисплея показаны на схеме серым цветом, вывод E второго дисплея здесь подключается к контакту 6 Arduino). Разумеется, в программе при этом надо создавать два экземпляра библиотеки (например, OLED1 и OLED2), у которых все выводы одинаковые, за исключением E. При этом дисплеи могут быть разных конфигураций и размеров (8х2, 16х2, 12х2, 12х4 и т.п.). Это относится и к случаю обычных ЖК-дисплеев на HD44780.

А зачем там реле на питание? Самый главный недостаток WS0010 — отсутствие аппаратного «резета». В HD44780 встроенный резет, возможно, оправдан — автор не имеет достаточно опыта работы с ЖК-экранами, чтобы утверждать это наверняка. Но Winstar, пытаясь в своей разработке следовать стандарту, с этой задачей явно не справилась. Перезагрузка контроллера без отключения питания приводит к тому, что на дисплее появляется всякая муть, и избавиться от нее можно только передергиванием питания всей схемы и инициализацией дисплея «с нуля».

Кроме того, дисплей при выключении/включении питания может путать строки местами. Народ уверяет, что помогает полноценное 8-битовое включение (вместо 4-битового), но у меня оно работало еще хуже. Упорно твердят также, что в гипотетических «новых партиях» это все уже исправлено, но верится с трудом (о каких таких «новых» партиях идет речь, когда OLED-дисплеи Winstar выпускает с 2008 года, а у меня были дисплеи 13 и 14 годов выпуска?).

Реле и поставлено для искусственной перезагрузки дисплея при перезагрузке Arduino без выключения питания. Это надежно избавляет от мусора на экране. Включение питания дисплея (или дисплеев) производится отдельно через это реле, включающееся от свободного вывода Arduino (в данном случае вывода 4) в начале процедуры setup, когда контроллер уже работает устойчиво. Причем перед включением реле неплохо еще дать дополнительную задержку 1000 мс (см. скетч далее). Указанное реле EDR202A05 герконовое, ток обмотки 10 мА, потому спокойно управляется от вывода Arduino.

Что же касается путаницы между строками при включении, то, кроме указанных выше изменений в процедуре инициализации, от этого эффекта отлично избавляет питание всей схемы от достаточно мощного (не менее 1-2 А) внешнего источника со стабильным напряжением под нагрузкой не менее 7,5 вольт. Эта зависимость от питания и служит, очевидно, источником разночтений во многих публикациях, где многие авторы уверяют, что у них все отлично работает. Дисплей (или дисплеи) при этом могут подключаться через внутренний стабилизатор Arduino (вывод 5V платы), а могут и через отдельный стабилизатор, но главное, чтобы входное напряжение стабилизатора было достаточно стабильным независимо от бросков потребления в момент включения.

Проверка


Для проверки я накидал демонстрационный скетч Proba_Rus_Liquid_Crystal_OLED, имитирующий дисплей часов-календаря с датчиком внешней температуры:

Пример для дисплея WEH1602
#include <LiquidCrystalRus_OLED.h>

// initialize the library with the numbers of the interface pins
// RS, E, DB4, DB5, DB6, DB7
LiquidCrystalRus OLED1(3, 5, 7, 8, 9, 10);
#define RelayPin 4 //вывод 4 - обмотка реле

void setup() {
delay (1000);
pinMode(RelayPin, OUTPUT);
digitalWrite(RelayPin, HIGH); //включаем питание дисплея
delay (500);
  OLED1.begin(16,2); //16 символов 2 строки
  OLED1.clear();
  OLED1.setCursor(0,0); //верхняя строка, нулевая позиция
  OLED1.print("-22,3\337C"); //10 град Цельсия
  OLED1.setCursor(11,0); //верхняя строка, 11 позиция
  OLED1.print("10:22"); //время
  OLED1.setCursor(0,1); //нижняя строка нулевая позиция
  OLED1.print("16.01.17 понедел"); //дата 16 января понедельник
  OLED1.setCursor(13,0); //верхняя строка, 13 позиция ":"
  OLED1.blink(); //мигаем двоеточием
   delay(1000);
}

void loop() {
/* Здесь не забывать при смене показаний на дисплее
 каждый раз устанавливать курсор на позицию двоеточия 13,0 
 и снова вызывать blink
*/
}


Здесь применены все характерные изменения в библиотеке, указанные выше. В программе также показано, как осуществить мигание двоеточия в значении часов: минут с помощью функции blink(). Учтите, что новый вывод в ту же позицию уничтожает мигание знакоместа, и при обновлении его приходится возобновлять заново, предварительно установив невидимый курсор на ту же позицию 13 в нулевой строке. При реальном обновлении часов может быть проще обновлять только цифры в позициях 11-12 и 14-15, оставляя мигающее двоеточие в неприкосновенности.

Результаты вывода примера показаны на фото:

image

Следует отметить, что фотография не передает оттенок свечения зеленого OLED-дисплея (в данном случае). На самом деле он глубокого зеленого цвета, с длиной волны короче, чем обычные 568 нм у LED-дисплеев (семисегментных или матричных). Отчего последние на фоне OLED кажутся «выцветшими», и их совместное применение затруднено.

WS0010 имеет графический режим, и в графических OLED-дисплеях Winstar (типа WEG010016) также установлен этот контроллер. Кто-то обратил внимание, что у них даже одинаковые матрицы. На мой взгляд, пытаться применять на текстовом строчном дисплее графический режим довольно бессмысленно: у строчного дисплея наличествуют аппаратно установленные темные промежутки между символами и строками, которые делают картинку крайне неэстетичной (см. многочисленные примеры таких попыток).

И последнее замечание: о долговечности OLED-дисплеев Winstar. В даташитах указано время 100 000 часов, то есть 11 лет. И тем не менее, один из дисплеев 13-го года выпуска (желтого свечения) к настоящему моменту (зима 16-го) у меня резко потерял в яркости. Забавно, что остальные из той же (зеленый) и более поздней (желтый и зеленый 14 года) партии не подают никаких признаков умирания. Поэтому с определенностью я ничего утверждать не берусь, но на всякий случай советую не впаивать дисплеи в плату, а устанавливать на разъемах, чтобы в случае чего можно было бы заменить без проблем.

Скачать архив с отрихтованной библиотекой и примером можно отсюда.

UPD: нашлось решение проблемы устойчивого запуска без манипулирования питанием:
https://geektimes.ru/post/287234/
Tags:
Hubs:
Total votes 42: ↑40 and ↓2+38
Comments36

Articles