// Hemerson David Pabon Martinez
// Erick Alejandro Vega Gomez

// Variables globales para el conteo del reloj
byte segundos;
byte segundos_unidades;
byte segundos_decenas;
byte minutos;
byte minutos_unidades;
byte minutos_decenas;
byte horas;
byte horas_unidades;
byte horas_decenas;
byte dias;
byte dias_unidades;
byte dias_decenas;
byte meses;
byte meses_unidades;
byte meses_decenas;
int years;
int years_unidades;
int years_decenas;
int years_centenas;
int years_miles;


//variable que establece el modo del reloj
byte modo = 0;

int valorPotenciometro;

//Variable para contar ciclos del programa, se usa en la funcion de sinRebote
//para generar el blink
long contador;

// Arreglos de la entrada a los 7 segmentos
byte numeros[] = {
  0b11111100, //0
  0b01100000, //1
  0b11011010, //2
  0b11110010, //3
  0b01100110, //4
  0b10110110, //5
  0b10111110, //6
  0b11100000, //7
  0b11111110, //8
  0b11100110, //9
};

// Arreglo para imprimir las letras
byte letras[] = {  
  0b11101110, //A    0
  0b00111110, //B    1
  0b10011100, //C    2
  0b11111100, //D    3
  0b10011110, //E    4
  0b10001110, //F    5
  0b11110010, //G    6
  0b00001100, //I    7
  0b01110000, //J    8
  0b00011100, //L    9
  0b11101100, //M    10 
  0b11101100, //N    11 
  0b11111100, //O    12
  0b11001110, //P    13  
  0b10001100, //R    14
  0b10110110, //S    15
  0b00011110, //T    16
  0b01111100, //U    17 
  0b01000110, //V    18
  0b11100110, //Y    19

};


// alias para imprimir la combinacion necesaria para representar
// cada numeros
#define cero numeros[0]
#define uno numeros[1]
#define dos numeros[2]
#define tres numeros[3]
#define cuatro numeros[4]
#define cinco numeros[5]
#define seis numeros[6]
#define siete numeros[7]
#define ocho numeros[8]
#define nueve numeros[9]

// alias para los pines de carga serial, shift clock y latch clock
#define DS 5    // Entrada serial
#define STCP 6  // Latch clock
#define SHCP 7  // Shift clock

void setup(){
  Serial.begin(115200);

  // Asignar los pines DS, STCHP, SHCP como salidas
  DDRD = set_HIGH(DDRD, DS);
  DDRD = set_HIGH(DDRD, STCP);
  DDRD = set_HIGH(DDRD, SHCP);

  // pines para que controla los anodos de los 7 segmentos
  DDRD = set_HIGH(DDRD, 2);
  DDRD = set_HIGH(DDRD, 3);
  DDRD = set_HIGH(DDRD, 4);
  DDRB = set_HIGH(DDRB, 0);
  DDRB = set_HIGH(DDRB, 1);
  DDRB = set_HIGH(DDRB, 5);

}


