Модули · статья

OLED-дисплей SSD1306 0.96″ и Arduino: подключение, библиотеки, память

Маленький яркий экран на 128×64 точки, четыре провода и ни одного подстроечника. Разбираем, чем он отличается от LCD 1602, почему фирменный пример оставляет экран чёрным, какую из трёх библиотек брать — Adafruit, U8g2 или GyverOLED — и сколько каждая съедает из двух килобайт памяти Arduino Uno. Все числа мы измерили сборкой; живого экрана под рукой не было, и там, где это важно, мы так и пишем.

Что это за экран и чем он не LCD

OLED 0.96″ — это матрица 128 на 64 светящиеся точки под управлением контроллера SSD1306. Подсветки нет: каждая точка светится сама, поэтому чёрный на нём по-настоящему чёрный, углы обзора любые, а питания хватает от USB. Бывает двухцветным — верхние 16 строк жёлтые, остальное голубое; это не режим, а так напечатана матрица, и в коде это никак не выбирается.

От LCD 1602 он отличается принципиально. LCD показывает знаки из зашитой таблицы: вы шлёте код буквы, экран рисует её сам. OLED не знает никаких букв — это просто 8 192 точки, и каждую зажигает ваша программа. Отсюда всё: любые шрифты и картинки, в том числе русские буквы без фокусов — но и буфер кадра в памяти платы, который на Arduino Uno занимает половину всей оперативной памяти.

страница 0128 байт · 8 строк точек
страница 1128 байт · 8 строк точек
страница 2128 байт · 8 строк точек
страница 3128 байт · 8 строк точек
страница 4128 байт · 8 строк точек
страница 5128 байт · 8 строк точек
страница 6128 байт · 8 строк точек
страница 7128 байт · 8 строк точек
Экран 128×64 — это 8 192 точки, у каждой один бит: 1 024 байта на кадр. Контроллер SSD1306 хранит их восемью «страницами» по 8 строк; один байт — это столбик из восьми точек. Библиотека с полным буфером держит все 1 024 байта в памяти платы и отправляет кадр целиком; постраничный режим U8g2 держит одну полоску (128 байт) и рисует кадр за восемь проходов — медленнее, зато влезает в Uno с запасом.

Встречаются и родственники. Экран 0.91″ — это 128×32, те же контроллер и библиотеки, меняется размер в конструкторе: у Adafruit число 64 → 32, у U8g2 имя класса с «128X32», у GyverOLED параметр SSD1306_128x32. Экран 1.3″ выглядит так же, но внутри обычно стоит другой контроллер — SH1106; код для SSD1306 на нём даст сдвинутую картинку с мусором по краям, про это отдельный раздел ниже.

Подключение: четыре провода и один подвох

ARDUINOUNOUSBPOWERANALOG INGND5VA4A5Привет!128 × 64OLED 0.96″ на SSD1306GNDVCCSDASCL
  • GNDGND (земля)
  • 5VVCC (питание)
  • A4SDA (данные)
  • A5SCL (такт)
Те же четыре провода, что и у экрана 1602: OLED сидит на той же шине I2C. Единственная разница — порядок контактов на самом модуле бывает и GND-VCC-SCL-SDA, и VCC-GND-SCL-SDA: соединяйте по подписям, а не по местам.
На модулеUno, NanoMega 2560Leonardo, MicroESP8266 (NodeMCU, D1 mini)ESP32 (классический DevKit)
GNDGNDGNDGNDGNDGND
VCC5V или 3.3V5V или 3.3V5V или 3.3V3V33V3
SDAA4202D2 (GPIO4)21
SCLA5213D1 (GPIO5)22

Подвох в порядке выводов. У одних модулей слева направо идут GND, VCC, SCL, SDA, у других — VCC, GND, SCL, SDA. Они выглядят одинаково, и если воткнуть второй по памяти о первом, питание и земля поменяются местами — а защиты от этого на модуле нет, перепутанные провода могут его сжечь. Читайте подписи на плате до включения, а не положение контактов. Сам чип SSD1306 трёхвольтовый, но на модулях стоит стабилизатор, и от 5 В платы Arduino они питаются штатно; на ESP берите 3V3. И ещё: если у модуля не четыре вывода, а семь (GND, VCC, D0, D1, RES, DC, CS) — это версия с шиной SPI, и всё ниже про четыре провода и адрес к ней не относится; конструктор там другой, display(128, 64, &SPI, DC, RES, CS). Куда идут его семь проводов — в таблице ниже.

Вариант 1 (чаще всего)
GND
VCC
SCL
SDA
Вариант 2 (встречается не реже)
VCC
GND
SCL
SDA
Две одинаковые с виду платы 0.96″ — и разный порядок первых двух контактов. Если воткнуть второй модуль «по памяти» о первом, питание и земля поменяются местами: защиты от этого на модуле нет. Смотрите на буквы, напечатанные рядом с гребёнкой, каждый раз — даже если модуль куплен там же, где предыдущий.
Вывод модуля по SPIКуда на Uno и NanoЧто это
GNDGNDземля
VCC5V или 3.3Vпитание
D0 (SCK, CLK)13такт шины SPI
D1 (MOSI, SDA)11данные в дисплей
RES (RST)любой свободный, например 9сброс дисплея
DCлюбой свободный, например 8команда или данные
CSлюбой свободный, например 10выбор устройства

В коде меняется только конструктор: Adafruit_SSD1306 display(128, 64, &SPI, 8, 9, 10) — числа здесь это DC, RES и CS. Всё остальное в статье — библиотеки, буфер, шрифты, ошибки — к SPI-версии относится полностью: контроллер тот же.

Линии SDA и SCL у всех плат те же, что и для любого другого устройства I2C: на Uno это A4 и A5, они же продублированы двумя контактами рядом с AREF. Что за плата NodeMCU и почему у неё выводы зовутся D1 и D2 — в статье про ESP8266. Номера взяты из файлов pins_arduino.h ядер 1.8.8 и 3.1.2. Если к той же шине подключён LCD 1602 или датчик — ничего не меняется, у каждого свой адрес.

Адрес 0x3C и почему фирменный пример не работает

Почти все модули 0.96″ сидят на адресе 0x3C. На обратной стороне есть резистор или перемычка, которой адрес меняют на 0x3D — но с завода она стоит на 0x3C. Иногда прямо на плате напечатано «0x78»: это тот же 0x3C, только записанный со сдвигом на бит, как его видит сам контроллер; в код пишите 0x3C. И вот самая частая история первого запуска.

Пример Adafruit: ssd1306_128x64_i2c.ino
#define SCREEN_ADDRESS 0x3D ///< See datasheet for Address;
                            ///< 0x3D for 128x64, 0x3C for 128x32
...
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
  Serial.println(F("SSD1306 allocation failed"));
  for(;;);
}
Что на самом деле на модуле 0.96″
I2C scanner
Found 0x3C

Адрес 0x3D бывает только после перепайки перемычки
или резистора на обратной стороне платы.
Самая частая причина чёрного OLED после загрузки фирменного примера — строка с адресом. Пример ориентируется на фирменные модули Adafruit, а у дешёвых модулей 0.96″ почти всегда 0x3C. Причём функция begin() ответ дисплея не проверяет и честно вернёт «успех»: false она даёт только тогда, когда не хватило памяти под буфер. Так что «allocation failed» — это про память, а не про провода.

Человек открывает пример из библиотеки Adafruit, ssd1306_128x64_i2c, загружает — и видит чёрный экран. В примере стоит #define SCREEN_ADDRESS 0x3D, потому что Adafruit ориентируется на свои фирменные модули. Замените на 0x3C — и появится заставка. Мы это взяли прямо из файла примера версии 2.5.17; в более старых версиях цифра была та же. Та же ловушка прячется и без #define: вызов begin(SSD1306_SWITCHCAPVCC) без второго аргумента для экрана 128×64 подставит 0x3D сам (так написано в коде библиотеки). Всегда указывайте адрес явно.

Второй слой той же ловушки — в исходниках begin(). Эта функция не спрашивает у дисплея, есть ли он на шине: она выделяет память под буфер, шлёт команды настройки и возвращает «успех». false она возвращает в одном случае — если malloc не смог выделить 1 024 байта. Поэтому проверка if (!display.begin(…)) ловит не отсутствие экрана, а нехватку памяти, и надпись «SSD1306 allocation failed» значит именно это.

