#include <16F877A.h>
#use delay(clock=4000000)
#fuses XT, NOPROTECT, NOPUT, NOWDT, NOBROWNOUT, NOLVP, NOCPD
#use I2C(MASTER,SDA=PIN_C4,SCL=PIN_C3,SLOW)
#use rs232 (baud=9600, xmit = PIN_C6, rcv = PIN_C7)

#define escribir_reloj 0b10100000      //0xA0
#define leer_reloj 0b10100001          //0xA1

 struct Hora
{
   byte horas;
   byte minutos;
   byte segundos;
};

struct Hora h;

struct Alarma
{
   byte horas;
   byte minutos;
   byte segundos;
};

struct Alarma a;

//    Funcion para pasar de binario puro a BCD
//       (los datos del reloj estan en BCD)

byte bin_a_bcd(byte binario)
{
   return (((binario/10) << 4) + binario%10);
}

//    Funcion para pasar de BCD a binario puro
//       (los datos del reloj estan en BCD)

byte bcd_a_bin(byte bcd)
{
   return (((bcd >> 4)*10) + (bcd & 0x0F));
}

//Función para escribir en el registro de control

void registro_control(byte dato)
{
   i2c_start();
   i2c_write(escribir_reloj),
   i2c_write(0x00);
   i2c_write(dato);
   i2c_stop();
}

// Funcion para leer un byte del reloj mediante bus i2c

byte leer_byte(byte direccion)
{
   byte dato;

      i2c_start();
      i2c_write(escribir_reloj);
      i2c_write(direccion);
      i2c_start();
      i2c_write(leer_reloj);

      dato=i2c_read(0);
      i2c_stop();

   return dato;
}

// Funcion para leer el reloj: horas minutos y segundos
// Estos datos estan almacenados en estructuras.

void leer_todo_el_reloj(struct Hora *h)
{
   byte dato;

      dato = leer_byte(0x02);   //leemos los segundos
      h->segundos = bcd_a_bin(dato); //lo pasamos de bcd  binario y almacenamos
      dato = leer_byte(0x03);   //leer minutos
      h->minutos = bcd_a_bin (dato);
      dato = leer_byte(0x04);   //horas
      h->horas = bcd_a_bin(dato & 0x3f);

   i2c_stop();
}

//    Funcion para poner en hora el reloj, se le pasa fecha y hora y
//       lo escribe en el reloj, mediante bus i2c

void escribir_en_reloj(struct Hora *h)
{
   byte dato=0;

      i2c_start();
      i2c_write(escribir_reloj);
      i2c_write(0x01);
      i2c_write(dato);     //centesimas de segundo a cero...por defecto


      dato = bin_a_bcd(h->segundos);
      i2c_write(dato);

      dato = bin_a_bcd(h->minutos);
      i2c_write(dato);

      dato = bin_a_bcd(h->horas);
      i2c_write(dato);

   i2c_stop();

}

//  Función para configurar una alarma diaria, 
//   para cambiar el tipo de alarma, se puede modificar el reg de alarmas (0x08)
//  También se pueden añadir parámetros como día de la semana, mes, año

void escribir_alarma (struct Alarma *a)
{
   byte dato=0;

      registro_control(0x04);   //Registro de control de alarmas habilitado
      i2c_start();
       i2c_write(escribir_reloj);
       i2c_write(0x08); //dirección de reg de control de alarmas
       i2c_write(0b10010000); //Daily alarm habilitada
      i2c_write(dato); // Cent de segundo
   
      dato = bin_a_bcd(a->segundos);
         i2c_write(dato);

         dato = bin_a_bcd(a->minutos);
         i2c_write(dato);

         dato = bin_a_bcd(a->horas);
         i2c_write(dato);
   
    i2c_stop();

}

 
 void main () 
           // La explicación de cada función está en su definición 
 {

   byte status, alarm;

    h.horas=23;  h.minutos=59;  h.segundos=50; 
    
    escribir_en_reloj(&h);    //rutina para escribir en el PCF8583
   
   a.horas=0;  a.minutos=0;  h.segundos=00;
   
   escribir_alarma (&a);
   

   alarm=leer_byte(0x08);
   printf("\n alarm->%X  " ,alarm); //para visualizar el valor del reg de alarmas

      while(1)
         {
            leer_todo_el_reloj(&h);
         
         status=leer_byte(0x00);
            
            printf("\n %i : %i : %i " ,h.horas,h.minutos,h.segundos);
            printf("\n status->%X " ,status);
            delay_ms(1000);
            
         }
 }
