Как использовать RGB Full-colour LED матрицу Waveshare для Raspberry Pi Pico — Часть 1

RGB Full-colour LED матрица Waveshare для Raspberry Pi Pico — Часть 1

Плата Waveshare RGB Full-colour LED Matrix для Raspberry Pi Pico содержит 160 RGB светодиодов, расположенных в 10 рядах по 16 штук. Каждому из 160 светодиодов можно задать любой из 16 777 216 цветов, указав значения красного, зелёного и синего компонентов в диапазоне от 0 до 255.

Плата яркая, красочная и очень просто подключается к Pico. Её легко программировать, и её даже можно вручную соединить проводами с другими платами!

В этом двухчастном руководстве мы покажем вам, как отображать различные цвета, значения, время, прокручиваемые строки и показания датчиков на этом дисплее!

Что вам понадобится

Для первой части вам понадобится:

  • Raspberry Pi Pico с контактами

  • Установленный на вашем компьютере Thonny

  • Кабель Micro USB — для питания и программирования Pico

  • Плата Waveshare RGB Full-colour LED Matrix для Raspberry Pi Pico (16x10)

  • Умение вводить, редактировать, сохранять и запускать код MicroPython на Pico с помощью Thonny

В этом руководстве мы покажем, как:

  • Создавать яркие цветные дисплеи с помощью координат (x, y)

  • Отображать числовые значения в десятичном, шестнадцатеричном и двоичном виде

  • Показывать время в часах и минутах

Подключение оборудования

Подключение оборудования очень простое. Либо вставьте плату непосредственно в Pico, либо через плату-расширитель. Следите за правильной ориентацией — выровняйте сторону с USB-разъёмом:

Подключение RGB Full-colour LED матрицы Waveshare к Pico

В качестве альтернативы можно соединить контакты на нижней стороне дисплея с Pico с помощью соединительных проводов. 5V подключается к VBUS, GND — к GND, а DIN — к GP6 или другому подходящему контакту по вашему выбору. На нижней стороне платы есть перемычки для подключения DIN (Data In) к GP6, GP7 или GP22. Мы подключили к GP6.

Ручное подключение RGB LED матрицы Waveshare для Raspberry Pi Pico

Нумерация и координаты светодиодов

Если повернуть плату так, чтобы USB-разъём находился справа, то светодиоды нумеруются от 0 до 15 в верхнем ряду слева направо, от 16 до 31 — во втором ряду, и так далее вплоть до 44–159 в нижнем ряду.

Если использовать систему координат, где верхний левый светодиод — это начало координат (0,0), то нижний правый светодиод находится в точке (15,9). Исходя из этого, легко вычислить индекс/позицию любого светодиода на плате:

pos = x + y * 16

Таким образом, последний светодиод имеет номер 15 + 9 * 16 = 159

Мы написали функцию для удобной установки конкретных пикселей нужного цвета:

def xy_set(x, y, colour):
    # Проверка допустимого диапазона NeoPixel
    if (x >= 0) and (x < 16) and (y >= 0) and (y < 11):
        pos = x + y*16
        pixels_set(pos, colour)

x и y — это координаты пикселя, а colour — кортеж (tuple) со значениями красного, зелёного и синего в диапазоне от 0 до 255.

Что такое кортеж?

Кортежи используются для хранения нескольких элементов в одной переменной. Tuple — это один из 4 встроенных типов данных в Python, используемых для хранения коллекций данных; три других — это List, Set и Dictionary, каждый со своими особенностями и сферой применения. Кортеж — это упорядоченная и неизменяемая коллекция. Кортежи записываются в круглых скобках (цитата с w3schools.com).

Примеры кортежей

  • Красный = (255,0,0)

  • Зелёный = (0,255,0)

  • Синий = (0,0,255)

  • Жёлтый = (255,255,0)

  • Голубой = (0,255,255)

  • Пурпурный = (255,0,255)

Скобки обязательны! Найти значения RGB для сложных цветов, таких как коричневый или бледно-розовый, можно здесь: https://htmlcolors.com/

Ниже мы написали несколько демонстрационных программ на MicroPython, показывающих, как можно использовать плату.

Пример 1: Базовая красочная мигающая подсветка светодиодов

Базовые цвета на матрице Waveshare Pico RGB

Программу можно скачать здесь: WS Neopixels 160 Basic.py

Советуем скачать её и просмотреть в редакторе Thonny. Мы дадим комментарии (их можно распечатать из Thonny, добавив заметки или дополнительные комментарии).

Строки 1–49

Это стандартный код драйвера адресуемых светодиодов из официального руководства Raspberry Pi Pico, страница 134.

Количество светодиодов, контакт DIN и яркость дисплея задаются следующим образом:

# Настройка количества WS2812 светодиодов.
NUM_LEDS = 160 # 10 рядов по 16 NeoPixel
PIN_NUM = 6
brightness = 0.1

Встроенные процедуры

pixels_set(i, colour)

Изменяет настройку цвета светодиода. Помните, что colour — это трёхбайтовый кортеж!

pixels_set(159, (0, 127 ,0))

Устанавливает нижний левый пиксель в средне-зелёный цвет.

