//Interfaz MiniZ
#include <avr/io.h>

#define F_CPU 16000000UL
#include <util/delay.h>
#include <avr/interrupt.h>

#define Bus_Datos PORTC
#define Bus_Control PORTA

#define RS  PORTA5               
#define RW  PORTA6
#define E   PORTA7

#define LED1 PORTL7  //Amarillo
#define LED2 PORTL5  //Rojo
#define LED3 PORTG1  //Verde

//Comandos para situar el cursor en inicio de líneas.
#define DDRA_LINEA1 0x80    //1000 0000
#define DDRA_LINEA2 0xC0    //1100 0000
#define DDRA_LINEA3 0x94    //1001 0100
#define DDRA_LINEA4 0xD4    //1101 0100

void inicializar_puertos(void);
void reseteo(void);
void escribir_valor_decimal(unsigned char registro);
void escribir_direccion(unsigned char valorl, unsigned char valorh);
void escribir_int_decimal(unsigned int registro);

//Funciones para escribir en el LCD
void lcd_inicializar();
void lcd_escribir_c(char caracter);
void lcd_escribir(char *cadena);
void posicionar_cursor(unsigned char x, unsigned char y);
void lcd_comando(char comando);
char lcd_invertir_bits(char caracter);


//Funciones I2C
void i2c_ST(unsigned char dato);
unsigned char i2c_SR(void);
void i2c_error(void);




//Variables
volatile unsigned char botones;
volatile unsigned char programa;
volatile unsigned char i2c_enviar;
volatile unsigned char i2c_recibido;
volatile unsigned char boton_libre;
volatile unsigned char comunicaciones;

volatile unsigned char posicion;
volatile unsigned char velocidad;
volatile unsigned char r_estado;
volatile unsigned char baterial;
volatile unsigned char bateriah;
volatile unsigned char direccionl;
volatile unsigned char direccionh;
volatile unsigned char sensoresd;
volatile unsigned char sensoresi;
volatile unsigned char encoder1;
volatile unsigned char encoder0;
volatile unsigned char estadoleds;

int main(void)
{

    static unsigned char copia_i2c_enviar=0;
    static unsigned char copia_i2c_recibido=0;
    unsigned char pantalla=0;
    unsigned char pantalla_old=0;
    unsigned int posicion_sec;
    unsigned int velocidad_sec;
    unsigned int bateria;
    unsigned char copia_baterial;
    unsigned char copia_bateriah;
    unsigned char copia_sensoresd;
    unsigned char copia_sensoresi;

    char linea1[]="Interfaz MiniZ";  
    char linea2[]="con Arduino MeGa";
    char linea3[]="www.jmnlab.com";


    inicializar_puertos();
    reseteo();
    lcd_inicializar();

    PORTL &= ~((1<<LED1)|(1<<LED2));
    PORTG &= ~(1<<LED3);

    lcd_comando(0x01);
    posicionar_cursor(1,4);  
    lcd_escribir(linea1);         
     posicionar_cursor(2,3);         
    lcd_escribir(linea2);
    posicionar_cursor(4,4);
    lcd_escribir(linea3);


    while(1)
    {
        switch(botones)
        {

        case 7:
        {    
            if(boton_libre==0)
            {
                boton_libre=1;    
                r_estado ^=0x02;
            }
        }break;

        case 6:
        {
            if(boton_libre==0)
            {
                boton_libre=1;    
                r_estado ^=0x01;
            }
            
        }break;

        case 5:
        {
            if(boton_libre==0)
            {
                boton_libre=1;    
                r_estado ^=0x04;
            }
            
        }break;

        case 4:
        {
            ;
        }break;

        case 3:
        {
            pantalla=3;   
        }break;

        case 2:
        {
            pantalla=2;
        }break;

        case 1:
        {
            pantalla=1;
        }break;

        default: break;
        }

        ADMUX  &= ~(1<<MUX0);            //Canal 0.
        _delay_us(600);                     
        posicion=ADCH;

        posicionar_cursor(4,10);        //Canal 1
        ADMUX  |= (1<<MUX0);    
        _delay_us(600);                     
        velocidad=ADCH;

        /************************************************/

        switch(pantalla)
        {

        case 0:
        {
        }break;


        case 1:
        {        
            if(pantalla_old != 1)
            {
                   PORTL &= ~(1<<LED2);
                PORTL &= ~(1<<LED1);
                PORTG |= (1<<LED3);    
                pantalla_old=1;
                lcd_comando(0x01);;
                lcd_escribir("Prueba conexion I2C.");
                 posicionar_cursor(2,1);
                   lcd_escribir("Led V I:     C:");
                posicionar_cursor(3,1);
                lcd_escribir("Led A I:     C:");
                posicionar_cursor(4,1);
                lcd_escribir("Led R I:     C:");
            }

            copia_i2c_enviar=r_estado;
            copia_i2c_recibido=estadoleds;
        
    
            if(((copia_i2c_enviar)&(0x01))!=0)
                {
                    posicionar_cursor(2,10);
                 lcd_escribir_c('O');
                 lcd_escribir_c('N');
                 lcd_escribir_c(' ');
                }
                else
            {
                posicionar_cursor(2,10);
                lcd_escribir_c('O');
                lcd_escribir_c('F');
                lcd_escribir_c('F');
            }    

            copia_i2c_enviar=r_estado;
            if(((copia_i2c_enviar)&(0x02))!=0)
            {
                posicionar_cursor(3,10);
                lcd_escribir_c('O');
                lcd_escribir_c('N');
                lcd_escribir_c(' ');
            }
            else
            {
                posicionar_cursor(3,10);
                lcd_escribir_c('O');
                lcd_escribir_c('F');
                lcd_escribir_c('F');
                }

            copia_i2c_enviar=r_estado;
            if(((copia_i2c_enviar)&(0x04))!=0)
            {
                posicionar_cursor(4,10);
                lcd_escribir_c('O');
                lcd_escribir_c('N');
                lcd_escribir_c(' ');
            }
            else
            {
                posicionar_cursor(4,10);
                lcd_escribir_c('O');
                lcd_escribir_c('F');
                lcd_escribir_c('F');
            }

            if(((copia_i2c_recibido)&(0x01))!=0)
            {
                   posicionar_cursor(2,17);
                lcd_escribir_c('O');
                lcd_escribir_c('N');
                lcd_escribir_c(' ');
            }
            else
            {
                posicionar_cursor(2,17);
                lcd_escribir_c('O');
                lcd_escribir_c('F');
                lcd_escribir_c('F');
            }    

            copia_i2c_recibido=estadoleds;
            if(((copia_i2c_recibido)&(0x02))!=0)
            {
                posicionar_cursor(3,17);
                lcd_escribir_c('O');
                lcd_escribir_c('N');
                lcd_escribir_c(' ');
            }
            else
            {
                posicionar_cursor(3,17);
                lcd_escribir_c('O');
                lcd_escribir_c('F');
                lcd_escribir_c('F');
            }

            copia_i2c_recibido=estadoleds;
            if(((copia_i2c_recibido)&(0x04))!=0)
            {
                posicionar_cursor(4,17);
                lcd_escribir_c('O');
                lcd_escribir_c('N');
                lcd_escribir_c(' ');
            }
            else
            {
                posicionar_cursor(4,17);
                lcd_escribir_c('O');
                lcd_escribir_c('F');
                lcd_escribir_c('F');
            }
        }break;
        
        case 2:
        {
            if(pantalla_old != 2)
            {
                PORTL &= ~((1<<LED1)|(1<<LED2));
                PORTG &= ~(1<<LED3);
                PORTL |= (1<<LED1);
                pantalla_old=2;
                lcd_comando(0x01);
                lcd_escribir("Direccion:        s");
                posicionar_cursor(1,18);
                lcd_escribir_c(0b11100100);
                posicionar_cursor(2,1);
                lcd_escribir("Realimentacion:");
                posicionar_cursor(3,1);
                lcd_escribir("Velocidad:        s");
                posicionar_cursor(3,18);
                lcd_escribir_c(0b11100100);
                posicionar_cursor(4,1);
                lcd_escribir("EI:");
                posicionar_cursor(4,11);
                lcd_escribir("ED:");

            }
                posicionar_cursor(2,17);
                escribir_direccion(direccionl, direccionh);
                posicionar_cursor(4,5);
                escribir_valor_decimal(encoder1);
                posicionar_cursor(4,15);
                escribir_valor_decimal(encoder0);

                posicion_sec=posicion;
                velocidad_sec=velocidad;

                posicion_sec = 1000 + posicion_sec*4;
                velocidad_sec = 1000 + velocidad_sec*4;
                posicionar_cursor(1,12);
                escribir_int_decimal(posicion_sec);
                posicionar_cursor(3,12);
                escribir_int_decimal(velocidad_sec);
        }break;

        case 3:
        {
            if(pantalla_old != 3)
            {
                PORTL &= ~((1<<LED1)|(1<<LED2));
                PORTG &= ~(1<<LED3);
                PORTL |= (1<<LED2);
                pantalla_old=3;
                lcd_comando(0x01);
                lcd_escribir("Bateria:      mV");
                posicionar_cursor(3,7);
                lcd_escribir("Sensores");
            }

            copia_baterial = baterial;
            copia_bateriah = bateriah;
            bateria = ((int)bateriah * 256) + baterial;
            bateria=bateria*6;
            posicionar_cursor(1,10);
            escribir_int_decimal(bateria);

            posicionar_cursor(4,5);

            copia_sensoresd = sensoresi;
            copia_sensoresi= sensoresi;

            if(((copia_sensoresi)&(0x04)) != 0)
                lcd_escribir_c('0');
            else
                lcd_escribir_c('1');
            copia_sensoresi = copia_sensoresd;

            if(((copia_sensoresi)&(0x08)) != 0)
                lcd_escribir_c('0');
            else
                lcd_escribir_c('1');
            copia_sensoresi = copia_sensoresd;

            if(((copia_sensoresi)&(0x10)) != 0)
                lcd_escribir_c('0');
            else
                lcd_escribir_c('1');
            copia_sensoresi = copia_sensoresd;

            if(((copia_sensoresi)&(0x20)) != 0)
                lcd_escribir_c('0');
            else
                lcd_escribir_c('1');
            copia_sensoresi = copia_sensoresd;

            if(((copia_sensoresi)&(0x40)) != 0)
                lcd_escribir_c('0');
            else
                lcd_escribir_c('1');
            copia_sensoresi = copia_sensoresd;

            if(((copia_sensoresi)&(0x80)) != 0)
                lcd_escribir_c('0');
            else
                lcd_escribir_c('1');

            copia_sensoresd = sensoresd;
            copia_sensoresi= sensoresd;

//            posicionar_cursor(2,1);
//            escribir_valor_decimal(sensoresd);

            if(((copia_sensoresi)&(0x80)) != 0)
                lcd_escribir_c('0');
            else
                lcd_escribir_c('1');
            copia_sensoresi = copia_sensoresd;

            if(((copia_sensoresi)&(0x40)) != 0)
                lcd_escribir_c('0');
            else
                lcd_escribir_c('1');
            copia_sensoresi = copia_sensoresd;

            if(((copia_sensoresi)&(0x20)) != 0)
                lcd_escribir_c('0');
            else
                lcd_escribir_c('1');
            copia_sensoresi = copia_sensoresd;

            if(((copia_sensoresi)&(0x10)) != 0)
                lcd_escribir_c('0');
            else
                lcd_escribir_c('1');
            copia_sensoresi = copia_sensoresd;

            if(((copia_sensoresi)&(0x08)) != 0)
                lcd_escribir_c('0');
            else
                lcd_escribir_c('1');
            copia_sensoresi = copia_sensoresd;

            if(((copia_sensoresi)&(0x04)) != 0)
                lcd_escribir_c('0');
            else
                lcd_escribir_c('1');














        }break;

        default:break;
    }
}
}

void inicializar_puertos(void)              //Configurar hardware del pic.
{
   //Configurar entradas y salidas.
   DDRC=0xFF;     //1111 1111
   PORTC=0x00;
      
   DDRA|=((1<<RS)|(1<<RW)|(1<<E));     //1110 0000
   PORTA &= ~(1<<E);  
    
   DDRL= 0xA0;      //1010 0000
   PORTL=0x00;

   DDRG =0x02;      //0000 0010
   PORTG=0x00;

   //Configurar interrupciones externas.
   PCICR |= (1<<PCINT2);
   PCMSK2 |= 0xFE;
   sei();

   //Configurar ADC
    ADMUX |=(1<<REFS0);                           //Tensión de referencia 5 voltios.
    ADMUX |=(1<<ADLAR);                           //8 bits de resolución.
                                                  //Canal ADC por defecto ADC0, no tenemos que cambiarlo.
    ADCSRA |=(1<<ADATE);                          //Habilitamos el Free Running Mode, por defecto seleccionado
    ADCSRA |=((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0));  //Prescaler 128, Fadc 125 KHz @ 16MHz.
    DIDR0 |= ((1<<ADC0D)|(1<<ADC1D));             //Apagamos la parte digital del puerto.
    ADCSRA |= (1<<ADEN);                          //Encendemos ADC
    ADCSRA|= (1<<ADSC);                              //Comenzar conversiones.

    //Configurar I2C
    TWAR = 0xE2;                //Dirección de esclavo en el bus I2C.
    TWCR |= ((1<<TWEA)|(1<<TWEN)|(1<<TWIE));
}

void lcd_inicializar() //Se mandan los comandos de configuración según el datasheet.
{
    _delay_ms(100);                       
    lcd_comando(0x3C);    //Function Set RS0 RW0 0011NF** 0011 1100
    lcd_comando(0x3C);    //Function Set
    lcd_comando(0x0C);    //Display ON/OFF Control RS0 RW0 00001DCB 0000 1100
    lcd_comando(0x01);    //Display Clear RS0 RW0 00000001
    lcd_comando(0x06);    //Entry Mode Set RS0 RW0 000001I/DS 0000 0110
}

void lcd_escribir_c(char caracter)
{
    Bus_Control |= (1<<RS);        //RS1    Dato
    Bus_Control &= ~(1<<RW);  //RS0
    Bus_Datos = lcd_invertir_bits(caracter);       
    Bus_Control |= (1<<E);
    _delay_us(100);
    Bus_Control &= ~(1<<E);
    _delay_ms(1);
}

void lcd_comando(char comando)
{
    Bus_Control &= ~(1<<RS);    //RS0   Comando
    Bus_Control &= ~(1<<RW);   //RW0
    Bus_Datos  = lcd_invertir_bits(comando); //Comando
    Bus_Control |= (1<<E);
    _delay_us(100);
    Bus_Control &= ~(1<<E);
    _delay_ms(2);
}

void lcd_escribir(char *cadena)
{
    char *inicio = cadena;
    unsigned char i=0;

    for(i=0;((inicio[i]!='\0')&&(i<20));i++)
    {
        Bus_Control |= (1<<RS);    //RS0 RW0 caracter
        Bus_Control &= ~(1<<RW);
        Bus_Datos  = lcd_invertir_bits(inicio[i]);       
        Bus_Control |= (1<<E);
        _delay_us(100);
        Bus_Control &= ~(1<<E);
        _delay_ms(1);
    }
}

void posicionar_cursor(unsigned char x, unsigned char y) //línea x 1 a 4, carácter y de 1 a 20.
{                                                                                               
    unsigned char comando=DDRA_LINEA1;
    switch(x)
    {
        case 1:
        {
            comando=DDRA_LINEA1+y-1;
        }break;
        case 2:
        {
            comando=DDRA_LINEA2+y-1;
        }break;
        case 3:
        {
            comando=DDRA_LINEA3+y-1;
        }break;
        case 4:
        {
            comando=DDRA_LINEA4+y-1;
        }break;
        default:break;
    }
        lcd_comando(comando);
}

char lcd_invertir_bits(char caracter)
{
    char copia_caracter=caracter;
    char caracter_cambiado=0x00;

    caracter_cambiado |= (((copia_caracter)&(0x80))>>7);

    copia_caracter=caracter;
    caracter_cambiado |= (((copia_caracter)&(0x40))>>5);

    copia_caracter=caracter;
    caracter_cambiado |= (((copia_caracter)&(0x20))>>3);

    copia_caracter=caracter;
    caracter_cambiado |= (((copia_caracter)&(0x10))>>1);

    copia_caracter=caracter;
    caracter_cambiado |= (((copia_caracter)&(0x08))<<1);

    copia_caracter=caracter;
    caracter_cambiado |= (((copia_caracter)&(0x04))<<3);

    copia_caracter=caracter;
    caracter_cambiado |= (((copia_caracter)&(0x02))<<5);

    copia_caracter=caracter;
    caracter_cambiado |= (((copia_caracter)&(0x01))<<7);    
            
    return(caracter_cambiado);
}

void reseteo(void)
{

    PORTL |= ((1<<LED1)|(1<<LED2));
    PORTG |= (1<<LED3);
    _delay_ms(500);
    PORTL &= ~((1<<LED1)|(1<<LED2));
    PORTG &= ~(1<<LED3);
    _delay_ms(500);
    PORTL |= ((1<<LED1)|(1<<LED2));
    PORTG |= (1<<LED3);
    _delay_ms(500);
    PORTL &= ~((1<<LED1)|(1<<LED2));
    PORTG &= ~(1<<LED3);
    _delay_ms(500);
    PORTL |= ((1<<LED1)|(1<<LED2));
    PORTG |= (1<<LED3);
    _delay_ms(500);
    PORTL &= ~((1<<LED1)|(1<<LED2));
    PORTG &= ~(1<<LED3);
}

ISR(PCINT2_vect)
{

    if ((PINK&(1<<PINK1))==0)
        {
            botones=7;
            boton_libre=0;
        }

    else if ((PINK&(1<<PINK2))==0)
        {
            botones=6;
            boton_libre=0;
        }


    else if ((PINK&(1<<PINK3))==0)
        {
            botones=5;
            boton_libre=0;
        }


    else if ((PINK&(1<<PINK4))==0)
        {
            botones=4;
            boton_libre=0;
        }


    else if ((PINK&(1<<PINK5))==0)
        {
            botones=3;
            boton_libre=0;
        }


    else if ((PINK&(1<<PINK6))==0)
        {
            botones=2;
            boton_libre=0;
        }


    else if ((PINK&(1<<PINK7))==0)
        {
            botones=1;
            boton_libre=0;
        }

    PCIFR  |=(1<<PCIF2);
}

void escribir_valor_decimal(unsigned char registro) //Escribir binario a decimal.
{
    char centenas = 0;
    char decenas = 0;
    char unidades = 0;
    while(registro>=100)
    {
        registro= registro -100;
        centenas++;
    }
    while(registro>=10)
    {
        registro=registro -10;
        decenas++;
    }
    while(registro>0)
    {
        registro=registro-1;
        unidades++;
    }   
    lcd_escribir_c(centenas | 0b00110000);
    lcd_escribir_c(decenas | 0b00110000);
    lcd_escribir_c(unidades | 0b00110000);
}
/************************************************************************************/

ISR(TWI_vect)
{

    static unsigned char sincronizar;
    static unsigned char contador_byte;
    static unsigned char recibidos[9];
    unsigned char enviari2c[3];

    enviari2c[0] = posicion ;
    enviari2c[1] = velocidad;
    enviari2c[2] = r_estado;


    if((TWSR & 0xF8) == 0x60)
    {
        recibidos[contador_byte]=i2c_SR();
        contador_byte++;

        if(sincronizar<3)
            sincronizar=0;

    }
    else if((TWSR & 0xF8) == 0xA8)
    {
        i2c_ST(enviari2c[sincronizar]);
        sincronizar++;
        contador_byte=0;   
    }
    else
        i2c_error();
    if(sincronizar==3)
    {
        baterial = recibidos[0];
        bateriah = recibidos[1];
        direccionl = recibidos[2];
        direccionh = recibidos[3];
        sensoresd = recibidos[4];
        sensoresi = recibidos[5];
        encoder1 = recibidos[6];
        encoder0 = recibidos[7];
        estadoleds = recibidos[8];
        sincronizar=0;
    }



    TWCR |= (1<<TWINT);
}

void i2c_ST(unsigned char dato)
{

    TWDR=dato;                        //Cargar el dato a enviar.
    TWCR &= ~((1<<TWSTO)|(1<<TWEA));
    TWCR |= (1<<TWINT);                //Enviar dato.

    while (!(TWCR & (1<<TWINT)))    //Esperar a TWINT
    {
    }

    if((TWSR & 0xF8) != 0xC8);        //Dato enviado, no esperamos ACK.
        i2c_error();

    TWCR &= ~((1<<TWSTO)|(1<<TWSTA));//Dejamos el módulo preparado.
    TWCR |= ((1<<TWINT)|(1<<TWEA));
}

unsigned char i2c_SR(void)
{
    unsigned char dato=0;

    TWCR &= ~(1<<TWSTO);                //Preparados para recibir dato y devolver ACK
    TWCR |= ((1<<TWINT)|(1<<TWEA));

    while (!(TWCR & (1<<TWINT)))        //Esperar a TWINT
    {
    }

    if((TWSR & 0xF8) != 0x80);            //Hemos recibido dato y generado ACK.
        i2c_error();
    dato=TWDR;                            //Almacenamos dato recibido.

    TWCR &= ~(1<<TWSTO);                //Preparados para recibir STOP
    TWCR |= ((1<<TWINT)|(1<<TWEA));

    while (!(TWCR & (1<<TWINT)))        //Esperar a TWINT
    {
    }

    if((TWSR & 0xF8) != 0xA0);            //STOP
        i2c_error();

    TWCR &= ~((1<<TWSTO)|(1<<TWSTA));    //Dejamos el módulo preparado.
    TWCR |= ((1<<TWINT)|(1<<TWEA));

    return(dato);
}

void i2c_error(void)
{
}

void escribir_direccion(unsigned char valorl, unsigned char valorh)
{

    unsigned int registro=0;
    registro= (int)valorh*256+valorl;
    char miles=0;
    char centenas = 0;
    char decenas = 0;
    char unidades = 0;


    while(registro>=1000)
    {
        registro= registro -1000;
        miles++;
    }

    while(registro>=100)
    {
        registro= registro -100;
        centenas++;
    }

    while(registro>=10)
    {
        registro= registro -10;
        decenas++;
    }

    while(registro>=1)
    {
        registro= registro -1;
        unidades++;
    }
 //
    lcd_escribir_c(miles | 0b00110000);
    lcd_escribir_c(centenas | 0b00110000);
    lcd_escribir_c(decenas | 0b00110000);
    lcd_escribir_c(unidades | 0b00110000);
}

void escribir_int_decimal(unsigned int registro)
{
    char miles=0;
    char centenas = 0;
    char decenas = 0;
    char unidades = 0;

    while(registro>=1000)
    {
        registro= registro -1000;
        miles++;
    }

    while(registro>=100)
    {
        registro= registro -100;
        centenas++;
    }
    while(registro>=10)
    {
        registro=registro -10;
        decenas++;
    }
    while(registro>0)
    {
        registro=registro-1;
        unidades++;
    }   
    lcd_escribir_c(miles | 0b00110000);
    lcd_escribir_c(centenas | 0b00110000);
    lcd_escribir_c(decenas | 0b00110000);
    lcd_escribir_c(unidades | 0b00110000);
}