segunda-feira, 27 de junho de 2011

Arduino cubo LED




Cubo led não é nenhuma novidade, existem muitos tutoriais e vídeos na internet mostrando cubos 3x3x3, 4x4x4, 5x5x5, 8x8x8 e até maiores. Como me interessei pelo assunto há pouco tempo decidi começar com o 3x3x3 que é mais simples e barato apesar de, obviamente, ser mais limitado por ter menor definição.

Dois projetos postados no instructables me deram subsídio para montar meu primeiro cubo led : O 3x3x3 LED Cube (autor: portreathbeach) e o  LED Cube 8x8x8 (autor: chr) . O primeiro é montado com pic. No post o autor disponibiliza um programa em VB que pode ser usado para gerar os bytes para acionamento do cubo. Para ser usado com o arduino é preciso adaptar o programa ou  usar apenas os bytes do código gerado pelo programa. O segundo projeto, um cubo 8x8, é muito interessante e muito trabalhoso também. Nele o autor mostra passo a passo a construção tanto física como eletrônica do cubo de 512 leds, incluindo lista de componentes e a técnica usada para soldar simetricamente os leds.

Funcionameto

No cubo os leds são organizados em camadas horizontais, de modo que em uma mesma camada todos os catodos sejam unidos, e em colunas, formados pela união dos anodos três a três pelos anodos. Ligando o catodo comum de uma camada ao negativo e o anodo comum de uma coluna ao positivo o led que estiver simultaneamente na camada e na coluna escolhida acenderá.

Como cada coluna (anodos) de três leds é ligada a um pino do arduino (9 pinos) e cada camada (catodos) ligada, através de um transistor a um pino do arduino (3 pinos). Temos a seguinte dinâmica no cubo:

1- Coloca em nível alto o pino do arduino que liga ao GND, através do transistor correspondente, os catodos da camada inferior (camada 0);
2- Colocam-se em nível alto os pinos do arduino ligados aos leds da camada 0 que devem ser acesos;
3- Aguarda o tempo de exibição da camada;
4- Apaga todos os leds;
5- Repetem-se os passos anteriores para as camadas media (camada 1) e superior (camada 2).
Esse processo acontece em velocidade suficiente para parecer que leds de camadas distintas estão acesos simultaneamente.

Se chamarmos frame uma imagem "estática" exibida no cubo que seguida de outras imagens causa o efeito de movimento. O tempo de exibição desse frame é determinado pelo número de vezes que o ciclo citado acima se repete acendendo os mesmos leds nas mesmas camadas. Analisando o programa fica mais fácil entender.

Montagem

Soldar os leds é a parte que requer maior paciência para que fique o mais simétrico possível. Eu usei a técnica mostrada no segundo post mencionado acima. Ele traz muitas fotos que facilitam o entendimento.

O circuito é simples. Na matriz de contatos foram montados os 12 resistores e os 3 transistores BC548. O projeto usa 12 portas do arduino sendo 3 para polarizar os transistores responsáveis pelo GND de cada camada e 9 para as nove linhas verticais de leds.
O circuito completo pode ser visto ao lado. Os resistores ligados às bases dos transistores são de 330R e os demais são de 120R.

O Programa

O programa comentado pode ser visto abaixo.

 int camada[3] ={13,12,11};
int ledPin[9] = {1,2,3,5,6,7,8,9,10};// pinos de dados

byte aux[4] = {B00000000, B00000000, B00000000, B00000000};

                   // camada 0   camada 1  camada 2       
                                                     //012  camada
               //led  01234567   01234567   01234567   888 ultimo led de cada camada
byte efeito1[16] = { B10010010, B01000001, B00100100, B00100000,
                     B00000000, B11110111, B00000000, B01000000,
                     B00100100, B01000001, B10010010, B10000000,
                     B01001001, B01000001, B01001001, B00000000};
                     
byte efeito2[12] = { B11111111, B00000000, B00000000, B10000000,
                     B00000000, B11111111, B00000000, B01000000,
                     B00000000, B00000000, B11111111, B00100000};
                     
byte efeito3[8] = { B01011101, B01011101, B01011101, B00000000,
                    B10101010, B10101010, B10101010, B11100000};
                    
byte efeito4[16] = {B00011011, B00011011, B00011011, B00000000,
                    B11011000, B11011000, B11011000, B00000000,
                    B01101100, B01101100, B01101100, B00000000,
                    B00001101, B00001101, B00001101, B11100000};
                    
byte efeito5[32] = {B11100000, B11100000, B11100000, B00000000,
                    B11100000, B00011100, B00000011, B00100000,
                    B11111111, B00000000, B00000000, B10000000,
                    B00000011, B00011100, B11100000, B10000000,
                    B00000011, B00000011, B00000011, B11100000,
                    B00000011, B00011100, B11100000, B10000000,
                    B11111111, B00000000, B00000000, B10000000,
                    B11100000, B00011100, B00000011, B00100000};
                    
                    
byte efeito6[40] ={B00000011, B00010100, B11100000, B10000000,
                   B10010010, B01000001, B00100100, B00100000,
                   B00000000, B11110111, B00000000, B01000000,
                   B00100100, B01000001, B10010010, B10000000,
                   B01000001, B01000001, B01001001, B00000000,
                   B11100000, B00010100, B00000011, B00100000,
                   B10010010, B01000001, B00100100, B00100000,
                   B00000000, B11110111, B00000000, B01000000,
                   B00100100, B01000001, B10010010, B10000000,
                   B01000001, B01000001, B01001001, B00000000};
                   
byte efeito7[64] ={B10010000,B10010000,B10010000,B00000000,
                   B10001000,B10001000,B10001000,B00000000,
                   B11000000,B11000000,B11000000,B00000000,
                   B01001000,B01001000,B01001000,B00000000,
                   B01100000,B01100000,B01100000,B00000000,
                   B00101000,B00101000,B00101000,B00000000,
                   B00100100,B00100100,B00100100,B00000000,
                   B00001100,B00001100,B00001100,B00000000,
                   B00000100,B00000100,B00000100,B11100000,
                   B00001000,B00001000,B00001000,B11100000,
                   B00000001,B00000001,B00000001,B11100000,
                   B00001001,B00001001,B00001001,B00000000,
                   B00000011,B00000011,B00000011,B00000000,
                   B00001010,B00001010,B00001010,B00000000,
                   B00010010,B00010010,B00010010,B00000000,
                   B00011000,B00011000,B00011000,B00000000};
                    
int i =0;
int j=0;
int a =0;
int frame_time = 10;   // quantidade de iteracoes da cada frame
                                                           
void setup()                   
{
  int i;
  for(i=0;i<3;i++)
  pinMode(camada[i], OUTPUT);  // pinos como saida
  
  for(i=0;i<9;i++)
  pinMode(ledPin[i], OUTPUT);  // pinos como saida

}


void loop() // laço principal
{ 
 cubo(efeito1, 16, 10);  // vetor de efeito, qtd de bytes, numero de repeticoes de exibicao
 cubo(efeito2, 12, 10);
 cubo(efeito3, 8, 10);
 cubo(efeito4, 16, 10); 
 cubo(efeito5, 32, 10);
 cubo(efeito6, 40, 5);
 cubo(efeito7, 64, 10);
 
}  // fim do laço principal

   
 void cubo(byte *efeito, int tamanho, int repet)
 {
    while(repet > 0)
    {
         /* copia os bytes 4 a 4 para o vetor auxilias 
         na primeira iteração copia os 4 primeiros bytes do vetor efeito escolhido
         na segunda os 4 bytes seguintes
         repete até o final do vetor */
         
     for(int cnt1 =0; cnt1 < tamanho;)
      {   
       for(int cnt2 =0; cnt2 < 4; cnt2 ++)  // copia 4 bytes 
        {                                   
         aux[cnt2] = efeito[cnt1];          
         cnt1 ++;                           
        }                           
      mostra_frame();//acende os leds correspondentes aos 4 bytes         
     } 
     repet --;
   }                     
 }
 
                      
  void mostra_frame()
  {
    for(int cnt=0; cnt< frame_time; cnt++)
    {
       for(j=0; j< 3; j++) // seleciona a camada
       {
         digitalWrite(camada[j], HIGH); // polariza o transistor correspondente a camada j 
                                        // o que liga os catodos desta camadaao GND
         for(a=0; a< 8; a++) // verifica bit a bit o byte correspondente a camada ativa 
         {
           if(bitRead(aux[j] , a) == 1)  // se o bit for 1 
             digitalWrite( ledPin[7-a], HIGH); //acende o led correspondente
           else
             digitalWrite( ledPin[7-a], LOW); // se for 0 apaga
    
           if(bitRead(aux[3] , 7-j) == 1)  // verifica o bit do nono led que está no quarto byte
             digitalWrite( ledPin[8], HIGH);
           else
            digitalWrite( ledPin[8], LOW); 
        }
        delay(7);
        digitalWrite(camada[j], LOW);
      }
   }             
 }