pixels_show()

Делает ранее заданные значения цвета пикселей видимыми (забыть включить эту инструкцию — частая ошибка, и тогда дисплей не меняется).

Мы добавили несколько дополнительных процедур для удобства программирования:

xy_set(x, y, colour)

Устанавливает цвет пикселя с координатами (x, y). Проверяет допустимость позиции для дисплея.

pixels_fill(colour)

Устанавливает все пиксели одного цвета — кортежа.

clear()

Устанавливает все пиксели в чёрный цвет.

rect(x, y, w, h ,r , g, b)

Рисует прямоугольный контур шириной w, высотой h, начиная с верхнего левого угла в (x, y) с цветовыми значениями r, g и b.

vert(x, y, l, r, g, b)

Рисует вертикальную линию длиной l заданного цвета.

horiz(x, y, l, r, g, b)

Рисует горизонтальную линию длиной l заданного цвета.

Основная часть программы, начиная со строки 87, использует эти процедуры для демонстрации:

порядка пикселей, градиентов, линий, прямоугольников и диагоналей.

Градиенты — самая сложная часть: цвета меняются в зависимости от позиции по x.

# Градиенты
clear()
for i in range(16):
    xy_set(i,0,(i*8,0,0))          # Нарастающий красный — слева направо
    xy_set(15-i,1,(0,i*8,0))       # Убывающий зелёный
    xy_set(i,2,(0,0,i*8))          # Нарастающий синий
    xy_set(i,4,((15-i)*8,0,i*8))   # От красного к синему
    xy_set(i,6,((15-i)*8,i*8,0))   # От красного к зелёному
    xy_set(i,8,(0,i*8,(15-i)*8))   # От синего к зелёному
pixels_show()
utime.sleep(4)

Что попробовать

  1. Нарисуйте треугольники, направленные внутрь, с обоих концов дисплея

  2. Нарисуйте большую оранжевую стрелку на экране, направленную вправо

  3. Отображайте стрелку в цикле, каждый раз перерисовывая её другим случайным цветом

  4. Используя процедуру rect, создайте шоу, в котором прямоугольник расширяется и сужается от центра экрана. Можно добавить ещё одну процедуру, которая «выращивает» наименьший прямоугольник из 4 пикселей в квадрате из центра экрана.

Пример 2: Отображение числовых значений и времени

Отображение числовых значений и времени на матрице Waveshare Pico

Вторая программа показывает, как отображать статические числовые значения (см. выше) на дисплее в системах счисления 10, 16 и 2 (десятичной, шестнадцатеричной и двоичной — основание 10, основание 16 и основание 2), а также показывать время в формате ЧЧ:ММ — как в примере ниже:

Отображение времени на RGB LED матрице Waveshare

Программу можно скачать здесь: WSNeopixels 160 Numbers.py

Эта программа требует очень маленького шрифта. Каждый символ отображается в небольшом прямоугольнике шириной 3 пикселя и высотой 5 пикселей — очень маленьком, но удивительно легко читаемом. Нам нужны символы для цифр 0–9 и букв A–F для отображения шестнадцатеричных чисел.

#one row per 5x3 digit - 0 to 15 - Hexadecimal symbols
nums =[0,1,0,1,0,1,1,0,1,1,0,1,0,1,0,  # 0\
       0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,  # 1\
       1,1,1,0,0,1,0,1,0,1,0,0,1,1,1,  # 2\
       1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,  # 3\
       1,0,0,1,0,1,1,1,1,0,0,1,0,0,1,  # 4\
       1,1,1,1,0,0,1,1,1,0,0,1,1,1,1,  # 5\
       1,1,1,1,0,0,1,1,1,1,0,1,1,1,1,  # 6\
       1,1,1,0,0,1,0,1,0,1,0,0,1,0,0,  # 7\
       1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,  # 8\
       1,1,1,1,0,1,1,1,1,0,0,1,0,0,1,  # 9\
       0,1,0,1,0,1,1,1,1,1,0,1,1,0,1,  # A\
       1,1,0,1,0,1,1,1,0,1,0,1,1,1,0,  # B\
       0,1,1,1,0,0,1,0,0,1,0,0,0,1,1,  # C\
       1,1,0,1,0,1,1,0,1,1,0,1,1,1,0,  # D\
       1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,  # E\
       1,1,1,1,0,0,1,1,1,1,0,0,1,0,0]  # F

powers = [1,2,4,8,16,32,64,128] # Для двоичного и шестнадцатеричного

Битовый шаблон для каждого символа хранится в списке nums, начиная со строки 39. Каждый символ требует 15 единиц или нулей. Порядок — пять строк из трёх значений, начиная с верхней строки. Единица означает включённый пиксель, ноль — выключенный. Соответствующий цвет можно применить позднее.

Если рассмотреть ноль, в первой строке мы видим:

 0,1,0,1,0,1,1,0,1,1,0,1,0,1,0,  # 0
0 1 0
1 0 1
1 0 1
1 0 1
0 1 0

Теперь нам нужны процедуры для отображения этих шаблонов в виде светящихся пикселей на экране.

