Como utilizar LED endereçável na Raspberry Pi Pico Deixe um comentário

Fitas de LED são muito úteis em diversos projetos envolvendo plataformas microcontroladas. Neste artigo vamos aprender a utilizar uma fita de LED endereçável com a Raspberry Pi Pico. Vamos lá?

Introdução

Existem diversos tutoriais para uso de fitas de LED com uso de Arduino, Raspberry Pi, ESP8266. Claro que com a mais recente placa Raspberry Pi Pico, não seria diferente.
A fita utilizada neste tutorial trata-se da versão endereçável com controlador interno WS2812B. Possui alimentação 5V e com uma única porta GPIO é possível controlar individualmente todos os LEDs da fita. Para isso, é definido um pino de saída de dados da placa, que fará conexão com o pino DI (ou DIN) da fita. A fita, além deste pino, possui outro pino chamado DO (ou DOUT), que pode se conectar com outra fita, aumentando a quantidade de pixels.

Para o caso de fitas longas, é aconselhável o uso de fonte de alimentação externa 5V/2A ou de maior corrente.

Para mais informações sobre fitas de LED, leia este artigo publicado no blog.

Materiais utilizados

Montagem

O esquemático para montagem se encontra na figura a seguir:

Onde:

Raspberry Pi Pico Fita de LED
VBUS (pino 40) VCC – fio vermelho
GND (pino 3, 38 ou outro GND da placa) GND – fio branco ou preto
GPIO3 (pino 5) DI – fio verde

Preparação da placa

A Raspberry Pi Pico pode ser programada de diversas formas. Faremos uso de programação MicroPython através da Thonny IDE. Mas se sua placa for nova, siga os passos para instalação do MicroPython e Thonny IDE neste artigo.

Para programação e controle da fita de LED, faremos uso de uma biblioteca em Python chamada neopixel.py. Para isto, abra um arquivo novo na Thonny IDE e copie/cole o código a seguir, extraído do GitHub de blaz-r.

import array, time
from machine import Pin
import rp2
 
# PIO state machine for RGB. Pulls 24 bits (rgb -> 3 * 8bit) automatically
@rp2.asm_pio(sideset_init=rp2.PIO.OUT_LOW, out_shiftdir=rp2.PIO.SHIFT_LEFT, autopull=True, pull_thresh=24)
def ws2812():
	T1 = 2
	T2 = 5
	T3 = 3
    wrap_target()
    label("bitloop")
    out(x, 1)               .side(0)	[T3 - 1]
    jmp(not_x, "do_zero")   .side(1)	[T1 - 1]
    jmp("bitloop")          .side(1)	[T2 - 1]
    label("do_zero")
    nop().side(0)                       [T2 - 1]
    wrap()
 
# PIO state machine for RGBW. Pulls 32 bits (rgbw -> 4 * 8bit) automatically
@rp2.asm_pio(sideset_init=rp2.PIO.OUT_LOW, out_shiftdir=rp2.PIO.SHIFT_LEFT, autopull=True, pull_thresh=32)
def sk6812():
	T1 = 2
	T2 = 5
	T3 = 3
    wrap_target()
    label("bitloop")
    out(x, 1)               .side(0)	[T3 - 1]
    jmp(not_x, "do_zero")   .side(1)	[T1 - 1]
    jmp("bitloop")          .side(1)	[T2 - 1]
    label("do_zero")
    nop()                   .side(0)	[T2 - 1]
    wrap()
 
 
# Delay here is the reset time. You need a pause to reset the LED strip back to the initial LED
# however, if you have quite a bit of processing to do before the next time you update the strip
# you could put in delay=0 (or a lower delay)
#
# Class supports different order of individual colors (GRB, RGB, WRGB, GWRB ...). In order to achieve
# this, we need to flip the indexes: in 'RGBW', 'R' is on index 0, but we need to shift it left by 3 * 8bits,
# so in it's inverse, 'WBGR', it has exactly right index. Since micropython doesn't have [::-1] and recursive rev()
# isn't too efficient we simply do that by XORing (operand ^) each index with 3 (0b11) to make this flip.
# When dealing with just 'RGB' (3 letter string), this means same but reduced by 1 after XOR!.
# Example: in 'GRBW' we want final form of 0bGGRRBBWW, meaning G with index 0 needs to be shifted 3 * 8bit ->
# 'G' on index 0: 0b00 ^ 0b11 -> 0b11 (3), just as we wanted.
# Same hold for every other index (and - 1 at the end for 3 letter strings).
 
