Raspberry Pi Pico с I2C LCD-дисплеем (MicroPython)

В этом руководстве вы узнаете, как использовать I2C LCD-дисплей с Raspberry Pi Pico, программируя его на MicroPython. Мы покажем, как отображать статический текст, бегущую строку и пользовательские символы.

Raspberry Pi Pico - руководство по I2C LCD-дисплею MicroPython

Примечание

Данное руководство подготовлено для Raspberry Pi Pico. Оно также совместимо с Raspberry Pi Pico W.

Необходимые условия

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

Логотип MicroPython

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

В качестве альтернативы, если вам нравится программировать в VS Code, вы можете начать со следующего руководства:

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

Для выполнения примеров из этого руководства вам понадобятся следующие компоненты:

  • LCD-дисплей (с поддержкой I2C)

  • Raspberry Pi Pico или Raspberry Pi Pico W

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

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

Знакомство с LCD-дисплеем

Одним из самых простых и дешёвых экранов для отображения информации является жидкокристаллический дисплей (LCD). LCD-дисплеи можно встретить в повседневных электронных устройствах, таких как торговые автоматы, калькуляторы, паркоматы и принтеры, и они идеально подходят для отображения текста или небольших значков.

LCD-дисплей с I2C-интерфейсом

LCD-дисплеи характеризуются количеством строк и столбцов символов, которые помещаются на экране. LCD 16x2 может отображать 2 строки по 16 символов в каждой. Вы найдёте размеры от 8x1 до 40x4.

Один из самых простых способов управления LCD-дисплеем с помощью микроконтроллера – использование дисплея с I2C-интерфейсом. Мы будем использовать LCD 16x2 с I2C-связью.

Для выполнения этого руководства рекомендуется приобрести дисплей с поддержкой I2C. Что касается размера, вы можете выбрать любой удобный – он должен быть совместим.

LCD с I2C-драйвером

Преимущество использования I2C LCD заключается в том, что подключение очень простое. Вам нужно подключить только выводы SDA и SCL.

LCD-дисплей с I2C-драйвером

Кроме того, на плате имеется встроенный потенциометр для регулировки контрастности между фоном и символами на LCD. На «обычном» LCD без поддержки I2C вам пришлось бы добавлять потенциометр в схему для регулировки контрастности.

Подключение I2C LCD к Raspberry Pi Pico

Поскольку этот LCD-модуль поддерживает I2C-связь, подключение очень простое. Мы подключим выводы I2C к GPIO 5 и GPIO 4, но вы можете использовать любые другие выводы I2C, скорректировав код. Вывод VCC дисплея необходимо подключить к 5 В. Поэтому вы подключите его к выводу VBUS (5V).

LCD-дисплей

Raspberry Pi Pico

SCL

GPIO 5

SDA

GPIO 4

VCC

VBUS (5V)

GND

GND

Рекомендуем ознакомиться: Распиновка Raspberry Pi Pico и Pico W: назначение GPIO

Схема подключения

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

Подключение Raspberry Pi Pico к LCD-дисплею (I2C)

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

Большинство I2C LCD имеют адрес 0x27. Однако ваш может отличаться. Поэтому важно проверить I2C-адрес перед продолжением.

Для проверки I2C-адреса вашего дисплея воспользуйтесь следующим руководством:

Библиотеки для LCD – MicroPython

Существуют различные библиотеки, упрощающие взаимодействие с LCD-дисплеем. Мы будем использовать комбинацию двух различных модулей, разработанных и форкнутых этим пользователем GitHub.

Выполните следующие шаги для установки двух необходимых модулей.

Загрузка и установка lcd_api.py

  1. Нажмите здесь, чтобы скачать код lcd_api.py;

  2. Скопируйте код в файл в Thonny IDE;

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

  4. Сохраните файл с именем lcd_api.py (не меняйте имя).

# forked from https://github.com/T-622/RPI-PICO-I2C-LCD/
import time

