#include <Wire.h>
#define servo 2
int conC=0;  
int conD=0;
int conU=0;
int ren[]={27,14,12,13}; //pines para los renglones
int colum[]={32,33,25,26};//pines para las columnas
int esp=20;
int angulo=0;
int posi=0;
byte johnson;
byte tecla;
byte col=0x0f;
byte PCF_addr=0x27; //direccion para la lcd 
byte uni=0;
byte dec=0;
byte cen=0;
bool teclaActiva=0;
bool rw=0; //lcd
bool rs;//lcd
bool LED=1;//lcd
char conf []={3, 3, 3, 2, 2, 8, 0, 14, 0, 1, 0, 6}; //configuración para la lcd
char tiempos []={15, 5, 1, 1, 1, 1, 1, 1};
char msj1[] = {"Ang.Deseado= "}; //para la lcd
char msj2[] = {"Ang.Real= "}; //para lcd

hw_timer_t*timer= NULL; //inicializador del timer para el contador johnnson

void setup(){
  pinMode(servo, OUTPUT);
  Serial.begin(9600);

  for (byte i=0;i<=3;i++){
    pinMode(ren[i],OUTPUT);
    pinMode(colum[i],INPUT_PULLUP);
  }

    //Poner el contador johnson en su valor inicial
  johnson=0xfe;
  timer=timerBegin(0,80,true);
  timerAttachInterrupt(timer,cnt_johnson,true);
  timerAlarmWrite(timer,20000,true);
  timerAlarmEnable(timer);

    //Configuración de LCD
  Wire.begin();
  rs=0;
  for(byte i=0; i<=11; i++){   
    delay(tiempos[i]);
    send_Nibble(conf[i],LED,rs,rw);
  }
  //Configuración de mensaje 1 PARA LA LCD
  rs=1;
  for(byte i=0; i<=13; i++){
  send_byte(msj1[i]);
  }
   
   //Configuración de mensaje 2 y posicionar LCD en segunda linea
   rs=0;
  send_byte(0xc0);
  rs=1;
  for(byte i=0; i<=10; i++){
  send_byte(msj2[i]);
  }

}
//funcion para detectar teclados
  void cnt_johnson(){
   col=(digitalRead(colum[3])<<3)|(digitalRead(colum[2])<<2)|(digitalRead(colum[1])<<1)|(digitalRead(colum[0]));

   if (col == 0x0f){
    byte m,j,i;
    teclaActiva = 0;
    johnson= (johnson << 1)| 0x01;
    //Regresar el contador johnson a su valor inicial
    if(johnson == 0xef)
    johnson= 0xfe;
    m= 3;
    for(i=0; i <=3 ; i++){
      j=pow(2,m);
      digitalWrite(ren[i],(johnson & j));
      m--;
    }

   }

}

