Componentes Eletronicos

LEDs endereçáveis: conhecendo o WS2812B

Eletrogate 20 de setembro de 2022

Introdução

Há algum tempo, ensinamos aqui no blog a como utilizar fitas de LED RGB com o Arduino. Essas fitas são extremamente simples de se programar e possuem a limitação de apenas uma cor ao longo de toda a sua extensão. Hoje você conhecerá os LEDs WS2812B que compõem as fitas RGB endereçáveis e apresentam diversas vantagens em relação à anterior, pois permitem a programação de cada LED individualmente e isso amplia a gama de cores e efeitos que podemos adicionar ao longo de toda a fita. Acompanhe:


Conhecendo o chip WS2812B

Conforme falado anteriormente, os LEDs endereçáveis nos permitem programar a cor, intensidade e até mesmo qual LED (também chamado de pixel) irá acender ao longo do circuito.

Na imagem abaixo você pode conferir em detalhes como o componente é por dentro.

led_enderecavel

LED endereçável visto no microscópio. Repare os detalhes do chip interno e as conexões com cada setor.

Também montamos um gif mostrando como ocorre a troca de cor em detalhes. Observe abaixo:

troca_cor

Troca de cores em detalhes

Abaixo você pode analisar o pinout do chip:

Pinout WS2812B – Fonte: Datasheet

Observe que existem 4 pinos: VCC, GND, Din e Dout. Os pinos de VCC e GND já são conhecidos por todos, certo? São os pinos de alimentação do LED, que trabalha em 5V. Já os pinos Din e Dout são responsáveis pela programação. Como esses LEDs são programados em cascata (primeiro um, depois o outro), é necessário que haja uma “passagem” dos dados para os demais LEDs do circuito e quem faz essa função é o pino Dout. Ao longo do post você entenderá melhor como funciona essa parte, mas, a grosso modo, os dados “entram” pelo pino Din, o chip interno processa os dados referentes àquele LED (cor, intensidade e posição (caso haja mais de um no circuito), basicamente) e dispensa os demais pelo pino Dout (que vai conectado ao Din do segundo LED, segundo a configuração de cascata). A parte mais legal disso tudo é que através de um único fio de sinal é possível programar todos os parâmetros da sequência de LEDs, conforme citado. Abaixo você pode observar um diagrama com a conexão de mais de um LED, ilustrando essa configuração em cascata:

diagrama_cascata

Ligação em Cascata. Fonte: Datasheet


Montando o Circuito

Agora que você conhece todas as conexões de um LED endereçável, vamos iniciar a montagem de um circuito bem simples contendo 4 LEDs WS2812B. Acompanhe:

Materiais necessários para o projeto utilizando LEDs WS2812B

Vamos começar separando os materiais que serão usados nesse projeto. Você vai precisar de:

cta_cart

 

No diagrama abaixo você pode observar a montagem do circuito. Reproduza fielmente as conexões e vamos partir para a parte mais legal: a programação!

blog-eletrogate-ws2812b-esquematico


Programando os LEDs Endereçáveis

A programação do nosso circuito de exemplo é bem simples. Vamos começar instalando a biblioteca “Adafruit NeoPixel”. Você pode instalá-la pelo próprio Gerenciador de Bibliotecas da Arduino IDE, mas também deixarei o link de referência para o repositório no GitHub.

neopixel_lib

Feito isso, vamos iniciar a programação dos LEDs. Acompanhe o raciocínio:

O primeiro passo é adicionar a biblioteca usando o comando #include. Em seguida, usando o comando #define, vamos atribuir nomes a alguns parâmetros que utilizaremos ao longo do código, como o pino do Arduino responsável por enviar o sinal ao circuito e o número de LEDs que compõem nossa sequência. Feito isso, crie um objeto que referencie a biblioteca e informe dois parâmetros: a quantidade de LEDs e o pino do Arduino a ser utilizado. Aqui você pode usar o nome atribuído anteriormente sem problema algum, beleza?

#include <Adafruit_NeoPixel.h>

#define D_in 6       
#define qtdeLeds 4    

