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++);
- }
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