// O monitor mais simples do mundo, by DANTE MEIRA
// (World's simplest monitor)
// Sem bibliotecas, sem "drivers", uma saída de "vídeo" feita bit a bit.
// Programado em C puro, sem as funções da biblioteca do Arduino como
// setup(), loop() e digitalWrite(). Timer e portas de saída configurados
// diretamente nos registradores do ATmega328. O "monitor" é controlado por
// sete registradores de deslocamento (shift registers), um para cada linha.

#define ACESO true
#define APAGADO false

#define NUM_REGISTRADORES_DE_DESLOCAMENTO 7   // se mudar o número de shift registers basta mudar aqui
const uint8_t quantidadeLEDs = NUM_REGISTRADORES_DE_DESLOCAMENTO * 8; // LEDS = registers vezes 8
bool framebuffer[quantidadeLEDs]; // array de boolean para funcionar como "memória de vídeo" (um framebuffer)

const int DATA_PIN = PD2; // conecta ao pino DS
const int CLOCK_PIN = PD3; // conecta ao pino SHCP 
const int LATCH_PIN = PD4; // conecta ao pino STCP 

unsigned long counter = 0;

int main() {
 
 DDRD |= (B00000001 << DATA_PIN); // colocando DATA_PIN em modo OUTPUT direto no registrador DDRD
 DDRD |= (B00000001 << CLOCK_PIN); // colocando CLOCK_PIN em modo OUTPUT direto no registrador DDRD
 DDRD |= (B00000001 << LATCH_PIN); // colocando CLOCK_PIN em modo OUTPUT direto no registrador DDRD

  TCCR1A = 0;

 // colocando o timer no modo CTC (Clear Timer on Compare-match)
  TCCR1B &= ~(1 << WGM13);
  TCCR1B |= (B00000001 << WGM12);

 // setando prescaler do timer para 64 (16 mHz / 64 = 250 kHz)
  TCCR1B &= ~(1 << CS12);
  TCCR1B |= (1 << CS11);
  TCCR1B |= (1 << CS10);

  TCNT1 = 0;
  OCR1A = 2500; // um centésimo de 250 mil para o Compare-match

  TIMSK1 = (1 << OCIE1A);

  sei(); // habilita interrupções

  while(true){  // substituto do loop() vazio
        
  }

}


ISR(TIMER1_COMPA_vect){ // Rotina de Serviço de Interrupção (ISR) do Timer
    counter++;
    Condicionais();          
    Rasterizar();
}

void Rasterizar() {

  PORTD &= ~(B00000001 << LATCH_PIN); // colocando o LATCH em LOW direto no registrador PORTD
    for (int i = quantidadeLEDs - 1; i >= 0; i--) {      
      PORTD &= ~(B00000001 << CLOCK_PIN); // colocando o CLOCK em LOW direto no registrador PORTD

      if(framebuffer[i]){ // se true (aceso)
            PORTD |= (B00000001 << DATA_PIN); // colocando o DATA PIN em HIGH direto no registrador PORTD
      }else{ // se false (apagado)
            PORTD &= ~(B00000001 << DATA_PIN); // colocando o DATA PIN em LOW direto no registrador PORTD
      }  

       PORTD |= (B00000001 << CLOCK_PIN); // colocando o CLOCK em HIGH direto no registrador PORTD    
    }
   PORTD |= (B00000001 << LATCH_PIN); // colocando o LATCH em HIGH direto no registrador PORTD

}

void AcendeTudo(){
    for (int i = quantidadeLEDs - 1; i >= 0; i--) {
    framebuffer[i] = ACESO;
  }
}

void ApagaTudo() {
  for (int i = quantidadeLEDs - 1; i >= 0; i--) {
    framebuffer[i] = APAGADO;
  }
}

void mudaPixel(int index, int value) {
  framebuffer[index] = value;
}