class LcdApi:

    # Implements the API for talking with HD44780 compatible character LCDs.
    # This class only knows what commands to send to the LCD, and not how to get
    # them to the LCD.
    #
    # It is expected that a derived class will implement the hal_xxx functions.
    #
    # The following constant names were lifted from the avrlib lcd.h header file,
    # with bit numbers changed to bit masks.

    # HD44780 LCD controller command set
    LCD_CLR             = 0x01  # DB0: clear display
    LCD_HOME            = 0x02  # DB1: return to home position

    LCD_ENTRY_MODE      = 0x04  # DB2: set entry mode
    LCD_ENTRY_INC       = 0x02  # DB1: increment
    LCD_ENTRY_SHIFT     = 0x01  # DB0: shift

    LCD_ON_CTRL         = 0x08  # DB3: turn lcd/cursor on
    LCD_ON_DISPLAY      = 0x04  # DB2: turn display on
    LCD_ON_CURSOR       = 0x02  # DB1: turn cursor on
    LCD_ON_BLINK        = 0x01  # DB0: blinking cursor

    LCD_MOVE            = 0x10  # DB4: move cursor/display
    LCD_MOVE_DISP       = 0x08  # DB3: move display (0-> move cursor)
    LCD_MOVE_RIGHT      = 0x04  # DB2: move right (0-> left)

    LCD_FUNCTION        = 0x20  # DB5: function set
    LCD_FUNCTION_8BIT   = 0x10  # DB4: set 8BIT mode (0->4BIT mode)
    LCD_FUNCTION_2LINES = 0x08  # DB3: two lines (0->one line)
    LCD_FUNCTION_10DOTS = 0x04  # DB2: 5x10 font (0->5x7 font)
    LCD_FUNCTION_RESET  = 0x30  # See "Initializing by Instruction" section

    LCD_CGRAM           = 0x40  # DB6: set CG RAM address
    LCD_DDRAM           = 0x80  # DB7: set DD RAM address

    LCD_RS_CMD          = 0
    LCD_RS_DATA         = 1

    LCD_RW_WRITE        = 0
    LCD_RW_READ         = 1

    def __init__(self, num_lines, num_columns):
        self.num_lines = num_lines
        if self.num_lines > 4:
            self.num_lines = 4
        self.num_columns = num_columns
        if self.num_columns > 40:
            self.num_columns = 40
        self.cursor_x = 0
        self.cursor_y = 0
        self.implied_newline = False
        self.backlight = True
        self.display_off()
        self.backlight_on()
        self.clear()
        self.hal_write_command(self.LCD_ENTRY_MODE | self.LCD_ENTRY_INC)
        self.hide_cursor()
        self.display_on()

    def clear(self):
        # Clears the LCD display and moves the cursor to the top left corner
        self.hal_write_command(self.LCD_CLR)
        self.hal_write_command(self.LCD_HOME)
        self.cursor_x = 0
        self.cursor_y = 0

    def show_cursor(self):
        # Causes the cursor to be made visible
        self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY |
                               self.LCD_ON_CURSOR)

    def hide_cursor(self):
        # Causes the cursor to be hidden
        self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY)

    def blink_cursor_on(self):
        # Turns on the cursor, and makes it blink
        self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY |
                               self.LCD_ON_CURSOR | self.LCD_ON_BLINK)

    def blink_cursor_off(self):
        # Turns on the cursor, and makes it no blink (i.e. be solid)
        self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY |
                               self.LCD_ON_CURSOR)

    def display_on(self):
        # Turns on (i.e. unblanks) the LCD
        self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY)

    def display_off(self):
        # Turns off (i.e. blanks) the LCD
        self.hal_write_command(self.LCD_ON_CTRL)

    def backlight_on(self):
        # Turns the backlight on.

        # This isn't really an LCD command, but some modules have backlight
        # controls, so this allows the hal to pass through the command.
        self.backlight = True
        self.hal_backlight_on()

    def backlight_off(self):
        # Turns the backlight off.

        # This isn't really an LCD command, but some modules have backlight
        # controls, so this allows the hal to pass through the command.
        self.backlight = False
        self.hal_backlight_off()

    def move_to(self, cursor_x, cursor_y):
        # Moves the cursor position to the indicated position. The cursor
        # position is zero based (i.e. cursor_x == 0 indicates first column).
        self.cursor_x = cursor_x
        self.cursor_y = cursor_y
        addr = cursor_x & 0x3f
        if cursor_y & 1:
            addr += 0x40    # Lines 1 & 3 add 0x40
        if cursor_y & 2:    # Lines 2 & 3 add number of columns
            addr += self.num_columns
        self.hal_write_command(self.LCD_DDRAM | addr)

    def putchar(self, char):
        # Writes the indicated character to the LCD at the current cursor
        # position, and advances the cursor by one position.
        if char == '\n':
            if self.implied_newline:
                # self.implied_newline means we advanced due to a wraparound,
                # so if we get a newline right after that we ignore it.
                pass
            else:
                self.cursor_x = self.num_columns
        else:
            self.hal_write_data(ord(char))
            self.cursor_x += 1
        if self.cursor_x >= self.num_columns:
            self.cursor_x = 0
            self.cursor_y += 1
            self.implied_newline = (char != '\n')
        if self.cursor_y >= self.num_lines:
            self.cursor_y = 0
        self.move_to(self.cursor_x, self.cursor_y)

    def putstr(self, string):
        # Write the indicated string to the LCD at the current cursor
        # position and advances the cursor position appropriately.
        for char in string:
            self.putchar(char)

    def custom_char(self, location, charmap):
        # Write a character to one of the 8 CGRAM locations, available
        # as chr(0) through chr(7).
        location &= 0x7
        self.hal_write_command(self.LCD_CGRAM | (location << 3))
        self.hal_sleep_us(40)
        for i in range(8):
            self.hal_write_data(charmap[i])
            self.hal_sleep_us(40)
        self.move_to(self.cursor_x, self.cursor_y)

    def hal_backlight_on(self):
        # Allows the hal layer to turn the backlight on.
        # If desired, a derived HAL class will implement this function.
        pass

    def hal_backlight_off(self):
        # Allows the hal layer to turn the backlight off.
        # If desired, a derived HAL class will implement this function.
        pass

    def hal_write_command(self, cmd):
        # Write a command to the LCD.
        # It is expected that a derived HAL class will implement this function.
        raise NotImplementedError

    def hal_write_data(self, data):
        # Write data to the LCD.
        # It is expected that a derived HAL class will implement this function.
        raise NotImplementedError

    def hal_sleep_us(self, usecs):
        # Sleep for some time (given in microseconds)
        time.sleep_us(usecs)

