// Entrada e Saída (E/S) bidimensionais programadas no baixo nível

boolean aceso1 =  false;
boolean aceso2 =  false;
boolean aceso3 =  false;
boolean aceso4 =  false;
boolean aceso5 =  false;
boolean aceso6 =  false;
boolean aceso7 =  false;
boolean aceso8 =  false;
boolean aceso9 =  false;

unsigned long ultimaVezQueMudouEsq = 0;
unsigned long ultimaVezQueMudouDir = 0;
unsigned long ultimaVezQueMudouCima = 0;
unsigned long ultimaVezQueMudouBaixo = 0;

unsigned long centesimos = 0; // centésimos de segundo desde que o sistema foi iniciado

int pos = 5; //posição do "cursor"

int main() {

     asm("cli \n");   
 
     DDRD |= (B00000001 << DDD2); // pino 2 OUTPUT 
     DDRD |= (B00000001 << DDD3); // pino 3 OUTPUT
     DDRD |= (B00000001 << DDD4); // pino 4 OUTPUT
     DDRD |= (B00000001 << DDD5); // pino 5 OUTPUT 
     DDRD |= (B00000001 << DDD6); // pino 6 OUTPUT 
     DDRD |= (B00000001 << DDD7); // pino 7 OUTPUT      

     DDRB |= (B00000001 << DDB2); // pino 10 OUTPUT 
     DDRB |= (B00000001 << DDB3); // pino 11 OUTPUT 
     DDRB |= (B00000001 << DDB4); // pino 12 OUTPUT 

     DDRC &= ~(B00000001 << DDC0); // pino A0 input
     PORTC |= (B00000001 << PORTC0);  // pino A0 pullup
     DDRC &= ~(B00000001 << DDC1);   // pino A1 input
     PORTC |= (B00000001 << PORTC1); // pino A0 pullup
     DDRC &= ~(B00000001 << DDC2); // pino A2 input
     PORTC |= (B00000001 << PORTC2);  // pino A2 pullup
     DDRC &= ~(B00000001 << DDC3);   // pino A3 input
     PORTC |= (B00000001 << PORTC3); // pino A3 pullup
    
     TCCR1A = 0;  // limpando registrador TCCR1A

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

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

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

     TIMSK1 = (1 << OCIE1A);

    asm("sei \n");    

     while(true)   {
         // só se o pino A0 (pino 0 da porta C) estiver LOW      
         if(~(PINC) & (B00000001 << PC0)){
            //debounce de 15 centésimos de segundo
            if( (centesimos - ultimaVezQueMudouEsq) > 15 ){
               ultimaVezQueMudouEsq = centesimos;
               if( !((pos % 3)==1) ){ pos = pos-1; } 
            }
            
         }
         
         //  só se o pino A1 (pino 1 da porta C) estiver LOW  
         if(~(PINC) & (B00000001 << PC1)){
            //debounce de 15 centésimos de segundo
            if( (centesimos - ultimaVezQueMudouDir) > 15 ){
               ultimaVezQueMudouDir = centesimos;
               if( !((pos % 3)==0) ){ pos = pos+1; } 
            }
            
         }

         //  só se o pino A2 (pino 2 da porta C) estiver LOW  
         if(~(PINC) & (B00000001 << PC2)){
            //debounce de 15 centésimos de segundo
            if( (centesimos - ultimaVezQueMudouCima) > 15 ){
               ultimaVezQueMudouCima = centesimos;
               if(pos > 3){ pos = pos-3; } 
            }
            
         }

         //  só se o pino A3 (pino 3 da porta C) estiver LOW  
         if(~(PINC) & (B00000001 << PC3)){
            //debounce de 15 centésimos de segundo
            if( (centesimos - ultimaVezQueMudouBaixo) > 15 ){
               ultimaVezQueMudouBaixo = centesimos;
               if(pos < 7){ pos = pos+3; } 
            }
            
         }

         switch(pos){
            case 1:
               aceso1 = true;
               aceso2 = false;
               aceso4 = false;
            break;
            case 2:
               aceso1 = false;
               aceso2 = true;
               aceso3 = false;        
               aceso5 = false; 
            break;
            case 3:            
               aceso2 = false;
               aceso3 = true; 
               aceso6 = false;        
            break;  
            case 4:
               aceso1 = false;
               aceso4 = true; 
               aceso5 = false;  
               aceso7 = false;       
            break;  
            case 5:
               aceso2 = false;
               aceso4 = false;
               aceso5 = true;   
               aceso6 = false;   
               aceso8 = false;   
            break;  
            case 6:
               aceso3 = false;
               aceso5 = false;
               aceso6 = true;  
               aceso9 = false;       
            break;   
            case 7:
               aceso4 = false;          
               aceso7 = true;
               aceso8 = false;        
            break;   
            case 8:
               aceso5 = false;           
               aceso7 = false;
               aceso8 = true;
               aceso9 = false;           
            break;   
            case 9:
            aceso6 = false;            
            aceso8 = false;
            aceso9 = true;          
            break;                                                                             
         }


            if(aceso1){
               PORTD |= (B00000001 << PORTD5); // coloca em HIGH
               }else{
               PORTD &= ~(B00000001 << PORTD5); // coloca em LOW
            }

            if(aceso2){
               PORTD |= (B00000001 << PORTD2); // coloca em HIGH
               }else{
               PORTD &= ~(B00000001 << PORTD2); // coloca em LOW
            }  

            if(aceso3){
               PORTD |= (B00000001 << PORTD7); // coloca em HIGH
               }else{
               PORTD &= ~(B00000001 << PORTD7); // coloca em LOW
            }   

         if(aceso4){
               PORTB |= (B00000001 << PORTB4); // coloca em HIGH
               }else{
               PORTB &= ~(B00000001 << PORTB4); // coloca em LOW
            }

            if(aceso5){
               PORTB |= (B00000001 << PORTB3); // coloca em HIGH
               }else{
               PORTB &= ~(B00000001 << PORTB3); // coloca em LOW
            }  

            if(aceso6){
               PORTB |= (B00000001 << PORTB2); // coloca em HIGH
               }else{
               PORTB &= ~(B00000001 << PORTB2); // coloca em LOW
            }  

            if(aceso7){
               PORTD |= (B00000001 << PORTD6); // coloca em HIGH
               }else{
               PORTD &= ~(B00000001 << PORTD6); // coloca em LOW
            }
            
            if(aceso8){
               PORTD |= (B00000001 << PORTD4); // coloca em HIGH
            }else{
               PORTD &= ~(B00000001 << PORTD4); // coloca em LOW
            } 

            if(aceso9){
               PORTD |= (B00000001 << PORTD3); // coloca em HIGH
            }else{
               PORTD &= ~(B00000001 << PORTD3); // coloca em LOW
            }          
     }
      
}

ISR(TIMER1_COMPA_vect){ // Rotina de Serviço de Interrupção (ISR) do Timer
    centesimos++; // incrementa o contador de centésimos de segundo
}