class Neopixel:
	def __init__(self, num_leds, state_machine, pin, mode="RGB", delay=0.0001):
        self.pixels = array.array("I", [0 for _ in range(num_leds)])
        self.mode = set(mode)   # set for better performance
        if 'W' in self.mode:
            # RGBW uses different PIO state machine configuration
            self.sm = rp2.StateMachine(state_machine, sk6812, freq=8000000, sideset_base=Pin(pin))
            # dictionary of values required to shift bit into position (check class desc.)
            self.shift = {'R': (mode.index('R') ^ 3) * 8, 'G': (mode.index('G') ^ 3) * 8,
                      	'B': (mode.index('B') ^ 3) * 8, 'W': (mode.index('W') ^ 3) * 8}
        else:
            self.sm = rp2.StateMachine(state_machine, ws2812, freq=8000000, sideset_base=Pin(pin))
            self.shift = {'R': ((mode.index('R') ^ 3) - 1) * 8, 'G': ((mode.index('G') ^ 3) - 1) * 8,
                      	'B': ((mode.index('B') ^ 3) - 1) * 8, 'W': 0}
        self.sm.active(1)
        self.num_leds = num_leds
        self.delay = delay
        self.brightnessvalue = 255
 
	# Set the overal value to adjust brightness when updating leds
	def brightness(self, brightness=None):
        if brightness == None:
            return self.brightnessvalue
        else:
            if brightness < 1:
            	brightness = 1
        if brightness > 255:
            brightness = 255
        self.brightnessvalue = brightness
 
	# Create a gradient with two RGB colors between "pixel1" and "pixel2" (inclusive)
	# Function accepts two (r, g, b) / (r, g, b, w) tuples
	def set_pixel_line_gradient(self, pixel1, pixel2, left_rgb_w, right_rgb_w):
        if pixel2 - pixel1 == 0:
  	      return
        right_pixel = max(pixel1, pixel2)
        left_pixel = min(pixel1, pixel2)
 
        for i in range(right_pixel - left_pixel + 1):
            fraction = i / (right_pixel - left_pixel)
            red = round((right_rgb_w[0] - left_rgb_w[0]) * fraction + left_rgb_w[0])
            green = round((right_rgb_w[1] - left_rgb_w[1]) * fraction + left_rgb_w[1])
            blue = round((right_rgb_w[2] - left_rgb_w[2]) * fraction + left_rgb_w[2])
            # if it's (r, g, b, w)
            if len(left_rgb_w) == 4 and 'W' in self.mode:
            	white = round((right_rgb_w[3] - left_rgb_w[3]) * fraction + left_rgb_w[3])
            	self.set_pixel(left_pixel + i, (red, green, blue, white))
            else:
            	self.set_pixel(left_pixel + i, (red, green, blue))
 
	# Set an array of pixels starting from "pixel1" to "pixel2" (inclusive) to the desired color.
	# Function accepts (r, g, b) / (r, g, b, w) tuple
	def set_pixel_line(self, pixel1, pixel2, rgb_w):
        for i in range(pixel1, pixel2 + 1):
            self.set_pixel(i, rgb_w)
 
	# Set red, green and blue value of pixel on position <pixel_num>
	# Function accepts (r, g, b) / (r, g, b, w) tuple
	def set_pixel(self, pixel_num, rgb_w):
        pos = self.shift
 
        red = round(rgb_w[0] * (self.brightness() / 255))
        green = round(rgb_w[1] * (self.brightness() / 255))
        blue = round(rgb_w[2] * (self.brightness() / 255))
        white = 0
        # if it's (r, g, b, w)
        if len(rgb_w) == 4 and 'W' in self.mode:
            white = round(rgb_w[3] * (self.brightness() / 255))
 
        self.pixels[pixel_num] = white << pos['W'] | blue << pos['B'] | red << pos['R'] | green << pos['G']
 
	# Rotate <num_of_pixels> pixels to the left
	def rotate_left(self, num_of_pixels):
        if num_of_pixels == None:
            num_of_pixels = 1
        self.pixels = self.pixels[num_of_pixels:] + self.pixels[:num_of_pixels]
 
	# Rotate <num_of_pixels> pixels to the right
	def rotate_right(self, num_of_pixels):
        if num_of_pixels == None:
            num_of_pixels = 1
        num_of_pixels = -1 * num_of_pixels
        self.pixels = self.pixels[num_of_pixels:] + self.pixels[:num_of_pixels]
 
	# Update pixels
	def show(self):
        # If mode is RGB, we cut 8 bits of, otherwise we keep all 32
        cut = 8
        if 'W' in self.mode:
            cut = 0
        for i in range(self.num_leds):
            self.sm.put(self.pixels[i], cut)
        time.sleep(self.delay)
 
	# Set all pixels to given rgb values
	# Function accepts (r, g, b) / (r, g, b, w)
	def fill(self, rgb_w):
        for i in range(self.num_leds):
            self.set_pixel(i, rgb_w)
  	  time.sleep(self.delay)