Чтобы узнать адрес наверняка, нужен сканер I2C — тот же, что для LCD: он опрашивает все адреса и печатает, кто отозвался. Код и разбор — в статье про LCD 1602 по I2C; в Trema IDE сканер лежит в примерах, раздел «Полезное».

Три библиотеки и сколько памяти берёт каждая

Для SSD1306 в нашем каталоге десятки библиотек, но живых варианта три. Мы поставили каждую из каталога libraries.trema.ru и собрали один и тот же скетч «привет» для Arduino Uno — вот что вышло.

БиблиотекаФлеш, байт из 32 256 (у Nano — из 30 720)ОЗУ, байт из 2 048Русские буквыЧто надо знать
Adafruit SSD1306 2.5.17 + GFX 1.12.6 + BusIO 1.17.414 078 (43 %)569 (27 %) + 1 024 при запускенет: русские буквы выйдут мусоромБольше всего примеров в интернете. Буфер берётся командой malloc в begin() и в отчёте компилятора не виден.
U8g2 2.36.19, полный буфер (_F_)10 730 (33 %)1 572 (76 %)22 шрифта _t_cyrillicСотни шрифтов, все контроллеры монохромных экранов. Архив 14 МБ — самая тяжёлая установка.
U8g2, постранично (_1_)10 756 (33 %)676 (33 %)те же шрифтыТот же код, но кадр рисуется за восемь проходов; буфер — одна полоска в 128 байт. Лучший выбор для Uno с датчиками.
GyverOLED 1.6.4, с буфером5 530 (17 %)1 327 (64 %)да, включая строчную ёСамая лёгкая по флешу: в 2,5 раза меньше Adafruit. Один шрифт 5×7, но с русскими буквами (заглавная Ё печатается как Е); масштаб текста setScale(1…4).
iarduino_OLED_txt 1.2.5 (текст и числа)7 664 (23 %)325 (15 %)да, шрифты с кириллицейРусская библиотека под модули Trema: буфера кадра нет вовсе, поэтому ОЗУ почти свободно. Только текст и числа — ни линий, ни картинок. Понимает UTF-8, CP866 и Windows-1251.
iarduino_OLED 1.2.5 (графическая)8 118 (25 %)1 350 (65 %)да, те же шрифтыТа же библиотека, но с буфером 1 024 байта: добавляются линии, прямоугольники, круги и картинки. Кадр уходит на экран по update().
GyverOLED, без буфера5 524 (17 %)303 (14 %)даРисует прямо в дисплей байтами по 8 точек в высоту: текст и битмапы, выровненные по строкам из 8 точек, выходят чисто, а линии, контуры и окружности затирают соседние точки в том же столбике. Зато ОЗУ почти свободно.
Adafruit SSD1306 + GFX

Компилятор видит 569 байт (27 %). Ещё 1 024 библиотека просит при запуске, и в отчёте их нет — а получит их, только если свободно было не меньше ≈1 200.

U8g2, полный буфер (_F_)

Честные 1 572 байта (76 %) — буфер объявлен заранее, компилятор его показывает.

U8g2, постранично (_1_)

676 байт (33 %): вместо целого кадра хранится одна полоска в 128 байт, кадр рисуется за 8 проходов.

GyverOLED с буфером

1 327 байт (64 %). Зато флеша всего 5 530 байт — в два с половиной раза меньше, чем у Adafruit.

GyverOLED без буфера

303 байта (14 %): текст и фигуры уходят сразу в дисплей, но читать экран обратно нельзя.

  • в отчёте компилятора
  • выделяется при запуске, в отчёте не видно
  • свободно из 2 048 байт
Оперативная память Arduino Uno — 2 048 байт — под скетчем «привет» с экраном 128×64 на каждой из библиотек. Все цифры измерены сборкой. Полосы Adafruit и U8g2 (_F_) на деле почти равны: 569 + 1 024 = 1 593 против 1 572 — просто одна библиотека берёт буфер заранее, а другая — в момент запуска.

