OLED дисплей SSD1306 (128х64px) и Raspberry Pi, подключение и эксперименты

Содержание

Рассмотрены примеры работы с маленьким (128х64 пикселей) и экономичным OLED-дисплеем на основе микросхемы SSD1306. Для управления использована платформа Raspberry Pi, а программы будем писать на языке Python.

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

Дисплей на основе SSD1306 и что такое OLED

SSD1306 — это название универсальной микросхемы-контроллера, на основе которой построены миниатюрные, экономичные OLED-дисплеи.

Матрица таких дисплеев изготовляется по технологии OLED (Organic Light-Emitting Diode). Если простыми словами, то каждый пиксель такой матрици представляет из себя светоизлучающий прибор, который построен на основе органических соединений, при подаче электрического тока на такие соединения они начинают излучать свет.

В магазинах электронных компонентов можно найти достаточно много разных дисплеев которые построены на данной микросхеме. В данной статье я буду рассматривать дисплей с разрешением 128х64 пикселей (0,96 дюйма) и шиной для управления — I 2 C.

Рис. 1. Экономичный OLED дисплей 128х64 пикселей на SSD1306 с шиной I2C.

Основные характеристики дисплея:

  • Драйвер — SSD1306;
  • Размер экрана — 0.96 дюйма;
  • Тип матрицы — OLED;
  • Разъем для подключения — 4-pin (I 2 C + питание);
  • Напряжение питания — от 3,3В до 5В;
  • Потребляемый одним сегментом ток — 100 мкА;
  • Общий потребляемый ток — примерно 15(20) мА;
  • Разрешение матрицы дисплея — 128×64 пикселей;
  • Угол обзора — более 160 градусов;
  • Размеры — 11x27x27мм (толщина без разъема — 4мм);
  • Вес — 4 грамма;
  • Рабочая температура — от 30 до +70 градусов по Цельсию.

Каждый пиксель такого дисплея — это органический светодиод. Поэтому, потребляемый дисплеем ток прямо пропорционален количеству светящихся, в данный момент, пикселей.

Также важно знать, что через 3-5 лет своей работы, яркость свечения пикселей у дисплея может уменьшиться. Этого не стоит сильно опасаться, тем не менее, если дисплей не используется, то его пиксели все же лучше погасить (выключить) — это продлит его ресурс и сбережет некоторое количество энергии.

Приобретенный мною дисплей — двухцветный, верхняя часть (15 пикселей) светится желтым цветом, а остальная часть дисплея — синим. Благодаря двум цветам, на дисплее можно удобно разделить информационную и рабочую область, к примеру если вы строите самодельный GSM-мессенджер или еще что-то подобное, где вверху дисплея удобно выводить строку статуса и различные значки.

Дисплей SSD1306 отлично подойдет для какого-то маленького самодельного устройства, он миниатюрный, очень экономичный и имеет достаточно яркое, контрастное свечение.

При покупке такого OLED-дисплея нужно быть внимательным, поскольку из описания к нему часто можно подумать, что в нем каждый пиксель может светиться двумя разными цветами, но это не так. Двухцветная модель стоит немного дороже монохромной (один цвет, например белый).

Принципиальная схема

Ниже приведена принципиальная схема модуля с дисплеем SSD1306. Из схемы видно что на плате размещен сам дисплей, микросхема-стабилизатор напряжения (3,3В), а также несколько конденсаторов и резисторов для обвязки.

Резисторы R6 и R7 — подтягивающие для шины I 2 C. Если вы подключаете к шине несколько устройств то нужно оставить подтягивающие резисторы только на одном устройстве, а на остальных — выпаять. К примеру на платке с дисплеем можно резисторы оставить. а на всех остальных устройствах — выпаять! Об этой особенности я уже рассказывал в статье где мы знакомились с шиной I 2 C.

Принципиальная схема модуля SSD1306

Рис. 2. Принципиальная схема модуля SSD1306.

Подключение дисплея