void loop(){

int x;
if (presionaA(PINB) == 1){
  x = comparar(++modo, 7);
  modo *= x;
  convierteuno();
}

 if (modo != 0){
    controlPotenciometro();
  }

// El siguiente switch controla el estado del reloj:
// modo = 0 : El reloj cuenta normalmente
// modo = 1 : Programar segundos
// modo = 2 : Programar minutos
// modo = 3 : Programar horas
// modo = 4 : Programar dias
// modo = 5 : Programar meses
// modo = 6 : Programar años

  switch(modo){

    case 0:
    reloj();
    // Generar el latch clock
    PORTD = set_HIGH(PORTD, STCP);
    PORTD = set_LOW(PORTD, STCP);
    mostrar();
    break;

    case 1:
    // Esta condicional se encargar de generar el BLINK en la variable que 
    // se va a programar
    if (contador_millis(++contador) == 1){
      PORTD = set_HIGH(PORTD, 2);
    }
    else{
      PORTD = set_LOW(PORTD, 2);
    }

    // Estos condicionales detectan si se presiono el boton azul
    // o el boton Rojo y aumentan si se presiono azul o decrementa si se presiono rojo

    if (presionaZ(PINB) == 1){
      segundos++;
    }
    if (presionaR(PINB) == 1){
      segundos--;
    }
    // Esta funcion convierte el valor completo de la variable que se programa
    // a decenas, unidades y guarda esos valores y los parametro 2 y 3 de la funcion
    convertir(segundos, segundos_decenas, segundos_unidades);
    // Generar el latch clock
    PORTD = set_HIGH(PORTD, STCP);
    PORTD = set_LOW(PORTD, STCP);
    // Condicional para que la variable tenga un limite al programarla
    if (segundos > 59){
      segundos = 0;
    } 
    // Llamar la funcion mostrar parar cargar los valores en los displays
    mostrar();  
    break;
    
    case 2: 
    if (contador_millis(++contador) == 1){
      PORTD = set_HIGH(PORTD, 3);
    }
    else{
      PORTD = set_LOW(PORTD, 3);
    }
  

    if (presionaZ(PINB) == 1){
      minutos++;
    }
    if (presionaR(PINB) == 1){
      minutos--;
    }
    convertir(minutos, minutos_decenas, minutos_unidades);
    PORTD = set_HIGH(PORTD, STCP);
    PORTD = set_LOW(PORTD, STCP);
    minutos = (minutos > 59) ? minutos = 1 : minutos = minutos; 
    mostrar();   
    break;

    // caso 3, programa horas
    case 3:
     if (contador_millis(++contador) == 1){
      PORTD = set_HIGH(PORTD, 4);
    }
    else{
      PORTD = set_LOW(PORTD, 4);
    }

    if (presionaZ(PINB) == 1){
      horas++;
    }
    if (presionaR(PINB) == 1){
      horas--;
    }
    convertir(horas, horas_decenas, horas_unidades);
    PORTD = set_HIGH(PORTD, STCP);
    PORTD = set_LOW(PORTD, STCP);
    horas = (horas > 23) ? dias = 1 : horas = horas; 
    mostrar();
    break;

    // caso 4, programa dias
    case 4:
     if (contador_millis(++contador) == 1){
      PORTB = set_HIGH(PORTB, 0);
    }
    else{
      PORTB = set_LOW(PORTB, 0);
    }


    if (presionaZ(PINB) == 1){
      dias++;
    }
    if (presionaR(PINB) == 1){
      dias--;
    }
    convertir(dias, dias_decenas, dias_unidades);
    PORTD = set_HIGH(PORTD, STCP);
    PORTD = set_LOW(PORTD, STCP);
    dias = (dias == 0 | dias > 30) ? dias = 1 : dias = dias; 
    mostrar();
    break;

    //caso 5; programa mes
    case 5:
      if (contador_millis(++contador) == 1){
      PORTB = set_HIGH(PORTB, 1);
    }
    else{
      PORTB = set_LOW(PORTB, 1);
    }


    if (presionaZ(PINB) == 1){
      meses++;
    }
    if (presionaR(PINB) == 1){
      meses--;
    }
    PORTD = set_HIGH(PORTD, STCP);
    PORTD = set_LOW(PORTD, STCP);
    meses = (meses > 11) ? meses = 0 : meses = meses; 
    mostrar();
    break;

    // caso 6: programar años
    case 6:
     if (contador_millis(++contador) == 1){
      PORTB = set_HIGH(PORTB, 5);
    }
    else{
      PORTB = set_LOW(PORTB, 5);
    }

    if (presionaZ(PINB) == 1){
      years++;
    }
    if (presionaR(PINB) == 1){
      years--;
    }
    PORTD = set_HIGH(PORTD, STCP);
    PORTD = set_LOW(PORTD, STCP);
    years = (years > 9999) ? years = 0 : years = years; 
    mostrar();
    break;
  }


}


// La funcion cargar permite cargar un valor de 8 bits al registro serial

void cargar(byte valor){

  PORTD = set_LOW(PORTD, DS);
  PORTD = set_LOW(PORTD, STCP);
  PORTD = set_LOW(PORTD, SHCP);

    byte i = 0;
    while (i <= 7){
      if((valor & 0x01) == 0){
      PORTD = set_LOW(PORTD, DS);
      }
     else{
      PORTD = set_HIGH(PORTD, DS);
     }
      PORTD = set_HIGH(PORTD, SHCP);
      PORTD = set_LOW(PORTD, SHCP);
      valor >>= 1;
      i++;
    }
   }

// Funciones para modificar bits en los registro : 
// la función set_HIGH y set_LOW tiene como parametros el registro para modificar
// y la ubicación del bit a modificar, la función set_HIGH asigna uno y la 
// función set_LOW asgina un cero.

byte set_HIGH(byte registro, byte nroBit){ 
  return registro | (1 << nroBit);  
}

byte set_LOW(byte registro, byte nroBit){
  return registro & ~(1 << nroBit);
}

// Esta funcion compara el parametro var con el limite, si var es igual al limite
// retorna un 0, pero si es menor retorna valor 1 

int comparar(int var, int limite){
  int resta = var + ~(limite) + 1;
  resta = (resta >> 31) & 0x01;
  return resta;
}

// Esta funcion se encarga de carga 15 paquetes de datos de bits hacia los displays,
// cargar los valores de todas las variables de tiempo
void mostrar(){
  cargar(numeros[segundos_unidades]);
  cargar(numeros[segundos_decenas]);
  cargar(numeros[minutos_unidades]);
  cargar(numeros[minutos_decenas]);
  cargar(numeros[horas_unidades]);
  cargar(numeros[horas_decenas]);
  cargar(numeros[dias_unidades]);
  cargar(numeros[dias_decenas]);
  // Esta funcion convierte el valor numerico a un valor en letras que
  // corresponde al mes
  convertir_meses(meses);
  cargar(numeros[years_unidades]);
  cargar(numeros[years_decenas]);
  cargar(numeros[years_centenas]);
  cargar(numeros[years_miles]);
  separar(years, years_unidades, years_decenas, years_centenas, years_miles);
}

// esta funcion se encargar de convertir del dato numerico del mes,
// a un dato en forma de letras correspondiente a cada mes.
void convertir_meses(int mes){
   switch(meses){
    case 0: 
    cargar(letras[4]);
    cargar(letras[11]);
    cargar(letras[4]);
    break;
    case 1:
    cargar(letras[1]);
    cargar(letras[4]);
    cargar(letras[5]);
    break;
    case 2:
    cargar(letras[14]);
    cargar(letras[0]);
    cargar(letras[10]);
    break;
    case 3:
    cargar(letras[14]);
    cargar(letras[1]);
    cargar(letras[0]);
    break;
    case 4:
    cargar(letras[19]);
    cargar(letras[0]);
    cargar(letras[10]);
    break;
    case 5:
    cargar(letras[11]);
    cargar(letras[17]);
    cargar(letras[8]);
    break;
    case 6:
    cargar(letras[9]);
    cargar(letras[17]);
    cargar(letras[8]);
    break;
    case 7:
    cargar(letras[12]);
    cargar(letras[0]);
    cargar(letras[6]);
    break;
    case 8:
    cargar(letras[13]);
    cargar(letras[4]);
    cargar(letras[15]);
    break;
    case 9:
    cargar(letras[16]);
    cargar(letras[2]);
    cargar(letras[12]);
    break;
    case 10:
    cargar(letras[16]);
    cargar(letras[12]);
    cargar(letras[11]);
    break;
    case 11:
    cargar(letras[2]);
    cargar(letras[7]);
    cargar(letras[3]);
    break;
  }
}


// Esta funcion es el reloj, va de años, meses, dias, horas, minutos y segundos.
void reloj(){
 byte x;

 x = comparar(++segundos, 60);
 segundos *= x;
 convertir(segundos, segundos_decenas, segundos_unidades);

 minutos += !x;
 x = comparar(minutos, 60);
 minutos *= x;
 convertir(minutos, minutos_decenas, minutos_unidades);
 
 horas += !x;
 x = comparar(horas, 24);
 horas *= x;  
 convertir(horas, horas_decenas, horas_unidades); 
 
 dias += !x;
 x = comparar(dias, 31);

 // Este condicional sirve para que cuando se resetee el valor de dias,
 // inmediatamente el valor vuelva a 1 ya que cuenta los dias
if (dias == 0){
    dias = 1;
}
 dias *= x;
 convertir(dias, dias_decenas, dias_unidades); 
 
 meses += !x;
 x = comparar(meses, 12);
 meses *= x;
 convertir(meses, meses_decenas, meses_unidades);


 years += !x;
 x = comparar(years, 9999);
 years *= x;
 separar(years, years_unidades, years_decenas, years_centenas, years_miles);

}