Главное, что стоит вынести из этой картинки: буфер кадра — это 1 024 байта, и он есть у всех, просто библиотеки берут его по-разному. U8g2 в полном режиме и GyverOLED объявляют его заранее, и компилятор честно показывает 76 % и 64 % — при 76 % он ещё и напишет «Недостаточно памяти, программа может работать нестабильно»: это предупреждение, прошивка загрузится, но это сигнал перейти на постраничный режим. Adafruit берёт его командой malloc в момент запуска, и компилятор о нём не знает: в отчёте 27 %, а по факту те же 78 %. Мы проверили на скетче с массивом из 300 чисел: отчёт сборки говорит «59 %, свободно 829 байт», сборка зелёная, а при запуске begin() попросит 1 024 — и получит отказ. Экран чёрный, в мониторе «allocation failed», и ни одной ошибки при компиляции. Причём мало, чтобы свободных было ровно тысяча: по документации avr-libc malloc держит запас в 128 байт до стека и два байта тратит на заголовок, да и самому стеку нужно место — на практике буфер влезает, когда отчёт показывает не меньше ≈1 200 свободных, то есть статика не больше ≈40 %.

Для Arduino Uno и Nano отсюда простой совет: если экран — не единственное, что делает плата, берите U8g2 в постраничном режиме (676 байт) или GyverOLED без буфера (303 байта). На Mega 2560 с её 8 КБ и на ESP8266 с 80 КБ всё это не имеет значения: на Mega Adafruit вместе с буфером берёт 1 593 байта из 8 192 (19 %; компилятор покажет 569, то есть 6 %), на ESP8266 — около 1,7 КБ из 80 (2 %; в отчёте будет 35 %, но это само ядро ESP8266 занимает 28 КБ на любом скетче) — мы собрали и для них. Подробнее про то, какие бывают памяти и куда деваются байты, — в статье «Память Arduino».

Про зависимости. Adafruit SSD1306 тянет за собой Adafruit GFX Library, а та — Adafruit BusIO. Каталог знает эти связи, и при установке первой встают все три. Если ставили архивом вручную и получили Adafruit_GFX.h: No such file or directory или Adafruit_I2CDevice.h: No such file — это они. Любопытно, что строка #include <Adafruit_GFX.h> в самом скетче не обязательна: мы собрали без неё, и всё сошлось, потому что заголовок SSD1306 подключает её сам.

Если экрана ещё нет. В магазине, для модулей которого мы и делаем среду, лежит ровно такой: OLED-экран 128×64 / 0,96″ (Trema-модуль) — артикул 830, 594 ₽, контроллер SSD1306, белое свечение, питание 3,3–5 В, плата 30×30 мм. Два его отличия от безымянных модулей стоят упоминания: адрес переключается переключателем на обороте (0x3C или 0x3D — то есть два экрана на одной шине заводятся без пайки), и к нему идут две русские библиотеки с готовыми шрифтами кириллицы — мы их измерили и внесли в таблицу выше.

Про эти две библиотеки отдельно, потому что в списке выше они выглядят выгоднее всех для Arduino Uno. iarduino_OLED_txt вообще не держит буфер кадра: текст уходит прямо в экран, и в оперативной памяти остаётся 1 723 байта из 2 048 — больше, чем у любой другой библиотеки с русским текстом. Платой служит флеш: русские шрифты лежат в нём, и «привет» весит 7 664 байта (со вторым шрифтом 12×16 — 11 980). iarduino_OLED — та же библиотека с буфером и графикой: 8 118 байт флеша и 1 350 ОЗУ. Обе есть в нашем каталоге, ставятся оттуда же.

Первый скетч: Adafruit

Начнём с самой распространённой библиотеки — под неё написано больше всего чужих примеров, и её стоит понимать, даже если потом перейдёте на другую.

// Первый скетч на библиотеке Adafruit: текст двух размеров.
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// 128×64 точки, шина Wire, вывода сброса нет (-1).
Adafruit_SSD1306 display(128, 64, &Wire, -1);

void setup() {
  Serial.begin(9600);
  // Адрес 0x3C — у почти всех модулей 0.96". В фирменном примере стоит
  // 0x3D, и с ним экран останется чёрным.
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println("SSD1306 allocation failed");   // не хватило ОЗУ под буфер
    for (;;);
  }
  display.clearDisplay();
  display.setTextSize(1);                 // 6×8 точек на знак: 21 знак в строке
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println("Hello, Arduino!");
  display.setTextSize(2);                 // 12×16: 10 знаков в строке
  display.println("OLED");
  display.display();                      // без этой строки на экране ничего
}

