Raspberry Pi Pico: OLED-дисплей SSD1306 (MicroPython)

В этом руководстве показано, как использовать OLED-дисплей SSD1306 с Raspberry Pi Pico, запрограммированным с прошивкой MicroPython. Вы узнаете, как выводить текст и другие полезные функции для взаимодействия с OLED-дисплеем.

Raspberry Pi Pico: OLED-дисплей SSD1306 MicroPython

Предварительные требования – прошивка MicroPython

Для выполнения этого руководства вам необходимо, чтобы прошивка MicroPython была установлена на вашу плату Raspberry Pi Pico. Вам также нужна IDE для написания и загрузки кода на плату.

Рекомендуемая IDE для MicroPython на Raspberry Pi Pico – это Thonny IDE. Следуйте следующему руководству, чтобы узнать, как установить Thonny IDE, прошить прошивку MicroPython и загрузить код на плату.

Знакомство с OLED-дисплеем 0.96 дюйма

OLED-дисплей, который мы будем использовать в этом руководстве – это модель SSD1306: монохромный дисплей размером 0.96 дюйма с разрешением 128x64 пикселей, как показано на следующем рисунке.

OLED-дисплей 0.96 дюйма SSD1306

OLED-дисплей не требует подсветки, что обеспечивает очень хороший контраст в темных условиях. Кроме того, его пиксели потребляют энергию только когда они включены, поэтому OLED-дисплей потребляет меньше энергии по сравнению с другими дисплеями.

Модель, которую мы используем, имеет четыре контакта и взаимодействует с любым микроконтроллером по протоколу I2C. Существуют модели с дополнительным контактом RESET или использующие протокол SPI.

Необходимые компоненты

Вот список компонентов, которые вам понадобятся для этого проекта:

  • OLED-дисплей 0.96 дюйма

  • Raspberry Pi Pico

  • Макетная плата

  • Соединительные провода

Распиновка OLED-дисплея SSD1306

OLED-дисплей использует протокол связи I2C, поэтому подключение достаточно простое. Вы можете использовать следующую таблицу в качестве справки. Мы используем GPIO 4 (SDA) и GPIO 5 (SCL) в качестве контактов I2C, но вы можете использовать любую другую пару контактов I2C (убедитесь, что вы проверили схему распиновки Raspberry Pi Pico).

Контакт

Raspberry Pi Pico

Vin

3.3V (OUT)

GND

GND

SCL

GPIO 5

SDA

GPIO 4

Вы также можете использовать следующую схему подключения в качестве справки.

Схема подключения Raspberry Pi Pico с OLED-дисплеем

Библиотека SSD1306 OLED

Библиотека для записи на OLED-дисплей не входит в стандартную библиотеку MicroPython по умолчанию. Поэтому вам нужно загрузить библиотеку на вашу плату Raspberry Pi Pico.

# MicroPython SSD1306 OLED driver, I2C and SPI interfaces created by Adafruit

import time
import framebuf

# register definitions
SET_CONTRAST        = const(0x81)
SET_ENTIRE_ON       = const(0xa4)
SET_NORM_INV        = const(0xa6)
SET_DISP            = const(0xae)
SET_MEM_ADDR        = const(0x20)
SET_COL_ADDR        = const(0x21)
SET_PAGE_ADDR       = const(0x22)
SET_DISP_START_LINE = const(0x40)
SET_SEG_REMAP       = const(0xa0)
SET_MUX_RATIO       = const(0xa8)
SET_COM_OUT_DIR     = const(0xc0)
SET_DISP_OFFSET     = const(0xd3)
SET_COM_PIN_CFG     = const(0xda)
SET_DISP_CLK_DIV    = const(0xd5)
SET_PRECHARGE       = const(0xd9)
SET_VCOM_DESEL      = const(0xdb)
SET_CHARGE_PUMP     = const(0x8d)

