РадиоКот :: Работа с OLED дисплеем 128х64 на SSD1306 с управлением по I2C
Например TDA7294

РадиоКот >Статьи >

Теги статьи: OLEDI2CДобавить тег

Работа с OLED дисплеем 128х64 на SSD1306 с управлением по I2C

Автор: rozorh
Опубликовано 23.02.2017
Создано при помощи КотоРед.

Здравствуйте, уважаемые коты, кошечки и котята.

В этой статье я хочу рассказать о маленьком, но весьма интересном, на мой взгляд, OLED дисплее 128х64 на SSD1306 с управлением по I2C. На незабвенном Ali его почему-то называют дисплеем для Arduino.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Cразу оговорюсь: я не писал для него никаких библиотек, но внизу статьи вы найдёте исходник с некоторым количеством комментариев, которые помогут обойти потенциальные «грабли», оставившие незабываемые впечатления на моём лбу при изучении работы этого чуда.

А выглядит оно вот так:

 

 

 

 

 

 

 

 

 

Yellow Blue означает, что в нём присутствуют два соответствующих, жёстко привязанных к областям вывода на экран, цвета. Если за верхнюю часть дисплея принять область, расположенную рядом с пинами подключения питания и интерфейса связи, то в верхнюю ¼ дисплея вывод информации будет осуществляться жёлтым цветом, а в нижние ¾ дисплея, соответственно, синим.

Но это так, приятное дополнение. Что же меня в нём действительно подкупило, так это управление по I2C и нужные мне габариты: небольшой экран размером 0.96” (что при замере линейкой даёт периметр в 25х15 мм), смонтированый на плате 26х26 мм.

Соответственно, подключение простейшее:

 

 

 

 

 

 

 

 

 

 

 

 

Ценник тоже приятно удивил: с доставкой они (а заказывал я шесть штук у разных продавцов) обошлись около 180 руб./шт., хотя говорят, что можно найти и дешевле.

Из даташита на SSD1306 мы узнаём, что, во-первых, адресом устройства на шине может быть или 0111100 или 0111101, в зависимости от того, как настроено оборудование в сборочном подвале у Дядюшки Ляо. Пять из полученных мною модулей откликаличь на адрес 0111100 – я так понимаю, что это самый распространённый вариант распайки, шестой отозвался на 0111101.

Вообще же в даташите алгоритм работы с этим дисплеем расписан весьма своеобразно. В режиме I2C это выглядит вот так:

 

 

 

 

 

С первого взгляда всё логично и, вроде бы, понятно: сначала выдаём старый добрый СТАРТ, потом байт со Slave-АДРЕСом (0111100 или 0111101) дополненный нулём в младшем бите (потому что мы ничего не будем читать из дисплея, а будем только передавать ему команды или данные). Потом принимаем бит ACK подтверждения от дисплея… А потом отсылаем некий CONTROL BYTE, содержащий всего два возможных для изменения бита: 7-й ”Cо” и 6-й “D/C” (остальные всегда нули), которые изрядно попортили мне кровь, пока я разобрался, как себя с ними вести.

Вот, что мы можем почерпнуть про них из даташита:

The D/C# bit determines the next data byte is acted as a command or a data. If the D/C# bit is set to logic “0”, it defines the following data byte as a command. If the D/C# bit is set to logic “1”, it defines the following data byte as a data which will be stored at the GDDRAM. The GDDRAM column address pointer will be increased by one automatically after each data write. If the Co bit is set as logic “0”, the transmission of the following information will contain data bytes only.

Если коротко, то “D/C” может быть единицей или нулём. Первый вариант говорит дисплею, что в СЛЕДУЮЩЕМ БАЙТЕ мы собираемся передать ему данные для отображения на экране, второй – что в СЛЕДУЮЩЕМ БАЙТЕ мы будем передавать какую-то команду, т.е. собираемся им (дисплеем) управлять.

Бит “Со” равный нулю сообщает ему же, что ВСЕ СЛЕДУЮЩИЕ БАЙТЫ пойдут потоком в виде данных для вывода на экран. И всё бы хорошо, но нет ни слова о варианте, в котором этот бит мог бы быть равным единице. А такой вариант существует. И не один – их на самом деле целых два, а вот вариант с нулём оказался единственным.

