O funcionamento do APA102 está detalhado no post anterior. Resumindo, precisamos gerar dois sinais (dado e clock) para enviar frames de 32 bits. O primeiro frame é uma marca especial de início (com zeros), cada frame seguinte controla um LED RGB e um frame final (com uns) fornece os clocks para garantir o tratamento de todos os bits.
No caso vamos usar a interface SPI do Arduino para gerar os sinais. O código abaixo está organizado para ser mais didático que eficiente. Uma animação simples é usada para demonstrar que estamos controlando cada um dos LEDs.
// Teste simples de controle de fita de LEDs RGB com // controlador APA102 // // A fita de LED deve estar conectada aos pinos de SPI // UNO: 11 ou ISP-4 (MOSI) e 13 ou ISP-3 (SCK) // Mega: 51 ou ISP-4 (MOSI) e 52 ou ISP-3 (SCK) // Due: ICSP-4 (MOSI) e ISP-3 (SCK) // // Daniel Quadros - Jan/16 - http://dqsoft.blogspot.com #include <SPI.h> // Número de LEDs na fita const int NUM_LEDS = 10; // Frames byte frameStart[4] = { 0x00, 0x00, 0x00, 0x00 }; byte frameOff[4] = { 0xE8, 0x00, 0x00, 0x00 }; byte frameB[4] = { 0xE8, 0xFF, 0x00, 0x00 }; byte frameG[4] = { 0xE8, 0x00, 0xFF, 0x00 }; byte frameR[4] = { 0xE8, 0x00, 0x00, 0xFF }; byte frameEnd[4] = { 0xFF, 0xFF, 0xFF, 0xFF }; // Iniciação void setup() { SPI.begin(); acionaLED (0, NUM_LEDS, frameOff); } // Laço perpétuo void loop() { int nLeds = 0; while (nLeds < NUM_LEDS) { nLeds++; anima (nLeds, frameR); anima (nLeds, frameG); anima (nLeds, frameB); } } // Faz a "animação" dos primeiros n LEDs // usando a cor indicada void anima (int n, byte *cor) { for (int i = 1; i <= n; i++) { acionaLED (i, i, cor); } for (int i = n; i > 1; i--) { acionaLED (i-1, i, cor); } } // Acende o LED iLed com cor e // apaga os demais n-1 LEDs void acionaLED (int iLed, int n, byte *cor) { sendFrame (frameStart); for (int i = 1; i <= n; i++) { sendFrame ((i == iLed) ? cor : frameOff); } sendFrame (frameEnd); delay(100); } // Envia um frame para a fita void sendFrame (byte *frame) { for (int i = 0; i < 4; i++) SPI.transfer(*frame++); }O vídeo abaixo mostra o resultado.
Este código é suficiente para animações simples, com a fita de LED parada. A motivação inicial deste estudo foi gerar animações por persistência de visão, girando a fita a velocidades absurdas. Para isto o código é lento. O problema principal é que a execução fica parada durante SPI.transfer, esperando o byte atual ser transmitido. Como o ATmega possui apenas um byte de buffer e vamos querer trabalhar com um clock alto na SPI, usar interrupções não vai trazer um grande alívio. Por exemplo, colocando a SPI do Arduino na taxa máxima, podemos executar apenas 16 instruções enquanto transmitimos um byte. A simples chamada e retorno da interrupção devem gastar algo muito próximo disto.
No próximo post vamos melhorar isto usando um Arduino Due, que tem um clock mais elevado e dispõe do recurso de DMA.
Nenhum comentário:
Postar um comentário