Определяющая часть таких дисплеев совместима по управлению с контроллером HD44780 (фирма Hitachi). Самые популярные (по крайней мере, в нашей стране) дисплеи этой разновидности выпускает фирма Winstar. Причем ЖК-разновидности (название начинается с букв WH, например, WH1602) один в один совместимы с системой команд HD44780, а OLED-типы (название начинается с WEH, например, WEH001602) имеют усовершенствованный контроллер WS0010. К сожалению, или к счастью — сейчас будем разбираться.
В отличие от разобранных нами ранее графических дисплеев на основе контроллера ks0108, знакогенератор в строчных дисплеях встроенный. При этом для нас главным отличием WS0010 от стандартного HD44780 является наличие нескольких (четырех) кодовых таблиц для вывода разноязычного текста. У HD44780 такая таблица всего одна, отчего фирмам приходится в каждый регион продавать отдельную разновидность дисплея. OLED-дисплеи на основе WS0010 разбивки по регионам не требуют, что гораздо удобнее. Но только не пользователю: по умолчанию в WEH-дисплеях включена таблица ENGLISH_JAPANESE, и для включения русских символов нужно ее переключить на ENGLISH_RUSSIAN.
Стандартная (прилагаемая к Arduino IDE) библиотека LiquidCrystal, естественно, про четыре таблицы ничего не знает, и потому требует рихтовки, как минимум, в этом отношении. Но не только: можно, в конце концов, было бы обойтись английским языком. Однако, у WS0010 заметно отличается процедура инициализации, и если ее не подправить, то дисплей будет выдавать невесть что при каждом запуске.
Почему-то на дисплеи 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 показано на следующем рисунке:
Выводы 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, имитирующий дисплей часов-календаря с датчиком внешней температуры:
#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, оставляя мигающее двоеточие в неприкосновенности.
Результаты вывода примера показаны на фото:
Следует отметить, что фотография не передает оттенок свечения зеленого OLED-дисплея (в данном случае). На самом деле он глубокого зеленого цвета, с длиной волны короче, чем обычные 568 нм у LED-дисплеев (семисегментных или матричных). Отчего последние на фоне OLED кажутся «выцветшими», и их совместное применение затруднено.
WS0010 имеет графический режим, и в графических OLED-дисплеях Winstar (типа WEG010016) также установлен этот контроллер. Кто-то обратил внимание, что у них даже одинаковые матрицы. На мой взгляд, пытаться применять на текстовом строчном дисплее графический режим довольно бессмысленно: у строчного дисплея наличествуют аппаратно установленные темные промежутки между символами и строками, которые делают картинку крайне неэстетичной (см. многочисленные примеры таких попыток).
И последнее замечание: о долговечности OLED-дисплеев Winstar. В даташитах указано время 100 000 часов, то есть 11 лет. И тем не менее, один из дисплеев 13-го года выпуска (желтого свечения) к настоящему моменту (зима 16-го) у меня резко потерял в яркости. Забавно, что остальные из той же (зеленый) и более поздней (желтый и зеленый 14 года) партии не подают никаких признаков умирания. Поэтому с определенностью я ничего утверждать не берусь, но на всякий случай советую не впаивать дисплеи в плату, а устанавливать на разъемах, чтобы в случае чего можно было бы заменить без проблем.
Скачать архив с отрихтованной библиотекой и примером можно отсюда.
Комментарии (31)
kresh
17.01.2017 19:34+2А есть ли доступные eink дисплеи которые можно было бы так же просто подключить к Arduino?
fundorin
18.01.2017 00:07+2есть на али. насколько доступные — сложно сказать. www.youtube.com/watch?v=RuSb8L2jzfI
kaSKAdik
18.01.2017 10:28+3Хорошие дисплеи делает контора Pervasive Displays. У них очень хорошая документация, разнообразные платы расширения, но стоят они дорого и продаются на Digi-key.
Есть ещё китайская фирма Good display которая, похоже, тупо копирует у Pervasive Displays всё и вся, но цены ниже в разы. У них есть оффициальный магазин на али.
В принципе, большинство этих дисплеев имеют SPI (вплоть до 7,5 дюймовых), поэтому с подключением к ардуине проблем не должно возникнуть.
av0000
18.01.2017 10:58Мне одно время seeedstudio «навязывало» дисплеи из своего магазина после заказа у них плат.
2" с SPI и даташитом на сайте. Правда, цена — вдвое по сравнению с вышеприведёнными китайцами. И шлейф, кажись, другой — пошире
UPD: У них как раз от Pervasive Displays дисплеи оказались :)
Psychosynthesis
17.01.2017 20:01+1Вообще подключить и работать с этими дисплеями не сложно. Сложности возникают, когда надо понять как его инициализировать. Я купил на али пару таких дисплеев, уже с модулями I2C, что называется «на сдачу». Так вот по стандартной схеме инициализации, которая приведена на большинстве ресурсов, он не заводился. Я перепробовал несколько вариантов, нашёл рабочий. Но некоторые команды всё равно явно работали не так как должны. В итоге нормально отображать символы, обновлять строку и тому подобное, я так и не научился. И самая проблема в том, что я даже не могу понять кто их производитель — никаких особых опознавательных знаков на самом дисплее не видно… Разве что снять I2C модуль, но хотелось бы как-то без этого обойтись. Кто-то может посоветовать как их распознавать?
fundorin
18.01.2017 00:13попробуйте библиотеку u8g2 — она много разных дисплеев поддерживает.
Psychosynthesis
18.01.2017 01:53+1Извините, забыл написать, я под PIC всё это дело пытаюсь поднять.
Ну и библиотеки вообще не сильно люблю для подобных вещей, хочется понимать как оно внутри работает.
Dioxin
18.01.2017 07:28Когда я баловался с атмегой то начал с бэйсика — там настолько все просто с дисплеями(и не только) что дети отдыхают.
kaSKAdik
18.01.2017 09:40+1Я использую OLED-дисплеи последние 4 года. Пишу исключительно на ассемблере под AVR (спасибо вам, Юрий Всеволодович, и вашим книгам), поэтому никакой мороки с допиливанием библиотек не испытываю: следуешь даташиту (который, кстати, китайцы присылают по первому запросу на почту sales@winstar.com.tw, или можно попросить у наших продавцов, например, терраэлектроники) и всё сразу начинает работать. А вообще, касательно даташитов: самые лучшие, которые мне пока удалось встретить — это от компании Newhavendisplay.Пробовал 4-хпроводный, 8-проводный интерфейсы, SPI, I2C, но, по возможности, стараюсь использовать 8-проводный, как самый быстрый.
На мой взгляд, пытаться применять на текстовом строчном дисплее графический режим довольно бессмысленно: у строчного дисплея наличествуют аппаратно установленные темные промежутки между символами и строками, которые делают картинку крайне неэстетичной (см. многочисленные примеры таких попыток).
Как раз недавно делал другу погодную станцию с огромным дисплеем WEH001602B, работающим в графическом режиме. Тёмные промежутки совершенно не мешают считыванию цифр, особенно издалека.
О долговечности могу сказать, что за 4 года я использовал штук 20 разных OLED-дисплеев (символьных, графических, в том числе RGB). Пока все работают без нареканий.YRevich
18.01.2017 10:10Большое спасибо за информацию. О Newhavendisplay я, конечно, слышал, но не пробовал, буду иметь в виду.
madf
18.01.2017 13:26"И тем не менее, один из дисплеев 13-го года выпуска (желтого свечения) к настоящему моменту (зима 16-го) у меня резко потерял в яркости" — это всё фигня, вот если брать китайские мелкие экраны на SSD1306, там если экран работает 24/7, то его хватает на месяца 2-3, дальше начинают выгорать/сыпаться пиксели, выглядит это всё настолько убого…
Ну и общая проблема экранов — это довольно большое потребление, в общем не LCD.kaSKAdik
18.01.2017 15:58это всё фигня, вот если брать китайские мелкие экраны на SSD1306, там если экран работает 24/7, то его хватает на месяца 2-3, дальше начинают выгорать/сыпаться пиксели, выглядит это всё настолько убого…
Большинство этих экранов имеют белые или синие пиксели. Они быстрее всего деградируют. Лучше брать жёлтые, красные или зелёные — прослужат на порядок дольше.
А ещё у китайских дисплеев есть 2 большие проблемы: это повышающий DC-DC преобразователь с КПД 60-70% (который я сразу стараюсь менять на более эффективный) и настройки яркости по-умолчанию, при которых через диоды прогоняют слишком высокий ток. Лучше сразу снижать яркость вдвое.
Ну и общая проблема экранов — это довольно большое потребление, в общем не LCD.
Если сравнивать с LCD без подсветки — то да.madf
18.01.2017 16:08Лучше брать жёлтые, красные или зелёные — прослужат на порядок дольше.
Спасибо за совет, попробую.
это повышающий DC-DC преобразователь
В моих версиях (что покупал) — это не проблема, всё что могли они отрезали, сэкономили, да и у SSD1306 есть внутренняя схема питания (на стекле).
Лучше сразу снижать яркость вдвое
Это "да", но есть ещё и программная возможность этим управлять, впрочем на этом Г это не спасает.
Вообще у китайцев есть и двухцветные матрицы, как в старом, добром КВН, когда наклеивали прозрачную, цветную пленку. Вот здесь порой кажется, что они делают тоже самое. :D
Ну и видимо выгодно получается, когда экраны приходят в негодность весьма быстро. Хотя для меня, ценность такого подхода ровна нулю, т.е. больше уже покупать не буду.
ElectricFromUfa
18.01.2017 14:50Отличные дисплеи, тонкие, яркие, контрастные.
Только имеют свойство выгорать. Был опыт обслуживания оборудования с такими OLED-дисплеями. Работали они по 12-14 часов в день и за первый год эксплуатации выгорели несколько десятков штук.
На выгоревших дисплеях в выключенном состоянии можно было различить текст, который выводился на дисплей 90% времени работы)
Lebets_VI
Спасибо!
Эх, где вы были 5 лет назад :)
YRevich
Пять лет назад я полагал, что Arduino игрушка для детей, а язык СИ применительно к контроллерам — извращение. (Ну, примерно как фон Нейман когда-то по отношению к Фортрану: «Это же отходы для канцеляристов!»). С тех пор мнение во многом поменял, но жалею, кстати, что тогда не задался задачей управления графическими и строчными дисплеями на ассемблере: сейчас бы разбирался в них гораздо лучше.
Nataly75
Реле — зачётное ноу-хау, нужно патентовать.)) Диодик бы только поставить, а не то Ардуино может того-сь...))
YRevich
На такой маломощной обмотке не может. Хотя, строго говоря, замечание правильное.
YRevich
Нет, неправильное замечание, потом сообразил. У AVR есть защитные диоды, и для обмотки с собственным сопротивлением 500 Ом их более, чем достаточно.
Nataly75
Может само реле неправильное? Вообще, сочетание OLED с реле не коробит?
Уж хотя бы транзистор поставили, если с инициализацией никак.
YRevich
Вы это реле видели? http://www.chipdip.ru/product/edr202a0500/. Корпус Дип-16 с отсутствующими частично ногами, ток обмотки 10 мА, время включения 1 мс. Оно идеально вписывается в 5-вольтовую логику. Главное — сопротивление контактов на высоте. У упомянутого ниже FDV303P сопротивление 0,45 Ома (в идеальных условиях), что в момент включения даст заметный провал напряжения. А от этих скачков мы и стараемся избавиться. Если уж ключевой транзистор, то не ниже вот такого: IRF7416PBF
vasimv
У нас любят наезжать агрессивно на тех, кто хоть что-то делает. :) Но в реле действительно смысла нет, один маломощный p-fet (типа FDV303P) легко будет делать тоже самое. Затвор — на D4, исток — на +5, сток — на дисплей. Подаем 0 — открывается, подаем 1 — закрывается.
Alyoshka1976
Спасибо за наводку на мосфет с пороговым напряжением меньше полутора вольт!
P.S. Перфекционистская жаба настаивает на совете добавить в цепь затвора хотя бы стоомный резистор.:-)
vasimv
Практика показывает, что atmega нормально справляется с единичными переключениями такого «легкого» mosfet-а без токоограничительного резистора. Вот если бы там часто переключать требовалось или stm32 какой-нибудь, тогда да — лучше поставить с номиналом для 10 миллиампер максимум.
Кстати, опечатался в названии, FDV304P, конечно же. FDV303N — его комплиментарный N-FET. Есть еще FDV301/FDV302 — те менее мощные, зато и емкость затвора гораздо ниже.
Alyoshka1976
я и написал, моя перфекционистская жаба :-)
P.S. Жаль только, что на ebay они только в SOT23, хотел купить, а TO-92 и нет.
vasimv
Да, TO-92 не особо популярный формат для цифровых mosfet-ов. Какой-нибудь TSM2N7000K подойдет? 100 миллиампер, всего, правда. :(
Alyoshka1976
Спасибо!
iig
Кроме AVR есть и другие arduino совместимые контроллеры.
Alexeyslav
Ничего страшного. Проблема возникает когда цепь РАЗМЫКАЕТСЯ, а в случае ардуины выход полноценный, не открытый и он не размыкается а переключается с "+" на "-" шину и роль диода играет нижний полевик выходного драйвера контроллера. Конечно, если не сделать глупость — перевести выход в высокоимпендансное состояние — тогда есть риск что что-то погорит, но тут начинает работать второй уровень защиты — защитные диоды в микроконтроллере которые сольют выброс на шину питания, а там уже всё зависит от 1) потребления схемы, 2) наличия конденсатора у выводов питания контроллера 3) индуктивности обмотки реле, 4) тока через обмотку перед выключением. Идея такова: энергия импульса переходит в конденсатор по питанию, если выброс небольшой то это приведёт лишь к повышению напряжения питания порядка десятой доли вольта. Но, если индуктивность большая, ток через реле больше чем потребление контроллером и другой периферии в момент отключения а шунтирующий конденсатор по питанию способный поглотить энергию выброса отсутствует или слишком мал — выброс повысит напряжение на шине питания что МОЖЕТ привести к выходу и строя чувствительных к перенапряжению микросхем, например STM-микроконтроллеры к этому уязвимы, как и большая часть 3.3В высокоскоростной логики.
При этом есть ещё риск выхода из строя стабилизатора напряжения — многие из них ох как не любят превышение напряжения на выходе по сравнению со входным, даже кратковременное превышение может запустить лавину повреждений. Но при следовании рекомендациям разводки питания от производителей микросхем(в т.ч. и стабилизаторов) вероятность развития такого сценария крайне невелика.