Для подключения дисплея к устройствам и управления отображением информации на нем используется шина I 2 C (4 провода — VCC, GND, SDA, SCL), о том как работать с этой шиной я писал в статье по ADC-DAC PCF8591.

Адрес дисплея на шине I 2 C по умолчания — 0x3c. Для подключения к одной шине двух таких дисплеев нужно задать им разные адреса, сделать это можно перепаяв перемычку (резистор) на плате дисплея под названием "IIC ADDRESS SELECT".

В моем варианте адреса на обратной стороне указаны не верно (привет китайцам): 0x78 и 0x7A, в реальности дисплей имеет адрес 0x3c, в этом можно убедиться подключив его к Raspberry Pi и просканировав устройства на шине при помощи команды "i2cdetect". После перепайки перемычки нужно будет определить новый реальный адрес, это может быть 0x3d или другой.

Для подключения трех и более таких дисплеев (или других устройств с одинаковым адресом) на одну шину I 2 C можно использовать I 2 C-мультиплексоры (I2C Multiplexers/Switches), например микросхему PCA9540BD или другие с нужными параметрами и количеством каналов.

Ниже приведена простая схема подключения дисплея к Raspberry Pi 2, для питания используем пин 1 (3,3В).

Схема подключения дисплея SSD1306 к Raspberry Pi2 по шине I2C

Рис. 3. Схема подключения дисплея SSD1306 к Raspberry Pi2 по шине I2C.

Библиотека для работы с SSD1306 на Python

Для экспериментов с дисплеем мы напишем несложные программы на языке Python, будем использовать готовые библиотеки написанные разработчиком Ричардом Халом (Richard Hull).

Первым делом создадим временный каталог для наших экспериментов:

Библиотеки для работы с SSD1306 на Python можно скачать из репозитория — https://github.com/rm-hull/ssd1306.

Примечание: на момент написания статьи была использована бибилиотека версии "0.2.0", сейчас же проект Ричарда вырос, появились новые возможности и зависимости, понятное дело что и нужные нам файлы также изменились. Поэтому для приведенных ниже примеров будем использовать архив — сохраненную копию библиотеки версии "0.2.0" без папки "doc".

Выполним на raspberry Pi приведенные ниже команды, создадим новый каталог, скачаем и локально распакуем библиотеку:

В приведенных ниже примерах мы не будим устанавливать в систему данную библиотеку. По сути, для использования в наших примерах нам нужны только два файла device.py и render.py, а также установленная библиотека Pillow (для работы с изображениями) для Python.

Чтобы проверить установлен ли модуль Pillow для Python в операционной системе нашего Raspberry Pi, выполним следующую команду, подключившись для этого к малинке по консоли:

Если библиотека присутствует то будет выведена ее название и версия, а если же вывод пуст то нужно установить данную библиотеку следующей командой:

Теперь скопируем в текущую директорию (

/Temp) из недавно склонированного репозитория файлы device.py и render.py. Для этого выполним две команды:

Теперь все готово к проведению экспериментов!

Управление дисплеем

Управление дисплеем осуществляется отправкой команд на шину I2C с указанным адресом устройства. Ниже приведу несколько примеров команд для управления параметрами дисплея SSD1306, их можно использовать совместно с другими примерами из статьи.

Здесь первая команда со значением "0x81" указывает что нужно изменить контрастность, а последующая команда со значением "0x00" задает уровень контрастности. Значение контрастности может быть в пределах от 0x00 до 0xFF, например: 0x11, 0xCC и т.п.

Полное описание других команд для управления дисплеем можно узнать из даташита на SSD1306, в разделе "10. COMMAND DESCRIPTIONS".

Выводим текст на экран

В первом эксперименте с дисплеем SSD1306 мы выведем текст "Hello World" в двух строчках — сверху и по середине экрана. Откроем для редактирования новый файл:

Скопируем в окно редактора следующий код:

Выходим из редактора (Ctrl+X) и сохраняем файл (Y и Ентер), после этого можем запустить программу и посмотреть результат:

В результате дисплей должен "ожить" и на нем появятся строчки с приветствием и через 3 секунды изображение пропадет и появится 2 раза:

Результат работы программы hello_world для ssd1306

Рис. 4. Результат работы программы hello_world для ssd1306.

Код программы не сложный, всю основную "низкоуровневую" работу выполняют библиотеки и модуль Pilow, поэтому расскажу кратко. Сначала мы импортируем класс ssd1306 (для работы с дисплеем по шине I2C) из модуля device (файл deice.py), потом из модуля render (файл render.py) импортируем класс canvas (для подготовки области вывода на дисплей), оба файла должны лежать в одной директории с файлом программы. Также из библиотеки PIL (Pillow, установлена в системе) импортируем ImageFont для работы со шрифтами.

Для использования функции задержки по времени "sleep" выполнен ее импорт из модуля "time" — "from time import sleep" .

Инициализация дисплея и получение экземпляра класса для устройства выполняется в строке "device = ssd1306(port=1, address=0x3C)" , где адрес устройства на шине I 2 C — "0x3C", а адрес шины I 2 C — "1" (1 — для Raspberry Pi rev2, 0 — для rev1).

Для рисования выполним подготовку шрифта "font = ImageFont.load_default()" — здесь используется шрифт по умолчанию (позже в примерах мы попробуем использовать свой внешний шрифт).

С помощью "canvas(device)" мы выполняем подготовку области вывода в нужных размерах для отображения на экране, для отображения в этой области готовим две строчки с текстом, который рисуется пикселями с применением ранее подготовленного шрифта.

Если более детально, то в приведенном примере "draw" является экземпляром класса ImageDraw библиотеки Pillow, в котором уже содержится набор методов для рисования различной 2D-графики. Этот экземпляр нам подготовлен и передан из класса canvas (модуль render.py).

Строчкой кода "draw.text((10, 0), "*** Hello World ***", font=font, fill=255)" мы готовим к выводу текст "*** Hello World ***" в координатах экрана x=10, y=0 и с заполнением — 255 (если 0 — то не отображается).

В следующей строчке кода мы готовым к выводу еще одну строку текста, задаем ей координаты так чтобы она была помещена примерно по центру.

И напоследок, в конце программы реализовано включение и выключение дисплея с интервалом в 1 секунду "sleep(1)". Таким образом, выведенное на дисплей изображение два раза исчезнет и появится (мигнет).

Используем внешний TrueType шрифт (TTF)

Для следующей демонстрации мы скопируем из репозитория файл со шрифтом "CC Red Alert [INET].ttf", выполним команду:

/Temp появится файл с названием "ra.ttf".

Теперь модифицируем немного предыдущую программу таким образом, чтобы текст по середине дисплея выводился с использованием шрифта из файла "ra.ttf" и был покрупнее в размере.

Создадим новый файл для этого эксперимента:

Поместим в редактор код для новой программы:

Выходим из редактора и сохраняем изменения. Здесь мы при помощи метода "ImageFont.truetype" подгрузили шрифт из файла "ra.ttf" , а потом указали при подготовке текста что нужно использовать экземпляр этого шрифта "font=font_ra" .

Результат работы программы:

Текст на дисплее ssd1306 с использованием шрифта TTF

Рис. 5. Текст на дисплее ssd1306 с использованием шрифта TTF. Фото получилось размытое, экран достаточно контрастный и сфокусировать камеру было очень не просто.

Отображаем символы кириллицы (TTF)

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

Где взять подходящий шрифт? -Вот два источника со свободными шрифтами (для верстки, типографии, дизайна, разных поделок и т.п.):

Качаем понравившийся шрифт, распаковываем архив и используем нужный *.ttf файл.