void Condicionais(){
  if(counter == 50){        
        EscreveLetra('D');        
     } 
  if(counter == 80){        
        ApagaTudo() ;     
     }   
    if(counter == 110){        
        EscreveLetra('D');        
     } 
  if(counter == 140){        
        ApagaTudo() ;     
     } 
  if(counter == 170){        
       EscreveLetra('D');       
     } 

   if(counter == 270){        
        ApagaTudo() ;     
     } 

   if(counter == 350){        
         EscreveLetra('A');     
     } 
   
    if(counter == 380){        
        ApagaTudo() ;     
     } 
     if(counter == 410){        
         EscreveLetra('A');     
     } 
   if(counter == 440){        
        ApagaTudo() ;     
     } 
     if(counter == 470){        
         EscreveLetra('A');     
     } 

       if(counter == 570){        
          ApagaTudo() ;      
     } 

      if(counter == 640){        
         EscreveLetra('N');         
     } 
     if(counter == 670){        
          ApagaTudo() ;      
     } 
     if(counter == 700){        
         EscreveLetra('N');         
     }
     if(counter == 730){        
          ApagaTudo() ;      
     }  
      if(counter == 760){        
         EscreveLetra('N');         
     }

    if(counter == 860){        
          ApagaTudo() ;      
     }  

      if(counter == 930){        
         EscreveLetra('T');         
     }

    if(counter == 960){        
          ApagaTudo() ;      
     }  

  if(counter == 990){        
         EscreveLetra('T');         
     }

    if(counter == 1020){        
          ApagaTudo() ;      
     }  

    if(counter == 1050){        
         EscreveLetra('T');         
     }

      if(counter == 1150){        
          ApagaTudo() ;      
     }  

      if(counter == 1220){        
         EscreveLetra('E');         
     }
     if(counter == 1250){        
          ApagaTudo() ;      
     }  
     if(counter == 1280){        
         EscreveLetra('E');         
     }
    
     if(counter == 1310){        
          ApagaTudo() ;      
     } 
    if(counter == 1340){        
         EscreveLetra('E');         
     }

       if(counter == 1540){        
         ApagaTudo() ;         
     }

     if(counter == 1600){        
         EscreveLetra('D');         
     }
     
      if(counter == 1650){  
         ApagaTudo() ;       
         EscreveLetra('A');         
     }
     if(counter == 1700){  
        ApagaTudo() ;       
         EscreveLetra('N');         
     }

    if(counter == 1750){  
        ApagaTudo() ;       
         EscreveLetra('T');         
     }
  
    if(counter == 1800){  
        ApagaTudo() ;       
         EscreveLetra('E');         
     }

     if(counter == 1900){  
        ApagaTudo() ;              
     }

    if(counter == 2000){  
       counter = 0;             
     }


}


void EscreveLetra(char letra){
    if(letra == 'A'){
        
      for(byte n = 10; n <= 13; n++){
           mudaPixel(n, ACESO);
      }  

      for(byte n = 26; n <= 29; n++){
           mudaPixel(n, ACESO);
      } 

       mudaPixel(17, ACESO);
       mudaPixel(22, ACESO);
       mudaPixel(25, ACESO);
       mudaPixel(30, ACESO);
       mudaPixel(33, ACESO);
       mudaPixel(38, ACESO);
       mudaPixel(41, ACESO);
       mudaPixel(46, ACESO);
        
  }

  if(letra == 'D'){
        
      for(byte n = 9; n <= 13; n++){
           mudaPixel(n, ACESO);
      }  

       mudaPixel(19, ACESO);
       mudaPixel(22, ACESO);
       mudaPixel(27, ACESO);
       mudaPixel(30, ACESO);
       mudaPixel(35, ACESO);
       mudaPixel(38, ACESO);

      for(byte n = 41; n <= 45; n++){
           mudaPixel(n, ACESO);
      }      
  }

   if(letra == 'E'){
        
      for(byte n = 9; n <= 13; n++){
           mudaPixel(n, ACESO);
      }  
     mudaPixel(17, ACESO);
     for(byte n = 25; n <= 29; n++){
           mudaPixel(n, ACESO);
      } 
     mudaPixel(33, ACESO);
      for(byte n = 41; n <= 45; n++){
           mudaPixel(n, ACESO);
      }      
  }

   if(letra == 'N'){
        
       mudaPixel(9, ACESO);
       mudaPixel(14, ACESO);
       mudaPixel(17, ACESO);
       mudaPixel(18, ACESO);
       mudaPixel(22, ACESO);
       mudaPixel(25, ACESO);
       mudaPixel(27, ACESO);
       mudaPixel(30, ACESO);
       mudaPixel(33, ACESO);
       mudaPixel(36, ACESO);
       mudaPixel(38, ACESO);
       mudaPixel(41, ACESO);
       mudaPixel(45, ACESO);
       mudaPixel(46, ACESO);
        
  }

      if(letra == 'T'){
        
      for(byte n = 10; n <= 14; n++){
           mudaPixel(n, ACESO);
      }  


       mudaPixel(20, ACESO);       
       mudaPixel(28, ACESO);     
       mudaPixel(36, ACESO);      
       mudaPixel(44, ACESO);
      
        
  }
}
74HC595
74HC595
74HC595
74HC595
74HC595
74HC595
74HC595