![](/media/cache/profiles/IMG-20170731-WA002223234124.jpg.50x50_q85.jpg)
Controlador PID
Dependencies: Debounced Pulse1 QEI RTC-DS1307 TextLCD_1 mbed
Fork of grafica_PID_android by
Diff: main.cpp
- Revision:
- 5:f39e8f190857
- Parent:
- 4:82ac4b34c3d9
diff -r 82ac4b34c3d9 -r f39e8f190857 main.cpp --- a/main.cpp Sat Jun 03 01:07:49 2017 +0000 +++ b/main.cpp Tue Jun 05 15:42:17 2018 +0000 @@ -1,255 +1,451 @@ /* - * Código por: Laura Álvila - * Daniela López - * Nicolás Villegas - */ - +ESTE PROGRAMA SIMULA EL CONTROL DE UN HORNO DE REFLUJO CON UN PID, USANDO SALIDA ANALÓGICA +O PWM (OPCION DISPONIBLE EN MENU). ADEMÁS SE ENVÍAN LOS DATOS POR BLUETOOTH A UNA APLICACIÓN +EN ANDROID (DESARROLLADA EN APPINVENTOR) PARA SU VISUALIZACIÓN. +ESTA TAREA FUE DESARROLLADA POR SEBASTIÁN CAMILO CASTAÑO VANEGAS Y CARLOS MAURICIO ALZATE TORRES +PARA LA MATERIA DE PROCESADORES DE LA UNIVERSIDAD NACIONAL DE MEDELLÍN SEMESTRE I DEL AÑO 2018 +*/ + #include "mbed.h" +#include "DebouncedIn.h" +#include "TextLCD.h" #include "QEI.h" -#include "TextLCD.h" +#include "Rtc_Ds1307.h" +#include "string.h" +#include "Pulse1.h" Serial GSM(PTE0,PTE1); // Módulo Bluetooh TextLCD lcd(PTB10, PTB11, PTE2, PTE3, PTE4, PTE5); // rs, e, d4-d7 -QEI encoder (PTA13, PTD5, NC, 10); +Rtc_Ds1307 rtc(PTC9, PTC8); //Reloj +QEI wheel (PTA13, PTD5, NC, 10); Timer t; AnalogIn y(PTC2); // Entrada análoga: Salida del sistema AnalogOut u(PTE30); // Salida análoga: Señal de control +PwmOut u2(PTE29); // Salida wn PWM: Señal de control +DigitalOut rele(PTB8); // Activación de relé -DigitalOut led1(LED1); -DigitalOut led2(LED2); -DigitalOut led3(LED3); +DigitalOut red(LED1); +DigitalOut green(LED2); +DigitalOut blue(LED3); -DigitalIn button3(PTC16); // Botón del encoder -DigitalIn button4(PTC17); // Pulsador +DebouncedIn button3(PTC16); // Botón del encoder -> cambiar opciones dentro de los menu +DebouncedIn button4(PTC17); // Pulsador -> cambiar de menu int C1=0x0F; int C2=0x18; int C3=0x1A; int C4=0x0C; - +int conta=0; +int m=0; int cambio = 0, diferencia = 0; float pid, o, ai, ad, ap, med, err, setpoint; float err_v; -int spnum = 0, kinum = 0, kpnum = 0 ,kdnum = 0, pos = 1; +int spnum = 0, kinum = 15, kpnum = 50 ,kdnum = 3; int j,k; long t_pid = 0, t_btn = 0; -int main() { +int c = 0; //consigna +int min = 0; //minutos +int seg = 0; //segundos +int T1 = 120,T2 = 180,T3 = 240; //tiempos consigna +int Tmax = 500; //temperatura maxima +int TI = 25; //temperatura ambiente (Fija) +int pos = 0; // posicion inicializada en cero +int state = 0; // estado inicializado en cero +int selsalida=0; //Salida Análoga:0 PWM:1 +int salidaAn=0; int salidaPWM=0; +int tiemp=0; + +// FUNCIONES ---------------------------------------------------------------------------------------------------- + +// Funcion para consigna + +void cons(int m, int n){ - // Se asigna baudrate y se configura el puerto serie de la USART + tiemp= 60*m+ n; //el tiempo a segundos + if(tiemp <=T1){ + c = ((Tmax-TI)*tiemp/T1)+TI; //Tramo 1: Rampa subida temperatura + } + else if(tiemp > T1 and tiemp <= T2){ + c = Tmax; + } + else if(tiemp > T2 and tiemp <= T3){ + c = ((TI - Tmax)*(tiemp-T2)/(T3-T2)) + Tmax; + } + else if(tiemp>T3){ + c = TI; + } +} + +//Funcion para presiones de botones +void buttpress(){ + //Presion boton de encoder + if (button3.falling()) + { + pos++; + } + if (button4.falling()) + { + state++; + pos=0; + conta=0; + selsalida=0; + rele=0; + lcd.cls(); + lcd.writeCommand(C1); + } +} + +// FUNCIÓN PRINCIPAL +int main() { + red=1; + blue=1; + green=1; + rele=0; + Rtc_Ds1307::Time_rtc tm = {}; //Estructura para el reloj + rtc.getTime(tm); //lee el tiempo del DS1307 + u2.period_ms(10); + // Se asigna baudrate y se configura el puerto serie de la USART GSM.baud(9600); GSM.format(8,Serial::None,1); t.start(); - - // Animación de bienvenida: - - for (int i = 3; i < 15; ++i) { - lcd.cls(); - lcd.locate(0,0); - lcd.printf("**Control PID**"); - wait_ms(1000/i); - - ++i; - lcd.cls(); - lcd.locate(1,0); - lcd.printf("**Control PID**"); - wait_ms(1000/i); - - ++i; - lcd.cls(); - lcd.locate(1,1); - lcd.printf("**Control PID**"); - wait_ms(1000/i); - - ++i; - lcd.cls(); - lcd.locate(0,1); - lcd.printf("**Control PID**"); - wait_ms(1000/i); - } - -init: - + lcd.cls(); + lcd.locate(0,0); + lcd.printf(" Control PID "); + lcd.locate(0,1); + lcd.printf("Horno de reflujo"); + wait_ms(3000); lcd.cls(); lcd.writeCommand(C1); - - lcd.locate(8,0); - lcd.printf("Ki=%d", kinum); - lcd.locate(0,1); - lcd.printf("Kd=%d", kdnum); - - lcd.locate(8,1); - lcd.printf("**PID**"); - - lcd.locate(0,0); - lcd.printf("Kp=%d", kpnum); - - bool state = 1; // Esta variable determina si se están modificando las constantes del controlador o el Set-Point. - - while(true) { - - diferencia=(encoder.getPulses() - cambio)*3; - cambio=encoder.getPulses(); - - if (diferencia != 0 && state) { - switch (pos) { - case 1: - kpnum += diferencia; - - if (kpnum >= 999) - kpnum = 999; - else if (kpnum < 0) - kpnum = 0; - - lcd.locate(3,0); - lcd.printf(" "); - lcd.locate(3,0); - lcd.printf("%d", kpnum); - break; - case 2: - kinum += diferencia; - - if (kinum >= 999) - kinum = 999; - else if (kinum < 0) - kinum = 0; - - lcd.locate(11,0); - lcd.printf(" "); - lcd.locate(11,0); - lcd.printf("%d", kinum); - break; - case 3: - kdnum += diferencia; - - if (kdnum >= 999) - kdnum = 999; - else if (kdnum < 0) - kdnum = 0; - - lcd.locate(3,1); - lcd.printf(" "); - lcd.locate(3,1); - lcd.printf("%d", kdnum); - break; - } - } - - if (diferencia != 0 && !state) { - - spnum += diferencia; - - if (spnum >= 999) spnum = 999; - else if (spnum < 0) spnum = 0; + while(true){ + switch(state%4){ //Menus + case 0: //Menu 1: Configuracion controlador + //Grafica titulos + if(conta==0){ + lcd.locate(0,0); + lcd.printf(" Constantes PID "); + wait_ms(2000); + lcd.cls(); + conta++; + } + lcd.locate(0,0); + lcd.printf("Kp= %03d",kpnum); + lcd.locate(8,0); + lcd.printf("Ki= %03d",kinum); + lcd.locate(0,1); + lcd.printf("Kd= %03d",kdnum); + switch(pos%3){ //Configuracion variables + case 0: //Kp + red=0; + blue=1; + green=1; + m=0; + m=wheel.getPulses(); + if (m!=0) + { + kpnum+=m*3; + if (kpnum >= 999) + kpnum = 999; + else if (kpnum < 0) + kpnum = 0; + wheel.reset(); + m=0; + } + lcd.locate(4,0); + lcd.printf("%03d", kpnum); + buttpress(); //Verifica si se presiono el boton + break; + case 1: //Ki + red=1; + blue=1; + green=0; + m=0; + m=wheel.getPulses(); + if (m!=0) + { + kinum+=m*3; + if (kinum >= 999) + kinum = 999; + else if (kinum < 0) + kinum = 0; + wheel.reset(); + m=0; + } + lcd.locate(12,0); + lcd.printf("%03d", kinum); + buttpress(); //Verifica si se presiono el boton + break; + case 2: //Kd + red=1; + blue=0; + green=1; + m=0; + m=wheel.getPulses(); + if (m!=0) + { + kdnum+=m*3; + if (kdnum >= 999) + kdnum = 999; + else if (kdnum < 0) + kdnum = 0; + wheel.reset(); + m=0; + } + lcd.locate(4,1); + lcd.printf("%03d", kdnum); + buttpress(); //Verifica si se presiono el boton + break; + } + break; + case 1: //Menu 2: Configuracion referencia + if(conta==0){ + lcd.locate(0,0); + lcd.printf(" Parametros del "); + lcd.locate(0,1); + lcd.printf(" Horno "); + wait_ms(2000); + lcd.cls(); + conta++; + } + //Grafica titulos + red=0; + blue=0; + green=0; + lcd.locate(0,0); + lcd.printf("Tmax="); + lcd.locate(9,0); + lcd.printf("T1="); + lcd.locate(0,1); + lcd.printf("T2="); + lcd.locate(9,1); + lcd.printf("T3="); + //Grafica valores iniciales de variables + lcd.locate(5,0); + lcd.printf("%03d",Tmax); + lcd.locate(12,0); + lcd.printf("%04d",T1); + lcd.locate(3,1); + lcd.printf("%04d",T2); + lcd.locate(12,1); + lcd.printf("%04d",T3); + + switch(pos%4){ // Se mueve entre las variables + case 0: + m=0; + m=wheel.getPulses(); + if (m!=0) + { + Tmax+=m*10; + if (Tmax >= 800) + Tmax = 800; + else if (Tmax < TI) + Tmax = TI; + wheel.reset(); + m=0; + } + lcd.locate(5,0); + lcd.printf("%03d", Tmax); + buttpress(); + break; - lcd.locate(10,0); - lcd.printf(" "); - lcd.locate(10,0); - lcd.printf("%d", spnum); - } - - - if (!button3) { // Cambia la posición de ingreso de parámetros - led2 = !led2; - switch(pos++) { - case 3: - pos = 1; - lcd.locate(3,0); - lcd.printf("%d", kpnum); - break; case 1: - lcd.locate(11,0); - lcd.printf("%d", kinum); - break; + m=0; + m=wheel.getPulses(); + if (m!=0) + { + T1+=m*10; + if (T1 >= 1800) + T1 = 1800; + else if (T1 < 0) + T1 = 0; + wheel.reset(); + m=0; + } + if (T2<T1)T2=T1; + lcd.locate(12,0); + lcd.printf("%4d", T1); + buttpress(); + break; + case 2: + m=0; + m=wheel.getPulses(); + if (m!=0) + { + T2+=m*10; + if (T2 >= 1800) + T2 = 1800; + else if (T2 < T1) + T2 = T1; + wheel.reset(); + m=0; + } + if (T3<T2)T3=T2; lcd.locate(3,1); - lcd.printf("%d", kdnum); - break; + lcd.printf("%4d", T2); + buttpress(); + break; + + case 3: + m=0; + m=wheel.getPulses(); + if (m!=0) + { + T3+=m*10; + if (T3 >= 1800) + T3 = 1800; + else if (T3 < T2) + T3 = T2; + wheel.reset(); + m=0; + } + lcd.locate(12,1); + lcd.printf("%4d", T3); + buttpress(); + break; } - wait(0.2); - } - - if (!button4 && state) { - lcd.cls(); - lcd.locate(8,1); - lcd.printf("**PID**"); + break; +////// ELECCIÓN DE SALIDA ///////////////////////////////////////////////////////////////////////////////////////////////////// + case 2: + if(conta==0){ + lcd.locate(0,0); + lcd.printf(" Seleccione el "); + lcd.locate(0,1); + lcd.printf(" tipo de salida "); + wait(2); + lcd.locate(0,0); + lcd.printf("-> Analogica "); + lcd.locate(0,1); + lcd.printf("-- PWM "); + conta++; + } + if(selsalida==0) //Salida Analógica + { + red=0; + green=1; + blue=1; + salidaAn=1; + salidaPWM=0; + m=wheel.getPulses(); + if(m!=0) + { + selsalida=1; + m=0; + wheel.reset(); + + lcd.locate(1,0); + lcd.printf("- Analogica "); + lcd.locate(1,1); + lcd.printf("> PWM "); + } + } + + /////////////////// + + if(selsalida==1) //Salida PWM + { + red=1; + green=1; + blue=0; + salidaAn=0; + salidaPWM=1; + m=wheel.getPulses(); + if(m!=0) + { + selsalida=0; + m=0; + wheel.reset(); + + lcd.locate(1,0); + lcd.printf("> Analogica "); + lcd.locate(1,1); + lcd.printf("- PWM "); + } + } + + if (button4.falling()) + { + state++; + pos=0; + conta=0; + lcd.cls(); + lcd.writeCommand(C1); + } + break; + case 3: // Menu 3: Dinamica del sistema y visualizacion + //control: + + rtc.getTime(tm); //READING THE RTC + //Grafica titulos + if(conta==0){ + + if (salidaAn==1){ + red=0; + green=1; + blue=1; + } + if (salidaPWM==1){ + red=1; + green=1; + blue=0; + rele=1; + } + + lcd.locate(0,0);lcd.printf(" Parametros "); + lcd.locate(0,1);lcd.printf(" Guardados "); + wait(1.5); + lcd.locate(0,0);lcd.printf(" Inicia control "); + lcd.locate(0,1);lcd.printf(" de reflujo "); + wait(1.5); + lcd.cls(); + tm.min=0; + tm.sec=0; + conta++; + rtc.setTime(tm,true,false); + } + min=tm.min; + seg=tm.sec; + cons(min,seg); lcd.locate(0,0); - lcd.printf("Set-Point="); - lcd.locate(10,0); - lcd.printf("%d", spnum); - wait(0.2); - state = 0; - } - else if (!button4 && !state) { - wait(0.2); - break; - } - wait(0.1); - } - - - // Transición - lcd.writeCommand(C4); // Escribimos un comando segun el manual del módulo LCD para quitar cursor bajo - lcd.cls(); - lcd.locate(0,0); lcd.printf("y="); - lcd.locate(8,0); lcd.printf("e="); - lcd.locate(0,1); lcd.printf("r="); - lcd.locate(8,1); lcd.printf("u="); - -loop: + lcd.printf("y= %3.0f",med); + lcd.locate(8,0); + lcd.printf("e=%3.0f ",err); + lcd.locate(0,1); + lcd.printf("r= %03d",c); + lcd.locate(8,1); + lcd.printf("t=%02d:%02d ",tm.min,tm.sec); - if (t.read_ms() - t_pid > 10) { - - med = y.read()*999; - err = spnum - med; // Se calcula el error - ap = kpnum*err*0.01f; // Se calcula la acción proporcional - ai += kinum*err*0.01f; // Cálculo de la integral del error - ad = kdnum*(err - err_v)*0.01f; // Cálculo de la acción derivativa - pid = ap + ai + ad; - - if (pid <= 0) pid = 0; - if (pid > 999) pid = 999; - - setpoint = spnum; - GSM.printf("#%3.0f%3.0f&", med, setpoint); // Se envía una cadena de caracteres por el puerto serial. Se agregan identificadores #...& que denotan el comienzo y la terminación de la misma. - // Esto se hace con el fin de evitar errores en la transmisión. Estos identificadores se usan en la aplicación de AppInventor. - lcd.locate(3,0); lcd.printf("%3.0f ", med); - lcd.locate(3,1); lcd.printf("%3d ", spnum); - lcd.locate(11,0); lcd.printf("%3.0f ", err); - lcd.locate(11,1); lcd.printf("%3.0f ", pid); - - err_v = err; - o = pid/999; - u.write(o); - - t_pid = t.read_ms(); + if (t.read_ms() - t_pid > 20) { + cons(min,seg); + med = y.read()*999; + err = c - med; // Se calcula el error + ap = kpnum*err*0.01f; // Se calcula la acción proporcional + ai += kinum*err*0.01f; // Cálculo de la integral del error + ad = kdnum*(err - err_v)*0.01f; // Cálculo de la acción derivativa + pid = ap + ai + ad; + + if (pid <= 0) pid = 0; + if (pid > 999) pid = 999; + + setpoint = c; + GSM.printf("#%3.0f%3.0f&", med, setpoint); // Se envía una cadena de caracteres por el puerto serial. Se agregan identificadores #...& que denotan el comienzo y la terminación de la misma. + // Esto se hace con el fin de evitar errores en la transmisión. Estos identificadores se usan en la aplicación de AppInventor. + err_v = err; + o = pid/999; + if (salidaAn==1)u.write(o); + if (salidaPWM==1)u2.write(o); + t_pid = t.read_ms(); + } + + buttpress(); + break; + } - else { - - diferencia=(encoder.getPulses() - cambio)*6; // Es posible cambiar el Set-Point cuando el controlador ya está funcionando. - cambio=encoder.getPulses(); - - if (diferencia != 0) { - spnum += diferencia; - if (spnum >= 999) spnum = 999; - else if (spnum < 0) spnum = 0; - } - } - - if (!button4) { // Si se presiona el pulsador se vuelve al menú inicial para configurar de nuevo el controlador. - u.write(0); - med = 0; - err = 0; - pid = 0; - - goto init; - } - else - goto loop; - -} \ No newline at end of file +} + +