На этом уроке мы разберёмся с подключением OLED дисплея к микроконтроллеру из семейства STM32. Для эксперимента используем отладочную плату на STM32F030F4P6, хотя на месте этого МК может быть любой другой STM32.
Подключать будем достаточно распространённый дисплей OLED, с контроллером SSD1306 и разрешением 128 x 32 точки.
Соединяем эти два устройство шиной I2C. Хотя в данном примере мы использовали QIIC разъёмы (подробнее о QIIC), в действительности можно использовать любую другую плату и соединить их хоть пайкой. Главное соблюдать принцип подключения по шине I2C.
Оба использованных в данном уроке устройства можно приобрести у нас в магазине:
Настройка выводов
Создаём новый проект в STM32CubeIDE и выбираем подходящую модель микроконтроллера. В данном примере использовался STM32F030F4P6.
Затем, открываем экран Pinout & Configuration, далее раздел Connectivity. Выбираем там любой доступный I2C и в настройках параметр Mode устанавливаем в значение I2C.
Библиотека stm32-ssd1306
Чтобы не писать код управления дисплеем с нуля, используем готовую библиотеку, в которой реализовано общение с контроллером дисплея SSD1306. Ссылка на исходный код в конце статьи.
Создаём в корне проекта папку SSD1306. В эту папку добавляем две подпапки src и inc, приводя её вид к традиционному. В подпапки складываем соответствующие файлы библиотеки:
- в src исходники с расширением .c
- в inc заголовки с расширением .h
Должно получиться так:
Теперь настраиваем проект, чтобы он увидел библиотеку. Сначала открываем раздел C/C++ Build и далее подраздел Settings. Затем в иерархии настроек выбираем MCU GCC Compiler/Include paths и добавляем путь: ../SSD1306/Inc
Затем идём в раздел C/C++ General, подраздел Paths and Symbols. Здесь открываем сначала вкладку Includes и добавляем путь SSD1306/Inc.
Теперь идём на вкладку Source Location (где искать исходники) и добавляем путь к общей папке библиотеки относительно нашего workspace: /f103_stp_ctrl/SSD1306
Ну вот, теперь проект хотя бы будет успешно собираться.
Программа
Открываем в редакторе файл main.c. Подключаем библиотеку, добавив соответствующую директиву в начале программы:
/* USER CODE BEGIN Includes */
#include "ssd1306.h"
/* USER CODE END Includes */
И чуть ниже вставляем код для вывода текста на дисплей.
/* USER CODE BEGIN 2 */
ssd1306_Init();
ssd1306_Fill(Black);
ssd1306_SetCursor(5, 10);
ssd1306_WriteString("Hello world!", Font_11x18, White);
ssd1306_UpdateScreen();
/* USER CODE END 2 */
Готово. Загружаем программу на микроконтроллер и наблюдаем:
В рассматриваемой библиотеке есть все основные функции для создания графики. Описание этих функций можно подсмотреть в файле ssd1306.h. Вот некоторые из них:
ssd1306_Fill — заливка экрана одним цветом
ssd1306_DrawPixel — отрисовка точки
ssd1306_Line — отрисовка линии по алгоритму Брезенхэма
ssd1306_WriteString
ssd1306_Line — отрисовка лигии по алгоритму Брезенхэма
ssd1306_DrawCircle — окружность
ssd1306_DrawRectangle — прямоугольник
ssd1306_DrawBitmap — изображение
Собственно, остановимся на последней функции. Выведем на экран логотип RobotClass.
Вывод изображения на OLED
Для начала, как и в предыдущих примерах для работы с дисплеями (OLED 0.96, Nokia5110) мы подготовим изображение. Преобразуем его в массив.
Разрешение нашего дисплея — 128 x 32 точки. Следовательно, обрезаем и масштабируем картинку ровно под этот размер и сохраняем в формате BMP в режиме 256 цветов на точку. При этом сама картинка должна быть монохромной, без градаций серого.
Есть в вашем конкретном редакторе не получается сохранить файл в таком формате, можно открыть его в обычном Paint и сохранить там.
Затем, открываем наш инструмент для конвертирования картинок в массив:
https://tools.robotclass.ru/bmp2bin/bmp2bin.html
Загружаем файл, и жмём «Конвертировать». Настройки можно не трогать. Полученный массив вставляем в нашу программу:
/* USER CODE BEGIN PV */
const uint8_t logo [] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x04, 0xfc, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1f, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1f, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1f, 0x83, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1e, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0xf0, 0x3e, 0x00, 0xf0, 0xfc, 0x03, 0xf0, 0xff, 0x81, 0xc0, 0x00, 0x00, 0x0c, 0x07, 0x00,
0x03, 0xfc, 0xfc, 0x00, 0xfc, 0xfe, 0x0f, 0xf8, 0xff, 0x87, 0xf7, 0x00, 0x70, 0x3f, 0x1f, 0x80,
0x03, 0x9e, 0xfc, 0x00, 0xfc, 0xc7, 0x1e, 0x3c, 0x1c, 0x0f, 0xf7, 0x00, 0xf0, 0x7f, 0x3f, 0x80,
0x03, 0x8e, 0xfc, 0x00, 0x7c, 0xc7, 0x3c, 0x1e, 0x1c, 0x1c, 0x17, 0x00, 0xf8, 0x71, 0x38, 0x00,
0x03, 0x8e, 0xfc, 0x00, 0xfc, 0xc7, 0x38, 0x0e, 0x1c, 0x38, 0x07, 0x01, 0xf8, 0x70, 0x38, 0x00,
0x03, 0xfc, 0xfc, 0x00, 0xfc, 0xfe, 0x38, 0x0e, 0x1c, 0x38, 0x07, 0x01, 0xf8, 0x78, 0x3e, 0x00,
0x03, 0xf8, 0x3e, 0x00, 0xf0, 0xfe, 0x38, 0x0e, 0x1c, 0x38, 0x07, 0x01, 0xdc, 0x3e, 0x1f, 0x80,
0x03, 0xf0, 0x1f, 0x03, 0xe0, 0xff, 0x38, 0x0e, 0x1c, 0x38, 0x07, 0x03, 0xfc, 0x1f, 0x0f, 0xc0,
0x03, 0xf8, 0x1f, 0xc7, 0xf0, 0xc3, 0xb8, 0x0e, 0x1c, 0x38, 0x07, 0x03, 0xfe, 0x07, 0x81, 0xc0,
0x03, 0xb8, 0x3f, 0xff, 0xf0, 0xc3, 0xbc, 0x0e, 0x1c, 0x3c, 0x07, 0x07, 0xfe, 0x03, 0xa1, 0xc0,
0x03, 0x9c, 0x1f, 0xff, 0xe0, 0xc7, 0x9e, 0x1c, 0x1c, 0x1e, 0x37, 0x07, 0x0e, 0x63, 0xb1, 0xc0,
0x03, 0x8e, 0x0d, 0xff, 0xc0, 0xff, 0x0f, 0xfc, 0x1c, 0x0f, 0xf7, 0xf7, 0x07, 0x7f, 0x3f, 0xc0,
0x03, 0x8f, 0x00, 0x78, 0x00, 0xfe, 0x07, 0xf0, 0x1c, 0x07, 0xf7, 0xfe, 0x07, 0x7e, 0x3f, 0x80,
0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
/* USER CODE END PV */
Предыдущий код можно не удалять. Лучше оформим его в виде функции для последующего использования.
Для этого объявим две функции, старую для отрисовки текста и новую для изображения:
/* USER CODE BEGIN PFP */
void displayDrawBitmap();
void displayDrawText();
/* USER CODE END PFP */
А затем реализации для них:
/* USER CODE BEGIN 4 */
void displayDrawBitmap(){
ssd1306_Fill(Black);
ssd1306_DrawBitmap(0, 0, logo, 128, 32, White);
ssd1306_UpdateScreen();
}
void displayDrawText(){
ssd1306_Fill(Black);
ssd1306_SetCursor(5, 10);
ssd1306_WriteString("Hello world!", Font_11x18, White);
ssd1306_UpdateScreen();
}
/* USER CODE END 4 */
Теперь в суперцикле добавим вызовы этих функций через паузу в 3 секунды.
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
displayDrawText();
HAL_Delay(3000);
displayDrawBitmap();
HAL_Delay(3000);
}
/* USER CODE END 3 */
Готово. Загружаем на STM32 и смотрим.
Полезные ссылки
Исходный код библиотеки stm32-ssd1306 на github: