GIF анимация на ESP32-C3 с OLED дисплеем SSD1306

Сегодня у меня в руках очень маленький Wi‑Fi микроконтроллер с встроенным OLED‑дисплеем — ESP32‑C3 Super Mini OLED.
Он пришёл в прозрачной коробочке с голографической наклейкой. Такая упаковка защищает плату при доставке. А наклейка показывает, что коробочку не вскрывали.

Для понимания его размеров давайте сравним его с первой версии микроконтроллера ESP32-C3 Super mini. Как вы можете видеть на фото, размер платы контроллера увеличились совсем незначительно. По размеру эта версия почти такая же, как и первый ESP32C3 SuperMini.

Технические характеристики
| Микроконтроллер | ESP32‑C3 (RISC‑V, 32‑бит, 160 МГц) |
| Ядра | 1 ядро RISC‑V |
| Flash‑память | 4 MB SPI Flash |
| ОЗУ | 400 KB SRAM |
| Wi‑Fi | IEEE 802.11 b/g/n (2,4 ГГц) |
| Bluetooth | BLE 5.0 |
| Дисплей | OLED 0.42", 72×40 px, SSD1306 I²C |
| Интерфейсы | I²C, SPI, UART, I2S, PWM, GPIO, ADC |
| Питание | USB‑C, 5 В или 3,3 В |
| Потребление в режиме Wi-Fi | 80–160 мА |
| Режим глубокого сна | 5–10 мкА |
| Размеры платы | 20×25 мм |
| Вес | 5 г |
| Рабочая температура | −40…+85 °C |
С обратной стороны платы установлена сама микросхема контроллера ESP32‑C3. Это современный чип на архитектуре RISC‑V с одним ядром, частотой до 160 МГц.
Он умеет подключаться к Wi‑Fi в диапазоне 2,4 ГГц и работать с Bluetooth 5.0 BLE. Памяти внутри достаточно для большинства задач: 4 мегабайта флэш‑памяти для программ и 400 килобайт оперативной памяти.

Дисплей здесь маленький — 0.42 дюйма, монохромный. Разрешение 72×40 пикселей
Подключён он через интерфейс I²C, а линии шины подключены на выводы микроконтроллера GPIO6 (SCL) и GPIO5 (SDA).
Кнопку BOOT можно использовать в своем программном коде, это ни как не скажется на работе устройства, так как она ему нужна только при включении контроллера. Кнопка подключена на GPIO9. Системный светодиод синего цвета подключен к GPIO8.

Что изменилось
В этой версии платы разработчики перенесли кварцевый резонатор и сам чип подальше от антенны и заэкранировали внутренним медным слоем. Это уменьшило помехи, сделало плату более стабильной и увеличило дальность работы Wi‑Fi. На старые платы было много нареканий по этому поводу.
Кнопки BOOT и RESET вынесены на край платы, так что пользоваться ими стало проще и удобней.
Пример кода вывода текста с самым мелким шрифтом.
Нажмите, что бы посмотреть код
#include <u8g2lib.h>
#define x_Offset ((128-72)/2) //стартовая позиция экрана по оси X
#define y_Offset (64-40) //стартовая позиция экрана по оси X
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE, 6, 5); // инициализация
void setup(void)
{
u8g2.begin();
u8g2.setContrast(255); // Устанавливаем контрастность на максимум
u8g2.setBusClock(400000); // частота шины 400kHz I2C
}
void loop(void)
{
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_4x6_tr); // используем шрифт 4x6
u8g2.drawStr(x_Offset, y_Offset + 5, "Display is working");
u8g2.drawStr(x_Offset, y_Offset + 11, " duino.ru");
u8g2.drawStr(x_Offset, y_Offset + 18, " Channel CyberLab");
u8g2.drawStr(x_Offset, y_Offset + 25, " duino.ru/blog");
u8g2.drawStr(x_Offset, y_Offset + 32, " VK duino_ru");
u8g2.drawStr(x_Offset, y_Offset + 39, " Thank you");
u8g2.sendBuffer();
delay(1000);
}
Смотрим результат на фото