// La funcion convertir toma un valor de 2 digitos y los separa, se usa en las 
// variables horas, dias, meses

void convertir(byte valor, byte &masSig, byte &menosSig){
  if (valor < 10 ){
    menosSig = valor;
    masSig = 0;
  }else{
    menosSig = valor % 10;
    masSig = valor / 10;
  }
  valor = (masSig * 10) + menosSig;
}

// Esta funcion realiza la misma tarea de la funcion convertir con la diferencia
// de que se usa sobre la variable de años y separa cuatro digitos

void separar(int numero, int &unidades, int &decenas, int &centenas, int &miles){
  unidades = numero % 10;
  numero /= 10;
  decenas = numero % 10;
  numero /=10;
  centenas = numero % 10;
  numero /=10;
  miles = numero % 10;
}

// Funciones para detectar si el usuario presiono alguna tecla:
// El boton amarillo sirve para cambiar el modo y la variable que se programa
// El boton azul incrementa la variable
// El boton rojo decrementa la variable

byte presionaA(byte pines){
  long antiRebote;
  delay(120);
  return (((PINB & (1 << 4)) == 0) && (millis() - antiRebote) > 200);
}

byte presionaZ(byte pines){
  long antiRebote;
  delay(15);
  return (((PINB & (1 << 3)) == 0) && (millis() - antiRebote) > 200);
}

byte presionaR(byte pines){
  long antiRebote;
  delay(15);
  return (((PINB & (1 << 2)) == 0) && (millis() - antiRebote) > 200);  
}

// Esta funcion es un contador que retorna 1 cada 2 ciclos, se usar para controlar
// el parpadeo de los displays

boolean contador_millis(long y){
  boolean x = !(y % 2);
  return x;
}

// Esta funcion asigna un cero a los pines que van conectados a los catodos
// de los displays 

void convierteuno(){
  PORTD = set_LOW(PORTD, 2);
  PORTD = set_LOW(PORTD, 3);
  PORTD = set_LOW(PORTD, 4);
  PORTB = set_LOW(PORTB, 0);
  PORTB = set_LOW(PORTB, 1);
  PORTB = set_LOW(PORTB, 5);
}