class SSD1306:
    def __init__(self, width, height, external_vcc):
        self.width = width
        self.height = height
        self.external_vcc = external_vcc
        self.pages = self.height // 8
        # Note the subclass must initialize self.framebuf to a framebuffer.
        # This is necessary because the underlying data buffer is different
        # between I2C and SPI implementations (I2C needs an extra byte).
        self.poweron()
        self.init_display()

    def init_display(self):
        for cmd in (
            SET_DISP | 0x00, # off
            # address setting
            SET_MEM_ADDR, 0x00, # horizontal
            # resolution and layout
            SET_DISP_START_LINE | 0x00,
            SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0
            SET_MUX_RATIO, self.height - 1,
            SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0
            SET_DISP_OFFSET, 0x00,
            SET_COM_PIN_CFG, 0x02 if self.height == 32 else 0x12,
            # timing and driving scheme
            SET_DISP_CLK_DIV, 0x80,
            SET_PRECHARGE, 0x22 if self.external_vcc else 0xf1,
            SET_VCOM_DESEL, 0x30, # 0.83*Vcc
            # display
            SET_CONTRAST, 0xff, # maximum
            SET_ENTIRE_ON, # output follows RAM contents
            SET_NORM_INV, # not inverted
            # charge pump
            SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14,
            SET_DISP | 0x01): # on
            self.write_cmd(cmd)
        self.fill(0)
        self.show()

    def poweroff(self):
        self.write_cmd(SET_DISP | 0x00)

    def contrast(self, contrast):
        self.write_cmd(SET_CONTRAST)
        self.write_cmd(contrast)

    def invert(self, invert):
        self.write_cmd(SET_NORM_INV | (invert & 1))

    def show(self):
        x0 = 0
        x1 = self.width - 1
        if self.width == 64:
            # displays with width of 64 pixels are shifted by 32
            x0 += 32
            x1 += 32
        self.write_cmd(SET_COL_ADDR)
        self.write_cmd(x0)
        self.write_cmd(x1)
        self.write_cmd(SET_PAGE_ADDR)
        self.write_cmd(0)
        self.write_cmd(self.pages - 1)
        self.write_framebuf()

    def fill(self, col):
        self.framebuf.fill(col)

    def pixel(self, x, y, col):
        self.framebuf.pixel(x, y, col)

    def scroll(self, dx, dy):
        self.framebuf.scroll(dx, dy)

    def text(self, string, x, y, col=1):
        self.framebuf.text(string, x, y, col)