Для примера: заходим на страничку со шрифтами от Гугла, справа в выпадающем списке "Languages" выбираем — "Cyrillic", нам ведь нужно чтобы шрифт поддерживал кириллицу. Выбираем понравившийся шрифт, жмем "Select this font" — снизу видим уведомление что шрифт выбран, жмем на это уведомление — всплывет окно, сверху справа будет иконка при нажатии на которую можно будет скачать весь пак со семейством шрифтов.

В примере ниже я использовал Open Sans — из архива извлек OpenSans-Regular.ttf. Шрифт должен лежать рядом с файлом программы, а также рядом с файлами device.py render.py (все в одной папке). Для размещения файла со шрифтом в другой директории в коде придется прописать полный путь к файлу.

Создадим новый файл для этого эксперимента:

Код программы для вывода кириллици на дисплей SSD1306:

Вот что изменилось в программе по сравнению с предыдущей в которой мы также выводили текст:

  • Указана внутренняя кодировка файла для Python: "# -*- coding: utf-8 -*-";
  • Используем шрифт с поддержкой кириллицы, размером 12: "(‘OpenSans-Regular.ttf’, 12)";
  • Перед передачей текста на обработку конвертируем его в UTF-8: "unicode("Доброго дня, друже! :)", ‘utf-8’)".

Команда для запуска:

отображаем кириллический текст на дисплее SSD1306

Рис. 6. Отображаем кириллический текст (украинский, русский и другой) на дисплее SSD1306.

Кроме символов кириллицы можно попробовать отобразить другие буквы и символы в кодировке UTF-8 для разных языков (зависит от шрифта). К примеру со шрифтом Open Sans корректно отображается символ Ω (знак Ома U+03A9) и другие. Тестируйте сами нужную вам комбинацию.

Для удобного поиска и выбора символов в Linux есть программа KCharSelect, установку можно выполнить из репозитория (Ubuntu, Debian, Mint. ) командой:

Все просто и работает отлично!

Рисуем геометрические фигуры

После того как научились выводить простой текст, неплохо бы попрактиковаться в выводе геометрических фигур. В следующем примере мы выведем на экран:

  • 1-я точка;
  • 2-я точка (по сути будем рисовать линию длиной в 1 пиксель);
  • Линия (последовательность пикселей);
  • Прямоугольник 40×30 пикселей, заполним его цветом. Для двухцветного дисплея получится прапор Украины (желто-синий);
  • Колечко (елипс без заполнения цветом);
  • Круг (елипс заполненный цветом);
  • Треугольник (полигон, набор соединенных прямых линий).

Создадим новый файл для программы:

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

Рисуем геометрические фигуры на дисплее ssd1306 используя Python и Raspberry Pi

Рис. 7. Рисуем геометрические фигуры на дисплее ssd1306 используя Python и Raspberry Pi.

Более детальную информацию по работе с функциями рисования 2D-графики можно узнать почитав документацию по модулю ImageDraw для Pillow (PIL), смотри ссылку внизу статьи.

Отображаем рисунки

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

Для следующего примера скопируем из репозитория файл с логотипом Raspberry Pi, выполним команду:

Откроем новый файл для программы:

Отображаем PNG-рисунок на дисплее ssd1306 используя Python и Raspberry Pi

Рис. 8. Отображаем PNG-рисунок на дисплее ssd1306 используя Python и Raspberry Pi.

Как видим, все предельно просто благодаря использованию библиотеки Pillow!

Подготовка рисунков

Для приведенного выше примера вы можете загрузить в папку с экспериментом свой рисунок, а для его отображения нужно будет изменить строчку кода "pic = Image.open(‘pi_logo.png’)" , указав имя и путь для своего файла-рисунка вместо pi_logo.png. Можно также использовать графические файлы в формате JPG.

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

Для подготовки рисунков отлично подойдет графический редактор GIMP. Создадим новый бланк рисунка (CTRL+N) с размерами 128 на 64 пикселя, поместим туда какое-то изображение (можно использовать буфер обмена для вставки рисунка — CTRL+V) или же нарисуем что либо при помощи инструментов редактора.

