#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, 
//   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();

}

// Función para programar una alarma temporizada de 10 seg
void escribir_timer ()
{
	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(0b11000010); //Timer seg habilitado
	i2c_stop();
	
      	i2c_start();
	    i2c_write(escribir_reloj);
	    i2c_write(0x0F); 
		
		dato = bin_a_bcd(10);
	    i2c_write(dato); //Timer seg habilitado
		i2c_stop();
	
	 i2c_stop();
   	delay_ms (5);

}

// Función para programar una alarma por desbordamiento del timer 
//  al llegar a 99 s
void desbordamiento_timer ()
{
	byte dato=0;
	dato=leer_byte(0x00);
	dato|=0x04;
registro_control(dato);
	i2c_start();
	i2c_write(escribir_reloj);
	i2c_write(0x08); //dirección de reg de control de alarmas
	i2c_write(0b00001010); //Interrupción x overflow del timer; resolución timer -> seg
i2c_stop();
}


// Función para poner el reloj en hora a 23:59:55:00 Lunes 
// y programar una alarma que se active a las 00:00:05:00 del Martes
void ejweekday()
{
	i2c_start ();
i2c_write (0xA0); // enviar la dirección del dispositivo
i2c_write (0x00); // enviar dirección de byte
// Escribir a RTC 23:59:55:00 Lunes
// hora de alarma es 00:00:05:00 Martes
i2c_write (0x80); // Control de Registro, detener el conteo
i2c_write (0x00); // Hund.de segundos
i2c_write (0x55); // Segundos
i2c_write (0x59); // Acta
i2c_write (0x23); // Horas
i2c_write (0x01); // Year_Date
i2c_write (0x01); // Weekday_Month
i2c_write (0x00); // Temporizador
i2c_write (0X90); // Alarma de Control de Registro
i2c_write (0x00); // Alarma Hund.de segundos
i2c_write (0x05); // Alarma Segundos
i2c_write (0x00); // Acta de alarma
i2c_write (0x00); // Alarma Horas
i2c_write (0x00); // Fecha de alarma no tiene ningún efecto en los días de la semana de alarma
i2c_write (0x02); // Día de la semana de alarma
i2c_stop ();
delay_ms (5);

i2c_start ();// inicia de nuevo
i2c_write (0xA0); // enviar la dirección del dispositivo
i2c_write (0x00); // enviar dirección de byte
i2c_write (0x04);
i2c_stop ();
}


 
 void main () // Se pueden ir seleccionando o desactivando las funciones usando "//"
			  // La explicación de cada función está en su definición 
 {

	byte status, timer;

    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; //Se usa sólo para la función escribir_alarma
	
	//escribir_alarma (&a);

	//escribir_timer ();
	

	desbordamiento_timer ();
//	ejweekday(); // esta función ya ajusta la hora 
				 //por lo que no hay que ejercutar escribir_en_reloj

	//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);
			timer=leer_byte(0x07);
            
            printf("\n %i : %i : %i " ,h.horas,h.minutos,h.segundos);
            printf("\n status->%X " ,status);
            delay_ms(1000);
            
         }
 }