// para controlar 
void controlPotenciometro(){
  valorPotenciometro = analogRead(0);
  if ((valorPotenciometro >= 0) & (valorPotenciometro <= 170)){
    modo = 6;
  }
  if ((valorPotenciometro >= 171) & (valorPotenciometro <= 340)){
    modo = 5;
  }
  if ((valorPotenciometro >= 341) & (valorPotenciometro <= 510 )){
    modo = 4;
  }
  if ((valorPotenciometro >= 511 ) & (valorPotenciometro <= 680 )){
    modo = 3;
  }
  if ((valorPotenciometro >= 681) & (valorPotenciometro <= 850 )){
    modo = 2;
  }
  if ((valorPotenciometro >= 851 ) & (valorPotenciometro <= 1022 )){
    modo = 1;
  }
  if (valorPotenciometro == 1023){
    modo = 0;
  }
  convierteuno();
}
uno:A5.2
uno:A4.2
uno:AREF
uno:GND.1
uno:13
uno:12
uno:11
uno:10
uno:9
uno:8
uno:7
uno:6
uno:5
uno:4
uno:3
uno:2
uno:1
uno:0
uno:IOREF
uno:RESET
uno:3.3V
uno:5V
uno:GND.2
uno:GND.3
uno:VIN
uno:A0
uno:A1
uno:A2
uno:A3
uno:A4
uno:A5
74HC595
sr1:Q1
sr1:Q2
sr1:Q3
sr1:Q4
sr1:Q5
sr1:Q6
sr1:Q7
sr1:GND
sr1:Q7S
sr1:MR
sr1:SHCP
sr1:STCP
sr1:OE
sr1:DS
sr1:Q0
sr1:VCC
74HC595
sr2:Q1
sr2:Q2
sr2:Q3
sr2:Q4
sr2:Q5
sr2:Q6
sr2:Q7
sr2:GND
sr2:Q7S
sr2:MR
sr2:SHCP
sr2:STCP
sr2:OE
sr2:DS
sr2:Q0
sr2:VCC
vcc1:VCC
vcc2:VCC
gnd1:GND
sevseg1:COM.1
sevseg1:COM.2
sevseg1:A
sevseg1:B
sevseg1:C
sevseg1:D
sevseg1:E
sevseg1:F
sevseg1:G
sevseg1:DP
sevseg2:COM.1
sevseg2:COM.2
sevseg2:A
sevseg2:B
sevseg2:C
sevseg2:D
sevseg2:E
sevseg2:F
sevseg2:G
sevseg2:DP
74HC595
sr3:Q1
sr3:Q2
sr3:Q3
sr3:Q4
sr3:Q5
sr3:Q6
sr3:Q7
sr3:GND
sr3:Q7S
sr3:MR
sr3:SHCP
sr3:STCP
sr3:OE
sr3:DS
sr3:Q0
sr3:VCC
vcc3:VCC
sevseg3:COM.1
sevseg3:COM.2
sevseg3:A
sevseg3:B
sevseg3:C
sevseg3:D
sevseg3:E
sevseg3:F
sevseg3:G
sevseg3:DP
74HC595
sr4:Q1
sr4:Q2
sr4:Q3
sr4:Q4
sr4:Q5
sr4:Q6
sr4:Q7
sr4:GND
sr4:Q7S
sr4:MR
sr4:SHCP
sr4:STCP
sr4:OE
sr4:DS
sr4:Q0
sr4:VCC
vcc4:VCC
sevseg4:COM.1
sevseg4:COM.2
sevseg4:A
sevseg4:B
sevseg4:C
sevseg4:D
sevseg4:E
sevseg4:F
sevseg4:G
sevseg4:DP
74HC595
sr5:Q1
sr5:Q2
sr5:Q3
sr5:Q4
sr5:Q5
sr5:Q6
sr5:Q7
sr5:GND
sr5:Q7S
sr5:MR
sr5:SHCP
sr5:STCP
sr5:OE
sr5:DS
sr5:Q0
sr5:VCC
vcc5:VCC
sevseg5:COM.1
sevseg5:COM.2
sevseg5:A
sevseg5:B
sevseg5:C
sevseg5:D
sevseg5:E
sevseg5:F
sevseg5:G
sevseg5:DP
74HC595
sr6:Q1
sr6:Q2
sr6:Q3
sr6:Q4
sr6:Q5
sr6:Q6
sr6:Q7
sr6:GND
sr6:Q7S
sr6:MR
sr6:SHCP
sr6:STCP
sr6:OE
sr6:DS
sr6:Q0
sr6:VCC
vcc6:VCC
sevseg6:COM.1
sevseg6:COM.2
sevseg6:A
sevseg6:B
sevseg6:C
sevseg6:D
sevseg6:E
sevseg6:F
sevseg6:G
sevseg6:DP
74HC595
sr7:Q1
sr7:Q2
sr7:Q3
sr7:Q4
sr7:Q5
sr7:Q6
sr7:Q7
sr7:GND
sr7:Q7S
sr7:MR
sr7:SHCP
sr7:STCP
sr7:OE
sr7:DS
sr7:Q0
sr7:VCC
vcc7:VCC
sevseg7:COM.1
sevseg7:COM.2
sevseg7:A
sevseg7:B
sevseg7:C
sevseg7:D
sevseg7:E
sevseg7:F
sevseg7:G
sevseg7:DP
74HC595
sr8:Q1
sr8:Q2
sr8:Q3
sr8:Q4
sr8:Q5
sr8:Q6
sr8:Q7
sr8:GND
sr8:Q7S
sr8:MR
sr8:SHCP
sr8:STCP
sr8:OE
sr8:DS
sr8:Q0
sr8:VCC
vcc8:VCC
sevseg8:COM.1
sevseg8:COM.2
sevseg8:A
sevseg8:B
sevseg8:C
sevseg8:D
sevseg8:E
sevseg8:F
sevseg8:G
sevseg8:DP
74HC595
sr9:Q1
sr9:Q2
sr9:Q3
sr9:Q4
sr9:Q5
sr9:Q6
sr9:Q7
sr9:GND
sr9:Q7S
sr9:MR
sr9:SHCP
sr9:STCP
sr9:OE
sr9:DS
sr9:Q0
sr9:VCC
vcc9:VCC
sevseg9:COM.1
sevseg9:COM.2
sevseg9:A
sevseg9:B
sevseg9:C
sevseg9:D
sevseg9:E
sevseg9:F
sevseg9:G
sevseg9:DP
74HC595
sr10:Q1
sr10:Q2
sr10:Q3
sr10:Q4
sr10:Q5
sr10:Q6
sr10:Q7
sr10:GND
sr10:Q7S
sr10:MR
sr10:SHCP
sr10:STCP
sr10:OE
sr10:DS
sr10:Q0
sr10:VCC
vcc10:VCC
sevseg10:COM.1
sevseg10:COM.2
sevseg10:A
sevseg10:B
sevseg10:C
sevseg10:D
sevseg10:E
sevseg10:F
sevseg10:G
sevseg10:DP
74HC595
sr11:Q1
sr11:Q2
sr11:Q3
sr11:Q4
sr11:Q5
sr11:Q6
sr11:Q7
sr11:GND
sr11:Q7S
sr11:MR
sr11:SHCP
sr11:STCP
sr11:OE
sr11:DS
sr11:Q0
sr11:VCC
vcc11:VCC
sevseg11:COM.1
sevseg11:COM.2
sevseg11:A
sevseg11:B
sevseg11:C
sevseg11:D
sevseg11:E
sevseg11:F
sevseg11:G
sevseg11:DP
74HC595
sr12:Q1
sr12:Q2
sr12:Q3
sr12:Q4
sr12:Q5
sr12:Q6
sr12:Q7
sr12:GND
sr12:Q7S
sr12:MR
sr12:SHCP
sr12:STCP
sr12:OE
sr12:DS
sr12:Q0
sr12:VCC
vcc12:VCC
sevseg12:COM.1
sevseg12:COM.2
sevseg12:A
sevseg12:B
sevseg12:C
sevseg12:D
sevseg12:E
sevseg12:F
sevseg12:G
sevseg12:DP
74HC595
sr13:Q1
sr13:Q2
sr13:Q3
sr13:Q4
sr13:Q5
sr13:Q6
sr13:Q7
sr13:GND
sr13:Q7S
sr13:MR
sr13:SHCP
sr13:STCP
sr13:OE
sr13:DS
sr13:Q0
sr13:VCC
vcc13:VCC
sevseg13:COM.1
sevseg13:COM.2
sevseg13:A
sevseg13:B
sevseg13:C
sevseg13:D
sevseg13:E
sevseg13:F
sevseg13:G
sevseg13:DP
74HC595
sr14:Q1
sr14:Q2
sr14:Q3
sr14:Q4
sr14:Q5
sr14:Q6
sr14:Q7
sr14:GND
sr14:Q7S
sr14:MR
sr14:SHCP
sr14:STCP
sr14:OE
sr14:DS
sr14:Q0
sr14:VCC
vcc14:VCC
sevseg14:COM.1
sevseg14:COM.2
sevseg14:A
sevseg14:B
sevseg14:C
sevseg14:D
sevseg14:E
sevseg14:F
sevseg14:G
sevseg14:DP
74HC595
sr15:Q1
sr15:Q2
sr15:Q3
sr15:Q4
sr15:Q5
sr15:Q6
sr15:Q7
sr15:GND
sr15:Q7S
sr15:MR
sr15:SHCP
sr15:STCP
sr15:OE
sr15:DS
sr15:Q0
sr15:VCC
vcc15:VCC
sevseg15:COM.1
sevseg15:COM.2
sevseg15:A
sevseg15:B
sevseg15:C
sevseg15:D
sevseg15:E
sevseg15:F
sevseg15:G
sevseg15:DP
btn1:1.l
btn1:2.l
btn1:1.r
btn1:2.r
btn2:1.l
btn2:2.l
btn2:1.r
btn2:2.r
btn3:1.l
btn3:2.l
btn3:1.r
btn3:2.r
r1:1
r1:2
r2:1
r2:2
r3:1
r3:2
vcc16:VCC
pot1:VCC
pot1:SIG
pot1:GND
vcc17:VCC
gnd2:GND