#include <xc.h>
#define _XTAL_FREQ  4000000
#pragma config FOSC = XT, WDTE = OFF, PWRTE = OFF, BOREN = OFF
#pragma config LVP = OFF, CPD = OFF, WRT = OFF, CP = OFF 
#define RS       PORTDbits.RD4
#define EN       PORTDbits.RD5

void            INICIALIZAR         (void);
void            i2c_Configurar      (void);      
void            i2c_Esperar         (void);       
void            i2c_Start           (void);   
void            i2c_ReStart         (void); 
void            i2c_Stop            (void);     
unsigned char   i2c_Enviar          (unsigned char dato); 
unsigned char   i2c_Recibir         (void);
unsigned char   DECIMAL_BCD         (unsigned char num);
unsigned char   BCD_DECIMAL         (unsigned char num);
void            ESCRIBE_DS1307      (unsigned int  dir, 
                                     unsigned char dato);
unsigned char   LEE_DS1307          (unsigned int  dir);

void            NUMEROLCD           (unsigned int  NUM, 
                                     unsigned char NUME,
                                     unsigned char POSI);
void            MOSTRARCADENA       (const char    *CAD, 
                                     unsigned char POSI);
void            LCD                 (unsigned char CARACTER, 
                                     unsigned char MODO);

unsigned char HORA, MINUTO, SEGUNDO;

void main(void)
{
    INICIALIZAR();
    ESCRIBE_DS1307(0x07,10);        // configuro el registro de control
    ESCRIBE_DS1307(0x00,25);        // envío unos segundos de prueba
    ESCRIBE_DS1307(0x01,20);        // envío unos minutos de prueba
    ESCRIBE_DS1307(0x02,15);        // envío unas horas de prueba
    MOSTRARCADENA("  /  /",0x80);   // y el RTC los graba perfectamente
    while(1)
    {
        SEGUNDO = LEE_DS1307(0x00); // aqui empieza la lectura del DS1307
        MINUTO  = LEE_DS1307(0x01); // pero solo logro leer D1 que es el 
        HORA    = LEE_DS1307(0x02); // ultimo dato que se carga en el buffer
        NUMEROLCD(HORA,2,0x80);
        NUMEROLCD(MINUTO,2,0x83);
        NUMEROLCD(SEGUNDO,2,0x86);
    }
}

void INICIALIZAR(void)
{
    TRISA = 0;          PORTA = 0;
    TRISB = 0;          PORTB = 0;
    TRISC = 0;          PORTC = 0;
    TRISD = 0;          PORTD = 0;
    TRISE = 0;          PORTE = 0;
    LCD(0b00111100,0);  LCD(0b00010100,0);      
    LCD(0b00001100,0);  LCD(0b00000110,0);
    i2c_Configurar();
}

/* 
 * FUNCION PARA CONFIGURAR EL MC AJUSTANDO 
 * LOS PARAMETROS PARA EL I2C
 */
void i2c_Configurar(void)
{
    TRISCbits.TRISC3 = 1;  TRISCbits.TRISC4 = 1;
    PORTCbits.RC3    = 1;  PORTCbits.RC4    = 1;
    SSPSTAT=0b10000000;    SSPCON =0b00101000;
    SSPCON2=0b00000000;    SSPADD=9; 
}

/* 
 * FUNCION PARA ESPERAR SE CUMPLAN LAS 
 * CONDICIONES BASICAS DE ENVIO O RECEPCION
 */
void i2c_Esperar(void)
{
    while((SSPCON2 & 0b00011111) || (SSPSTAT & 0b00000100));
}

/* 
 * GENERA LA CONDICION DE START O 
 * ARRANQUE DE LA COMUNICACION
 */
void i2c_Start(void) 
{
    i2c_Esperar();        
    SSPCON2bits.SEN = 1; 
}

/* 
 * GENERA LA CONDICION DE RESTART O 
 * NUEVO ARRANQUE DE LA COMUNICACION
 */
void i2c_ReStart(void)
{
    i2c_Esperar();            
    SSPCON2bits.RSEN = 1; 
}

/* 
 * GENERA LA CONDICION DE STOP O 
 * PARADA DE LA COMUNICACION
 */
void i2c_Stop(void) 
{
    i2c_Esperar();           
    SSPCON2bits.PEN = 1; 
}
 
/* 
 * FUNCION QUE ENVIA UN DATO DESEADO POR EL 
 * BUFFER HACIA EL DS1307
 */
unsigned char i2c_Enviar(unsigned char dato) 
{
    i2c_Esperar();
    SSPBUF = dato;
    return(ACKSTAT);
}
 
/* 
 * FUNCION QUE RECIBE UN DATO GUARDADO EN EL 
 * BUFFER POR EL DS1307
 */
unsigned char i2c_Recibir(void)
{ 
    unsigned char datoleido;
    i2c_Esperar(); 
    datoleido = SSPBUF;   
    i2c_Esperar();            
    SSPCON2bits.ACKDT = 1;  
    SSPCON2bits.ACKEN = 1;
    return(datoleido);
}

/* 
 * TRANSFORMA UN NUMERO DECIMAL A BCD
 */
unsigned char DECIMAL_BCD (unsigned char num)
{
    unsigned char A, B;
    B = num/10;
    A = num - B * 10;
    return (B*16+A);
}

/* 
 * TRANSFORMA UN NUMERO BCD A DECIMAL
 */
unsigned char BCD_DECIMAL (unsigned char num)
{
    unsigned char A, B;
    B = num/16;
    A = num - B * 16;  
    return (B*10+A);
}

/* 
 * FUNCION BASICA QUE PERMITE ESCRIBIR dato EN LA DIRECCION 
 * dir DEL DS1307
 */
void ESCRIBE_DS1307(unsigned int dir, unsigned char dato)
{
    dato = DECIMAL_BCD(dato);
    i2c_Start();
    i2c_Enviar(0xD0);
    i2c_Enviar(dir);
    i2c_Enviar(dato);
    i2c_Stop();
}
 
/* 
 * FUNCION BASICA QUE DEBERIA LEER EL DATO ALMACENADO 
 * EN LA DIRECCION dir DEL DS1307
 */
unsigned char LEE_DS1307(unsigned int dir)
{
    unsigned char datoleido;
    i2c_Start();    
    i2c_Enviar(0xD0);
    i2c_Enviar(dir);   
    i2c_ReStart();
    i2c_Enviar(0xD1);
    datoleido = BCD_DECIMAL(i2c_Recibir());
    i2c_Stop();
    return(datoleido); 
}

/*
 * ENVIA UN NUMERO A LA LCD 
 */
void NUMEROLCD (unsigned int AUXNUM, unsigned char NUME, unsigned char POSI)
{
    unsigned int DIGITO;
    LCD(POSI,0);
    if(NUME>3)    
    { 
        DIGITO = AUXNUM/1000; 
        LCD(DIGITO+48,1); 
        AUXNUM = AUXNUM - DIGITO*1000;
    }
    if(NUME>2)    
    {
        DIGITO = AUXNUM/100;  
        LCD(DIGITO+48,1); 
        AUXNUM = AUXNUM - DIGITO*100;
    }
    if(NUME>1)    
    {
        DIGITO = AUXNUM/10;   
        LCD(DIGITO+48,1); 
        AUXNUM = AUXNUM - DIGITO*10;
    }
    LCD(AUXNUM+48,1);  
}

/*
 * MUESTRA UNA CADENA EN LA LCD
 */
void MOSTRARCADENA (const char *CAD, unsigned char POSI) 
{
    unsigned char CADENA;    
    LCD(POSI,0);
    while(*CAD!=0x00)
    {
        CADENA=*CAD; 
        LCD(CADENA,1); 
        *CAD++;
    }
}

/*
 * FUNCION BASICA DE ENVIO DE DATOS A LA LCD
 */
void LCD (unsigned char CARACTER, unsigned char MODO)   
{
    unsigned char I, CAJA, AUX=0;
    RS = MODO;
    for(I=0;I<8;I++)
    {   
        AUX = AUX<<1; 
        CAJA = CARACTER&0b00000001; 
        AUX = AUX+CAJA; 
        CARACTER = CARACTER>>1;
    }
    PORTB = AUX; EN=1; __delay_ms(2); EN=0;
}



