#include <avr/io.h>

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

#define Bus_Datos PORTK
#define Bus_Control PORTF
#define RS  PORTF5
#define RW  PORTF6
#define E   PORTF7

//Inicializar timers
void inicializar_timer4(void);
void inicializar_timer0(void);

//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();

//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(unsigned char comando);

void escribir_valor_decimal(unsigned int registro);
void escribir_espacio(unsigned long int registro);

/***************** VARIABLES ***********************/
volatile unsigned int cuenta;
volatile unsigned int cuenta_old;
volatile unsigned char contador;
volatile unsigned int suma_cuenta;
volatile unsigned long int espacio;

int main(void)
{
    inicializar();
    lcd_inicializar();
    inicializar_timer4();
    inicializar_timer0();

    char linea1[]="www.jmnlab.com";  //Poner en la Flash de programa las cadenas.
    char linea2[]="Contar los pulsos";
    char linea3[]="de un encoder";
    char linea4[]="Pulsos/seg:";
    char linea5[]="Velocidad:";
    char linea6[]="Espacio:";
    char linea7[]="***Encoders MiniZ***";

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

    posicionar_cursor(1,1);
    lcd_escribir(linea7);
    posicionar_cursor(2,1);
    lcd_escribir(linea4);
    posicionar_cursor(3,1);
    lcd_escribir(linea5);
    posicionar_cursor(4,1);
    lcd_escribir(linea6);
    posicionar_cursor(3,17);
    lcd_escribir_c('m');
    lcd_escribir_c('m');
    lcd_escribir_c('/');
    lcd_escribir_c('s');
    posicionar_cursor(4,17);
    lcd_escribir_c('m');

    unsigned int suma_cuenta_local=0;
    unsigned int velocidad=0;

    while(1)
    {

    if(contador>62)
    {
        suma_cuenta_local=suma_cuenta;
        contador=0;
        suma_cuenta=0;

        posicionar_cursor(2,13);
        escribir_valor_decimal(suma_cuenta_local);

        velocidad= suma_cuenta_local*12;
        posicionar_cursor(3,12);
        escribir_valor_decimal(velocidad);

        espacio= espacio + (unsigned long int)suma_cuenta_local*12036;
        posicionar_cursor(4,10);
        escribir_espacio(espacio);
    }    

    }
}

void inicializar()              //Configurar hardware del pic.
{
    DDRK=0xFF;     //1111 1111
    PORTK=0x00;    
    DDRF|=((1<<RS)|(1<<RW)|(1<<E));     //1110 0000
    PORTF &= ~(1<<E);  
}

/*************************************************************************/
void lcd_inicializar() //Se mandan los comandos de configuración según el dibujo.
{
    _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 = caracter;       
    Bus_Control |= (1<<E);
    _delay_us(100);
    Bus_Control &= ~(1<<E);
    _delay_ms(10);
}

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

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  = inicio[i];       
        Bus_Control |= (1<<E);
        _delay_us(100);
        Bus_Control &= ~(1<<E);
        _delay_ms(3);
    }
}

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);
}

/****************************************************************************************************/
void inicializar_timer4(void) //Configura el timer y la interrupción.
{
//    DDRA |= (1<<PA7);    //Puerto A7 pin osciloscopio
    OCR4A= 0x0F9F;
    TCCR4B |=((1<<WGM42)|(1<<CS41)|(1<<CS40));    //Los bits que no se tocan a 0 por defecto
    TIMSK4 |= (1<<OCIE4A);
    sei();
}

void inicializar_timer0(void)
{
    TCCR0B |=((1<<CS02)|(1<<CS01)|(1<<CS00));     //Normal Mode y reloj externo flanco de subida
}

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

ISR(TIMER4_COMPA_vect)
{
    unsigned int cuenta_actual=TCNT0;


    if (cuenta_actual>cuenta_old)
    {
        cuenta=cuenta_actual-cuenta_old;
        suma_cuenta=suma_cuenta+cuenta;
    }

    else if(cuenta_actual<cuenta_old)
    {
        cuenta=256+cuenta_actual-cuenta_old;
        suma_cuenta=suma_cuenta+cuenta;
    }

    cuenta_old=TCNT0;
    contador++;

    TIFR4 |= (1<<OCF4A);
}

/************************* Escribir registros *****************************************************/

void escribir_valor_decimal(unsigned int registro) //Escribir binario a decimal.
{
    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);
}

void escribir_espacio(unsigned long int registro)
{


    char miles=0;
    char centenas = 0;
    char decenas = 0;
    char unidades = 0;
    char decena_cm=0;

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

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

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

    while(registro>=1000000)
    {
        registro= registro -1000000;
        unidades++;
    }

    while(registro>=100000)
    {
        registro= registro -100000;
        decena_cm++;
    }

 
    lcd_escribir_c(miles | 0b00110000);
    lcd_escribir_c(centenas | 0b00110000);
    lcd_escribir_c(decenas | 0b00110000);
    lcd_escribir_c(unidades | 0b00110000);
    lcd_escribir_c('.');
       lcd_escribir_c(decena_cm | 0b00110000);
}