Онлайн конвертер ЧБ(BW) картинок
Для работы с чёрно‑белыми изображениями на этом дисплее я создал онлайн‑конвертер. Он преобразует любую картинку в формат XBM, совместимый с контроллером SSD1306. В конвертере предусмотрена галочка для инверсии — она позволяет сделать получаемый код изображения «негативом». Это важно, так как по умолчанию дисплей требует инвертированное изображение для правильного отображения.
Конвертер также учитывает особенность формата XBM, где младший бит в байте расположен слева. Основой нового конвертера стал мой ранее опубликованный конвертер для монохромных (BW) экранов, доработанный специально для работы с OLED на контроллере SSD1306.
Пример кода выводящего статические изображение.
Нажмите, что бы посмотреть код
#include <u8g2lib.h>
#define x_Offset (((128-72)/2)) //стартовая позиция экрана по оси X
#define y_Offset ((64-42)) //стартовая позиция экрана по оси Y
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE, 6, 5); // инициализация</u8g2lib.h>
// Для получения этого кода использовался онлайн конвертер https://duino.ru/media/image-converter/conv.html
const uint16_t logo_duino_widht PROGMEM = 72; // Размер по горизонтали в пикселях, а не в байтах
const uint16_t logo_duino_height PROGMEM = 42; // // Размер по вертикали
const uint8_t logo_duino[378] PROGMEM = {
0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b11111111, 0b11110011, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b11111111, 0b00000011, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b11111111, 0b00100011, 0b11111111, 0b10011111, 0b11111100, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b11111111, 0b00000011, 0b11111111, 0b10011111, 0b11111100, 0b11111111, 0b11111111, 0b11111111, 0b11110111,
0b11111111, 0b00000011, 0b11111111, 0b00011111, 0b11111100, 0b11111111, 0b11111111, 0b01101111, 0b10000101,
0b11111111, 0b00100011, 0b11111111, 0b01111111, 0b11111111, 0b01111111, 0b11111111, 0b00010111, 0b10000100,
0b11111111, 0b00000011, 0b11111111, 0b11111111, 0b10111111, 0b11111111, 0b11100000, 0b00000011, 0b10000100,
0b11111111, 0b00000011, 0b11111111, 0b10011111, 0b01000010, 0b11111000, 0b11000000, 0b00100011, 0b10000110,
0b01111111, 0b00000101, 0b11111111, 0b10001100, 0b00000000, 0b00001000, 0b11000010, 0b00100001, 0b11000100,
0b11111111, 0b00010001, 0b11101001, 0b00000000, 0b00000000, 0b01000000, 0b11000111, 0b00100011, 0b10000100,
0b01011111, 0b00000000, 0b11000001, 0b00010000, 0b11000000, 0b00000010, 0b11000111, 0b00100001, 0b11000110,
0b00110111, 0b00000000, 0b11101001, 0b00000000, 0b11000010, 0b00000000, 0b11000011, 0b00100011, 0b11010000,
0b00010011, 0b00000111, 0b11000001, 0b00010000, 0b11000000, 0b00000000, 0b01000011, 0b01100001, 0b11000000,
0b10000001, 0b00010111, 0b11100001, 0b00000000, 0b11000010, 0b00000000, 0b10001111, 0b01100000, 0b11100000,
0b10001001, 0b00000111, 0b11100001, 0b00010000, 0b11000000, 0b00000000, 0b00000000, 0b11100000, 0b11110001,
0b11000001, 0b00000111, 0b11000001, 0b00000000, 0b11000010, 0b00010000, 0b00100000, 0b11110010, 0b11111111,
0b11000001, 0b00000111, 0b11100001, 0b00010000, 0b11000000, 0b00111000, 0b11110000, 0b11111111, 0b11111111,
0b11000001, 0b00000111, 0b01100001, 0b00000001, 0b11000010, 0b01110000, 0b11111100, 0b11111111, 0b11111111,
0b11000001, 0b00000111, 0b00000001, 0b00010001, 0b11100000, 0b11111001, 0b11111111, 0b11111111, 0b11111111,
0b10000101, 0b00001011, 0b00000011, 0b00000000, 0b11110110, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b00000011, 0b00001000, 0b00000011, 0b11110000, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b00000011, 0b00000001, 0b10001111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b00001111, 0b00000000, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b00011111, 0b11111000, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111,
};
void setup(void)
{
u8g2.begin();
u8g2.setBusClock(400000); // Выбираем частоту шины 400kHz I2C
u8g2.setContrast(255); // Устанавливаем яркость на максимум
}
void loop(void)
{
u8g2.drawXBMP( x_Offset, y_Offset, logo_duino_widht, logo_duino_height, logo_duino);
u8g2.sendBuffer();
delay(10000);
}
Конвертируем изображение

