Almaraz Bettig TP1_Ejer1: Sistema de Control

Dependencies:   mbed DS1820

main.cpp

Committer:
nicoalmaraz
Date:
2019-06-16
Revision:
10:0d636b09764c
Parent:
9:b6cca45c8314

File content as of revision 10:0d636b09764c:

//Almaraz y Bettig
//TP1 Ejercicio 1: Sistema de Control
#include "mbed.h"
#include "DS1820.h"

char velocidad_angular_leida=0;//Flag que indica si ya termine de medir las rpm
char velocidad_angular_maxima_leida=0;//Flag que indica si ya definí a qué velocidad puede girar el cooler como máximo
char habilitacion_pulsos=0; //Flag que permite contar los pulsos del sensor de efecto hall
char duty_definido=0; //Flag que indica que se definió el duty con el que el cooler gira  a 200rpm
char ruido=0; //Flag que indica que se detectó ruido en el pulsador
char lectura_pulsador_valida=0; //Flag que indica que se detectó un cambio en el pulsador y ya se ejecutó la orden
char sensores_lazo_cerrado_leidos=0; //Flag que indica que ya se terminaron de leer los sensores de temperatura y velocidad angular
int cuenta_pulsos=0;//Variable que cuenta los pulsos del sensor de efecto hall
char modo = 1; //Variable que indica si estoy en modo lazo abierto o modo lazo cerrado
float duty=0; //Variable donde se guarda el duty del PWM del cooler
float velocidad_deseada=0; //Es la velocidad angular a la que corresponde llegar en función de la temperatura leida
unsigned int velocidad_angular_maxima=0; //Es la velocidad máxima que puede alcanzar el cooler empleado
float duty_200_rpm=0.5; //Es el duty con el que el cooler gira  a 200rpm
unsigned int velocidad_angular; //Variable donde se guarda la velocidad angular calculada
float temperatura; //Variable donde se guarda la temperatura recibida por el sensor de temperatura
int tiempo_defino_velocidad_maxima=0; //Variable de tiempo
int tiempo_pulsadores=0; //Variable de tiempo
char tiempo_lazo_abierto=0; //Variable de tiempo
int tiempo_sensor_efecto_hall=0;//Variable de tiempo
int tiempo_cooler=0; //Variable de tiempo
int tiempo_informacion=0;//Variable de tiempo
int tiempo_estabilizacion=0;//Variable de tiempo

void pulsadores(char pulsador);
void timer();
void interrput_sensor_efecto_hall();
void leer_velocidad_angular();
void defino_velocidad_angular_maxima();
void defino_duty_para_lograr_200_rpm();
void lazo_cerrado();
void lectura_sensores_lazo_cerrado();

DS1820 probe(A0);
AnalogIn preset(A1);
DigitalIn pulsador_con_rebote(A2);
PwmOut cooler(A3);
InterruptIn sensor_efecto_hall(D0);
Ticker ticker;

int main()
{
    char sistema_de_control=0;
    sensor_efecto_hall.rise(&interrput_sensor_efecto_hall); //Interrupcion para el sensor de efecto hall
    cooler.period(0.0001f); //PWM para el cooler - 10khz
    ticker.attach(&timer, 0.001); //Timer cada 1ms
    printf("Definiendo velocidad maxima...\r\n");
    while (1) {
        switch(sistema_de_control) {
            default:
            case 0://Hago la medicion de velocidad maxima posible para el cooler empleado
                defino_velocidad_angular_maxima();
                if(velocidad_angular_maxima_leida) {
                    sistema_de_control=1;
                    printf("Velocidad Maxima: %d\r\n\r\nDefiniendo duty necesario para lograr 200 rpm...\r\nEste proceso puede durar varios segundos\r\n", velocidad_angular_maxima);
                }
                break;
            case 1://Determino qué duty necesito para lograr que el cooler gire a 200rpm
                defino_duty_para_lograr_200_rpm();
                if(duty_definido) {
                    sistema_de_control=2;
                    printf("\r\nDuty necesario: %4.1f\r\n",duty_200_rpm*100);
                    printf("\r\n-----------------\r\n");
                    printf("Modo lazo cerrado\r\n");
                    printf("-----------------\r\n\r\n");
                }
                break;
            case 2://Ejecuto el modo lazo cerrado
                lazo_cerrado();
                //Si se presiona el pulsador proceso la información
                if(pulsador_con_rebote==0)
                    sistema_de_control=4;
                break;
            case 3://Ejecuto el modo lazo abierto
                leer_velocidad_angular();
                if(velocidad_angular_leida) {
                    velocidad_angular_leida=0;
                    printf("Velocidad_angular: %d\r\n",velocidad_angular);
                    //Si la velocidad angular es muy baja le doy un "empujon" para subirla
                    if(velocidad_angular<100)
                        duty=1;
                }
                //cada 50ms actualizo el preset
                if(tiempo_lazo_abierto>50) {
                    duty = preset * (1-duty_200_rpm) + duty_200_rpm;
                    tiempo_lazo_abierto=0;
                }
                //Si se presiona el pulsador proceso la información
                if(pulsador_con_rebote==0)
                    sistema_de_control=4;
                break;
            case 4: //Analizo el pulsador y si es necesario cambio de estado
                pulsadores(pulsador_con_rebote);
                if(ruido||lectura_pulsador_valida) {
                    lectura_pulsador_valida=0;
                    if(ruido)
                        printf("Se detecto ruido en el pulsador\r\n");
                    ruido=0;
                    if(modo%2) {
                        sistema_de_control=2;
                        printf("\r\n-----------------\r\n");
                        printf("Modo lazo cerrado\r\n");
                        printf("-----------------\r\n");
                    } else {
                        sistema_de_control=3;
                        printf("\r\n-----------------\r\n");
                        printf("Modo lazo abierto\r\n");
                        printf("-----------------\r\n");
                    }
                }
                break;
        }
        //Actualizo el duty cada 10ms
        if(tiempo_cooler>10) {
            tiempo_cooler=0;
            cooler.write(duty);
        }
    }
}

void defino_velocidad_angular_maxima()
//Esta fucion hace girar el cooler a maxima velocidad y lee cuantas rpm puede alcanzar
{
    static char estado_defino_velocidad_angular_maxima=0;
    switch(estado_defino_velocidad_angular_maxima) {
        default:
        case 0:
            duty=1;
            //Doy 5 segundos a que se acelere el cooler
            if(tiempo_defino_velocidad_maxima>=5000) {
                estado_defino_velocidad_angular_maxima=1;
            }
            break;
        case 1:
            leer_velocidad_angular();
            if(velocidad_angular_leida) {
                velocidad_angular_maxima=velocidad_angular;
                velocidad_angular_leida=0;
                velocidad_angular_maxima_leida=1;
            }
            break;
    }
}

void leer_velocidad_angular()
//Esta funcion cuenta los pulsos que entrega el sensor de efecto hall y calcula las rpm
{
    static char estado_interpretar_velocidad_angular=0;
    switch(estado_interpretar_velocidad_angular) {
        default:
        case 0:
            //Habilito con un flag la cuenta de pulsos en el interrupt del pin
            cuenta_pulsos=0;
            habilitacion_pulsos=1;
            tiempo_sensor_efecto_hall=0;
            estado_interpretar_velocidad_angular=1;
            break;
        case 1:
            //Deshabilito despues de 2 seg y calculo las rpm
            if(tiempo_sensor_efecto_hall>=2000) {
                habilitacion_pulsos=0;
                velocidad_angular=cuenta_pulsos*30/2; //Nuestro cooler da 2 pulsos por vuelta
                estado_interpretar_velocidad_angular=0;
                velocidad_angular_leida=1;
            }
            break;
    }
}

void interrput_sensor_efecto_hall()
{
    if(habilitacion_pulsos)
        cuenta_pulsos++;
}

void defino_duty_para_lograr_200_rpm()
{
    static char estado_definir_200_rpm=0;
    switch(estado_definir_200_rpm) {
        default:
        case 0:
            //Ajusto el duty hasta un aproximado de 200rpm
            //Leo velocidad angular
            leer_velocidad_angular();
            if(velocidad_angular_leida) {
                velocidad_angular_leida=0;
                //Hago ajuste grueso
                if((velocidad_angular>300)||(velocidad_angular<150)) {
                    if(velocidad_angular>=1000)
                        duty-=0.09;
                    if((velocidad_angular>=300)&&(velocidad_angular<1000))
                        duty-=0.01;
                    if(velocidad_angular<150)
                        duty+=0.05;
                    //Protejo contra overflow
                    if(duty<0)
                        duty=0;
                    if(duty>1)
                        duty=1;
                    printf("Velocidad angular: %d, Duty: %4.1f\r\n",velocidad_angular,duty*100);
                } //Si estoy muy proximo hago ajuste fino
                else {
                    estado_definir_200_rpm=1;
                    tiempo_estabilizacion=0;
                    printf("Ya casi termna el proceso...\r\n");
                }
            }
            break;
        case 1:
            //Si estoy muy proximo al valor hago un ajuste fino
            //Dejo funcionar al cooler por 3 segundos asi verificar que
            //mas adelante no se frene o varie su velocidad en ese tiempo
            if(tiempo_estabilizacion>3000) {
                leer_velocidad_angular();
                if(velocidad_angular_leida) {
                    //Me quedo con el duty que haga girar al cooler entre 180rpm y 220rpm
                    if((velocidad_angular<220)&&(velocidad_angular>180)) {
                        duty_definido=1;
                        duty_200_rpm=duty;
                    }
                    //Corrijo la señal vaiando muy de a poco el duty
                    else {
                        printf("Ajuste fino...\r\n");
                        if(velocidad_angular>200)
                            duty-=0.003;
                        if(velocidad_angular<200)
                            duty+=0.003;
                        if(velocidad_angular<150)
                            duty+=0.05;
                    }
                    printf("Velocidad angular: %d, Duty: %4.1f\r\n",velocidad_angular,duty*100);
                    velocidad_angular_leida=0;
                    tiempo_estabilizacion=0;
                    //Si ocurrio algun error y no estoy lo sufucientemente cerca vuelvo al ajuste grueso
                    if((velocidad_angular>350)||(velocidad_angular==0)) {
                        estado_definir_200_rpm=0;
                    }
                }
            }
            break;
    }
}

void lazo_cerrado()
//Máquina de estados del sistema de conrtol lazo cerrado
{
    static char estado_lazo_cerrado=0;
    switch(estado_lazo_cerrado) {
        default:
        case 0:
            //Leo la teperatura y la velocidad angular
            lectura_sensores_lazo_cerrado();
            if(sensores_lazo_cerrado_leidos) {
                sensores_lazo_cerrado_leidos=0;
                estado_lazo_cerrado=1;
            }
            break;
        case 1://Actuo en función de lo leido
            //Caso menor a 20°C
            if(temperatura<20) {
                velocidad_deseada=0;
                duty=0;
            }
            //Caso mayor a 70°C
            if(temperatura>70) {
                velocidad_deseada=velocidad_angular_maxima;
                duty=1;
            }
            //Caso mayor a 20°C y menor a 70°C
            if((temperatura>=20)&&(temperatura<=70))
                velocidad_deseada=(temperatura-20)*(velocidad_angular_maxima-200)/70+200;
            //Cada 2 segundos imprimo los parametros leidos
            if(tiempo_informacion>=2000) {
                tiempo_informacion=0;
                printf("Temperatura: %4.2f oC\r\n",temperatura);
                printf("Velocidad actual: %drpm\r\n",velocidad_angular);
                printf("Velocidad deseada: %4.2frpm\r\n\r\n\r\n",velocidad_deseada);
            }
            //Actuo
            //Si estoy muy lejos del valor deseado varío de al 10%
            if(velocidad_angular<(velocidad_deseada-500))
                duty+=0.1;
            if(velocidad_angular>(velocidad_deseada+500))
                duty-=0.1;
            //Si estoy proimo al valor deseado varío de al 1%
            if(velocidad_angular<(velocidad_deseada))
                duty+=0.01;
            if(velocidad_angular>velocidad_deseada)
                duty-=0.01;
            //Si tengo que hacer arrancar al cooler hago variaciones extras del 20%
            //Ya que hay que vencer la fuerza mínima de arranque
            if((velocidad_angular==0)&&(velocidad_deseada>velocidad_angular))
                duty+=0.2;
            estado_lazo_cerrado=0;
            break;
    }
}

void lectura_sensores_lazo_cerrado()
//Leo los sensores de efecto hall y temperatura
{
    static char estado_sensores_lazo_cerrado=0;
    switch(estado_sensores_lazo_cerrado) {
        default:
        case 0:
            leer_velocidad_angular();
            if(velocidad_angular_leida) {
                velocidad_angular_leida=0;
                estado_sensores_lazo_cerrado=1;
            }
            break;
        case 1:
            //Haciendo pruebas notamos que a veces el sensor mide mal entregando -1000°C
            //Para corregir esto forzamos a que lea siempre bien con un "do while"
            //El rango que consideramos correcto va de -5°C a 500°C
            do {
                probe.convertTemperature(false, DS1820::all_devices);
                temperatura=probe.temperature();
            } while((temperatura<-5)&&(temperatura>500));
            estado_sensores_lazo_cerrado=0;
            sensores_lazo_cerrado_leidos=1;
            break;
    }
}

void pulsadores(char pulsador)
// Leo el pulsador, le quito el rebote y modifico el modo en caso de ser necesario
{
    static char estado_pulsadores;
    switch(estado_pulsadores) {
        default:
        case 0: //Espero a que apreten
            if(pulsador_con_rebote==0) {
                tiempo_pulsadores=0;
                estado_pulsadores=1;
            }
            break;
        case 1: //Espero 50ms para quitar el rebote rise y analizo si fue ruido o realmente presionaron
            if(tiempo_pulsadores>=50) {
                if(pulsador_con_rebote==0) {
                    estado_pulsadores=2;
                    modo++;
                } else {
                    estado_pulsadores=0;
                    ruido=1;
                }
            }
            break;
        case 2: //Si se habia apretado espero a que se suelte
            if(pulsador_con_rebote==1) {
                tiempo_pulsadores=0;
                estado_pulsadores=3;
            }
            break;
        case 3: //Espero 50ms para quitar el rebote fall y analizo si ya se fue o debo darle más tiempo
            if(tiempo_pulsadores<=50) {
                if(pulsador_con_rebote==1) {
                    estado_pulsadores=0;
                    lectura_pulsador_valida=1;
                } else
                    tiempo_pulsadores=0; // si todavia no se fue el rebote espero más tiempo
            }
            break;
    }
}

void timer()
//Incremento contadores cada 1ms
{
    tiempo_pulsadores++;
    tiempo_lazo_abierto++;
    tiempo_defino_velocidad_maxima++;
    tiempo_cooler++;
    tiempo_informacion++;
    tiempo_sensor_efecto_hall++;
    tiempo_estabilizacion++;
}