Adafruit_NeoPixel pixels(qtdeLeds, D_in);

O próximo passo é configurar o setup do nosso código, que é bem simples. Aqui você só precisa aplicar o comando pixels.begin(). Esse comando inicia a “comunicação” entre os parâmetros presentes na biblioteca e os LEDs. Lembre-se apenas de trocar o termo “pixels” pelo nome que você atribuiu ao objeto que criou anteriormente sempre que for se referir à biblioteca, ok? Estamos utilizando “pixels.begin()” pois “pixels” foi o nome que escolhemos para o objeto, portanto você deve alterá-lo caso não seguir esse mesmo exemplo. A sintaxe ficaria: “nomeDoObjeto.begin()”.

void setup() {
  pixels.begin();             
}

Por fim, vamos configurar o loop, que é onde toda a nossa lógica será desenvolvida. Começamos aplicando o comando pixels.clear() para que todos os LEDs sejam desligados ao fim do ciclo e, em seguida, iniciamos um laço for para conter a lógica de funcionamento, que é bem simples: a variável i incrementará seu valor até igualar ao número de LEDs que configuramos, tornando a condição falsa. Enquanto for verdadeira, os LEDs serão acionados conforme os comandos dados. São eles:

pixels.setPixelColor(i, pixels.Color(255, 0, 0)) -> O comando setPixelColor é responsável por configurar os parâmetros referentes ao número do LED na cascata e também a cor, onde i representa o número do LED (de 0 a 3, no nosso exemplo) e o comando pixels.Color(255, 0, 0) se encarrega de configurar as cores (lembre-se que pixels é o nome do objeto, beleza?). Aqui, informamos a intensidade de 0 a 255 para cada canal do padrão RGB, onde zero mantém a cor desligada e 255 completamente ligada. No exemplo acima, o LED está configurado para ligar a cor vermelha pois setamos o canal R como 255 e os demais, G e B, como zero.

pixels.show() -> Executa a linha de configuração anterior. Lembre-se de adicioná-lo sempre que trocar algum parâmetro do comando setPixelColor e não se esqueça de trocar o nome do objeto aqui também, ok?

delay -> aguarda um tempo em milissegundos entre a execução dos parâmetros configurados.

void loop() {
  pixels.clear();      

  for(int i=0; i<qtdeLeds; i++){        
    pixels.setPixelColor(i, pixels.Color(255, 0, 0));     
    pixels.show();      
    delay(500);         
    
    pixels.setPixelColor(i, pixels.Color(0, 255, 0));     
    pixels.show();      
    delay(500);         
    
    pixels.setPixelColor(i, pixels.Color(0, 0, 255));     
    pixels.show();      
    delay(500);         
  }
}

Aqui você tem o código completo para esse exemplo, devidamente comentado caso tenha ficado alguma dúvida.

#include <Adafruit_NeoPixel.h>      //Adiciona a biblioteca Adafruit NeoPixel

#define D_in 6       //Nomeia o pino 6 do Arduino
#define qtdeLeds 4    //Informa a quantidade de LEDs que serão ligados em cascata

Adafruit_NeoPixel pixels(qtdeLeds, D_in);     //Instancia o objeto "pixels", informando a quantidade e o pino de sinal

void setup() {
  pinMode(D_in, OUTPUT);      //Configura o pino 6 como saída
  pixels.begin();             //Inicia o objeto "pixels"
}

void loop() {
  pixels.clear();      //desliga todos os LEDs

  for(int i=0; i<qtdeLeds; i++){        //para i = 0, se i menor que a quantidade de leds, incremente 1 em i
    pixels.setPixelColor(i, pixels.Color(255, 0, 0));     //liga o led correspondente ao número da variável i na cor vermelha
    pixels.show();      //executa os parâmetros do comando acima
    delay(500);         //Aguarda 500 milissegundos
    
    pixels.setPixelColor(i, pixels.Color(0, 255, 0));     //liga o led correspondente ao número da variável i na cor verde
    pixels.show();      //executa os parâmetros do comando acima
    delay(500);         //Aguarda 500 milissegundos
    
    pixels.setPixelColor(i, pixels.Color(0, 0, 255));     //liga o led correspondente ao número da variável i na cor azul
    pixels.show();      //executa os parâmetros do comando acima
    delay(500);         //Aguarda 500 milissegundos
  }
}

Após carregar o código no Arduino, espera-se obter o resultado mostrado no vídeo a seguir:

No próximo exemplo, vamos te mostrar como misturar as cores e acender os leds de forma aleatória. O circuito é o mesmo, vamos apenas implementar uma nova função do Arduino: a random().

A função random é a responsável por gerar números pseudoaleatórios em um intervalo pré-definido. Sua sintaxe é bem simples:

random(max) -> Nessa sintaxe, informamos apenas o valor máximo (que no nosso caso será 255) e a função irá retornar um número entre zero – que é o número inicial quando não informamos nenhum outro valor, e o número que foi estipulado como limite máximo.
random(min, max) -> Nessa outra opção de sintaxe, podemos usar um valor mínimo diferente de zero, definindo o range que desejamos. Vale ressaltar que ambas estão corretas, cabe a você decidir qual se encaixa melhor em sua lógica.

O código novamente é bem simples. Desta vez vamos deixar toda a explicação nos comentários, ok? Basta carregar no Arduino e ligar o circuito:

#include <Adafruit_NeoPixel.h>      //Adiciona a biblioteca Adafruit NeoPixel

#define D_in 6       //Nomeia o pino 6 do Arduino

int qtdeLeds = 4;    //Informa a quantidade de LEDs que serão ligados em cascata

Adafruit_NeoPixel pixels(qtdeLeds, D_in);     //Instancia o objeto "pixels", informando a quantidade e o pino de sinal

void setup() {
  pinMode(D_in, OUTPUT);      //Configura o pino 6 como saída  
  pixels.begin();             //Inicia o objeto "pixels"
  pixels.clear();      //desliga todos os LEDs
}

void loop() {
  //                   número de LEDs,    vermelho,     verde,       azul
  pixels.setPixelColor(random(qtdeLeds), random(255), random(255), random(255)); //escolhe, de maneira pseudoaleatória, o número do LED e a intensidade de cada cor do canal RGB
  pixels.show();    //executa os parâmetros do comando acima
  delay(500);       //Aguarda 500 milissegundos
}

Novamente o resultado esperado você pode observar no vídeo abaixo:


Como Funciona o Endereçamento dos LEDs

Para você que ficou curioso para entender como esses LEDs recebem os parâmetros, vamos tentar explicar de maneira bem didática com o apoio de um osciloscópio. Veja só:

O primeiro passo para entender como funciona a programação e a transmissão de dados para um LED endereçável é conhecer um pouquinho de eletrônica digital. Sabemos que só podemos ter dois estados: 0 (desligado) e 1 (ligado), certo? Os pulsos de sinal são enviados para os LEDs através de um pino digital do Arduino, logo se beneficia dessa característica. Com isso em mente, concluímos que os dados são transmitidos apenas quando o pino está “ligado”, em nível lógico 1, e isso faz com que seja necessário recorrer a outras táticas para ligar e desligar os LEDs: é necessário variar a largura do pulso, ou seja, o tempo (normalmente em microssegundos) em que o pino fica em nível lógico alto ou baixo, afim de obter outros dois estados lógicos, mas dessa vez, esses estados serão referentes ao LED, não ao Arduino.

Conforme você pode observar no datasheet do LED WS2812B e na tabela a seguir, para ser considerado nível lógico 1, o pulso deve durar 0,8 microssegundo em high e 0,4 microssegundo em low, enquanto que, para ser considerado nível lógico zero, a duração deverá ser de 0,4 microssegundo em high e 0,8 microssegundo em low, totalizando um período total de, aproximadamente, 1,2 microssegundo.

blog-eletrogate-ws2812b-tabela

Com o auxílio do osciloscópio podemos ver essa diferença de tempo na prática. Duplicamos a forma de onda obtida e mapeamos os limites de cada período para facilitar o entendimento. Veja só:

pulsos