В моём исходнике все три варианта определены через дефайны, как COM (СЛЕДУЮЩИЙ БАЙТ будет командой), DAT (СЛЕДУЮЩИЙ БАЙТ будет данными) и DATS (ВСЕ СЛЕДУЮЩИЕ БАЙТЫ будут данными):

     #define   COM     0b10000000
     #define   DAT     0b11000000
     #define   DATS   0b01000000

Итак, если мы хотим передать в дисплей команду, т.е. изменить в нём какие-либо настройки, провести инициализацию и т.п., то после бита подтверждения ACK нам необходимо отослать контрольный байт 0b10000000 (COM), после чего, получив ещё один ACK, нашу команду, а затем вновь дождаться подтверждения ACK. Соответственно, если нам необходимо последовательно передать несколько команд, то нам придётся "крутиться" по этому же алгоритму: COM, ACK, <8_бит_команды>, ACK, … и т.д. до бесконечности.

Теперь о передаче данных для вывода на экран: если мы хотим передать в дисплей ОДИН БАЙТ данных, то в качестве контрольного байта необходимо отослать 0b11000000 (DAT), а затем работать по аналогии с алгоритмом выше – DAT, ACK, <8_бит_данных>, ACK, … и т.д. Однако, если нам необходимо передать целый массив данных, тогда в качестве контрольного байта мы будем отсылать уже 0b01000000 (DATS), а затем поочерёдно все данные, что мы хотим увидеть на экране, т.е. DATS, ACK, <8_бит_данных>, ACK, <8_бит_данных>, ACK, … и т.д. Здесь необходимо обратить внимание на то, что если после передачи последнего байта из этого массива мы вновь захотим передать какую-либо команду, нам будет необходимо отправить СТОП, после чего начать общение, что называется, с нуля – СТАРТ, АДРЕС+0, ACK, и т.д.

Байты, отосланные в дисплей, выводятся на экран последовательными вертикальными столбцами младшим битом сверху, приращение счётчика колонки вывода и переход на новую страницу/строку ведётся автоматически. Вообще о режимах вывода данных на дисплей в даташите написано хорошо и с картинками, поэтому на них останавливаться не буду, если что – настройка прокоментирована в исходнике в разделах "Очистка экрана дисплея" и "Последовательный вывод цифр от 1-го до 5-ти".

Отдельно следует затронуть вопрос инициализации. Для её проведения необходимо передать в дисплей следующую абракадабру:

СТАРТ, АДРЕС+0, 0x80, 0xA8, 0x80, 0x3F, 0x80, 0xD3, 0x80, 0x00, 0x80, 0x40, 0x80, 0xA1, 0x80, 0xC8, 0x80, 0xDA, 0x80, 0x12, 0x80, 0x81, 0x80, 0x7F, 0x80, 0xA4, 0x80, 0xA6, 0x80, 0xD5, 0x80, 0x80, 0x80, 0x8D, 0x80, 0x14, 0x80, 0xAF, СТОП

Не забывайте про бит подтверждения ACK после каждого байта (считайте, что вместо каждой запятой – кроме запятой после СТАРТ – в последовательности выше нужно вставить бит ACK).

Байты, отмеченные синим, определяют формат вывода информации на экран:
     • 0х7F – яркость свечения пикселей (максимум задаётся 0xFF);
     • 0хA1 – данные выводятся слева направо, 0хA0 – справа налево;
     • 0хC8 – данные выводятся построчно сверху вниз, 0хС0 – снизу вверх (где у экрана условный верх мы разбирали раньше).

Т.о., заменив одновременно 0хA1 на 0хA0 и 0хC8 на 0хC0 мы получим разворот изображения на дисплее на 180 градусов, при этом области вывода жёлтым и синим цветом всё равно останутся там же, где и были (((

Если при подаче питания выключатель сильно «дребезжит», до начала инициализации дисплея рекомендую выждать ~ 500 – 700 ms.

И пару слов о uC - это AVR ATtiny2313 с заводской установкой фьюзов.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Засим, наверное, всё. По крайней мере всё, чем действительно хотелось поделиться.
Надеюсь, что это поможет тем, кто как и я только начинает разбираться с подобными вещами.

Спасибо за внимание и удачи решившим повторить.

 

 

 


Файлы:
Исходник_С


Все вопросы в Форум.




Как вам эта статья?

Заработало ли это устройство у вас?

53 6 1
2 1 2