Подключение графического OLED дисплея к ESP32
Хотите добавить стильную графику в свои проекты на ESP32 или отображать IP-адрес устройства без открытия Serial Monitor? Тогда пришло время зажечь OLED-экран. Эти маленькие дисплеи невероятно лёгкие, очень тонкие и создают более чёткие и яркие изображения, которые буквально выпрыгивают с экрана.
В этом практическом руководстве мы расскажем вам, как подключить OLED дисплей к ESP32. Вы узнаете, как отображать текст, рисовать простые фигуры и даже показывать собственные изображения. А чтобы было ещё интереснее, мы добавили инструмент для конвертации любого изображения в код, готовый для отображения!
Давайте приступим и оживим ваши проекты — пиксель за пикселем!
Обзор OLED дисплейного модуля
OLED дисплеи доступны в широком ассортименте, предоставляя вам множество вариантов в зависимости от потребностей вашего проекта. Они доступны в различных размерах, таких как 128×64 пикселей или 128×32 пикселя, и вы можете выбрать из множества цветов: белый, синий или даже интересные двухцветные версии. Эти дисплеи также поддерживают различные способы связи с вашим ESP32 — одни используют I2C, другие — SPI.
В этом руководстве мы будем работать с 0.96-дюймовым I2C OLED дисплеем 128×64. Но если ваш дисплей имеет другой размер или цвет, не беспокойтесь. Основные принципы, которые мы рассмотрим, по-прежнему применимы, и шаги по его настройке будут очень похожими.
Независимо от того, какой размер, цвет или способ связи вы выберете, все эти OLED дисплеи работают на одной и той же маленькой, но мощной микросхеме — драйвере OLED SSD1306. Эта микросхема выступает в роли «мозга» дисплея. Она отвечает за рисование всего, что вы видите на экране, сохраняя данные изображения в собственной памяти (буферизация RAM). Благодаря такому продуманному дизайну вашему микроконтроллеру не нужно постоянно обновлять экран — он может сосредоточиться на других задачах.
Питание
В отличие от традиционных LCD дисплеев, OLED дисплеям не нужна подсветка, потому что пиксели OLED сами излучают свет. Это обеспечивает OLED высокую контрастность, отличные углы обзора и по-настоящему глубокий чёрный цвет. Поскольку им не нужна подсветка, OLED дисплеи потребляют меньше энергии — в среднем около 20 мА, что делает их идеальными для проектов с батарейным питанием.
OLED дисплеи работают с напряжением от 3.3В до 5В. Это означает, что вы можете легко подключить свой OLED дисплей к микроконтроллеру с напряжением 3.3В или 5В без каких-либо проблем.
Карта памяти OLED
Чтобы управлять тем, что отображается на вашем OLED дисплее, нужно понимать, как организована память дисплея.
Независимо от размера вашего OLED дисплея, драйвер SSD1306 внутри имеет 1 КБ (килобайт) памяти, известной как Graphic Display Data RAM (GDDRAM). Эта память хранит шаблон пикселей, который отображается на экране. Каждый бит в этой памяти управляет одним пикселем.
Вот как организован этот 1 КБ памяти:
Память разделена на 8 страниц (пронумерованных от 0 до 7)
Каждая страница содержит 128 столбцов (также называемых сегментами)
Каждый столбец содержит 8 вертикальных пикселей на экране
Итого математика выглядит так:
8 страниц × 128 столбцов × 8 бит = 8 192 бита = 1 024 байта = 1 КБ памяти
Весь 1 КБ памяти, включая страницы, сегменты и данные, показан ниже.
Примечание
Помните, что каждый OLED модуль содержит 1 КБ RAM, независимо от его размера. Модуль OLED 128×64 отображает всё содержимое этого 1 КБ RAM (все 8 страниц), тогда как модуль OLED 128×32 показывает только половину RAM (первые 4 страницы).
Распиновка
Прежде чем мы перейдём к подключению и примерам кода, давайте рассмотрим подробнее распиновку I2C OLED дисплейного модуля.
GND — вывод заземления.
VCC — вывод питания дисплея. Вы можете подключить его к выводу 3.3В или 5В на вашем микроконтроллере.
SCL — вывод тактового сигнала для интерфейса I2C.
SDA — вывод данных для интерфейса I2C.
Подключение OLED дисплейного модуля к ESP32
Давайте подключим OLED дисплей к ESP32.
Подключение простое. Сначала подключите вывод VCC дисплея к выходу 3.3В ESP32, а вывод GND — к земле.
Далее нам нужно подключить выводы, используемые для I2C связи. Подключите вывод SCL на дисплее к D22 на ESP32, а вывод SDA — к D21 на ESP32.
Вот краткая справочная таблица подключения выводов:
OLED дисплей |
ESP32 |
|---|---|
VCC |
3.3V |
GND |
GND |
SCL |
D22 |
SDA |
D21 |
Эта схема показывает, как именно всё подключить:
Установка библиотеки
Контроллер SSD1306, используемый в OLED дисплеях, очень гибкий, но может быть довольно сложным при прямом использовании. Чтобы правильно с ним работать, обычно необходимо хорошее понимание адресации памяти, что может быть непросто — особенно для начинающих.
К счастью, нам не нужно обо всём этом беспокоиться. Библиотека Adafruit SSD1306 была создана, чтобы значительно упростить задачу. Эта библиотека берёт на себя всю сложную работу за кулисами, так что вы можете управлять OLED дисплеем с помощью простых и понятных команд.
Чтобы установить библиотеку:
Сначала откройте программу Arduino IDE. Затем нажмите на иконку Library Manager на левой боковой панели.
Введите «adafruit ssd1306» в поле поиска для фильтрации результатов.
Найдите Adafruit SSD1306 Library от Adafruit.
Нажмите кнопку Install, чтобы добавить её в Arduino IDE.
Поскольку библиотека Adafruit SSD1306 зависит от других библиотек, вам будет предложено установить её зависимости, которые включают библиотеку Adafruit Bus IO и библиотеку Adafruit GFX.
Когда появится это сообщение, просто нажмите INSTALL ALL, чтобы убедиться, что всё настроено правильно.
Пример кода ESP32 1 — Отображение текста
Теперь начинается самое интересное — давайте начнём отображать крутые вещи на OLED-экране!
Скетч ниже показывает, как:
Отображать простой текст
Отображать инвертированный текст
Отображать числа
Отображать числа с указанием основания (Hex, Dec)
Отображать ASCII символы
Прокручивать текст горизонтально и вертикально
Прокручивать часть дисплея
Как только вы разберётесь в этом примере, вы будете на верном пути к созданию более креативных и продвинутых проектов с вашим OLED дисплеем.
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Declaration for SSD1306 display connected using I2C
#define OLED_RESET -1 // Reset pin
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
void setup() {
Serial.begin(9600);
// initialize the OLED object
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;)
; // Don't proceed, loop forever
}
// Clear the buffer.
display.clearDisplay();
// Display Text
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0, 28);
display.println("Hello world!");
display.display();
delay(2000);
display.clearDisplay();
// Display Inverted Text
display.setTextColor(BLACK, WHITE); // 'inverted' text
display.setCursor(0, 28);
display.println("Hello world!");
display.display();
delay(2000);
display.clearDisplay();
// Changing Font Size
display.setTextColor(WHITE);
display.setCursor(0, 24);
display.setTextSize(2);
display.println("Hello!");
display.display();
delay(2000);
display.clearDisplay();
// Display Numbers
display.setTextSize(1);
display.setCursor(0, 28);
display.println(123456789);
display.display();
delay(2000);
display.clearDisplay();
// Specifying Base For Numbers
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();
// Display ASCII Characters
display.setCursor(0, 24);
display.setTextSize(2);
display.write(3);
display.display();
delay(2000);
display.clearDisplay();
// Scroll full screen
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();
// Scroll part of the screen
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. Эти библиотеки позволяют ESP32 взаимодействовать с OLED дисплеем. Хотя мы используем I2C (для которого библиотека SPI не нужна), мы всё равно подключаем SPI.h, чтобы код компилировался без ошибок.
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
Далее мы определяем ширину и высоту экрана в пикселях. Большинство распространённых OLED дисплеев имеют ширину 128 пикселей и высоту 64 пикселя, поэтому мы устанавливаем SCREEN_WIDTH равным 128 и SCREEN_HEIGHT равным 64.
Затем мы создаём объект display с помощью библиотеки Adafruit_SSD1306. Мы указываем размер нашего экрана — 128 пикселей в ширину и 64 пикселя в высоту — и сообщаем, что используем I2C. Поскольку наш OLED модуль не имеет вывода сброса, мы передаём -1, чтобы показать, что мы его не используем.
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Declaration for SSD1306 display connected using I2C
#define OLED_RESET -1 // Reset pin
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Внутри функции setup() мы сначала инициализируем последовательную связь для вывода сообщений в Serial Monitor для отладки.
Затем мы вызываем display.begin() для начала связи с OLED дисплеем. Первый аргумент включает внутреннюю схему зарядки (charge pump), которая помогает питать экран, а второй аргумент задаёт I2C адрес (I2C адрес экрана обычно 0x3C, но некоторые дисплеи используют 0x3D, поэтому при необходимости его можно изменить). Если дисплей не запускается корректно, мы показываем сообщение об ошибке и останавливаем программу.
Serial.begin(9600);
// initialize the OLED object
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;)
; // Don't proceed, loop forever
}
Когда дисплей готов, мы очищаем экран с помощью display.clearDisplay(). Это гарантирует, что мы работаем с чистым экраном.
// Clear the buffer.
display.clearDisplay();
Отображение простого текста (Hello World)
// Display Text
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,28);
display.println("Hello world!");
display.display();
delay(2000);
Чтобы показать текст на OLED-экране, мы сначала задаём размер текста с помощью функции setTextSize(). Эта функция принимает число, где 1 — наименьший размер, а большие числа делают текст крупнее.
Далее мы выбираем цвет текста с помощью setTextColor(). Используйте WHITE для тёмного фона и BLACK для светлого фона. Поскольку наш OLED-экран имеет тёмный фон, мы используем WHITE, чтобы текст был хорошо виден.
Прежде чем что-то печатать, мы указываем дисплею, где начать запись, устанавливая позицию курсора с помощью setCursor(x, y). Значение x определяет, насколько далеко от левого края начинается текст, а y — насколько далеко от верхнего. Верхний левый угол — это позиция (0, 0).
Чтобы фактически отобразить сообщение на экране, мы используем функции print(" ") или println(" "). Они работают точно так же, как вывод в Serial Monitor. Помните, что println() переводит курсор на следующую строку после печати, тогда как print() оставляет его на той же строке.
Наконец, мы используем display() для обновления экрана и отображения всего, что мы подготовили в коде. Экран не обновляется, пока вы не вызовете эту функцию.
Отображение инвертированного текста
// Display Inverted Text
display.clearDisplay();
display.setTextColor(BLACK, WHITE); // 'inverted' text
display.setCursor(0,28);
display.println("Hello world!");
display.display();
delay(2000);
Если вы хотите отобразить текст с перевёрнутыми цветами (чёрный текст на белом фоне), вы можете сделать это, используя функцию setTextColor() снова, но на этот раз с двумя значениями. Когда мы используем setTextColor(BLACK, WHITE), мы указываем дисплею рисовать чёрные буквы на белом прямоугольнике. Причина, по которой мы теперь можем передать два значения, связана с так называемой «перегрузкой функций» — это просто означает, что одна и та же функция может вести себя по-разному в зависимости от того, сколько значений мы ей передаём.
Масштабирование размера шрифта
// Changing Font Size
display.clearDisplay();
display.setTextColor(WHITE);
display.setCursor(0,24);
display.setTextSize(2);
display.println("Hello!");
display.display();
delay(2000);
Ранее в скетче мы использовали функцию setTextSize() и передали число 1 для установки размера шрифта по умолчанию. Но вы не ограничены только этим — вы можете сделать текст крупнее, передав большее число.
Например, вызов setTextSize(2) сделает текст вдвое больше размера 1. Вы можете использовать любое целое число (например, 2, 3, 4…) в зависимости от того, насколько крупным вы хотите видеть текст.
Обратите внимание, что каждый символ на OLED-экране рисуется в прямоугольной области с соотношением сторон 7:10. Итак:
Размер шрифта 1 рисует каждый символ в 7×10 пикселей
Размер шрифта 2 рисует каждый символ в 14×20 пикселей
Размер шрифта 3 будет 21×30 пикселей, и так далее
Отображение чисел
// Display Numbers
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0,28);
display.println(123456789);
display.display();
delay(2000);
Так же, как и с текстом, вы можете использовать print() или println() для отображения чисел на экране. Эти функции принимают 32-битные беззнаковые целые значения, что означает, что вы можете отображать числа в диапазоне от 0 до 4 294 967 295.
Указание основания для чисел
// Specifying Base For Numbers
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);
Иногда вам может понадобиться показать число в другом формате, например, двоичном (основание 2), восьмеричном (основание 8), десятичном (основание 10) или шестнадцатеричном (основание 16). Функции print() и println() позволяют это сделать, добавив второй параметр, который указывает, какой формат использовать. Например, print(78, BIN) покажет 1001110, а print(78, HEX) покажет 4E.
Этот второй параметр также можно использовать для десятичных чисел, чтобы контролировать, сколько цифр появится после запятой. Например, print(1.23456, 2) покажет 1.23, а print(1.23456, 4) покажет 1.2346.
Отображение ASCII символов
// Display ASCII Characters
display.clearDisplay();
display.setCursor(0,24);
display.setTextSize(2);
display.write(3);
display.display();
delay(2000);
Вы также можете отображать специальные символы с помощью функции write(). Она работает немного иначе, чем print() — вместо обычного текста она отправляет число, представляющее ASCII символ, непосредственно на экран. Например, write(3) отобразит символ сердечка. Это забавный способ добавить иконки на ваш дисплей!
Прокрутка всего экрана
// Scroll full screen
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() или startscrollleft(), чтобы текст двигался в этом направлении. Вы также можете использовать startscrolldiagright() или startscrolldiagleft() для диагональной прокрутки.
Каждая из этих функций требует два параметра: начальную страницу и конечную страницу. Для получения дополнительной информации о страницах обратитесь к разделу Карта памяти OLED. Поскольку дисплей имеет восемь страниц, пронумерованных от 0 до 7, вы можете прокрутить весь экран, прокручивая все страницы. Для этого просто передайте параметры 0x00 (для начальной страницы) и 0x07 (для конечной страницы).
Когда вы хотите остановить прокрутку, просто используйте stopscroll().
Прокрутка определённой части
// Scroll part of the screen
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);
Иногда вам может не понадобиться прокручивать весь экран, а только его часть. Вы можете сделать это, указав правильные значения начальной и конечной страниц в функциях прокрутки. Например, если вы передадите 0x00 для обеих — начальной и конечной страницы, это прокрутит только первую страницу дисплея.
Пример кода ESP32 2 — Базовые рисунки
Этот пример скетча показывает, как рисовать простые фигуры, такие как прямоугольники, круги и треугольники, на OLED дисплее.
Загрузите скетч на ваш Arduino, чтобы увидеть, как он работает, прежде чем мы объясним его подробно.
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Declaration for SSD1306 display connected using I2C
#define OLED_RESET -1 // Reset pin
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
void setup() {
Serial.begin(9600);
// initialize the OLED object
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;)
; // Don't proceed, loop forever
}
// Clear the buffer.
display.clearDisplay();
// Draw Rectangle
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();
// Draw Filled Rectangle
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();
// Draw Round Rectangle
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();
// Draw Filled Round Rectangle
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();
// Draw Circle
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();
// Draw Filled Circle
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();
// Draw Triangle
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();
// Draw Filled Triangle
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(). Так же, как и drawRect(), вы указываете координаты X и Y, ширину и высоту, а также цвет. Но этой функции также нужен дополнительный параметр, который указывает, насколько скруглёнными должны быть углы (радиус скругления).
Опять же, если вы хотите залить скруглённый прямоугольник, используйте 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 центра круга, а также радиус и цвет. Эта функция рисует только контур круга.
Если вы хотите нарисовать сплошной круг, используйте 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(). Эта функция немного отличается, потому что нам нужно указать три точки — каждая точка состоит из координат X и Y. Эти три точки представляют вершины треугольника. Первая точка — верхняя вершина, а две другие — левая и правая вершины, в таком порядке. Эта функция рисует контур треугольника, соединяя три точки прямыми линиями. Вы также передаёте цвет, как и раньше.
Если вы хотите залитый треугольник, используйте fillTriangle() и укажите те же координаты и цвет.
Пример кода ESP32 3 — Отображение изображения
В этом заключительном примере мы научимся отображать изображение на OLED-экране. Это может быть очень полезно, когда вы хотите отобразить такие вещи, как логотипы, иконки, игровые спрайты или даже простую инфографику.
Чтобы отобразить изображение на OLED, вам сначала нужно преобразовать его в формат, понятный OLED — специальный байтовый массив. Этот массив состоит из чисел, представляющих каждый отдельный пиксель изображения.
Чтобы упростить задачу, мы разработали простой инструмент, который помогает превратить ваше изображение в массив, который может использовать OLED дисплей.
Конвертер изображений для OLED
1. Select image
2. Image Settings
3. Preview
4. Output
Как использовать конвертер?
Для начала загрузите изображение, которое вы хотите отобразить на OLED-экране.
Для этого примера мы выбрали фотографию Мэрилин Монро.
После загрузки изображения заполните поле Identifier именем, соответствующим вашему изображению. Это имя будет использоваться как заголовок массива в вашем итоговом коде Arduino.
Поскольку наше изображение — Мэрилин Монро, мы ввели «MarilynMonroe» в качестве идентификатора.
Прежде чем двигаться дальше, очень важно убедиться, что ваше изображение соответствует разрешению OLED-экрана 128×64 пикселей. Если ваше изображение больше, оно может неправильно отображаться на экране.
Вы увидите текущий размер вашего изображения в разделе «Image size» в настройках изображения. Чтобы изменить размер, введите 128 для ширины и 64 для высоты. Затем выберите подходящий вариант масштабирования для вашего изображения. Вы также можете центрировать изображение по вертикали или горизонтали и даже отразить его, если хотите. Все ваши изменения отобразятся мгновенно в разделе предварительного просмотра.
В нашем случае оригинальное изображение Мэрилин Монро имело размер 400×300 пикселей. Поэтому мы ввели 128 для ширины и 64 для высоты, выбрали «scale to fit» и центрировали изображение горизонтально, чтобы убедиться, что оно расположено красиво.
Одна из самых важных настроек — порог яркости. Эта настройка определяет, какие пиксели станут чёрными, а какие белыми. Любой пиксель ярче порога будет белым, а всё, что темнее — чёрным. Также есть настройка, которая позволяет инвертировать цвета изображения, что может быть полезно в зависимости от того, как вы хотите, чтобы оно выглядело на дисплее.
Для нашего изображения мы установили порог яркости на 171, чтобы захватить больше деталей и сделать изображение чётче.
При настройке этих параметров следите за разделом предварительного просмотра — он обновляется в реальном времени, чтобы вы могли видеть, как именно изображение будет выглядеть на OLED.
Когда вы будете довольны тем, как всё выглядит, просто нажмите кнопку Generate code.
Вот и всё! Ваше изображение будет преобразовано в готовый к использованию массив, который вы можете скопировать и вставить в ваш скетч Arduino.
Код Arduino
Чтобы отобразить ваше изображение на OLED-экране, вставьте сгенерированный байтовый массив в скетч Arduino ниже.
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Declaration for SSD1306 display connected using I2C
#define OLED_RESET -1 // Reset pin
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Bitmap of MarilynMonroe Image
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() {
Serial.begin(9600);
// initialize the OLED object
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;)
; // Don't proceed, loop forever
}
// Clear the buffer.
display.clearDisplay();
// Display bitmap
display.drawBitmap(0, 0, MarilynMonroe, 128, 64, WHITE);
display.display();
// Invert Display
//display.invertDisplay(1);
}
void loop() {
}
После загрузки этого скетча на Arduino ваше изображение появится на OLED-экране точно так же, как в предварительном просмотре инструмента конвертера.
Попробуйте и получайте удовольствие, экспериментируя со своими любимыми изображениями!
Объяснение кода
Этот скетч начинается так же, как и предыдущие примеры, где мы сначала настраиваем OLED дисплей. Мы подключаем необходимые библиотеки и инициализируем дисплей с помощью функции begin(). Как только настройка завершена, мы добавляем пользовательское изображение на экран.
Для этого мы сначала размещаем данные изображения — байтовый массив — в глобальной секции кода, выше функции setup(). Этот массив генерируется с помощью нашего инструмента конвертации изображений, который превращает картинку в формат, понятный OLED-экрану. В нашем примере массив называется MarilynMonroe.
Внутри функции setup(), после очистки дисплея, мы используем новую функцию drawBitmap() для рисования изображения на экране. Эта функция является ключом к отображению изображений и требует шести входных параметров.
Первые два значения — это координаты X и Y, которые определяют, где на экране начнётся изображение. В нашем случае мы установили оба в 0, что означает, что изображение начинается с верхнего левого угла дисплея. Третье значение — это имя массива изображения, который мы хотим нарисовать, в нашем примере это MarilynMonroe. Следующие два значения — ширина и высота изображения в пикселях. Наш OLED-экран имеет ширину 128 пикселей и высоту 64 пикселя, и наше изображение точно такого же размера, поэтому мы передаём 128 и 64. Последний параметр — цвет. Поскольку мы работаем с монохромным экраном, мы используем WHITE для отображения изображения белыми пикселями на тёмном фоне.
Итого полная строка выглядит так:
// Display bitmap
display.drawBitmap(0, 0, MarilynMonroe, 128, 64, WHITE);
Однако, хотя эта функция подготавливает изображение к показу, оно фактически не появится на экране, пока мы не вызовем display.display();. Эта строка отправляет всё, что мы подготовили в памяти, на реальный OLED-экран, чтобы это можно было увидеть.
display.display();
Поскольку изображение не нужно менять или повторять в этом примере, мы оставляем функцию loop() пустой.