Version Final

Dependencies:   mbed DS1820

main.cpp

Committer:
NIcolasFernandezSanz
Date:
2019-06-05
Revision:
7:a16d4e848e5e
Parent:
6:75b0f24dad9b
Child:
8:53555acc118b

File content as of revision 7:a16d4e848e5e:

/*
FERNANDEZ-CLERICI
EJER01 - TP01

PTB0 -- Habilitacion Cooler
PTB1 -- DS18B20 (Data) (4K7 PullUp)
D3   -- Sensor Efecto de Hall          --> PullUp 4k7
PTB3 -- Pulsador                       --> 0 = Nada || 1 = Pulsado
PTC2 -- Preset
A3   -- Pin Para Probar que el programa no retiene

*/

/*Librerias*/
#include "mbed.h"
#include "DS1820.h"


/*Definicion Pines*/
#define EN_COOLER          PTB0
#define DS18B20_PIN        PTB1
#define VELOCIDAD          D3
#define PULSADOR           A5
#define PRESET             PTC2

/*Definicion de Elementos*/
DS1820 probe(DS18B20_PIN);

DigitalOut Rojo(LED1);
DigitalOut Verde(LED2);
DigitalOut Azul(LED3);

DigitalOut RET(A3);

PwmOut      Cooler(EN_COOLER);
InterruptIn velocidad(VELOCIDAD);
AnalogIn    Preset(PRESET);
DigitalIn   P(PULSADOR);


/*MAQUINA DE ESTADOS CENTRAL*/

#define InicioSistema 0
#define LazoAbierto 1
#define LazoCerrado 2
#define VelocidadMaxima 3

/*Variables maquina de estado lazos*/
int Modo = 0; //Me avisa en que modo estoy : Lazo Abierto , Lazo Cerrado, Inicio Sistema y Velocidad maxima
int ta   = 0; //Acumulador de tiempo del Inicio Sistema
void medicion_velocidad(void);
int VMAX = 0; //Velocidad maxima del Cooler


/*MAQUINA DE ESTADOS ANTI REBOTE*/

#define INICIO_P 0
#define RISING_P 1
#define RETENCION_P 2

bool antirrebote(bool lectura);
int estado = 0;//Variable que guaarda el estado de la maquina de estados
int tp     = 0;//Acumulador de tiempo de la maquina
void CambioDeModo(); //Funcion que me sirve para switchear entre los dos modos


/*MAQUINA DE ESTADOS MEDICION VELOCIDAD*/

#define INCIO_V 0
#define RISE_1 1
#define FALL_1 2
#define ESPERA_V 3

//Interrupciones de deteccion de cambios en pin de medicion de valocidad
void R_ton(); //Funcion relacionada a la interrupcion de deteccion de flancos ascendentes
void F_ton();    //Funcion relacionada a la interrupcion de deteccion de flancos descendentes

//Flags medicion de ancho de pulso
bool em = 0;      //Estoy midiendo
bool tmv = 0;     //Termine de medir
int tv = 0;       //Acumulacion de tiempo maquina control velocidad
int EMV = 0;      //Guardar estado medicion de velocidad
float RPM = 0;    //Guardo la velocidad



/*MAQUINA DE ESTADOS CAMBIO DE DUTY (LAZO ABIERTO)*/

#define INICIO_CM 0
#define CAMBIO_MAYOR 1
#define CAMBIO_MENOR 2
#define INICIO_CAMBIO_MENOR 5
#define ESPERA_DECREMENTO 3
#define ESPERA_FINAL      4

int tcd = 0;     //Acumulador de tiempo
int ECM = 0;     //Guardo el estado de la maquina
float cantv = 0; //Cantidad de veces que debo modificar el duty (funciona como entero)
char jv = 0;     //Cantidad de veces que modifique el duty
float D = 1.00f; //Duty Actual
float DAN = 0.5f;//Duty Anterior

void cambio_duty_pwm(float nuevoDuty); //Funcion que engloa la maquina


/*MAQUINA DE ESTADOS LAZO CERRADO (DUTY EN FUNCION DE TEMPERATURA)*/

#define INCIO_LAZOCERRADO 0
#define MEDICION_TEMPERATURA 1
#define MEDICION_RPM 2
#define CAMBIO_PWM 3
#define ESPERA_CAMBIOS_PWM 4
#define ESPERA_ENTRE_MODIFICACIONES 5

void control_PWM_Temp(void); //Funcion que engloba la maquina de estados

int CPT = 0;    //Guardo el estado de la maquina
int IM = 0;     //Acumulador de tiempo base
float duty = 0; //Guardo el duty actual

/*SubMaquina utilizada para modificar el duty*/
int   FTR  = 0;     //Control de estados de la submaquina
bool  tdm = 0;      //Flag que me notifica cuando termine de cambiar el duty..

float NuevoDuty = 0;                //Duty que voy enviando a forma de prueba y error..

/*VALORES DE CONFIGURACION LAZO CERRADO*/
#define DEFINICION_CAMBIO_PWM 0.02f //Resolucion de barrido, valores altos agilizan el cambio pero pueden hacer que nunca se alcance lo pedido..
#define MinRPM 500.0f               //Minima velocidad establecida por el Cooler
#define ToleranciaRPM 100.0f        //Tolerancia de calculos en torno a la velocidad (Cuanto me puedo desviar de la regla de tres simple y considerarlo verdadero)

/*RELACION DE REVOLUCIONES POR MINUTO EN FUNCION DE LA TEMPERATURA*/
/*
                    20ºC ==> 500rpm
                    x ºC ==> x  rpm
*/

void cambio_gradual_duty(float obj);//Funcion que engloba la maquina de modificacion del duty , en especial la zona que no puedo enviar directamente..

int ty = 0;                         //Acumulador de tiempo


/*ELEMENTOS GENERALES DEL SISTEMA*/
void leds(int num);
/*Tickers*/
Ticker TiempoBase;
Ticker TiempoRapido;
void base_de_tiempo();
void tiempo_rapido();
/*Timmers*/
Timer ap;

int main()
{
    /*Apago Todos los LEDS*/
    leds(0);
    printf("TRABAJO PRACTICO 1 : MAQUINAS DE ESTADO\r\n EJERCICIO 1\r\n ALUMNOS: FERNANDEZ SANZ Y CLERICI \r\n INICIANDO.............\r\n");
    /*Attach Timmers*/
    TiempoBase.attach(&base_de_tiempo, 0.5f);
    TiempoRapido.attach(&tiempo_rapido, 0.05f);
    /*Inicio PWM*/
    Cooler.period(0.01f);   //Establezco un periodo de 100mS para el PWM

    while(1) {

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /*Maquina de Estados Central del Sistema*/
        switch(Modo) {

            //La primera vez arranco el motor al maximo y inicializo la medicion de velocidad..
            case InicioSistema:
                Cooler.write(1);
                //Espero un tiempo para q arranque el motor
                if(ta > 5) {
                    ta = 0;
                    /*Attach Pin Interrupt del medidor de velocidad*/
                    velocidad.rise(&R_ton);
                    velocidad.fall(&F_ton);
                    printf("Termine de incializar....\r\n");
                    Modo = VelocidadMaxima;
                }

                break;

            //Mido la velocidad maxima del Cooler.. Lo setie al meximo en "InicioSistema"
            case VelocidadMaxima:
                medicion_velocidad();
                break;

            //Mido el Preset y seteo el duty del Cooler en funcion de la lectura
            case  LazoAbierto:
                float lec = Preset;
                cambio_duty_pwm(lec);
                break;

            //Mido la temperatura y establezco la velocidad del Cooler
            case  LazoCerrado:
                control_PWM_Temp();
                break;
        }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        //Actualizo el pulsador...
        CambioDeModo();
        
        RET = !RET; //Cambio el estado del pin de verificacion..

    }
}

//Funcion utilizada para controlar los Leds On Board
//IN ==> Combinacion Binaria de estados || OUT ==> Actualizacion estado de leds

void leds(int num)
{
    switch(num) {
        case 0:
            Rojo = 1;
            Verde = 1;
            Azul = 1;
            break;
        case 4:
            Rojo = 0;
            Verde = 1;
            Azul = 1;
            break;
        case 2:
            Rojo = 1;
            Verde = 0;
            Azul = 1;
            break;
        case 1:
            Rojo = 1;
            Verde = 1;
            Azul = 0;
            break;
        case 7:
            Rojo = 0;
            Verde = 0;
            Azul = 0;
            break;
    }
}

//Maquina de estados que elimina el Rebote de los pulsadores
//IN ==> DigitalIn || OUT ==> Detector de flancos ascendentes del pulsador
bool antirrebote(bool lectura)
{
    static bool lecant = 0;

    switch(estado) {
        case INICIO_P:
            //Si tengo un flanco ascendente
            if((lectura == 1) && (lecant == 0)) {
                estado = RISING_P;
            }
            tp = 0;//Reinicio el acumulador de tiempo
            break;
        case RISING_P:
            /*Devuelvo el estado uno , una unica vez (Saco el rebote)*/
            estado = RETENCION_P;
            tp = 0;
            return 1;   //Devuelvo el estado alto ya que tuve un flanco
        case RETENCION_P:
            /*Durante un segundo y siempre que la lectura siga siendo alta retengo*/
            if((tp >= 2) && (lectura == 0)) {
                estado = INICIO_P;
            }
            break;
    }
    lecant = lectura;   //Asigno el estado previo para el proximo ciclo..
    return 0;           //Devuelvo el estado nulo o cero 
}

//Funcion relacionada al timmer , es llamada cada 0.5 segundos
void base_de_tiempo()
{
    tp ++; //Acumulador Antirebote
    tv ++; //Acumulador Mediciond de velocidad
    ta ++; //Acumulador Inicio del sistema..
    IM++;  //Acumulador Lazo Cerrado
}

//Funcion del timmer dos, es llamada cada 0.05 segundos
void tiempo_rapido()
{
    tcd ++;//Acumulador Cambio de Duty(Lazo Abierto)
    ty ++; //Acumulador Cambio de Duty(Lazo Cerrado)
}

//Funcion dedicada a controlar el pulsador y analizar los cambios de modo..
void CambioDeModo()
{
    /*Si tengo un flanco ascendente en el pulsador (Apretaron)*/
    if(antirrebote(P)) {
        /*Switcheo entre MODO = 1 y MODO = 2 (LazoAbierto | LazoCerrado)*/
        Modo ++;
        if(Modo > 2) {
            Modo = 1;
            printf("Lazo Abierto!!\r\n");
        }
    }
}

/*///////////////////////////////////////////////////////////////////////////ETAPAS DE MEDICION DE VELOCIDAD///////////////////////////////////////////////////////////////////////////*/

/*
UN PERIODO ==> RISE - FALL - RISE
2 PERIODOS ==> Una vuelta 
60 seg ==> 1 minuto / tiempo que tardo en dar una vuelta ==> RPM
*/

/*LA MAQUINA DE ESTADOS SE SUBDIVIDE EN TRES FUNCIONES (2 INTERRUPCIONES + 1 FUNCION EN LA MAQUINA PRINCIPAL)*/

//Interrupcion relacionada al Rising..

void R_ton()
{
    switch(EMV) {
        case INCIO_V:
            ap.reset();     //Reseteo el timmer
            ap.start();     //Inicio la cuenta
            em = 1;         //Aviso que estoy midiendo
            tmv = 0;        //Aviso que no termine de medir
            EMV = RISE_1;
            break;

        case RISE_1:
            printf("ERROR MIDIENDO VELOCIDAD, EMV = %d!!\r\n", EMV);
            break;

        case FALL_1:
            ap.stop();    //Freno el timmer
            tmv = 1;      //Aviso que termine de medir
            em = 0;       //Ya no estoy midiendo
            tv = 0;       //Reinicio el acumulador de tiempo
            EMV = ESPERA_V;
            break;

    }
}

//Interrupcion relacionada a el falling..

void F_ton()
{
    if(em) {
        switch(EMV) {
            case INCIO_V:
                printf("ERROR MIDIENDO VELOCIDAD, EMV = %d!!\r\n", EMV);
                break;
            case RISE_1:
                EMV = FALL_1;
                break;
            case FALL_1:
                printf("ERROR MIDIENDO VELOCIDAD, EMV = %d!!\r\n", EMV);
                break;
        }
    }

}

//Estado final de la maquina de estados
//Aqui genero la cuenta de donde obtengo las RPM y espero el tiempo prudencial..

void medicion_velocidad(void)
{
    if(EMV == ESPERA_V) {
        if(tv >= 1) {
            RPM = 60.00 / (ap.read() * 2);
            printf("Velocidad maxima = %f RPM\r\n",RPM);
            VMAX = RPM;
            tv = 0;
            EMV = INCIO_V;
            Modo = LazoAbierto;
            printf("Modo Lazo Abierto...!\r\n");
        }
    }
}

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



void cambio_duty_pwm(float nuevoDuty)
{
    static float ND = 0;

    switch(ECM) {
        case INICIO_CM:

            ND = nuevoDuty;
            Azul = 1;               //Apago el indicador de LazoCerrado

            //Me fijo si estoy por poner mas o menos el mismo duty para evitar el proceso
            if(abs(ND * 100.00f - DAN * 100.00f ) < 2) {
                //printf("El duty es el mismo del ciclo previo...\r\n");
                tcd = 0;
                ECM = ESPERA_FINAL;
                break;
            }

            printf("Inicio el cambio de duty....\r\n");
            Rojo = 0;
            tcd = 0;
            if(ND < 0.07f) {
                Cooler.write(0);
                duty = 0;
                printf("Cooler APAGADO!\r\n");
                tcd = 0;
                DAN = 0.5f;
                ECM = ESPERA_FINAL;
                Rojo = 1;
                break;
            }
            if(ND >= 0.5f) {
                ECM = CAMBIO_MAYOR;
            } else
                ECM = INICIO_CAMBIO_MENOR;
            break;
        case CAMBIO_MAYOR:
            Cooler.write(ND);
            printf("\tNuevo Duty = %f%\r\n", floor(ND* 100.0f));
            DAN = ND;
            tcd = 0;
            ECM = ESPERA_FINAL;
            break;
        case INICIO_CAMBIO_MENOR:
            cantv = abs( (int(DAN*100)) - (int(ND*100)));
            //printf("\tVoy a hacer %.0f pasos intermedios desde %.0f para llegar a %.0f%\r\n", cantv, DAN*100, ND * 100);
            ECM = CAMBIO_MENOR;
            jv = 0;
            D = DAN;
            break;
        case CAMBIO_MENOR:
            if(cantv >= jv) {
                Cooler.write(D);
                //printf("\t\tEtapa intermedia en %.0f%\r\n", D * 100.00f);
                /*Si quiero alcanzar un duty inferior*/
                if(ND < DAN)
                    D -= 0.01f;                                             //Decremeto 1%
                /*Si quiero alcanzar un duty superior*/
                if(ND > DAN)
                    D += 0.01f;                                             //Incremento 1%
                tcd = 0;
                ECM = ESPERA_DECREMENTO;
                jv++;
                break;
            } else {
                tcd = 0;
                ECM = ESPERA_FINAL;
                printf("\t\tNuevo Duty = %.0f\r\n", floor(ND*100.00f));
                DAN = ND;
            }
            break;
        case ESPERA_DECREMENTO:
            if(tcd >= 2) {
                ECM = CAMBIO_MENOR;
                tcd = 0;
            }
            break;
        case ESPERA_FINAL:
            Rojo = 1;
            if(tcd >= 100) {
                ECM = INICIO_CM;
                tcd = 0;
            }
            break;
    }

}

//Maquina LazoCerrado
void control_PWM_Temp(void)
{
    static float temperatura = 0;
    float val = 0;
    switch(CPT) {
        case INCIO_LAZOCERRADO:
            ECM = 0; //Reincio la maquina de cambio de duty de lazo abierto..
            Rojo = 1;//Apago el Led rojo..
            Azul = 0;//Prendo el Led azuil...
            /*Fijo el duty en 50%*/
            Cooler.write(0.5f);
            duty = 0.5f;
            printf("Lazo Cerrado!!\r\n");
            CPT = MEDICION_TEMPERATURA;
            break;

        case MEDICION_TEMPERATURA:
            probe.convertTemperature(false, DS1820::all_devices);   //Le digo que convierta la temperatura del sensor, false ==> No retiene || True ==> Retiene
            temperatura = probe.temperature();                      //Guardo la temperatura
            printf("La temperatura es de %3.1foC\r\n",temperatura );
            /*Reinicio la medicion de RPM*/
            CPT = MEDICION_RPM;
            tv = 0;
            EMV = INCIO_V;  //Pongo en el estado inicial la maquina de medicion de velocidad
            IM = 0; //Pongo en cero el acumulador para darle un TimeOut a la medicion de velocidad
            break;

        case MEDICION_RPM:
            /*Si termine de medir la velocidad...*/
            if(EMV == ESPERA_V) {
                if(tv >= 1) {
                    RPM = 60.00 / (ap.read() * 2);
                    //printf("Velocidad = %f RPM\r\n",RPM);
                    tv = 0;
                    EMV = INCIO_V;

                    val = floor(temperatura * MinRPM / 20);
                    printf("Deberia tener %f RPM y tengo %f RPM\r\n", val, RPM);

                    /*Aca me fijo si debo modificar el duty*/
                    if(abs(RPM - val) > ToleranciaRPM) {

                        /*Miro que duty debo enviar...*/
                        if(val < RPM)
                            NuevoDuty = duty - DEFINICION_CAMBIO_PWM;
                        if(val > RPM)
                            NuevoDuty = duty + DEFINICION_CAMBIO_PWM;

                        IM = 0;
                        CPT = CAMBIO_PWM;
                        break;
                    } else {
                        printf("EL duty es correcto! Estoy en %0.1f% :D\r\n", floor(duty * 100.0f));
                        IM = 0;
                        CPT = ESPERA_ENTRE_MODIFICACIONES;
                        break;

                    }

                }
            }
            /*Verifico que no se me apago el motor...*/
            if(IM > 10) {
                printf("El cooler estaba apagadoo!!..Reiniciando Lazo cerrado..\r\n");
                EMV = INCIO_LAZOCERRADO;
                IM = 0;
            }

            break;

        case CAMBIO_PWM:
            cambio_gradual_duty(NuevoDuty); //Actualizo el duty, si el valor es menor a 50% hago un proceso especial..
            /*Si termine de modificar el duty*/
            if(tdm) {
                IM = 0;
                CPT = ESPERA_CAMBIOS_PWM;
            }
            break;

        case ESPERA_CAMBIOS_PWM:
            /*Si se cumplio un tiempo prudencial.. El motor se debe adecuar a la nueva velocidad*/
            if(IM >= 2) {
                tdm = 0;            //Reinicio el flag de cambio de duty
                EMV = 0;            //Reinico la maquina de medicion de velocidad..
                IM  = 0;            //Reinicio el acumulador de tiempo
                CPT = MEDICION_RPM; //Mido nuevamente la velocidad y me fijo si debo modificar denuevo
                break;
            }

            break;

        case ESPERA_ENTRE_MODIFICACIONES:
            /*Si se cumplio el tiempo..*/
            if(IM >= 1)
                CPT = MEDICION_TEMPERATURA;
            break;
    }
}

//Maquina de cambio de duty gradual....

void cambio_gradual_duty(float obj)
{
    static float dtf = 0;   //Variable que va a guardar durante todo el proceso el objetivo, es estatico... lo modifico en el estado inicial solamente..

    switch(FTR) {
        case INICIO_CM:
        
            dtf = obj; //Fijo el nuevo objetivo...
            tdm = 0;                //Aviso que estoy modificando el duty...
            printf("Inicio el cambio de duty....\r\n");
            Rojo = 0;

            /*Si estoy por debajo del minimo del Cooler directamente lo apago...*/
            if(dtf < 0.07f) {
                /*Apago el PWM*/
                Cooler.write(0);
                duty = 0;
                //printf("Cooler APAGADO!\r\n");
                /*Voy al final de la maquina*/
                ty = 0;                 //Reinicio el acumulador de tiempo final...
                FTR = ESPERA_FINAL;
                Rojo = 1;
                break;
            }
            if(dtf >= 0.5f) {
                FTR = CAMBIO_MAYOR;
            } else
                FTR = INICIO_CAMBIO_MENOR;
            break;

        case CAMBIO_MAYOR:
            Cooler.write(dtf);   //Coloco el nuevo valor en el PWM de una..
            //printf("\tNuevo Duty = %f%\r\n", dtf * 100);
            duty = dtf;         //Actualizo el duty actual..
            ty = 0;             //Reinicio el acumulador de tiempo base
            FTR = ESPERA_FINAL;
            break;

        case INICIO_CAMBIO_MENOR:
            cantv = abs( (int(duty*100)) - (int(dtf*100))); //Me fijo cuantos pasos intermedios voy a dar...
            //printf("\tVoy a hacer %.0f pasos intermedios desde %.0f para llegar a %.0f%\r\n", cantv, duty*100, dtf * 100);
            D = duty;                                       //Parto desde el PWM actual
            jv = 0;                                         //Reinico el acumulador de veces
            FTR = CAMBIO_MENOR;
            break;

        case CAMBIO_MENOR:
            /*La cantidad de pasos intermedios calculados en el estado anterior...*/
            if(cantv >= jv) {
                Cooler.write(D);                                            //Pongo el duty
                //printf("\t\tEtapa intermedia en %.0f%\r\n", D * 100.00f);
                /*Si quiero alcanzar un duty inferior*/
                if(dtf < duty)
                    D -= 0.01f;                                             //Decremeto 1%
                /*Si quiero alcanzar un duty superior*/
                if(dtf > duty)
                    D += 0.01f;                                             //Incremento 1%

                if(D < 0 || D > 1) {                                         //Si estoy en valores no logicos...
                    //printf("Valores de duty no logicos... ERORR!!!! D:\r\n");
                    FTR = INICIO_CM;
                    break;
                }

                jv++;                                                       //Acumulo el paso realizo en la variable(Lo cuento)..
                ty = 0;                                                     //Reinicio el acumulador de tiempo
                FTR = ESPERA_DECREMENTO;                                    //Espero un tiempo para que se ajuste la salida..
                break;
            }
            /*Si termine con las modificaciones de duty..*/
            else {
                //printf("\t\tNuevo Duty = %.0f\r\n", (D+0.01f)*100);
                duty = dtf;                                                 //Guardo el nuevo valor de duty
                ty = 0;                                                     //Reinicio el acumulador de tiempo base
                FTR = ESPERA_FINAL;                                         //Paso a la espera final...
            }
            break;

        case ESPERA_DECREMENTO:
            /*Si se cumplio el tiempo*/
            if(ty >= 1) {
                ty = 0;            //Reinico el acumulador de tiempo
                FTR = CAMBIO_MENOR;//Paso al nuevo paso
            }
            break;
        case ESPERA_FINAL:
            /*Termine el proceso de cambio de duty*/
            Rojo = 1;             //Apago el led modificador..
            tdm  = 1;             //Notifico a las otras maquinas de estado que termine de modificar el duty..
            /*Si se cumplio el tiempo*/
            if(ty >= 1) {
                ty = 0;          //Reinicio el acumulador de tiempo
                FTR = INICIO_CM; //Vuelvo al estado inicial del proceso..
            }
            break;
    }
}