def show_num(val,xd,yd,r,g,b):     # Одиночная цифра
    offset = val * 15
    for p in range(offset,offset + 15):
        if nums[p] == 1:
            xt = p % 3
            yt = (p-offset) // 3
            xy_set(xt+xd,yt+yd,(r,g,b))

Эта функция отображает один цифровой символ из шрифта (val) с верхним левым углом в позиции (xd, yd) в цвете, заданном значениями r, g, b. val должен быть в диапазоне 0–15.

Смещение — это вычисленная позиция первого 0 или 1 в таблице для val. Цикл проходит по 15 битам таблицы для этого символа. Если бит равен 1, вычисляется позиция (xt+xd, yt+yd) и этому пикселю задаётся нужный цвет. Эта процедура при необходимости вызывается следующей процедурой.

def show_number(val,r,g,b):  #Основание 10 — сотни, десятки и единицы
    abs_val = abs(val)
    temp = abs_val
    hund = abs_val // 100
    temp = abs_val - hund *100
    tens = temp // 10
    units = temp % 10
    clear()
    if (abs_val > 99): show_num(hund,4,2,r,g,b)
    if (abs_val > 9): show_num(tens,8,2,r,g,b)
    show_num(units,12,2,r,g,b)

Эта процедура рисует целое число val в диапазоне 0–999 на дисплее заданного цвета.

  1. Абсолютное значение (всегда положительное) разбивается на сотни, десятки и единицы.

  2. Экран очищается.

  3. Сотни, десятки и единицы отображаются по мере необходимости с помощью show_num().

def show_utime(hrs,mins,r,g,b):
    clear()
    tens = hrs // 10
    units = hrs % 10
    show_num(tens,0,2,r,g,b)
    show_num(units,4,2,r,g,b)
    show_colon(7,3)
    tens = mins // 10
    units = mins % 10
    show_num(tens,8,2,r,g,b)
    show_num(units,12,2,r,g,b)

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

Отображение символов на матрице Waveshare Pico RGB
powers = [1,2,4,8,16,32,64,128] # Для двоичного

def show_binary(val,r,g,b):
    for index in range(0, 8):
        if powers[index] & val:
            xy_set(11-index,9,(r,g,b)) # Цветной
        else:
            xy_set(11-index,9,(0,0,0)) # Чёрный

def show_hex(val,r,g,b):
      nibble_hi = val // 16   # Нибл/нибл — половина байта
      nibble_low = val % 16
      show_num(nibble_hi,4,2,r,g,b)
      show_num(nibble_low,8,2,r,g,b)

Эти процедуры отображают значения в шестнадцатеричном и двоичном виде.

Основная часть программы вызывает эти процедуры для демонстрации различных форматов. В секции подсчёта цвет отрицательных значений и знак минус применяются отдельно.

Что попробовать

Считать температуру Pico

Считайте температуру с встроенного в Pico датчика и отобразите её целую часть на светодиодах вместе с буквой C.

import machine
import utime
sensor_temp = machine.ADC(4)
conversion_factor = 3.3 / (65535)

while True:
    reading = sensor_temp.read_u16() * conversion_factor
    temperature = 27 - (reading - 0.706)/0.001721
    print(temperature)
    utime.sleep(2)

Это не очень точно, и мы всегда замечали, что значения получаются завышенными. Для повышения точности можно использовать датчик температуры DHT11, DHT22, TMP36 или DS18B20.

Создать цифровые часы

Используйте «тикер» с периодом в одну секунду или utime.ticks_ms() для создания цифровых часов с дисплеем для удобства чтения. Использование time.sleep(1) между обновлениями дисплея будет работать слишком медленно, так как настройка и обновление экрана занимают некоторое время. Смотрите страницу 73 руководства по Pico для получения помощи по utime.ticks_ms().

Использовать часы реального времени

Для большей точности и удобства настройки используйте RTC (часы реального времени), например DS1302 или DS3231.

Отскакивающий пиксель

#========== MAIN ===============
x = 4   # позиция x
xd = 1  # направление x
y = 5   # позиция y
yd = 1  # направление y

clear()
xy_set(x,y,(280,0,0))
pixels_show()
while True:
    clear()
    x = x + xd
    if x > 14:
        xd = -1
    elif x < 1:
        xd = 1
    xy_set(x,y,(280,0,0))
    pixels_show()
utime.sleep(0.1)

Полную программу можно скачать здесь: WS Neopixels 160 Bounce.py

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

Что можно изменить

  • Добавьте код для диагонального движения, обновляя значение y в цикле и отскакивая от верхнего и нижнего краёв

  • Изменяйте цвет пикселя в зависимости от направления его движения

  • Нарисуйте серую рамку по краю экрана и заставьте его отскакивать от неё

  • Увеличьте размер отскакивающего объекта до квадрата из 4 пикселей

Что будет во второй части

Во второй части этого руководства мы покажем вам, как прокручивать красочный текст и числовые значения по экрану с использованием расширенного набора символов. Мы также рассмотрим, как отображать показания датчиков от температурного датчика BME680!

Не забудьте ознакомиться с разделом Raspberry Pi Pico для получения дополнительных отличных модулей и аксессуаров!