Просмотреть исходный код

Загрузка и установка pico_i2c_lcd.py

  1. Нажмите здесь, чтобы скачать код pico_i2c_lcd.py;

  2. Скопируйте код в файл в Thonny IDE;

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

  4. Сохраните файл с именем pico_i2c_lcd.py (не меняйте имя).

# forked from https://github.com/T-622/RPI-PICO-I2C-LCD/
import utime
import gc

from lcd_api import LcdApi
from machine import I2C

# PCF8574 pin definitions
MASK_RS = 0x01       # P0
MASK_RW = 0x02       # P1
MASK_E  = 0x04       # P2

SHIFT_BACKLIGHT = 3  # P3
SHIFT_DATA      = 4  # P4-P7

class I2cLcd(LcdApi):

    #Implements a HD44780 character LCD connected via PCF8574 on I2C

    def __init__(self, i2c, i2c_addr, num_lines, num_columns):
        self.i2c = i2c
        self.i2c_addr = i2c_addr
        self.i2c.writeto(self.i2c_addr, bytes([0]))
        utime.sleep_ms(20)   # Allow LCD time to powerup
        # Send reset 3 times
        self.hal_write_init_nibble(self.LCD_FUNCTION_RESET)
        utime.sleep_ms(5)    # Need to delay at least 4.1 msec
        self.hal_write_init_nibble(self.LCD_FUNCTION_RESET)
        utime.sleep_ms(1)
        self.hal_write_init_nibble(self.LCD_FUNCTION_RESET)
        utime.sleep_ms(1)
        # Put LCD into 4-bit mode
        self.hal_write_init_nibble(self.LCD_FUNCTION)
        utime.sleep_ms(1)
        LcdApi.__init__(self, num_lines, num_columns)
        cmd = self.LCD_FUNCTION
        if num_lines > 1:
            cmd |= self.LCD_FUNCTION_2LINES
        self.hal_write_command(cmd)
        gc.collect()

    def hal_write_init_nibble(self, nibble):
        # Writes an initialization nibble to the LCD.
        # This particular function is only used during initialization.
        byte = ((nibble >> 4) & 0x0f) << SHIFT_DATA
        self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E]))
        self.i2c.writeto(self.i2c_addr, bytes([byte]))
        gc.collect()

    def hal_backlight_on(self):
        # Allows the hal layer to turn the backlight on
        self.i2c.writeto(self.i2c_addr, bytes([1 << SHIFT_BACKLIGHT]))
        gc.collect()

    def hal_backlight_off(self):
        #Allows the hal layer to turn the backlight off
        self.i2c.writeto(self.i2c_addr, bytes([0]))
        gc.collect()

    def hal_write_command(self, cmd):
        # Write a command to the LCD. Data is latched on the falling edge of E.
        byte = ((self.backlight << SHIFT_BACKLIGHT) |
                (((cmd >> 4) & 0x0f) << SHIFT_DATA))
        self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E]))
        self.i2c.writeto(self.i2c_addr, bytes([byte]))
        byte = ((self.backlight << SHIFT_BACKLIGHT) |
                ((cmd & 0x0f) << SHIFT_DATA))
        self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E]))
        self.i2c.writeto(self.i2c_addr, bytes([byte]))
        if cmd <= 3:
            # The home and clear commands require a worst case delay of 4.1 msec
            utime.sleep_ms(5)
        gc.collect()

    def hal_write_data(self, data):
        # Write data to the LCD. Data is latched on the falling edge of E.
        byte = (MASK_RS |
                (self.backlight << SHIFT_BACKLIGHT) |
                (((data >> 4) & 0x0f) << SHIFT_DATA))
        self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E]))
        self.i2c.writeto(self.i2c_addr, bytes([byte]))
        byte = (MASK_RS |
                (self.backlight << SHIFT_BACKLIGHT) |
                ((data & 0x0f) << SHIFT_DATA))
        self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E]))
        self.i2c.writeto(self.i2c_addr, bytes([byte]))
        gc.collect()

