Взаимодействие NodeMCU ESP8266 с графическим OLED дисплеем
Хотите добавить немного графики в свои IoT проекты на ESP8266? Или, может, хотите отобразить IP адрес вашего ESP8266, не прибегая к последовательному выходу. Для этого идеально подойдут суперкрутые OLED дисплеи (на органических светодиодах)! Они сверхлегкие, толщиной почти с бумагу, теоретически гибкие и дают более яркое и четкое изображение.

Обзор модуля OLED дисплея
Главная особенность модуля OLED дисплея – небольшой монохромный OLED дисплей. Его ширина составляет 128 пикселей, а высота – 64 пикселя, а толщина – 0,96 дюйма. Он миниатюрен, но всё еще обладает преимуществами – OLED дисплей очень хорошо читабелен благодаря высокой контрастности, и вы можете разместить на нем обманчиво большое количество графики.
Поскольку дисплей обладает собственной подсветкой, то внешняя подсветка не требуется. Это значительно снижает мощность, необходимую для работы OLED, и поэтому дисплей обладает такой высокой контрастностью, чрезвычайно широким углом обзора и может отображать глубокие уровни черного.

Сердцем модуля является мощный однокристальный CMOS контроллер OLED драйвера, SSD1306, который обрабатывает всю буферизацию ОЗУ, поэтому вашему ESP8266 остается совсем немного работы. Рабочее напряжение контроллера SSD1306 составляет от 1,65 В до 3,3 В – идеально подходит для взаимодействия с микроконтроллерами 3,3 В, такими как ESP8266.
Распределение памяти OLED модуля
Чтобы иметь абсолютный контроль над вашим модулем OLED дисплея, важно знать о его распределении памяти.
Независимо от размера OLED модуля драйвер SSD1306 обладает встроенным ОЗУ для отображаемых графических данных (Graphic Display Data RAM, GDDRAM) объемом 1 КБ для экрана, который содержит отображаемый битовый рисунок. Эта область памяти 1K организована в 8 страниц (от 0 до 7). Каждая страница содержит 128 столбцов/сегментов (от 0 до 127). И каждый столбец может хранить 8 бит данных (от 0 до 7). Это наверняка говорит вам, что в итоге мы имеем
8 страниц х 128 сегментов х 8 бит данных = 8192 бита = 1024 байта = 1 КБ памяти
Весь 1K памяти с выделенными страницами, сегментами и данными показан ниже.

Каждый бит представляет собой определенный пиксель на OLED дисплее, который можно программным способом включить или выключить.
OLED дисплей 128×64 отображает всё содержимое ОЗУ, тогда как OLED дисплей 128x32 отображает только 4 страницы (половину содержимого) ОЗУ.
Подключение модуля OLED дисплея к NodeMCU ESP8266
Хватит теории, приступим к практике! Давайте подключим дисплей к ESP8266 NodeMCU.
Подключение довольно простое. Начните с подключения вывода VCC на модуле к выводу 3.3V на NodeMCU и соединения выводов GND.
Затем подключите вывод SCL к выводу D1 (тактовый сигнал I2C) на NodeMCU и подключите вывод SDA к выводу D2 (данные I2C) на NodeMCU. Распиновку NodeMCU ESP8266 можно посмотреть в следующих статьях:
- NodeMcu V3 Lua WiFi модуль (ESP8266 ESP-12E)
- Обзор платы NodeMCU ESP8266 и ее использование в Arduino IDE
Схема подключения показана на рисунке ниже.

Теперь вы готовы загрузить на NodeMCU ESP8266 какой-нибудь код и напечатать что-нибудь на дисплее.
Установка библиотеки для модуля OLED дисплея
У контроллера SSD1306 OLED дисплея гибкие, но сложные драйверы. Для использования контроллера SSD1306 требуются глубокие знания об адресации памяти. К счастью, была написана библиотека Adafruit SSD1306, чтобы скрыть все эти сложности, и чтобы мы могли выдавать простые команды для управления дисплеем.
Чтобы установить библиотеку, перейдите в меню Скетч → Подключить библиотеку → Управлять библиотеками…. Подождите, пока менеджер библиотеки загрузит список библиотек и обновит список установленных библиотек.

Отфильтруйте результаты поиска, набрав «adafruit ssd1306». Должна остаться пара записей. Ищите Adafruit SSD1306 by Adafruit. Нажмите на эту запись, а затем выберите Установить.