class SSD1306_I2C(SSD1306):
    def __init__(self, width, height, i2c, addr=0x3c, external_vcc=False):
        self.i2c = i2c
        self.addr = addr
        self.temp = bytearray(2)
        # Add an extra byte to the data buffer to hold an I2C data/command byte
        # to use hardware-compatible I2C transactions.  A memoryview of the
        # buffer is used to mask this byte from the framebuffer operations
        # (without a major memory hit as memoryview doesn't copy to a separate
        # buffer).
        self.buffer = bytearray(((height // 8) * width) + 1)
        self.buffer[0] = 0x40  # Set first byte of data buffer to Co=0, D/C=1
        self.framebuf = framebuf.FrameBuffer1(memoryview(self.buffer)[1:], width, height)
        super().__init__(width, height, external_vcc)

    def write_cmd(self, cmd):
        self.temp[0] = 0x80 # Co=1, D/C#=0
        self.temp[1] = cmd
        self.i2c.writeto(self.addr, self.temp)

    def write_framebuf(self):
        # Blast out the frame buffer using a single I2C transaction to support
        # hardware I2C interfaces.
        self.i2c.writeto(self.addr, self.buffer)

    def poweron(self):
        pass

class SSD1306_SPI(SSD1306):
    def __init__(self, width, height, spi, dc, res, cs, external_vcc=False):
        self.rate = 10 * 1024 * 1024
        dc.init(dc.OUT, value=0)
        res.init(res.OUT, value=0)
        cs.init(cs.OUT, value=1)
        self.spi = spi
        self.dc = dc
        self.res = res
        self.cs = cs
        self.buffer = bytearray((height // 8) * width)
        self.framebuf = framebuf.FrameBuffer1(self.buffer, width, height)
        super().__init__(width, height, external_vcc)

    def write_cmd(self, cmd):
        self.spi.init(baudrate=self.rate, polarity=0, phase=0)
        self.cs.high()
        self.dc.low()
        self.cs.low()
        self.spi.write(bytearray([cmd]))
        self.cs.high()

    def write_framebuf(self):
        self.spi.init(baudrate=self.rate, polarity=0, phase=0)
        self.cs.high()
        self.dc.high()
        self.cs.low()
        self.spi.write(self.buffer)
        self.cs.high()

    def poweron(self):
        self.res.high()
        time.sleep_ms(1)
        self.res.low()
        time.sleep_ms(10)
        self.res.high()

Следуйте следующим шагам, чтобы загрузить файл библиотеки на Raspberry Pi Pico.

1. Создайте новый файл в Thonny IDE и скопируйте код библиотеки. Код библиотеки OLED можно найти здесь.

Файл библиотеки SSD1306 MicroPython

2. Перейдите в File > Save as и выберите Raspberry Pi Pico.

Сохранение файлов на Raspberry Pi Pico в Thonny IDE

3. Назовите файл ssd1306.py и нажмите OK, чтобы сохранить файл на Raspberry Pi Pico.

Сохранение библиотеки ssd1306 OLED MicroPython

Вот и все. Библиотека была загружена на вашу плату. Теперь вы можете использовать функциональность библиотеки в вашем коде, импортировав библиотеку.

Определение I2C-адреса OLED

По умолчанию библиотека OLED, которую мы используем, предполагает, что I2C-адрес вашего OLED равен 0x3c. Для большинства I2C SSD1306-дисплеев это будет их адрес. Однако некоторые дисплеи могут иметь другой адрес, поэтому важно проверить I2C-адрес перед продолжением.

I2C-сканер – MicroPython

Откройте Thonny IDE или IDE по вашему выбору и скопируйте следующий код.

# I2C Scanner MicroPython
from machine import Pin, SoftI2C

# You can choose any other combination of I2C pins
i2c = SoftI2C(scl=Pin(5), sda=Pin(4))

print('I2C SCANNER')
devices = i2c.scan()

if len(devices) == 0:
  print("No i2c device !")
else:
  print('i2c devices found:', len(devices))

  for device in devices:
    print("I2C hexadecimal address: ", hex(device))

После копирования кода:

  • подключите Raspberry Pi Pico к компьютеру, если он еще не подключен;

  • убедитесь, что OLED-дисплей правильно подключен к вашей плате на правильных контактах I2C (SCL=GPIO5; SDA=GPIO4).

  • запустите предыдущий код (скетч I2C-сканера). Если вы используете Thonny IDE, вам просто нужно нажать зеленую кнопку запуска.

I2C-адрес вашего дисплея будет выведен в консоль. В моем случае это стандартный 0x3c. У вас он может быть другим.

Вывод текста – OLED-дисплей

Библиотека Adafruit для OLED-дисплея поставляется с несколькими функциями для вывода текста. В этом разделе вы узнаете, как выводить текст с помощью функций библиотеки.

Следующий скетч выводит сообщение Hello, World! три раза на OLED-дисплее.

from machine import Pin, SoftI2C
import ssd1306

#You can choose any other combination of I2C pins
i2c = SoftI2C(scl=Pin(5), sda=Pin(4))

oled_width = 128
oled_height = 64
oled = ssd1306.SSD1306_I2C(oled_width, oled_height, i2c)

oled.text('Hello, World 1!', 0, 0)
oled.text('Hello, World 2!', 0, 10)
oled.text('Hello, World 3!', 0, 20)

oled.show()

Давайте быстро рассмотрим, как работает код.

Начните с импорта необходимых модулей для взаимодействия с GPIO и отправки данных на OLED по I2C. Вам нужно импортировать классы Pin и SoftI2C из модуля machine.

from machine import Pin, SoftI2C

Вам также нужно импортировать библиотеку OLED, которую вы ранее загрузили на плату как файл ssd1306.py.

import ssd1306

Мы будем использовать GPIO 4 (SDA) и GPIO 5 (SCL) для связи с дисплеем по протоколу I2C, но вы можете использовать любые другие контакты I2C.

#You can choose any other combination of I2C pins
i2c = SoftI2C(scl=Pin(5), sda=Pin(4))

Определите ширину и высоту OLED в следующих переменных:

oled_width = 128
oled_height = 64

После этого создайте объект SSD1306_I2C с именем oled. Этот объект принимает ширину и высоту OLED, а также определенные ранее контакты I2C.

oled = ssd1306.SSD1306_I2C(oled_width, oled_height, i2c)

По умолчанию код предполагает, что ваш OLED-дисплей имеет стандартный I2C-адрес 0x3c. Если у вас другой I2C-адрес, измените предыдущую строку на:

oled = SSD1306_I2C(oled_width, oled_height, i2c, addr = YOUR_I2C_ADDRESS)

Например, если ваш I2C-адрес 0x3d, это будет выглядеть следующим образом:

oled = SSD1306_I2C(oled_width, oled_height, i2c, addr = 0x3d)

После инициализации OLED-дисплея вам просто нужно использовать функцию text() на объекте oled для записи текста. После функции text() вам нужно вызвать метод show() для обновления OLED.

oled.text('Hello, World 1!', 0, 0)
oled.text('Hello, World 2!', 0, 10)
oled.text('Hello, World 3!', 0, 20)
oled.show()

Метод text() принимает следующие аргументы (в таком порядке):

  • Сообщение: должно быть типа String

  • Позиция X: где начинается текст

  • Позиция Y: где текст отображается по вертикали

  • Цвет текста: может быть черным или белым. Цвет по умолчанию – белый, и этот параметр необязательный.

    • 0 = черный

    • 1 = белый

Например, следующая строка записывает сообщение „Hello, World 1!“ белым цветом. Текст начинается с x = 0 и y = 0.

oled.text('Hello, World 1!', 0, 0)

Следующая строка кода записывает текст на следующей строке (y = 10).

oled.text('Hello, World 2!', 0, 10)

Наконец, чтобы изменения вступили в силу, используйте метод show() на объекте oled.

oled.show()

Демонстрация

Сохраните код на вашу плату Raspberry Pi Pico, используя Thonny IDE или любую другую MicroPython IDE по вашему выбору.

Скопируйте предоставленный код в новый файл в Thonny IDE.

Код OLED MicroPython для Raspberry Pi Pico в Thonny IDE

Скопировав код в файл, нажмите на значок Сохранить. Затем выберите Raspberry Pi Pico.

Сохранение файла на Raspberry Pi Pico в MicroPython IDE

Сохраните файл с именем: main.py. Перезапишите все существующие файлы с таким же именем. Обратите внимание, что у вас также должен быть файл ssd1306.py, который вы сохранили ранее.

main.py в Thonny IDE с файлом ssd1306

Примечание

Когда вы называете файл main.py, Raspberry Pi Pico будет запускать этот файл автоматически при загрузке. Если вы назовете его по-другому, он все равно будет сохранен в файловой системе платы, но не будет запускаться автоматически при загрузке.

Перезагрузите плату (отключите и подключите ее к компьютеру). Нажмите маленькую зеленую кнопку «Run Current Script» или нажмите F5.

Запуск MicroPython-скрипта нажатием кнопки воспроизведения

На OLED-дисплее должны отображаться три сообщения «Hello World», которые мы написали в коде.

Raspberry Pi Pico Hello World на OLED-дисплее

Совет

Устранение неполадок: если вы получаете странные сообщения об ошибках и ваш OLED-дисплей не работает, попробуйте запитать его от 5V вместо 3V3. В этом случае подключите вывод VCC к контакту VBUS Raspberry Pi Pico.

Другие функции OLED

Библиотека предоставляет другие методы для взаимодействия с OLED-дисплеем.

Заливка экрана

Чтобы залить весь экран белым цветом, используйте функцию fill() следующим образом:

oled.fill(1)
oled.show()
OLED заливка белым экраном Raspberry Pi Pico MicroPython

Чтобы очистить экран, используйте метод fill() и передайте 0 в качестве аргумента. (Устанавливает все пиксели в черный цвет):

oled.fill(0)
oled.show()

Рисование пикселя

Чтобы нарисовать пиксель, используйте метод pixel(), за которым следует метод show(). Метод pixel() принимает следующие аргументы:

  • Координата X: расположение пикселя по горизонтали

  • Координата Y: расположение пикселя по вертикали

  • Цвет пикселя: может быть черным или белым

    • 0 = черный

    • 1 = белый

Например, чтобы нарисовать белый пиксель в верхнем левом углу:

oled.pixel(0, 0, 1)
oled.show()
Отображение пикселя на OLED-дисплее Raspberry Pi Pico MicroPython

Инверсия цветов

Вы также можете инвертировать цвета OLED: белый на черный и наоборот, используя метод invert():

oled.invert(True)
Инверсия цветов OLED Raspberry Pi Pico MicroPython

Чтобы вернуться к исходным цветам, используйте:

oled.invert(False)

Отображение данных с датчиков

Функция text() принимает только переменные типа String в качестве сообщения. Показания датчиков обычно хранятся в переменных типа int или float.

Если вы хотите отображать показания датчиков, и они хранятся в переменных int или float, их следует преобразовать в String. Для преобразования данных в строку вы можете использовать функцию str():

temperature = 12.34
temperature_string = str(temperature)

Затем вы можете отобразить переменную temperature_string на OLED, используя методы text() и show():

oled.text(temperature_string, 0, 0)
oled.show()

Заключение

В этом руководстве мы показали вам, как выводить текст на OLED-дисплее с Raspberry Pi Pico, запрограммированным с прошивкой MicroPython. Мы также показали вам другие полезные функции для управления OLED-дисплеем.