Tendo entendido como o Arduino consegue transmitir os pulsos para um LED, vamos entender como a transmissão é feita para os demais LEDs da cascata.

Como dito anteriormente, a configuração cascata recebe esse nome pois são ligados em uma espécie de circuito série, estando a entrada de dados do LED y conectado à saída de dados do LED x. Dessa forma, os circuitos integrados que controlam cada LED processam apenas os bits referentes à sua posição na fita e “descartam” os demais, para serem processados adiante.

Na imagem abaixo temos a representação gráfica desses bits, graças ao osciloscópio. Acompanhe:

fita_bits

Note que existem 24 bits nessa sequência. São 24 pois cada canal trabalha com até 256 valores (8 bits) de brilho diferentes (lembra do PWM?) e, como temos 3 canais, R, G e B, o total é de 24 bits.

Nesse exemplo, programei o circuito para ligar somente a cor azul do primeiro LED, logo, levando em consideração o que explicamos logo acima sobre como o chip WS2812B interpreta os níveis lógicos, você pode notar que os primeiros 16 bits da fita estão em zero e os 8 últimos estão em 1, ou seja, temos o número binário 000000000000000011111111, na qual as primeiras 8 posições são referentes à cor verde, o segundo conjunto refere-se à cor vermelha e, o último, à cor azul.

tabela_bits

Mapa de Bits

Você pode observar melhor esse conceito na imagem abaixo, onde mapeamos essa fita de bits para o LED desligado, ligado na cor vermelha, verde, azul e também na cor branca, que é a soma de todas as 3 cores do padrão RGB quando ligadas, respectivamente:

mapeamento_bits

Entendido isso fica muito simples compreender como os demais LEDs são programados e também como o Arduino é capaz de ligar qualquer LED ao longo da cascata sem alterar o estado dos LEDs anteriores. Observe o print a seguir:

48_bits_WS2812B

Na imagem acima, programamos o circuito de modo a ligar dois LEDs: O primeiro 100% azul e, o segundo, 100% verde. Você pode observar que, na onda amarela, ao invés de 24, temos 48 bits, enquanto que na onda verde, temos apenas 24 e essa é a chave do funcionamento! O Arduino envia uma fita de bits contendo o número de LEDs do circuito multiplicado por 24, enquanto que, na cascata, a fita de bits é processada/interpretada da seguinte forma: o primeiro conjunto de 24 bits recebidos são atribuídos ao primeiro LED – que os divide e distribui para cada cor. Os demais bits que não foram interpretados são passados adiante e esse processo se repete até que todos os LEDs recebam seu conjunto de 24 bits (para os LEDs que forem ficar desligados, os mesmos 24 bits são enviados, porém todos em zero). Ao final da fita de bits, é dado um tempo de 50 microssegundos entre o fim da primeira e o início da segunda, que é interpretado como reset, indicando o fim daquela instrução, e isso libera o primeiro LED para receber novamente os primeiros 24 bits da próxima sequência.


Conclusão

Concluímos aqui a apresentação do chip WS2812B, seu funcionamento e programação básica, utilizando a biblioteca Adafruit NeoPixel. Nos próximos posts sobre LEDs endereçáveis traremos dois projetos muito legais: uma fita de LEDs que reage a sons e um autorama de luzes para dois jogadores. Não deixe de conferir!

Conheça a Metodologia Eletrogate e ofereça aulas de robótica em sua escola!



Samuel Martins
@samuel.martins192

Cursando Eletroeletrônica no SENAI CETEL. Fanático por eletrônica, automação, impressão 3D e afins, dedico meu tempo livre a pesquisas e projetos ligados às principais áreas de interesse, pratico aeromodelismo e sou curioso por astrofotografia.


Eletrogate

20 de setembro de 2022

A Eletrogate é uma loja virtual de componentes eletrônicos do Brasil e possui diversos produtos relacionados à Arduino, Automação, Robótica e Eletrônica em geral.

Conheça a Metodologia Eletrogate e Lecione um Curso de Robótica nas Escolas da sua Região!

Eletrogate Robô

Assine nossa newsletter e
receba  10% OFF  na sua
primeira compra!