Библиотека Adafruit SSD1306 представляет собой аппаратную библиотеку, которая выполняет функции более низкого уровня. Для отображения графических примитивов (таких как точки, линии, круги, прямоугольники и т.д.) она должна работать в паре с библиотекой Adafruit GFX. Установите и эту библиотеку.

Примечание
Библиотека выделяет для буфера 1 КБ ((128×64)/8 бит) памяти ESP8266. Таким образом, она может манипулировать экранным буфером и затем выполнять групповую передачу из памяти ESP8266 во внутреннюю память контроллера SSD1306.
Модификация библиотеки Adafruit SSD1306
Библиотека Adafruit SSD1306 не настроена для дисплеев OLED 128×64 (один из которых мы сейчас используем). Чтобы она заработала, в заголовочном файле Adafruit_SSD1306.h необходимо изменить размер экрана. Если он не будет изменен, при попытке компиляции скетча может появиться сообщение об ошибке #error (“Height incorrect, please fix Adafruit_SSD1306.h!”) (некорректная высота, исправьте Adafruit_SSD1306.h):

Чтобы изменить заголовочный файл Adafruit_SSD1306.h, откройте папку с библиотеками. Стандартный путь: Мои Документы → Arduino. Теперь перейдите в libraries → Adafruit_SSD1306

Откройте файл Adafruit_SSD1306.h в текстовом редакторе. Прокрутите файл вниз, чтобы найти секцию SSD1306 Displays или сразу перейдите к строке 73. Закомментируйте #define SSD1306_128_32
и раскомментируйте #define SSD1306_128_64
, чтобы код в этом разделе выглядел следующим образом:

Вот и всё. Теперь сохраните файл и перезапустите Arduino IDE.
Код ESP8266: отображение текста
Теперь самое интересное!
Следующий тестовый скетч напечатает на дисплее сообщение «Hello World!». Он также включает в себя:
- отображение инвертированного текста;
- отображение чисел;
- отображение чисел с основанием (hex, dec);
- отображение символов ASCII
- прокрутка текста по горизонтали и по вертикали;
- прокрутка части дисплея.
Это даст вам полное представление о том, как использовать OLED дисплей, и может послужить основой для более практических экспериментов и проектов.
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
Adafruit_SSD1306 display(-1);
void setup()
{
// инициализация с I2C адресом 0x3C
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
// очистить буфер
display.clearDisplay();
// показать текст
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,28);
display.println("Hello world!");
display.display();
delay(2000);
display.clearDisplay();
// показать инвертированный текст
display.setTextColor(BLACK, WHITE); // 'инвертированный' текст
display.setCursor(0,28);
display.println("Hello world!");
display.display();
delay(2000);
display.clearDisplay();
// изменение размера шрифта
display.setTextColor(WHITE);
display.setCursor(0,24);
display.setTextSize(2);
display.println("Hello!");
display.display();
delay(2000);
display.clearDisplay();
// показать числа
display.setTextSize(1);
display.setCursor(0,28);
display.println(123456789);
display.display();
delay(2000);
display.clearDisplay();
// указать основание для чисел
display.setCursor(0,28);
display.print("0x"); display.print(0xFF, HEX);
display.print("(HEX) = ");
display.print(0xFF, DEC);
display.println("(DEC)");
display.display();
delay(2000);
display.clearDisplay();
// показать символы ASCII
display.setCursor(0,24);
display.setTextSize(2);
display.write(3);
display.display();
delay(2000);
display.clearDisplay();
// прокрутка всего экрана
display.setCursor(0,0);
display.setTextSize(1);
display.println("Full");
display.println("screen");
display.println("scrolling!");
display.display();
display.startscrollright(0x00, 0x07);
delay(2000);
display.stopscroll();
delay(1000);
display.startscrollleft(0x00, 0x07);
delay(2000);
display.stopscroll();
delay(1000);
display.startscrolldiagright(0x00, 0x07);
delay(2000);
display.startscrolldiagleft(0x00, 0x07);
delay(2000);
display.stopscroll();
display.clearDisplay();
// прокрутка части экрана
display.setCursor(0,0);
display.setTextSize(1);
display.println("Scroll");
display.println("some part");
display.println("of the screen.");
display.display();
display.startscrollright(0x00, 0x00);
}
void loop() {}
Скетч начинается с включения четырех библиотек, а именно SPI.h
, Wire.h
, Adafruit_GFX.h
и Adafruit_SSD1306.h
. Хотя библиотека SPI.h
для OLED дисплеев с I2C не требуется, нам нужно добавить ее для компиляции нашей программы.
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
Далее нам нужно создать объект Adafruit_SSD1306
. Конструктор Adafruit_SSD1306
принимает номер вывода ESP8266, к которому подключен вывод сброса дисплея. Поскольку используемый нами OLED дисплей не имеет вывода RESET, мы отправим конструктору значение -1, чтобы ни один из выводов ESP8266 не использовался в качестве сброса для дисплея.
Adafruit_SSD1306 display(-1);
В функции setup()
нам нужно инициализировать объект OLED дисплея с помощью функции begin()
. Эта функция принимает два параметра. Первый параметр SSD1306_SWITCHCAPVCC
включает внутреннюю схему питания, а второй параметр предоставляет I2C адрес OLED дисплея. Адрес I2C такого модуля OLED дисплея обычно равен 0x3C. Он фиксированный и не может быть изменен.
Далее перед печатью нашего первого сообщения на экране мы очищаем буфер.
// инициализация с I2C адресом 0x3C
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
// очистить буфер
display.clearDisplay();
Отображение простого текста (Hello World)