Ниже приведен оригинал изображения (иконка Адама Дженсена из Deus Ex HR, взята с просторов интернета) с которым будем работать:

Рис. 9. Исходный рисунок (128×64) для эксперимента с дисплеем ssd1306.

Поскольку дисплей на драйвере ssd1306 является черно-белым (белый цвет — это желтый и синий на дисплее) то нужно конвертировать рисунок в режиме "оттенки серого", для этого в редакторе GIMP выберем Image — Mode — Grayscale, получится вот такой рисунок:

Рис. 10. Черно-белый рисунок для эксперимента с дисплеем ssd1306.

В принципе уже можно экспортировать рисунок в файл формата JPG — жмем CTRL+E, указываем имя файла и в конце расширение ".jpg". При загрузке такого файла в нашей программе он будет автоматически конвертирован, цвета преобразованы с добавлением альфа-канала (Alpha-channel), на дисплее рисунок будет содержать только элементы которые имеют цвет или же содержат пустоту (прозрачные).

Рисунок с Адамом Дженсеном, выведенный на OLED дисплей ssd1306

Рис. 11. Рисунок с Адамом Дженсеном, выведенный на OLED дисплей ssd1306.

Если сейчас попытаться экспортировать и сохранить рисунок в формат PNG, то при загрузке программы получим ошибку: "ValueError: bad transparency mask".

Перед экспортом в PNG проведем дополнительную подготовку. Используем рисунок, полученный на предыдущем этапе (черно-белый), выбираем пункты меню Image — Mode — RGB.

Теперь преобразуем рисунок таким образом, чтобы черный цвет у нас стал прозрачным, выбираем Colors — Color to Alpha, нажимаем выпадающий список и в палитре цветов выбираем черный. Вот что должно получиться:

 Черный цвет преобразован в Альфа-канал в редакторе GIMP

Рис. 12. Черный цвет преобразован в Альфа-канал в редакторе GIMP (режим RGB).

После данной операции можем выполнить экспорт рисунка в файл формата PNG (CTRL+E) и загрузить его в нашу программу. Чтобы указать редактору GIMP что нужно сохранить рисунок в формате PNG достаточно изменить расширение сохраняемого файла на ".png".

Теперь на дисплее будет показано изображение и ошибка исчезнет. будут отрисованы все пиксели рисунка, которые имеют цвет и причем без учета интенсивности, оттенков.

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

  • Созадим пустое изображение (CTRL+N) с размерами 128 на 64 пикселя;
  • Скопируем откуда-то какой-то рисунок в буфер обмена и вставим его в редакторе (CTRL+V);
  • Переконвертируем рисунок в черно-белом режиме: Image — Mode — Grayscale;
  • Вернемся в цветной RGB режим: Image — Mode — RGB (рисунок останется в серых тонах).

У нас получится изображение как на рисунке 8. Теперь выберем в меню Colors — Posterize, укажем значение — 2 и жмем ОК. Вот что должно получиться:

Постеризированный в редакторе GIMP рисунок

Рис. 13. Постеризированный в редакторе GIMP рисунок (режим RGB).

Именно такое изображение отображалось на дисплее при загрузке в программу файла после его преобразования с альфа-каналом. Если же это изображение экспортировать в PNG и попытаться отобразить на дисплее то программа выдаст ту-же ошибку и это не удивительно, поскольку у нас нет Альфа-канала (прозрачности).

Преобразуем черный цвет в Альфа-канал: Colors — Color to Alpha, выбираем черный цвет и жмем ОК. Получится вот такой рисунок:

Готовый рисунок после постеризации и преобразования черного цвета в прозрачность

Рис. 14. Готовый рисунок после постеризации и преобразования черного цвета в прозрачность.

Теперь данный рисунок можно немного подкорректировать, что-то убрать или добавить, а потом выполнить экспорт в файл формата PNG. Загрузив такой файл программа без проблем его обработает и на дисплее мы увидим его точно 1 в 1 (посмотрите рисунок 11).