//funcion para enviar los nibbles para lcd
  void send_byte(char N){
   byte carac= N >> 4;
   send_Nibble(carac, LED, rw, rs);
   send_Nibble(N, LED, rw, rs);
}
//para la lecd 
  void send_Nibble(byte N, byte L, byte W, byte S) {
 
  byte dato=(N << 4) | (L << 3) | 0x04 | (W << 2) | S;
  Wire.beginTransmission(PCF_addr);
  Wire.write(dato);
  Wire.endTransmission();
  delay(10);

  dato= dato & 0xfb;
  Wire.beginTransmission(PCF_addr);
  Wire.write(dato);
  Wire.endTransmission();

}
  //para el movimiento del servo
  void movi(int pin, int an){
    float pul;
    pul=an * 1800.0/180.0 + 500;
    digitalWrite(pin, HIGH);
    delayMicroseconds(pul);
    digitalWrite(pin, LOW);
  }


  void loop(){
   if(col != 0x09){   // bandera
    //No repetir el número si la tecla sigue presionada
    if(teclaActiva == 0){
      teclaActiva=1;
    //Recorrer los 4 bits utilizables del contador johnson y agregar los de las columnas para iniciar el switch
      byte rengcol=(johnson << 4) | col;
      switch(rengcol){
        
        //La letra A funciona como nuestro boton de enter
        case 0b11101110: //la letra A

         //Juntamos centenas, decenas y unidades en una variable para tenerlos como un solo número
         angulo=cen*100+dec*10+uni;

         //Empezar con el incremento del contador para cuando se ponga un número mas grande que el anterior
         if(angulo>=posi){
          for(int i=posi;i<=angulo;i++){
            movi(servo, i);
            delay(esp);
            rs=0;
            send_byte(0xcc);
            rs=1;

            if (conC == 0){
              send_byte(0x20);
            }
            else{
              send_byte(0x30 | conC);
            }

            if ((conC == 0) && (conD == 0)){
              send_byte(0x20);
            }
            else{
              send_byte(0x30 | conD);
            }
            send_byte(0x30 | conU);
            conU++;
            
            //Cuando las unidades lleguen a 9 se regresan a 0 y comienza el incremento de una decena
            if(conU > 9){
              conD++;
              conU=0;
            }
            //Cuando las decenas lleguen a 9 se regresan a 0 y comienza el incremento de las centenas
            if(conD > 9){
              conC++;
              conD=0;
            }
          }
         }

        //Empezar con el decremento del contador para cuando se ponga un número mas chico que el anterior
         if(angulo<=posi) {
          for(int i = posi; i >= angulo; i--) {
            movi(servo, i); 
            delay(esp);      
            rs=0;
            send_byte(0xcc);
            rs=1;

            if(conC == 0){
            send_byte(0x20);
            }
            else{
            send_byte(0x30 | conC);
            }

            if ((conC == 0) && (conD == 0)){
            send_byte(0x20);
            }
            else{
            send_byte(0x30 | conD);
            }
            send_byte(0x30 | conU);

            conU--;
            
            //Cuando las unidades lleguen a 0 se le da el valor de 9 y las decenas decrementan un numero
            if (conU < 0) {
            conD--;
            conU = 9;
            }
            //Cuando las decenas lleguen a cero 
            if (conD < 0) {
            conC--;
            conD = 9;
              }
            } 
          }
          posi=angulo;

        break;

      case 0b11101101: //numero 3
       cen=dec;
       dec=uni;
       uni=0x03;
      break;

      case 0b11101011: //para el numero 2
       cen=dec;
       dec=uni;
       uni=0x02;
      break;

      case 0b11100111: //numero 1
       cen=dec;
       dec=uni;
       uni=0x01;
      break;

      case 0b11011110: //letra B
       tecla=0x0b;
      break;

      case 0b11011101: //Par numero 6
       cen=dec;
       dec=uni;
       uni=0x06;
      break;

      case 0b11011011: // para el numero 5
       cen=dec;
       dec=uni;
       uni=0x05;
      break;

      case 0b11010111: //para el numero 4
       cen=dec;
       dec=uni;
       uni=0x04;
      break;
    
    //Cuando se presiona la tecla C se borran los datos
      case 0b10111110: 
       cen=0;
       dec=0;
       uni=0;
      break; 

      case 0b10111101: //para el numero 9
       cen=dec;
       dec=uni;
       uni=0x09;
      break;

      case 0b10111011: // para el numero 8
       cen=dec;
       dec=uni;
       uni=0x08;
      break;
 
      case 0b10110111: // para el numero 7
       cen=dec;
       dec=uni;
       uni=0x07;
      break;  

      case 0b01111110: //Para La letra D
       tecla=0x0d;
      break;

      case 0b01111101:  //para el #
       tecla=0x0f;
      break;

      case 0b01111011: //para el numero cero
       cen=dec;
       dec=uni;
       uni=0x00;
      break;

      case 0b01110111: //para el *
       tecla=0x0e;
      break;
      }
    }
   }
   // logica para mover ceros y unos, decenas y unidades segun lo indicadp-----------------------------
   rs=0;
  send_byte(0x8c);
  rs=1;
  //Si las centenas son cero dejar un espacio
      if(cen==0){
        send_byte(0x20);
        }
      else{
        send_byte(0x30|cen);
        }
    //Si las centenas y decenas son cero dejar un espacio
      if((cen==0) && (dec==0)){
        send_byte(0x20);
        }
      else{
        send_byte(0x30|dec);
        }
      send_byte(0x30|uni);
      send_byte(0b11011111);
//-------------------------------------------------------------------------------------------------------
   

}