Просмотреть исходный код

После загрузки модулей на Raspberry Pi Pico вы можете использовать функции библиотеки в своём коде для вывода текста на LCD.

Отображение статического текста – код

Отображение статического текста на LCD-дисплее очень просто. Всё, что нужно сделать – выбрать, где на экране будут отображаться символы, и затем отправить сообщение на дисплей. Если вы не укажете место для отображения текста, он будет записан в первое доступное место.

Этот простой пример выводит сообщение «Hello, World!» сначала в первой строке, а затем во второй строке.

# Rui Santos & Sara Santos - Random Nerd Tutorials
# Complete project details at https://RandomNerdTutorials.com/raspberry-pi-pico-i2c-lcd-display-micropython/

from machine import Pin, SoftI2C
from pico_i2c_lcd import I2cLcd
from time import sleep

# Define the LCD I2C address and dimensions
I2C_ADDR = 0x27
I2C_NUM_ROWS = 2
I2C_NUM_COLS = 16

# Initialize I2C and LCD objects
i2c = SoftI2C(sda=Pin(4), scl=Pin(5), freq=400000)
lcd = I2cLcd(i2c, I2C_ADDR, I2C_NUM_ROWS, I2C_NUM_COLS)

lcd.putstr("It's working :)")
sleep(4)