void loop() {
}

14 078 байт флеша и 569 байт ОЗУ по отчёту (плюс тысяча при запуске). Три вещи, которые ловят всех. Первая — адрес 0x3C в begin(), уже обсудили. Вторая — display() в конце: всё рисование идёт в буфер, и пока не вызвать эту команду, на стекле ничего не меняется. Третья — встроенный шрифт 5×7 точек с шагом 6: при setTextSize(1) в строку помещается 21 знак, при размере 2 — 10, и кириллицы в нём нет: таблица на 256 знаков, и каждый байт русской буквы попадёт на чужой символ — рамки, чёрточки, греческие буквы. Вместо «Привет» выйдет двенадцать знаков мусора.

Версии 128×32 — тот же скетч с display(128, 32, …). Если перепутать высоту, картинка пойдёт «через строку» — сжатая или растянутая, — это не брак экрана.

U8g2: постраничный режим для Uno

U8g2 — самая большая библиотека для монохромных экранов: сотни шрифтов и почти любой контроллер. Платой за это служит архив в 14 МБ — ставится дольше остальных. Конструкторов в ней почти пять тысяч (для одного SSD1306 128×64 — девяносто), поэтому имя читается как формула: U8G2_SSD1306_128X64_NONAME_1_HW_I2C — контроллер, размер, тип платы, режим буфера, способ подключения. Режимов три: _F_ — полный кадр в памяти, _1_ — одна полоска в 128 байт, _2_ — две. Для Uno берите _1_.

// U8g2 в постраничном режиме: 676 байт ОЗУ вместо 1 572.
#include <Wire.h>
#include <U8g2lib.h>

// _1_ в имени — постраничный буфер. Замените на _F_ — будет полный.
U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);

void setup() {
  u8g2.begin();
}

void loop() {
  u8g2.firstPage();
  do {                                   // этот блок выполнится 8 раз
    u8g2.setFont(u8g2_font_ncenB14_tr);
    u8g2.drawStr(0, 24, "Hello, Arduino!");
  } while (u8g2.nextPage());
  delay(1000);
}

Цикл do … while (nextPage()) — это и есть постраничный режим: библиотека рисует кадр восемь раз, каждый раз только полоску в 8 строк, и шлёт её в дисплей. Код внутри цикла должен рисовать одно и то же все восемь проходов — поэтому считывать датчик надо до firstPage(), а не внутри. Мы измерили цену: 10 756 байт флеша, 676 байт ОЗУ против 1 572 у _F_ при том же флеше. Кадр обновляется медленнее, но для показаний датчиков и меню это незаметно.

Вот показания аналогового входа крупными цифрами с полоской внизу — скетч, который после замены analogRead на чтение любого датчика становится готовым прибором. Собран: 10 688 байт флеша, 670 байт ОЗУ — крупный цифровой шрифт стоит всего полкилобайта, потому что в нём только цифры и знаки, и вместе с мелким 6×12 это меньше одного шрифта ncenB14 из первого скетча.

// Крупное число с аналогового входа — как будто показания датчика.
#include <Wire.h>
#include <U8g2lib.h>

U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);

void setup() {
  u8g2.begin();
}

void loop() {
  int value = analogRead(A0);
  u8g2.firstPage();
  do {
    u8g2.setFont(u8g2_font_6x12_tr);
    u8g2.drawStr(0, 10, "A0 reading");
    u8g2.setFont(u8g2_font_logisoso32_tn);   // только цифры, 32 точки высотой
    u8g2.setCursor(0, 58);
    u8g2.print(value);
    // Полоска-индикатор вдоль нижнего края:
    u8g2.drawFrame(0, 60, 128, 4);
    u8g2.drawBox(0, 60, map(value, 0, 1023, 0, 128), 4);
  } while (u8g2.nextPage());
  delay(100);
}

Русский текст на OLED

