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