Смотрим результат

GIF Анимация
Как преобразовать gif анимацию я описал в этой статье. По этому я не буду здесь дублировать эту информацию, а только выложу архив со скетчем
Пример кода с анимированным автомобилем.
Нажмите, что бы посмотреть код
#include <U8g2lib.h>
#include "car.h"
#define x_Offset (((128-72)/2)) //стартовая позиция экрана по оси X
#define y_Offset ((64-42)) //стартовая позиция экрана по оси Y
#define anim_delay 100 // длительность отображения кадра
//массивы указателей. В каждом массиве находятся указатели на все кадры анимации
static const uint8_t * car_animation[] = { c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17,c18,c19,c20,c21,c22,c23 };
static const uint8_t * car[] = { c23,c22,c21,c20,c19,c18,c17,c16,c15,c14,c13,c12,c11,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1 };
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE, 6, 5); // инициализация
void setup(void)
{
u8g2.begin();
u8g2.setBusClock(400000); // Вбираем частоту шины 400kHz I2C
u8g2.setContrast(255); // Устанавливаем яркость на максимум
u8g2.clearBuffer(); // очищаем буфер
u8g2.clearDisplay(); // очищаем дисплей
}
void loop(void)
{
animatoin_view(car_widht, car_height, anim_delay, 23, 2, car_animation);
animatoin_view(car_widht, car_height, anim_delay, 23, 2, car);
}
//anim_widht-размер по гориз., anim_widht-рахмер по верт., animdelay-длительность кадра, anim_frame-количетво кадров в массиве, anim_repeat-количество показов, anim_n-массив указателей
void animatoin_view(uint8_t anim_widht, uint8_t anim_height, uint16_t animdelay, uint8_t anim_frame, uint8_t anim_repeat, const uint8_t * const anim_n[] )
{
for( uint8_t j = 0; j<anim_repeat; j++)
{
for( uint8_t i = 0; i<anim_frame; i++)
{
u8g2.drawXBMP(x_Offset, y_Offset, anim_widht, anim_height, anim_n[i]); // загрузить указанный кадр анимации в дисплей
u8g2.sendBuffer(); // отобразить на экране дисплея
delay(animdelay); // задержка между кадрами
}
}
}
Сморим результат на видео

Выводы:
ESP32‑C3 Super Mini OLED — это очень компактный микроконтроллер, который сочетает в себе Wi‑Fi, Bluetooth и встроенный экран. Маленький размер позволяет использовать его в проектах, где нет лишнего места, а встроенный дисплей упрощает вывод данных без дополнительных подключений к ПК.
Благодаря поддержке популярных интерфейсов (I²C, SPI, UART, GPIO, ADC) можно подключать датчики, модули и управлять различными устройствами. Плата подходит как для новичков, так и для опытных разработчиков, а наличие онлайн‑конвертера для изображений облегчает работу с экраном.
Надеюсь мой опыт вам пригодится.
0 комментариев