В отличие от LCD 1602, здесь никаких ограничений: буква — это просто точки. Нужен только шрифт, в котором эти буквы нарисованы. В U8g2 таких 22, их имена кончаются на _t_cyrillic, а строки надо печатать через print() после enableUTF8Print():

// Русский текст на OLED: шрифт с кириллицей и печать через print().
#include <Wire.h>
#include <U8g2lib.h>

U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);

void setup() {
  u8g2.begin();
  u8g2.enableUTF8Print();                // понимать русские буквы в строках
}

void loop() {
  u8g2.firstPage();
  do {
    u8g2.setFont(u8g2_font_10x20_t_cyrillic);   // _t_cyrillic — с кириллицей
    u8g2.setCursor(0, 24);
    u8g2.print("Привет, мир!");
  } while (u8g2.nextPage());
  delay(1000);
}

Собрано: 15 764 байта флеша — шрифт 10×20 с кириллицей весит почти 7 КБ против 1,4 КБ у того же шрифта без неё: в нём 387 знаков вместо 95, потому что это не только русский алфавит, а весь блок кириллицы с украинскими, сербскими и казахскими буквами. ОЗУ почти не изменилось — 682 байта против 676: шрифты лежат во флеше. Если нужно компактнее — u8g2_font_6x12_t_cyrillic или u8g2_font_5x8_t_cyrillic. А одну строку можно вывести и без enableUTF8Print() — командой drawUTF8(x, y, "Привет").

Второй путь — GyverOLED: русские буквы, включая строчную ё, у неё в единственном встроенном шрифте, и никаких настроек (одна мелочь из кода: заглавная Ё печатается как Е):

// GyverOLED: русские буквы сразу, 5,5 КБ флеша.
#include <GyverOLED.h>

// OLED_BUFFER — кадр в памяти платы (скетч берёт 1 327 байт ОЗУ, из них 1 024 — буфер),
// OLED_NO_BUFFER — рисовать прямо в дисплей (303 байта).
GyverOLED<SSD1306_128x64, OLED_BUFFER> oled;

void setup() {
  oled.init();
  oled.clear();
  oled.setScale(2);            // буквы вдвое крупнее
  oled.setCursor(0, 0);
  oled.print("Привет!");
  oled.setScale(1);
  oled.setCursor(0, 4);        // строка 4 — это 4-я «страница» по 8 точек
  oled.print("GyverOLED, 128x64");
  oled.update();               // отправить буфер в дисплей
}

void loop() {
}

5 530 байт флеша — в два с половиной раза меньше, чем у Adafruit, и 1 327 байт ОЗУ с буфером или 303 без (второй параметр шаблона OLED_NO_BUFFER). Масштаб setScale(2) делает буквы 12×16, и это простейший способ получить крупные цифры термометра. У библиотеки русский автор и русская документация — для кружка это аргумент.

И третий путь — русские библиотеки iarduino_OLED_txt и iarduino_OLED. Текст в них печатается функцией print(строка, столбец, строка_экрана), а шрифты с кириллицей уже внутри: SmallFontRus 6×8 и MediumFontRus 12×16. Скетч ниже мы собрали: 7 664 байта флеша и всего 325 байт ОЗУ.

// Русский текст библиотекой iarduino_OLED_txt: буфера кадра нет,
// в оперативной памяти остаётся 1 723 байта из 2 048.
#include <Wire.h>
#include <iarduino_OLED_txt.h>

// Адрес 0x3C или 0x3D — у модуля Trema он выбирается переключателем.
iarduino_OLED_txt oled(0x3C);

void setup() {
  oled.begin(&Wire);
  oled.setFont(SmallFontRus);            // шрифт 6x8 с кириллицей
  oled.print("Привет, мир!", OLED_C, 2); // OLED_C — по центру, строка 2
}

void loop() {
}

Если русский текст выходит «кракозябрами», у этих библиотек есть переключатель кодировки: setCoding(TXT_UTF8) — как сохраняет современная Arduino IDE и Trema IDE, TXT_CP866 и TXT_WIN1251 — для старых файлов. По умолчанию UTF-8, так что обычно трогать не нужно.

Яркость и выгорание

Подстроечника у OLED нет, но яркость регулируется из кода: у Adafruit — display.dim(true) или команда SSD1306_SETCONTRAST, у U8g2 и GyverOLED — setContrast(0…255). И одно свойство, о котором редко пишут: точки OLED изнашиваются от работы, и надпись, которая месяцами горит на одном месте, оставляет след — это заметно на приборах, включённых круглые сутки. Для таких гасите экран, когда на него не смотрят, или сдвигайте картинку на пару точек время от времени. Для кружкового проекта это не важно.

SSD1306 или SH1106: почему картинка съехала

Экраны 1.3″ и часть 0.96″ собраны на контроллере SH1106. Он почти совместим с SSD1306, но у него матрица 132 столбца, а не 128, и нет команды «горизонтальная адресация», которой пользуются библиотеки для SSD1306. В результате код для SSD1306 на SH1106 рисует, но со сдвигом на два столбца и полосой мусора у края — или не рисует вовсе.

  • U8g2: замените в конструкторе SSD1306 на SH1106 — всё остальное то же самое.
  • GyverOLED: первый параметр шаблона SSH1106_128x64 (именно с двумя S — так в библиотеке), и только вместе с OLED_BUFFER: без буфера SH1106 она не поддерживает.
  • Adafruit: нужна отдельная библиотека Adafruit SH110X с классом Adafruit_SH1106G; она тоже в каталоге — и, в отличие от SSD1306, её begin() честно возвращает false, если экрана нет на шине.

Определить контроллер по внешнему виду нельзя; продавец обычно пишет его в названии. Если не написано, а экран 1.3″ — скорее всего SH1106; 0.96″ — скорее всего SSD1306. Проверка простая: загрузить скетч для одного и посмотреть, ровная ли картинка.

Ошибки и странности, которые мы воспроизвели или разобрали

Что видноЧто этоЧто делать
Чёрный экран после примера AdafruitВ примере адрес 0x3D, у модуля 0x3CИсправить SCREEN_ADDRESS на 0x3C.
SSD1306 allocation failed в монитореНе хватило ОЗУ под буфер 1 024 байтаСтроки во флеш через F("…"), меньше массивов, или U8g2 _1_. Компилятор про это не предупредит.
Adafruit_SSD1306.h: No such file or directoryБиблиотека не установленаПоставить из каталога — вместе с ней встанут GFX и BusIO. Trema IDE предложит её сама.
U8g2lib.h: No such file or directoryНе установлена U8g2Поставить «U8g2» — архив 14 МБ, это нормально.
Рисую, а на экране ничегоНе вызван display() (Adafruit), sendBuffer() (U8g2 _F_) или update() (GyverOLED с буфером); в постраничном режиме U8g2 — нет цикла firstPage()/nextPage()Добавить вызов после рисования.
Картинка через строку — сжатая или растянутаяВысота 32 вместо 64 или наоборотИсправить число в конструкторе.
Сдвиг на два столбца и мусор у краяКонтроллер SH1106, код для SSD1306Сменить конструктор на SH1106.
Русские буквы — мусор (Adafruit) или пусто (U8g2)Шрифт без кириллицыU8g2: шрифт _t_cyrillic + enableUTF8Print(); или GyverOLED.
Сканер пишет No devicesЭкран не виден на шинеПровода SDA/SCL местами, VCC и GND местами (порядок выводов на модулях разный), нет земли.

OLED в Trema IDE

Мы делаем русскую среду для школ и кружков; OLED — одна из деталей, с которыми в ней знакомятся с окном «Нужна библиотека».

  • Библиотека ставится из окна ошибки. Напишите #include <Adafruit_SSD1306.h> или <U8g2lib.h>, нажмите «Проверить» — и программа предложит нужную библиотеку из нашего каталога, а зависимости Adafruit доставит сама. Каталог — российский сервер libraries.trema.ru; U8g2 со всеми её 14 МБ качается оттуда же.
  • Сканер адресов — в примерах, раздел «Полезное», скетч I2C_Scanner с русскими комментариями.
  • Ошибки объясняются по-русски. «Не хватает библиотеки: Adafruit_SSD1306.h» — карточка с кнопкой. Честно о том, чего нет: «SSD1306 allocation failed» — это сообщение из монитора порта во время работы, а не из компилятора, и карточки на него нет; подсказать, что 1 024 байта буфера не видны в отчёте сборки, программа пока тоже не умеет. Мы это знаем и думаем, как показать.

Живой дисплей к этой статье мы не подключали: все числа — из сборок, все ловушки — из исходников библиотек. Если у вас получается иначе — напишите, проверим.

Вопросы

Частые вопросы про OLED

Остались вопросы? Напишите нам

Как подключить OLED 0.96 дюйма к Arduino?

У модуля четыре вывода: GND к GND, VCC к 5V (или 3.3V — на модуле стоит свой стабилизатор), SDA к A4, SCL к A5 на Uno и Nano. На Mega это выводы 20 и 21, на NodeMCU — D2 и D1. Внимание: у некоторых модулей порядок выводов VCC–GND, а не GND–VCC, — читайте подписи, а не положение.

Какой адрес у OLED SSD1306 — 0x3C или 0x3D?

У почти всех модулей 0.96 дюйма — 0x3C. Адрес 0x3D получается только после перепайки резистора на обратной стороне. Фирменный пример Adafruit для 128×64 задаёт 0x3D, и из-за этого после его загрузки экран остаётся чёрным — замените строку SCREEN_ADDRESS на 0x3C.

Какую библиотеку выбрать для OLED SSD1306: Adafruit, U8g2 или GyverOLED?

Adafruit SSD1306 с Adafruit GFX — самая распространённая, по ней больше всего примеров, но она тяжёлая для Uno: 14 КБ флеша и почти 1,6 КБ из 2 КБ оперативной памяти с учётом буфера. U8g2 — самая богатая шрифтами, включая 22 кириллических, и умеет постраничный режим, который берёт всего 676 байт ОЗУ. GyverOLED — самая лёгкая по флешу (5,5 КБ) и с русскими буквами из коробки. Все три есть в каталоге Trema IDE.

Почему в мониторе порта написано SSD1306 allocation failed?

Это не про провода и не про адрес: библиотека Adafruit не смогла выделить 1 024 байта под буфер кадра в оперативной памяти. Компилятор этот буфер не показывает — отчёт может говорить 59 % занято, а при запуске места уже не хватит: буфер влезает, когда свободно не меньше примерно 1 200 байт. Освободите ОЗУ: вынесите строки во флеш через F(), уменьшите массивы или перейдите на U8g2 в постраничном режиме.

Почему OLED не показывает ничего, хотя скетч загрузился?

По порядку: адрес (0x3C, а не 0x3D), провода SDA и SCL не перепутаны, питание есть. Запустите сканер I2C — если он пишет No devices, дело в проводах; если находит 0x3C, а экран чёрный, — в адресе в скетче. У Adafruit функция begin() ответ дисплея не проверяет и вернёт успех даже при неверном адресе.

Как вывести русский текст на OLED?

В U8g2 выберите шрифт с суффиксом _t_cyrillic (например u8g2_font_10x20_t_cyrillic), включите enableUTF8Print() и печатайте через print() — мы собрали такой скетч, 15 764 байта флеша. В GyverOLED русские буквы работают сразу, в том числе ё. В Adafruit GFX встроенный шрифт кириллицу не содержит.

В чём разница между SSD1306 и SH1106?

Это два разных контроллера, которые ставят в одинаковые корпуса. SH1106 обычно стоит в экранах 1,3 дюйма, SSD1306 — в 0,96. Если на SH1106 запустить код для SSD1306, картинка будет сдвинута и с мусором по краям. У U8g2 и GyverOLED есть отдельные конструкторы для SH1106, у Adafruit — отдельная библиотека Adafruit SH110X.

Почему экран 128×64 показывает только половину или через строку?

В конструкторе указана высота 32 вместо 64 или наоборот: в обоих случаях картинка идёт через строку — сжатая вдвое или растянутая на весь экран с пропусками. Проверьте высоту в конструкторе Adafruit и имя класса U8g2.

Подключите OLED в Trema IDE

Библиотека ставится из окна ошибки вместе с зависимостями, сканер адресов в примерах, ошибки объясняются по-русски. Дома бесплатно: через неделю попросит бесплатную регистрацию по почте — и всё. Дальше по теме: LCD 1602 по I2C, память Arduino, как ставить библиотеки.