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
- 1 placa Raspberry Pi Pico com cabo micro USB e pinos soldados
- 1 fita de LED endereçável WS2812B
- Jumpers macho-macho
- 1 protoboard 400 pontos (ou maior)
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.