Vá ao menu Arquivo (ou File) => Salvar como… (Save as…). Será aberta uma pequena janela para você escolher onde o arquivo será salvo. Escolha a opção Raspberry Pi Pico para que seja salvo na própria placa.

Salve o arquivo com o nome neopixel.py, sem esquecer a extensão .py (Python). Pronto, a biblioteca está salva em sua Raspberry Pi Pico.

00

Este código, baseado no exemplo Rainbow da própria biblioteca, faz com que a fita acenda em cores pré-definidas em intervalo de tempo de 0.02s. Abra um novo arquivo e use o seguinte código em MicroPython:

# Biblioteca time
import time
# Biblioteca instalada neopixel
from neopixel import Neopixel
 
# número de pixels
numpix = 220
# objeto strip com quantidade de pixels, máquina de estado, número GPIO e modo de cor
strip = Neopixel(numpix, 0, 3, "GRB")
 
# Cores com índices R, B e B em cada uma
red = (255, 0, 0)
orange = (255, 165, 0)
yellow = (255, 150, 0)
green = (0, 255, 0)
blue = (0, 0, 255)
indigo = (75, 0, 130)
violet = (138, 43, 226)
pink = (255, 102, 178)
cyan = (0, 204, 204)
colors_rgb = (red, orange, yellow, green, blue, indigo, violet, pink, cyan)
 
# Índice de cores RGB, se houver a W adiciona mais um índice ou deixa 0
colors_rgbw = [color+tuple([0]) for color in colors_rgb]
colors_rgbw.append((0, 0, 0, 255))
 
# Remova o comentário emm colors_rgbw se a sua fita for RGBW
colors = colors_rgb
# colors = colors_rgbw
 
# Brilho da fita
strip.brightness(60)
 
# Laço de repetição
while True:
	for color in colors:
    	for i in range(numpix):
        	# Acende pixel do loop com cor vigente
        	strip.set_pixel(i, color)
        	# intervalo entre um pixel e outro
        	time.sleep(0.02)
        	strip.show()

Fique atento aos espaçamentos, pois se não estiverem indentados, podem apresentar erro no código. Todos os comentários estão com o símbolo # no início.

Salve o código em sua Raspberry Pi Pico. Para execução, clique no ícone ou F5 ou vá ao menu Executar => Executar programa atual. Se tudo estiver correto, você verá a fita acendendo nas cores conforme escritas no código.

Para acrescentar outras cores ao seu programa, veja neste site os índices R, G e B das cores desejadas e insira em seu código, lembrando que deve acrescentar a cor na sequência na linha colors_rgb.

Para a cor selecionada, os índices são:

  • R => 204
  • G => 0
  • B => 204

Escolha um nome para esta cor e a insira em seu código.

Gostou de aprender a utilizar uma fita de LED endereçável com a Raspberry Pi Pico? Esta é uma maneira simples de utilizar usando a biblioteca em Python. Deixe seu comentário logo abaixo se gostou do artigo.

Faça seu comentário

Acesse sua conta e participe