/*
RASTERIZAÇÃO DE MATRIZ PASSIVA DE LEDs RGB, COM POLOS
POSITIVOS RGB DE CADA LINHA LIGADOS EM SÉRIE E POLOS
NEGATIVOS DE CADA COLUNA TAMBÉM LIGADOS EM SÉRIE.

Utilizando portas AND para multiplicar a quantidade de LEDs
mantendo a mesma quantidade de pinos usados como terra (todos
na porta D), criando "setores" de 8 colunas cada um
*/

#define dataPoloPositivo 11
#define latchPoloPositivo 12
#define clockPoloPositivo 13

#define vermelho 3
#define verde 2
#define azul 1
#define apagado 0
#define amarelo 4
#define ciano 5
#define magenta 6
#define branco 7

/*
intervalo de tempo em milisegundos para rasterização de
cada coluna, quando o valor é muito baixo as cores ficam
mais pálidas porque o LED fica muito pouco tempo aceso
*/
int TempoPorColuna = 200;

boolean bitsPoloPositivo[12];
byte Pixels[64];

void setup() {
 pinMode(8, OUTPUT);
 pinMode(9, OUTPUT);
 pinMode(10, OUTPUT);
 pinMode(11, OUTPUT); 
 pinMode(12, OUTPUT); 
 pinMode(13, OUTPUT); 
}

void loop() {
      for (int x = 0; x < 32 ; x++){
        Pixels[x] = vermelho;
     }    
      for (int x = 32; x < 64 ; x++){
        Pixels[x] = verde;
     }   
   RasterizaFrame();

      for (int x = 0; x < 32 ; x++){
        Pixels[x] = amarelo;
     }    
      for (int x = 32; x < 64 ; x++){
        Pixels[x] = azul;
     }   
   RasterizaFrame();
}

void RasterizaFrame(){
   AtivaSetorEsquerdo(); 

   for(int i = 7; i >= 0; i--){
      LeftShiftDDRD(i); // ativa polo negativo da coluna
      for (int n = 0; n < 4 ; n++){
               EnviaPixel( (n*16)+(7-i) );
     }                         
      delay(TempoPorColuna);
      LimpaBitsPoloPositivo();
   }


AtivaSetorDireito(); 

  for(int i = 7; i >= 0; i--){
      LeftShiftDDRD(i); // ativa polo negativo da coluna
      for (int n = 0; n < 4 ; n++){
               EnviaPixel( (n*16)+(15-i) );
      }                       
      delay(TempoPorColuna);
      LimpaBitsPoloPositivo();
   }
}


//função que coloca os pinos selecionados em modo OUTPUT 
//para servirem de GND para as colunas
void LeftShiftDDRD(byte num){
   DDRD = B00000000;
   DDRD |= (B00000001 << num);   
}

void AtivaSetorEsquerdo(){
   digitalWrite(8, HIGH);
   digitalWrite(9, LOW);
}

void AtivaSetorDireito(){
   digitalWrite(8, LOW);
   digitalWrite(9, HIGH);
}

void EnviaPixel(byte pixel){
  byte cor = Pixels[pixel];
  int linha = (pixel/16) + 1;
  switch(cor){
     case vermelho:
        AtivaLinha(linha, vermelho);
     break;
     case verde:
        AtivaLinha(linha, verde);
     break;     
     case azul:
        AtivaLinha(linha, azul);
     break;  
     case amarelo:
        AtivaLinha(linha, vermelho);
        AtivaLinha(linha, verde);
     break; 
     case ciano:
        AtivaLinha(linha, verde);
        AtivaLinha(linha, azul);
     break;    
     case magenta:
        AtivaLinha(linha, vermelho);
        AtivaLinha(linha, azul);
     break;   
     case branco:
        AtivaLinha(linha, vermelho);
        AtivaLinha(linha, verde);
        AtivaLinha(linha, azul);
     break;    
     case apagado:
        
     break;                          
  }
}

void AtivaLinha(int numlinha, int cor){
    int i = (3 * numlinha) - cor;
    bitsPoloPositivo[i] = true;
    EnviaBitsPoloPositivo();
}

void LimpaBitsPoloPositivo(){
     for (int i = 11; i >=0; i--){      
       bitsPoloPositivo[i] = false;
     }
   EnviaBitsPoloPositivo();
}

void EnviaBitsPoloPositivo(){
     digitalWrite(latchPoloPositivo, LOW);

     for (int i = 11; i >=0; i--){       
         if ( bitsPoloPositivo[i] ){
            digitalWrite(dataPoloPositivo, HIGH);
         }else{
            digitalWrite(dataPoloPositivo, LOW);
         }
           digitalWrite(clockPoloPositivo, HIGH);
           digitalWrite(clockPoloPositivo, LOW);
     }

     digitalWrite(latchPoloPositivo, HIGH);
     digitalWrite(latchPoloPositivo, LOW);
  }
74HC595
74HC595