Nicolás Almaraz
/
TP1_Ejer1
Almaraz Bettig TP1_Ejer1: Sistema de Control
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++; }