// показать текст
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,28);
display.println("Hello world!");
display.display();
delay(2000);
Для отображения текста на экране нам нужно установить размер шрифта. Это можно сделать, вызвав setTextSize(font-size)
и передав в качестве параметра размер шрифта (размер начинается с 1).
Далее нам нужно установить цвет шрифта, вызвав функцию setTextColor(color)
. Передайте параметр WHITE
для темного фона или BLACK
для светлого фона. Теперь перед печатью сообщения нам нужно установить позицию курсора, вызвав функцию setCursor(X, Y)
. Пиксели на экране адресуются по горизонтальным (X) и вертикальным (Y) координатам. Система координат размещает начало координат (0,0) в верхнем левом углу, причем положительный X смещается вправо, а положительный Y смещается вниз.
Мы можем использовать функцию print(" ")
или println(" ")
, чтобы напечатать сообщение на экране так же, как мы печатаем данные в мониторе последовательного порта. Помните, println()
переместит курсор на новую строку.
Чтобы библиотека могла выполнять чрезвычайно быстрые математические операции с буфером экрана (более 100 кадров в секунду), вызовы функций печати не сразу передают содержимое экранного буфера на контроллер SSD1306. Для указания библиотеке выполнить массовую передачу из экранного буфера в ESP8266 во внутреннюю память контроллера SSD1306 необходимо вызвать функцию display()
. Как только содержимое памяти будет перенесено, на OLED дисплее появятся пиксели, соответствующие содержимому экранного буфера.
Отображение инвертированного текста

// показать инвертированный текст
display.clearDisplay();
display.setTextColor(BLACK, WHITE); // 'инвертированный' текст
display.setCursor(0,28);
display.println("Hello world!");
display.display();
delay(2000);
Для отображения инвертированного текста мы снова вызовем функцию setTextColor(FontColor, BackgroundColor)
. Если вы были внимательны, то знаете, что ранее мы передали этой функции только один параметр, но теперь мы передаем два параметра. Это возможно благодаря перегрузке функций. Перегрузка функций – это возможность создавать несколько функций с одинаковым именем, но с разными наборами параметров. Вызовы перегруженной функции будут запускать конкретную реализацию этой функции в зависимости от переданных параметров.
В нашем случае вызов setTextColor(BLACK, WHITE)
отобразит черный текст на заполненном светлом фоне.
Изменение размера шрифта

// изменение размера шрифта
display.clearDisplay();
display.setTextColor(WHITE);
display.setCursor(0,24);
display.setTextSize(2);
display.println("Hello!");
display.display();
delay(2000);
Ранее в этой статье мы вызывали функцию setTextSize(font-size)
, чтобы установить размер шрифта, и передавали в качестве параметра 1. Вы можете использовать эту функцию для масштабирования шрифта, передавая любое неотрицательное целое число.
Символы отображаются в соотношении сторон 7:10. Это означает, что при передаче размера шрифта 1 текст будет отображаться с разрешением 7×10 пикселей на символ, при передаче 2 текст будет отображаться с разрешением 14×20 пикселей на символ, и так далее.
За рендеринг шрифта отвечает библиотека Adafruit_GFX. По умолчанию выбран моноширинный шрифт. Однако более поздние версии библиотеки Adafruit GFX предлагают возможность использовать альтернативные шрифты. В библиотеку входит несколько альтернативных шрифтов, плюс есть возможность добавлять новые.
Отображение чисел