try:
    while True:
        # Clear the LCD
        lcd.clear()
        # Display two different messages on different lines
        # By default, it will start at (0,0) if the display is empty
        lcd.putstr("Hello World!")
        sleep(2)
        lcd.clear()
        # Starting at the second line (0, 1)
        lcd.move_to(0, 1)
        lcd.putstr("Hello World!")
        sleep(2)

except KeyboardInterrupt:
    # Turn off the display
    print("Keyboard interrupt")
    lcd.backlight_off()
    lcd.display_off()

Просмотреть исходный код

Как работает код

Давайте кратко рассмотрим, как работает код, чтобы понять, как взаимодействовать с LCD.

Подключение библиотек

Начнём с подключения всех необходимых модулей для связи с LCD. Мы будем использовать программный I2C.

from machine import Pin, SoftI2C
from pico_i2c_lcd import I2cLcd
from time import sleep

Параметры LCD

В следующих строках определите параметры вашего LCD. Наш LCD-дисплей – это LCD 2x16 (2 строки и 16 столбцов), а I2C-адрес – 0x27. Если ваш дисплей имеет другие размеры или другой адрес, измените следующие строки.

# Define the LCD I2C address and dimensions
I2C_ADDR = 0x27
I2C_NUM_ROWS = 2
I2C_NUM_COLS = 16

I2C-связь

Затем мы инициализируем I2C на GPIO 4 и 5 – выводах, которые мы используем для подключения LCD.

i2c = SoftI2C(sda=Pin(4), scl=Pin(5), freq=400000)

После создания экземпляра I2C мы можем инициализировать связь I2C с LCD следующей строкой.

lcd = I2cLcd(i2c, I2C_ADDR, I2C_NUM_ROWS, I2C_NUM_COLS)

Мы создаём новый объект lcd с помощью метода I2cLcd() и передаём в качестве аргументов экземпляр i2c, адрес, а также количество строк и столбцов. Теперь мы можем использовать lcd для обращения к LCD-экрану.

Вывод текста

Теперь, когда связь установлена, мы можем начать выводить текст. Вывод простого текста так же прост, как использование метода putstr() на объекте lcd и передача в качестве аргумента текста, который мы хотим отобразить. Например:

lcd.putstr("It's working :)")

Эта команда выведет сообщение «It’s working :)». Поскольку мы не указали место, а LCD-экран ещё пуст, сообщение будет отображено в позиции (0, 0) – первая строка, первый столбец.

Далее у нас есть цикл while, который непрерывно отображает «Hello World!» на LCD, чередуя верхнюю и нижнюю строки, создавая простой и повторяющийся шаблон отображения.

while True:
    # Clear the LCD
    lcd.clear()
    # Display two different messages on different lines
    # By default, it will start at (0,0) if the display is empty
    lcd.putstr("Hello World!")
    sleep(2)
    lcd.clear()
    # Starting at the second line (0, 1)
    lcd.move_to(0, 1)
    lcd.putstr("Hello World!")
    sleep(2)

Очистка экрана

Перед выводом новой информации мы очищаем содержимое экрана с помощью метода clear().

lcd.clear()

Затем мы выводим строку «Hello World!» на LCD. По умолчанию вывод начинается с верхнего левого угла дисплея (позиция 0, 0).

lcd.putstr("Hello World!")

Это сообщение будет на экране в течение двух секунд.

sleep(2)

После этого мы снова очищаем экран.

lcd.clear()

Перемещение курсора

Далее мы используем метод move_to(), который принимает в качестве аргументов номер строки и столбца, позволяя нам выбрать, где начать отображение текста. В данном случае мы устанавливаем позицию курсора в начало второй строки (строка 1, столбец 0) LCD. Это позволяет нам вывести второе сообщение «Hello World!» на второй строке.

