// PIC16F877 Configuration Bit Settings

// 'C' source line config statements

// CONFIG
#pragma config FOSC = EXTRC     // Oscillator Selection bits (RC oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config CP = OFF         // FLASH Program Memory Code Protection bits (Code protection off)
#pragma config BOREN = ON       // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = ON         // Low Voltage In-Circuit Serial Programming Enable bit (RB3/PGM pin has PGM function; low-voltage programming enabled)
#pragma config CPD = OFF        // Data EE Memory Code Protection (Code Protection off)
#pragma config WRT = OFF        // FLASH Program Memory Write Enable (Unprotected program memory may not be written to by EECON control)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.





#define _XTAL_FREQ 4000000 //Frecuencia del cristal para las funciones delays a 4Mhz  Y reloj a 4Mhz
#define __delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0))) //Para hacer retardos muy precisos
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))

#define direccion 0B1000000
#define comando_temperatura 0B11100011
#define comando_humedad 0B11110101


#include <xc.h>
#include "lcd_4bits.h"
char temperatura[3];
char humedad [3];
char ReadData;

void config_puertos (void)
{
    TRISD=0B00000000; //Puerto D como salidas.
    PORTD=0; //Inicializo el puerto D para mandar datos al LCD
    
    ANSELbits.ANS5 = 0;
    ANSELbits.ANS6 = 0;
    TRISEbits.TRISE0 = 0;
    TRISEbits.TRISE1 = 0;
    PORTE = 0;
    
    TRISBbits.TRISB0 = 1;
    ANSELHbits.ANS12 = 0;
    PORTBbits.RB0 = 0;
}

void config_interrupt (void)
{
    INTCON=0B11000000; //Interrupciones globales y perifericos habilitados.
    PIE1bits.SSPIE = 1; //Habilito la interrupcion del modulo SSP
    PIR1bits.SSPIF = 0; //Limpio el flag de la interrupcion del MSSP.
}

void config_MSSP (void)
{
    //Registo SSPCON  
    SSPCONbits.SSPEN = 1; // Habilito el modulo MSSP
    SSPCONbits.SSPM3 = 1;
    SSPCONbits.SSPM2 = 0; // Con estos 4 bits pongo el módulo MSSP en modo I2C modo Maestro.
    SSPCONbits.SSPM1 = 0; // Y la velocidad de trabajo viene dado por la formula   **clock = Fosc / (4 * SSPADD +1)
    SSPCONbits.SSPM0 = 0;
    //Los pines del modulo como entradas.
    TRISCbits.TRISC3 = 1; //SCL hay que poner el puerto como entrada. MSSP
    TRISCbits.TRISC4 = 1; //SCA hay que poner el puerto como entrada. MSSP
 //Registro SSPSTAT.   
    SSPSTAT = 0; //Pongo a 0 el registro de los flags
    SSPCON2 = 0; //Pongo a 0 el registro SSPCON2.
    SSPADD= 9; //100Khz baudrate
}

void idle_i2c (void) //Función que nos dirá si el bus está libre o no.
{
    while ((SSPSTAT & 0x04) || (SSPCON2 & 0x1F)); // Mientras uno de los bits activos de los dos registros y de las mascaras estará en el bucle.
}

void i2c_start (void)
{
    idle_i2c();
    SSPCON2bits.SEN = 1; //Se inicia la condición de Start
    while (SSPCON2bits.SEN) ; // Hasta que no termine de mandar la condicion de Start no se podrá en 0.   
}

void i2c_stop (void)
{
    idle_i2c();
    SSPCON2bits.PEN = 1; //Se inicia la condición de Stop.
    while (SSPCON2bits.PEN == 1); //Mientras no se termine de mandar la condición de Stop no volvera a 0.
}

void i2c_reset (void)
{
    idle_i2c();
    SSPCON2bits.RSEN = 1; //Se inicia el Reset.
    while (SSPCON2bits.RSEN); // Para asegurarnos que se manda el reset, hasta que no se ponga a 0 no se continuara
    //(Es repeat Start condition)
}



void ack (void) //Para mandar un ack al esclavo indicando que el dato enviado o recibido se ha realizado correctamente.
{
    PIR1bits.SSPIF = 0; //Limpio el flag de la interrupcion de SSP
    SSPCON2bits.ACKDT = 0; //Le indico que quiero que cuando lance un ACK sea un ACK y no un NACK
    SSPCON2bits.ACKEN = 1; //Activo la transmision de un ACK.
    while (PIR1bits.SSPIF == 0); //Mientras no acabe la transmisión.
}

void nack (void)
{
    PIR1bits.SSPIF = 0; //Limpio el flag de la interrupcion
    SSPCON2bits.ACKDT = 1; //En este caso lo pongo en 1 para que mande al final de la trama un NACK en vez de un ACK
    SSPCON2bits.ACKEN = 1; //Habilito la transmision del NACK
    while (PIR1bits.SSPIF == 0); //Mientras no acabe de mandar el NACK...
}

void i2c_write (char i2c_data)
{
    PIR1bits.SSPIF = 0; //Limpio el flag de interrupcion
    SSPBUF = i2c_data;
    while ( PIR1bits.SSPIF == 0); // Mientras no termine la transmision.
}

char i2c_read (void) //Para leer el dato que llega por el puerto I2C
{
    char a;
    idle_i2c();
    SSPCON2bits.RCEN = 1; //Activo la recepcion de datos del I2c
    idle_i2c();
    a = SSPBUF;
    idle_i2c();
    nack();
    return a; //Retorna el dato leido.
}

volatile char Read_data;

void sensor_write(char slave_address, char ADD_control_byte, char data)
{
    
}
char sensor_read (char slave_address, char ADD_control_byte)
{
    char Tempdata; // Temporary holder for a Data Byte.
    SSPCON2bits.SEN = 1; //Condicion de Start.
    while (SEN);   //Espera que termine la condicion de Start.
    
    PIR1bits.SSPIF = 0; // Limpio el flag de la interrupcion.
    SSPBUF = slave_address; //Cargo la direccion del esclavo en SSPBUF
    while (¡SSPIF); //Espero al ACK, SSPIF salta cada 9no ciclo de reloj Mientras no salte la interrupcion no habrá terminado de mandar los datos
    PIR1bits.SSPIF = 0; // Limpio el flag.
    if (SSPCON2bits.ACKSTAT) //Si no ha recibido ACK, es decir que ACKSTAT =1
    {
        SSPCON2bits.PEN = 1; //Inicio el protocolo STOP
        while (PEN); // Mientras se termine de mandar el STOP
        return (0xFF); //Exit read No ACK
    }
    
    SSPBUF = ADD_control_byte; //Mando la direccion del registro del sensor donde está el dato de la memoria
    while (¡SSPIF);  //Espero al ACK
    PIR1bits.SSPIF = 0; //Limpio el flag.
    if (SSPCON2bits.ACKSTAT) //Si no ha recibido ACK, es decir que ACKSTAT =1
    {
        SSPCON2bits.PEN = 1; //Inicio el protocolo STOP
        while (PEN); // Mientras se termine de mandar el STOP
        return (0xFF); //Exit read No ACK
    }
    
    SSPCON2bits.RSEN = 1; //Restart, mando nuevamente la condicion de Start
    while (RSEN);
    PIR1bits.SSPIF = 0;
    SSPBUF = (slave_address + 1); //Mando la direccion del dispositivo +1 para decir que ahora va con el bit de escritura
    while (¡SSPIF); //Espero al ACK
    PIR1bits.SSPIF = 0; //Limpio el flag
    if (SSPCON2bits.ACKSTAT) //Si no ha recibido ACK, es decir que ACKSTAT =1
    {
        SSPCON2bits.PEN = 1; //Inicio el protocolo STOP
        while (PEN); // Mientras se termine de mandar el STOP
        return (0xFF); //Exit read No ACK
    }
    
    SSPCON2bits.RCEN = 1; //Manda recepcion del Byte de temperatura del Slave
    while (¡SSPSTATbits.BF); //Espera a recibir completamente el dato a SSPBUF
    Tempdata = SSPBUF; //Cargo el dato de temperatura a la variable TempData
    
    SSPCON2bits.ACKDT = 1; //Coloco ACKDT en 1 para que me mande un NACK en vez de un ACK
    SSPCON2bits.ACKEN = 1; //Habilito para mandar un NACK.
    while (ACKEN); //Espero a que se complete el Nack
    
    SSPCON2bits.PEN =1 ; //Inicio la condicion de Stop
    while (PEN); //Espero a que se termine de mandar el Stop
    return Tempdata;
}
/*********************************
La siguiente función lo que se encarga es de transformar un número en binario a una cadena de caracteres
Para ello, se usará el código ASCI donde comprobaremos que los caracteres de los números son estos + 48, es decir, sumados 0x30
La meteré en una cadena de 4 caracteres, que es la variable global pulsaciones.
*********************************/
void binario_a_cadena_temperatura (unsigned char pregrados)
{
temperatura[0] = ((pregrados / 100) + 0X30); //Centenas
temperatura[2]=((pregrados%10) + 0X30); //Para las unidades. //% operador logico para obtener el resto entero al dividirlo por 10
pregrados/=10;
temperatura[1]=(pregrados%10 + 0X30); //Para las decenas.
}

void binario_a_cadena_humedad (unsigned char pregrados)
{
humedad[0] = ((pregrados / 100) + 0X30); //Centenas
humedad[2]=((pregrados%10) + 0X30); //Para las unidades. //% operador logico para obtener el resto entero al dividirlo por 10
pregrados/=10;
humedad[1]=(pregrados%10 + 0X30); //Para las decenas.
}

void main(void) {
    SSPSTAT = 0; //Pongo a 0 el registro de los flags
    SSPCON2 = 0; //Pongo a 0 el registro SSPCON2.
    const unsigned char texto1[] = {" Cama "};
    int x;
    config_puertos();
   // config_MSSP();
    config_interrupt();
    lcd_ini();  
    SSPADD = 9;
    SSPCON1 = 0x28;
    lcd_mando_instruccion (_lcd_display_clear);
    __delay_ms (2000);
    while (1)
    {
        if (PORTBbits.RB0 ==1)
        {
            //Para leer la temperatua del sensor.
        ReadData = sensor_read(direccion, comando_temperatura); // Para leer la temperatura comando 11100011
        binario_a_cadena_temperatura (ReadData);
       lcd_w_string (temperatura);
       __delay_ms (3000);
       
            //Para leer la humedad del sensor.
       ReadData = sensor_read (direccion, comando_humedad);
       binario_a_cadena_humedad (ReadData);
       lcd_w_string (humedad);
       __delay_ms (3000);
       
        }
        lcd_w_string (texto1);
    } 
    return;
}
   