// показать числа
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0,28);
display.println(123456789);
display.display();
delay(2000);
Отобразить числа на OLED дисплее можно, просто вызвав функцию print()
или println()
. Перегруженная реализация этих функций принимает 32-разрядные целые числа без знака, поэтому вы можете показывать числа в диапазоне только от 0 до 4 294 967 295.
Указание основания для чисел

// указать основание для чисел
display.clearDisplay();
display.setCursor(0,28);
display.print("0x"); display.print(0xFF, HEX);
display.print("(HEX) = ");
display.print(0xFF, DEC);
display.println("(DEC)");
display.display();
delay(2000);
У функций print()
и println()
есть необязательный второй параметр, который определяет основание (формат); допустимые значения: BIN
(двоичное, или основание 2), OCT
(восьмеричное, или основание 8), DEC
(десятичное, или основание 10), HEX
(шестнадцатеричное, или основание 16). Для чисел с плавающей запятой этот параметр указывает количество десятичных знаков. Например:
print(78, BIN)
дает “1001110”print(78, OCT)
дает “116”print(78, DEC)
дает “78”print(78, HEX)
дает “4E”println(1.23456, 0)
дает “1”println(1.23456, 2)
дает “1.23”println(1.23456, 4)
дает “1.2346”
Отображение символов ASCII

// показать символы ASCII
display.clearDisplay();
display.setCursor(0,24);
display.setTextSize(2);
display.write(3);
display.display();
delay(2000);
Функции print()
и println()
отправляют данные на дисплей в виде читаемого текста ASCII, а функция write()
отправляет на дисплей двоичные данные. Таким образом, вы можете использовать эту функцию для отображения символов ASCII. В нашем примере отправка числа 3 будет отображать символ сердца.
Прокрутка всего экрана

// прокрутка всего экрана
display.clearDisplay();
display.setCursor(0,0);
display.setTextSize(1);
display.println("Full");
display.println("screen");
display.println("scrolling!");
display.display();
display.startscrollright(0x00, 0x07);
delay(2000);
display.stopscroll();
delay(1000);
display.startscrollleft(0x00, 0x07);
delay(2000);
display.stopscroll();
delay(1000);
display.startscrolldiagright(0x00, 0x07);
delay(2000);
display.startscrolldiagleft(0x00, 0x07);
delay(2000);
display.stopscroll();
Вы можете прокручивать дисплей по горизонтали, вызывая функции startscrollright(startPage, stopPage)
и startscrollleft(startPage, stopPage)
, и по диагонали, вызывая startscrolldiagright(startPage, stopPage)
и startscrolldiagleft(startPage, stopPage)
. Все эти функции принимают два параметра, а именно, начальная страница (startPage
) и конечная страница (stopPage
). Для объяснения страниц обратитесь к разделу «Распределение памяти OLED модуля». Поскольку на дисплее отображается восемь страниц от 0 до 7, вы можете прокручивать весь экран, прокручивая все страницы, то есть, передавая параметры 0x00 и 0x07.
Чтобы остановить прокрутку дисплея, используется функция stopcroll()
.
Прокрутка определенной части

// прокрутка части экрана
display.clearDisplay();
display.setCursor(0,0);
display.setTextSize(1);
display.println("Scroll");
display.println("some part");
display.println("of the screen.");
display.display();
display.startscrollright(0x00, 0x00);
Иногда нам не нужно прокручивать весь экран. Прокрутку только определенной части можно выполнить, передав функциям прокрутки правильную информацию о стартовой и конечной страницах. Для объяснения страниц обратитесь к разделу «Распределение памяти OLED модуля». Поскольку на дисплее отображается восемь страниц от 0 до 7, вы можете прокрутить какую-либо часть экрана, передав в качестве параметров конкретные номера страниц.
В нашем примере мы передали в оба параметра значение 0x00. Это позволит прокрутить только первую страницу (первые 8 строк) дисплея.
Код ESP8266: основы рисования
В этом примере мы собираемся попробовать простейшее рисование. Данный скетч демонстрирует множество функций рисования, включая прямоугольники, скругленные прямоугольники, круги и треугольники. Попробуйте загрузить скетч, а затем мы рассмотрим его более подробно.
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
Adafruit_SSD1306 display(-1);
void setup()
{
// инициализация с I2C адресом 0x3C
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
// очистить буфер
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("Rectangle");
display.drawRect(0, 15, 60, 40, WHITE);
display.display();
delay(2000);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("Filled Rectangle");
display.fillRect(0, 15, 60, 40, WHITE);
display.display();
delay(2000);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("Round Rectangle");
display.drawRoundRect(0, 15, 60, 40, 8, WHITE);
display.display();
delay(2000);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("Filled Round Rectangl");
display.fillRoundRect(0, 15, 60, 40, 8, WHITE);
display.display();
delay(2000);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("Circle");
display.drawCircle(20, 35, 20, WHITE);
display.display();
delay(2000);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("Filled Circle");
display.fillCircle(20, 35, 20, WHITE);
display.display();
delay(2000);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("Triangle");
display.drawTriangle(30, 15, 0, 60, 60, 60, WHITE);
display.display();
delay(2000);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("Filled Triangle");
display.fillTriangle(30, 15, 0, 60, 60, 60, WHITE);
display.display();
delay(2000);
display.clearDisplay();
}
void loop() {}
Большая часть кода (включение библиотек и инициализация дисплея) такая же, как в примере выше, за исключением следующих фрагментов кода для рисования простых фигур.
Рисование прямоугольника

display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("Rectangle");
display.drawRect(0, 15, 60, 40, WHITE);
display.display();
delay(2000);

display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("Filled Rectangle");
display.fillRect(0, 15, 60, 40, WHITE);
display.display();
delay(2000);
Нарисовать прямоугольник на дисплее можно с помощью функции drawRect(X_координата, Y_координата, ширина, высота, цвет)
. На самом деле эта функция рисует «пустой» прямоугольник с границей в 1 пиксель. Вы также можете нарисовать закрашенный прямоугольник, используя функцию fillRect()
.
Рисование скругленного прямоугольника

display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("Round Rectangle");
display.drawRoundRect(0, 15, 60, 40, 8, WHITE);
display.display();
delay(2000);

display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("Filled Round Rectangl");
display.fillRoundRect(0, 15, 60, 40, 8, WHITE);
display.display();
delay(2000);
Нарисовать скругленный прямоугольник на дисплее можно с помощью функции drawRoundRect(X_координата, Y_координата, ширина, высота, радиус, цвет)
. Эта функция принимает те же параметры, что и функция drawRect()
, за исключением одного дополнительного параметра – радиуса скругления углов. Эта функция рисует полый скругленный прямоугольник с границей в 1 пиксель. Нарисовать закрашенный скругленный прямоугольник можно с помощью функции fillRoundRect()
.
Рисование круга

display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("Circle");
display.drawCircle(20, 35, 20, WHITE);
display.display();
delay(2000);

display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("Filled Circle");
display.fillCircle(20, 35, 20, WHITE);
display.display();
delay(2000);
Нарисовать окружность на дисплее можно с помощью функции drawCircle(X_координата_центра, Y_координата_центра, радиус, цвет)
. Эта функция рисует полый круг с границей в 1 пиксель. Нарисовать заполненный круг можно с помощью функции fillCircle()
.
Рисование треугольника

display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("Triangle");
display.drawTriangle(30, 15, 0, 60, 60, 60, WHITE);
display.display();
delay(2000);

display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("Filled Triangle");
display.fillTriangle(30, 15, 0, 60, 60, 60, WHITE);
display.display();
delay(2000);
Нарисовать треугольник на дисплее можно с помощью функции drawTriangle(x0, y0, x1, y1, x2, y2, color)
. Данная функция принимает семь параметров, а именно, координаты 3 вершин треугольника (x,y) и цвет. (x0, y0) представляет верхнюю вершину, (x1, y1) – левую вершину, и (x2, y2) – правую вершину.
Эта функция рисует полый треугольник с границей в 1 пиксель. Нарисовать заполненный треугольник можно с помощью функции fillTriangle()
.
Код NodeMCU ESP8266: отображение растрового изображения
В последнем примере показано, как на OLED дисплее рисовать растровые изображения. Это полезно для создания заставок с логотипом компании, создания спрайтов или просто создания забавной графики при отображении информации. Скопируйте следующий код, вставьте его в Arduino IDE и нажмите «Загрузить».
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
Adafruit_SSD1306 display(-1);
// Образ растрового изображения с Мэрилин Монро
const unsigned char MarilynMonroe [] PROGMEM = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xf0, 0x41, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x7f, 0xff, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xf1, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xff, 0xf8, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xfc, 0x02, 0x78, 0x7f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xfe, 0x03, 0x7c, 0x1f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x07, 0xff, 0xff, 0xfe, 0x01, 0xfe, 0x1f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfd, 0xe0, 0x03, 0xff, 0xff, 0xfc, 0x00, 0xfe, 0x0f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfe, 0x87, 0xe0, 0xff, 0xff, 0xfc, 0x00, 0x06, 0x07, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x1f, 0xf9, 0xff, 0xff, 0xfc, 0x00, 0x02, 0x07, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xfc, 0x00, 0xc3, 0xc3, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xe0, 0x0c, 0x00, 0xe7, 0x81, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xe0, 0x02, 0x00, 0x02, 0x00, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x3f, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x1e, 0x3f, 0xff, 0xff,
0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0x3f, 0xf8, 0x00, 0x18, 0x7f, 0x1f, 0xff, 0xff,
0xff, 0xff, 0xff, 0xf8, 0x01, 0x80, 0x03, 0xfc, 0x3f, 0xfc, 0x00, 0x70, 0xfe, 0x1f, 0xff, 0xff,
0xff, 0xff, 0xff, 0xf0, 0x43, 0xff, 0xff, 0xf8, 0x7f, 0xf8, 0x00, 0x00, 0x7e, 0x1f, 0xff, 0xff,
0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xf0, 0xff, 0xfc, 0x00, 0x00, 0x7c, 0x3f, 0xff, 0xff,
0xff, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xf1, 0xef, 0xf8, 0x00, 0x01, 0xfc, 0x3f, 0xff, 0xff,
0xff, 0xff, 0xff, 0xe4, 0xff, 0xff, 0xff, 0xf3, 0x80, 0xa0, 0x00, 0x07, 0xfc, 0xaf, 0xff, 0xff,
0xff, 0xff, 0xff, 0xec, 0x5f, 0xff, 0xff, 0xe7, 0xf0, 0x00, 0x00, 0x03, 0xfe, 0xdf, 0xff, 0xff,
0xff, 0xff, 0xff, 0xee, 0x7f, 0xff, 0xff, 0xc7, 0xf8, 0x00, 0x00, 0x03, 0xff, 0xdf, 0xff, 0xff,
0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xf7, 0xc7, 0xff, 0x06, 0x00, 0x03, 0xff, 0xbf, 0xff, 0xff,
0xff, 0xff, 0xff, 0xfe, 0x5f, 0xff, 0xc7, 0x07, 0xff, 0x80, 0x00, 0x07, 0xdb, 0xbf, 0xff, 0xff,
0xff, 0xff, 0xff, 0xee, 0xff, 0xff, 0x80, 0x03, 0xff, 0xc0, 0x00, 0x03, 0xc3, 0x0f, 0xff, 0xff,
0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x98, 0x03, 0xff, 0xf8, 0x00, 0x07, 0xe0, 0x0f, 0xff, 0xff,
0xff, 0xff, 0xff, 0xef, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xfc, 0x01, 0x07, 0xfc, 0x1f, 0xff, 0xff,
0xff, 0xff, 0xff, 0xcf, 0xef, 0xff, 0xff, 0xe1, 0xff, 0xfc, 0x01, 0x07, 0xf8, 0x1f, 0xff, 0xff,
0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0x7f, 0xf1, 0xff, 0xf8, 0x02, 0x07, 0x88, 0x3f, 0xff, 0xff,
0xff, 0xff, 0xff, 0xcf, 0xef, 0xf8, 0x0f, 0xff, 0xff, 0xe0, 0x00, 0x07, 0x84, 0x3f, 0xff, 0xff,
0xff, 0xff, 0xff, 0xe7, 0xef, 0xf0, 0x04, 0x7f, 0xff, 0xc0, 0x00, 0x07, 0x84, 0x7f, 0xff, 0xff,
0xff, 0xff, 0xff, 0x3f, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0x80, 0x00, 0x06, 0x04, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x3f, 0x7f, 0xe1, 0xf0, 0x07, 0xff, 0x80, 0x00, 0x07, 0x06, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0xfe, 0x03, 0xff, 0x00, 0x00, 0x03, 0x80, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xf2, 0x3f, 0xc6, 0x7f, 0x81, 0xce, 0x00, 0x00, 0x01, 0xc1, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xe0, 0x3f, 0xc0, 0x07, 0xc1, 0xfe, 0x00, 0x00, 0x0d, 0xc0, 0x7f, 0xff, 0xff,
0xff, 0xff, 0xff, 0xe0, 0x3f, 0xc0, 0x01, 0xe0, 0xfc, 0x00, 0x00, 0x0f, 0xc0, 0x7f, 0xff, 0xff,
0xff, 0xff, 0xff, 0xc0, 0x3f, 0xc0, 0x00, 0x50, 0xfc, 0x00, 0x00, 0x0e, 0xc0, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xc0, 0x3f, 0xc0, 0x00, 0x18, 0xf8, 0x00, 0x00, 0x0e, 0xc1, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xc0, 0x3f, 0xc0, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x66, 0x81, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xc0, 0x1f, 0xc7, 0x80, 0x00, 0xf8, 0x00, 0x01, 0xe0, 0x00, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xc0, 0x1f, 0xc1, 0xe0, 0x01, 0xf8, 0x00, 0x03, 0xf0, 0x01, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x80, 0x1f, 0xc0, 0x3e, 0x03, 0xf0, 0x00, 0x00, 0xe0, 0x03, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x00, 0x1f, 0xe0, 0xe0, 0x03, 0xf2, 0x00, 0x00, 0xc0, 0x03, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x80, 0x1f, 0xf0, 0x00, 0x07, 0xe6, 0x00, 0x00, 0xc0, 0x03, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x80, 0x1f, 0xff, 0x00, 0x1f, 0xee, 0x00, 0x00, 0x80, 0x07, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xb8, 0x0f, 0xff, 0xf0, 0x3f, 0xdc, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xbc, 0x0f, 0xff, 0xff, 0xff, 0xdc, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x9e, 0x0f, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x08, 0x0f, 0xff, 0xff, 0xff, 0x70, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x00, 0x0b, 0xff, 0xff, 0xfe, 0xe0, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x00, 0x0b, 0xff, 0xff, 0xf9, 0xc0, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x3c, 0x09, 0xff, 0xff, 0xf1, 0x80, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x1e, 0x08, 0x3f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x1f, 0x08, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x80, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xce, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xfe, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff
};
void setup()
{
// инициализация с I2C адресом 0x3C
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
// очистить буфер
display.clearDisplay();
// показать растровое изображение
display.drawBitmap(0, 0, MarilynMonroe, 128, 64, WHITE);
display.display();
// инвертировать экран
//display.invertDisplay(1);
}
void loop() {}
Вот так выглядит результат.

Чтобы показать растровое изображение на OLED дисплее, нам нужно вызвать функцию drawBitmap(X_координата, Y_координата, растровый_массив, ширина, высота, цвет)
. Она принимает шесть параметров, а именно, координата X левого верхнего угла, координата Y левого верхнего угла, байтовый массив монохромного растрового изображения, ширина растрового изображения в пикселях, высота растрового изображения в пикселях и цвет.
В нашем примере растровое изображение имеет размер 128×64. Таким образом, координаты X и Y установлены в 0, а ширина и высота установлены в 128 и 64.
// показать растровое изображение
display.drawBitmap(0, 0, MarilynMonroe, 128, 64, WHITE);
display.display();
Но прежде чем мы сможем вызвать функцию drawBitmap()
, нам сначала нужно нарисовать изображение. Помните, что разрешение OLED дисплея составляет 128×64 пикселей, поэтому изображения большего размера будут отображаться некорректно. Чтобы получить изображение правильного размера, вы можете использовать ваши любимые программы для рисования, такие как Inkscape, Photoshop, Paint и т.д., установив размер холста 128×64 пикселей.
В качестве примера мы взяли изображение Мэрилин Монро, преобразовали размер его в 128×64 пикселей с помощью Paint и сохранили в формате .bmp.
Теперь, когда у нас есть растровое изображение, самое время преобразовать его в массив, понятный OLED контроллеру SSD1306. Это можно сделать двумя способами: онлайн-метод с использованием image2cpp и офлайн-метод с использованием LCD Assistant.
Онлайн-генератор растровых массивов image2cpp
Онлайн-приложение image2cpp может преобразовать ваше изображение в массив. Image2cpp является более новым и намного более мощным, чем LCD Assistant. Оно позволит вам:
- преобразовать несколько изображений одновременно;
- масштабировать файл изображения (растянуть/масштабировать по размеру или относительно оригинала);
- настроить порог яркости между черным и белым;
- отцентрировать изображение по вертикали и/или по горизонтали;
- инвертировать цвета изображения.
Этот инструмент настолько мощный, что может работать и в автономном режиме. Просто сохраните страницу на своем ПК и откройте ее в браузере.
Для начала откройте image2cpp в вашем браузере и выберите любое изображение, которое вы хотите отобразить на OLED дисплее.

Размеры вашего изображения будут отображаться в параметре Canvas size в разделе Image settings. Если вы выбрали изображение большего размера, чем 128×64, измените его на 128×64 и выберите подходящий параметр масштабирования Scaling. Вы можете просмотреть вывод в разделе предварительного просмотра Preview section.
При необходимости вы можете изменить цвет фона (Background color) или инвертировать цвета изображения (Invert image colors).
Наконец, измените в соответствии с вашими требованиями наиболее важный параметр – порог яркости (Brightness threshold). Установка порога сделает пиксели выше этого уровня белыми и ниже черными. В нашем случае мы установили 171, чтобы получить достаточно детализированное изображение Мэрилин Монро.

Это изображение предварительного просмотра отражает все изменения, которые вы вносите в свои настройки. Вы можете изменять настройки, следя за ним.

Как только вы будете удовлетворены результатом, можете приступить к созданию массива данных. Просто выберите формат вывода кода (Code output format) как Arduino Code и нажмите кнопку Generate code.
Для информации, есть еще опция под названием Режим рисования (Draw mode). Она на самом деле создает изображение в соответствии с шаблоном сканирования дисплея. Если ваше изображение выглядит на дисплее испорченным, попробуйте изменить этот режим.

Вот и всё. Сейчас будет сгенерирован байтовый массив вашего растрового изображения. И вы можете использовать этот вывод непосредственно в коде нашего примера. Просто не забудьте назвать его соответствующим образом. А затем вызовите ваш массив внутри функции drawBitmap()
.

Автономный генератор массивов растровых изображений LCD Assistant
Преобразовать ваше растровое изображение в массив данных может еще одно приложение, LCD Assistant. Оно не такой мощное, как image2cpp, но по-прежнему популярно среди любителей.
Для начала вам необходимо преобразовать ваше изображение в монохромное растровое изображение 128×64. Чтобы сделать это, вы можете использовать ваши любимые программы для рисования, такие как Inkscape, Photoshop, Paint и т.д. Мы делали это в MS Paint.
Откройте ваш файл в MS Paint и измените его размер на 128×64.

Теперь сохраните ваш файл как растровое изображение. При сохранении файла выберите Сохранить как: Монохромный рисунок (*.bmp; *.dib). Это создаст 1-битное/двоичное растровое изображение, которое для каждого пикселя имеет только два возможных значения, то есть 0 (черный) или 1 (белый).

Единственным недостатком здесь является то, что вы не можете установить пороговый уровень яркости. По умолчанию он установлен на 50% и не может быть изменен.
Теперь скачайте программу LCD Assistant. Откройте ее и загрузите ваше растровое изображение из меню File.

Ничего особого с этим инструментом вы сделать не можете. Итак, просто зайдите в меню File и нажмите Save output. Сохраните файл как текстовый файл.
Для информации, здесь есть еще опция под названием Byte Orientation. Она создает изображение в соответствии с шаблоном сканирования дисплея. Если ваше изображение выглядит на дисплее испорченным, попробуйте изменить этот режим.

Вот и всё. Создав массив, вставьте его в свой код.

Просто не забудьте назвать его соответствующим образом. Затем вызовите ваш массив внутри функции drawBitmap()
.