Выключение подсветки

Мы также добавляем фрагмент кода для выключения подсветки LCD в случае, если программа остановлена прерыванием с клавиатуры. Вы можете использовать методы backlight_off() и display_off().

except KeyboardInterrupt:
    # Turn off the display
    print("Keyboard interrupt")
    lcd.backlight_off()
    lcd.display_off()

Этот простой пример демонстрирует наиболее полезные методы для взаимодействия с LCD. Мы рекомендуем ознакомиться с модулями pico_i2c_lcd.py и lcd_api.py, а также проверить и протестировать другие методы, которые могут быть вам полезны.

Тестирование кода

Запустите приведённый выше код на плате Raspberry Pi Pico. Сначала вы увидите сообщение о том, что всё работает.

Тестирование LCD на Raspberry Pi Pico

Затем дисплей будет отображать сообщение Hello, World! в первой строке в течение двух секунд, а затем во второй строке ещё две секунды. После этого цикл повторяется, пока вы не остановите программу.

LCD Raspberry Pi Pico Hello World - строка 1 LCD Raspberry Pi Pico Hello World - строка 2

Устранение неполадок

Если LCD имеет очень низкую контрастность и вы едва видите символы, поверните потенциометр на задней стороне для регулировки контрастности между символами и подсветкой.

Кроме того, убедитесь, что вы питаете LCD от 5 В через вывод VBUS. Питание от 3,3 В недостаточно для большинства этих модулей (если в даташите не указано иное).

Отображение бегущей строки

Бегущая строка на LCD полезна для отображения сообщений, длина которых превышает ширину вашего LCD (в нашем случае – длиннее 16 символов).

Используемая нами библиотека не содержит специальной функции для прокрутки текста, но вы можете создать собственную функцию, сдвигая текст влево на одну позицию за раз. Смотрите пример ниже.

# Rui Santos & Sara Santos - Random Nerd Tutorials
# Complete project details at https://RandomNerdTutorials.com/raspberry-pi-pico-i2c-lcd-display-micropython/

from machine import Pin, SoftI2C
from pico_i2c_lcd import I2cLcd
from time import sleep

# Define the LCD I2C address and dimensions
I2C_ADDR = 0x27
I2C_NUM_ROWS = 2
I2C_NUM_COLS = 16

# Initialize I2C and LCD objects
i2c = SoftI2C(sda=Pin(4), scl=Pin(5), freq=400000)
lcd = I2cLcd(i2c, I2C_ADDR, I2C_NUM_ROWS, I2C_NUM_COLS)

def scroll_message(message, delay=0.3):
    # Add spaces to the beginning of the message to make it appear from the right
    message = " " * I2C_NUM_COLS + message + " "
    # Scroll through the message
    for i in range(len(message) - I2C_NUM_COLS + 1):
        lcd.move_to(0, 0)
        lcd.putstr(message[i:i + I2C_NUM_COLS])
        sleep(delay)

try:
    lcd.putstr("Testing scroll!")
    sleep(2)

    # Define the message to be scrolled
    message_scroll = "This is a scrolling message with more than 16 characters"

    while True:
        # Scroll the message on the LCD
        lcd.clear()
        scroll_message(message_scroll)

except KeyboardInterrupt:
    # Turn off the display when the code is interrupted by the user
    print("Keyboard interrupt")
    lcd.backlight_off()
    lcd.display_off()

Просмотреть исходный код

Как работает код

В этом примере мы создаём простую функцию scroll_message(), которая принимает в качестве аргументов сообщение для отображения и задержку между каждым сдвигом. По умолчанию мы устанавливаем задержку в 0,3 секунды, но вы можете изменить её в зависимости от того, насколько быстро вы хотите прокручивать текст.

def scroll_message(message, delay=0.3):
    # Add spaces to the beginning of the message to make it appear from the right
    message = " " * I2C_NUM_COLS + message + " "
    # Scroll through the message
    for i in range(len(message) - I2C_NUM_COLS + 1):
        lcd.move_to(0, 0)
        lcd.putstr(message[i:i + I2C_NUM_COLS])
        sleep(delay)

В этой функции мы начинаем с добавления отступа к нашему сообщению, который состоит из такого количества пробелов, сколько столбцов (I2C_NUM_COLS), и одного пробела в конце. Мы делаем это, чтобы создать пространство, от которого начнётся прокрутка.

message = " " * I2C_NUM_COLS + message + " "

Затем у нас есть цикл for, который перебирает символы нашего сообщения. Мы устанавливаем позицию курсора в верхний левый угол LCD (столбец 0, строка 0), чтобы каждая итерация начиналась с начала LCD.

lcd.move_to(0, 0)

Затем мы отображаем часть сообщения на LCD, начиная с текущего индекса итерации i и покрывая ширину LCD (I2C_NUM_COLS символов).

lcd.putstr(message[i:i + I2C_NUM_COLS])

Выражение message[i:i + I2C_NUM_COLS] получает только часть сообщения, начиная с символа с индексом i и заканчивая символом i + I2C_NUM_COLS. По мере увеличения значения i мы выбираем новую часть сообщения, создавая эффект прокрутки.

Наконец, задержка в конце определяет скорость прокрутки.

sleep(delay)

Для прокрутки текста вызовите функцию scroll_message() и передайте в качестве аргументов сообщение, которое вы хотите прокрутить, и время задержки.

scroll_message(message_scroll, 0.4)

Тестирование кода

Запустите приведённый выше код на Raspberry Pi Pico. Вы должны увидеть бегущую строку. Вы можете настроить скорость прокрутки с помощью переменной задержки в функции scroll_message().

Raspberry Pi Pico LCD бегущая строка 1 Raspberry Pi Pico LCD бегущая строка 2 Raspberry Pi Pico LCD бегущая строка 3 Raspberry Pi Pico LCD бегущая строка 4

Отображение пользовательских символов

В LCD 16x2 есть 32 блока, в которых можно отображать символы. Каждый блок состоит из пикселей размером 5x8. Вы можете отображать пользовательские символы, определяя состояние каждого крошечного пикселя. Для этого можно создать переменную с байтовым массивом, хранящую состояние каждого пикселя.

Создание пользовательских символов

Большинство LCD позволяют загрузить около 8 пользовательских символов в память LCD, которые можно использовать позже. Затем вы можете обращаться к символам по их индексу (от 0 до 7).

Чтобы создать пользовательский символ, перейдите на эту страницу и нарисуйте свой символ. Затем сгенерируйте переменную с байтовым массивом для вашего символа. Например, сердце:

Создание байтового массива значков для LCD

Байтовый массив выделен жёлтым цветом. Скопируйте байтовый массив в одну строку. Например, для символа сердца:

0x00, 0x0A, 0x1F, 0x0E, 0x04, 0x00, 0x00

Сохраните ваш байтовый массив, так как он понадобится позже в коде.

Отображение пользовательских символов – код

Следующий код отображает три пользовательских символа: термометр, зонтик и сердце. Вы можете отобразить любой символ, используя его байтовый массив.

# Rui Santos & Sara Santos - Random Nerd Tutorials
# Complete project details at https://RandomNerdTutorials.com/raspberry-pi-pico-i2c-lcd-display-micropython/

from machine import Pin, SoftI2C
from pico_i2c_lcd import I2cLcd
from time import sleep

# Define the LCD I2C address and dimensions
I2C_ADDR = 0x27
I2C_NUM_ROWS = 2
I2C_NUM_COLS = 16

# Initialize I2C and LCD objects
i2c = SoftI2C(sda=Pin(4), scl=Pin(5), freq=400000)
lcd = I2cLcd(i2c, I2C_ADDR, I2C_NUM_ROWS, I2C_NUM_COLS)