В редакторе GIMP есть еще масса разных полезных инструментов, эффектов и фильтров при помощи которых можно улучшить изображение и подогнать его до нужного уровня. GIMP — отличная, свободная замена платным редакторам уровня Adobe Photoshop!

Индикатор качества воздуха

Теперь попробуем собрать более-менее полезный проект с использованием дисплея SSD1306, АЦП-ЦАП PCF8591P и газового анализатора MQ-135. О том как сдружить последних два блока я рассказывал в статье про датчик MQ-135, поэтому детально останавливаться на этом здесь не буду.

Вот что будет делать наш индикатор качества воздуха:

  • Отображать на дисплее в реальном времени числовое состояние входа АЦП PCF8591P, к которому подключен датчик MQ-135;
  • При превышении допустимого значения вредных веществ в воздухе на экране отобразим рисунок означающий "токсичность".

Для данного эксперимента соберем вот такую схему:

Схема подключения PCF8591P, MQ-135 и SSD1306 к Raspberry Pi 2

Рис. 15. Схема подключения PCF8591P, MQ-135 и SSD1306 к Raspberry Pi 2.

Схема включения выглядит идентично той, которую я приводил в эксперименте с датчиком газов MQ-135, здесь лишь к шине I 2 C дополнительно подключен дисплей SSD1306.

Напряжения питания модулей в этой схеме:

На платах каждого из модулей (PCF8591P, SSD1306) присутствуют подтягивающие резисторы для шины I 2 C. Поскольку на одну шину мы подключим только два устройства и в экспериментальных целях, то эти резисторы я не выпаивал — результирующее сопротивление (параллельное включение резисторов) уменьшится, но при этом ток через каждую из линий SCL, SDA будет все еще не большим.

После подключения схемы и загрузки Raspberry Pi подключимся к малинке и в консоли проверим какие устройства на шине I 2 C у нас присутствуют:

Пример вывода команды:

Здесь видно что на шине I 2 C присутствуют два устройства:

  • адрес 48 — это PCF8591P;
  • адрес 3с — это SSD1306.

Все отлично, можем приступать к программированию. Создадим новый файл для нашей программы:

Выполним запуск программы:

Установить значение при котором появится рисунок можно изменив число в строке "if value 40:" . Для следующего фото я специально занизил это значение, поэтому на экране уровень с датчика равен 30 и отображается картинка со знаком токсичности.

На приведенном ниже фото и видео (одни из первых экспериментов) модули PCF8591 и MQ-135 подключены напрямую, без делителя напряжения — не безопасно и так делать не желательно, єто детально рассмотрено в предыдущей статье.

Собранная экспериментальная конструкция из модулей с дисплеем SSD1306 в работе

Рис. 16. Собранная экспериментальная конструкция из модулей с дисплеем SSD1306 в работе.

На видео что ниже продемонстрирована работа связки "SSD1306 + PCF8591 + MQ-135 + Raspberry Pi", здесь был установлен пороговый уровень для отображения рисунка "токсично" — 100.

Для теста использован быстро испаряющийся и достаточно токсичный растворитель — дихлорэтан. Нанесенной на кончик отвертки капельки этого вещества вполне достаточно для уверенной реакции датчика.

Заключение

Как видим, на миниатюрном дисплее SSD1306 можно выводить тексты на английском, украинском, русском и других языках, отображать рисунки и геометрические фигуры — отображать что угодно с разрешением 128×64 пикселей!

Все файлы и скрипты для приведенных выше примеров собрал в один архив — ssd1306-display-raspberry-pi.zip (149 КБ).

Миниатюрному и экономичному OLED экранчику на основе SSD1306 еще найдется не мало применений. К примеру, можно сделать табло отображающее ресурсы в ОС для Raspberry Pi, подключить дисплей к AVR микроконтроллеру и собрать на их основе миниатюрный вольт-амперметр. и т.д.


Источник: ph0en1x.net