# Create custom characters here: https://maxpromer.github.io/LCD-Character-Creator/
thermometer = bytearray([0x04, 0x0A, 0x0A, 0x0A, 0x0A, 0x1B, 0x1F, 0x0E])
lcd.custom_char(0, thermometer)

umbrella = bytearray([0x00, 0x04, 0x0E, 0x1F, 0x04, 0x04, 0x014, 0x0C])
lcd.custom_char(1, umbrella)

heart = bytearray([0x00, 0x0A, 0x1F, 0x1F, 0x0E, 0x04, 0x00, 0x00])
lcd.custom_char(2, heart)

try:
    lcd.putstr("Characters")
    lcd.move_to(0, 1)
    # Display thermometer
    lcd.putchar(chr(0))
    # Display umbrella
    lcd.move_to(2, 1)
    lcd.putchar(chr(1))
    # Display heart
    lcd.move_to(4, 1)
    lcd.putchar(chr(2))

except KeyboardInterrupt:
    # Turn off the display when the code is interrupted by the user
    print("Keyboard interrupt")
    lcd.backlight_off()
    lcd.display_off()

Просмотреть исходный код

Как работает код

Сначала вам нужно сохранить ваш байтовый массив в переменную следующим образом:

thermometer = bytearray([0x04, 0x0A, 0x0A, 0x0A, 0x0A, 0x1B, 0x1F, 0x0E])

Замените байтовый массив на любой другой символ, который вы хотите отобразить. В нашем случае мы также отображаем зонтик и сердце.

Затем, чтобы сохранить ваш символ в памяти LCD, используйте функцию custom_char() на объекте lcd и передайте в качестве аргументов индекс, по которому вы хотите сохранить символ, и байтовый массив этого символа.

lcd.custom_char(0, thermometer)

Мы выполняем этот процесс для всех пользовательских символов, которые хотим отобразить, но каждый из них сохраняется по другому индексу custom_char().

thermometer = bytearray([0x04, 0x0A, 0x0A, 0x0A, 0x0A, 0x1B, 0x1F, 0x0E])
lcd.custom_char(0, thermometer)

umbrella = bytearray([0x00, 0x04, 0x0E, 0x1F, 0x04, 0x04, 0x014, 0x0C])
lcd.custom_char(1, umbrella)

heart = bytearray([0x00, 0x0A, 0x1F, 0x1F, 0x0E, 0x04, 0x00, 0x00])
lcd.custom_char(2, heart)

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

lcd.putchar(chr(0))

В нашем случае chr(0) соответствует термометру – символу, который мы сохранили по индексу 0. Аналогично поступаем со всеми остальными символами. В нашем случае мы отображаем статическое сообщение в первой строке, а затем выводим пользовательские символы во второй строке.

try:
    lcd.putstr("Characters")
    lcd.move_to(0, 1)
    # Display thermometer
    lcd.putchar(chr(0))
    # Display umbrella
    lcd.move_to(2, 1)
    lcd.putchar(chr(1))
    # Display heart
    lcd.move_to(4, 1)
    lcd.putchar(chr(2))

Как видите, отображение пользовательских символов достаточно просто.

Тестирование кода

Запустите код на Raspberry Pi Pico. LCD-дисплей отобразит ваши пользовательские символы. Не стесняйтесь модифицировать код и отображать собственные пользовательские символы. Вы также можете использовать несколько соседних блоков для создания более крупного значка на дисплее.

Raspberry Pi Pico с LCD - отображение пользовательских символов

Заключение

В этом руководстве вы узнали, как использовать I2C LCD с Raspberry Pi Pico. Мы рассмотрели, как отображать статический текст, бегущую строку и пользовательские символы.

У нас есть аналогичное руководство для OLED-дисплея, которое может быть вам полезно:

Теперь вы можете использовать LCD-дисплей для отображения полезных данных, таких как показания датчиков, время, данные из интернета и многое другое. У нас есть руководства для различных датчиков с Raspberry Pi Pico, которые могут быть вам полезны: