PID for ramp temperature control using LM35 temperature sensor and two actuators, a bulb and a ventilator.
Dependencies: DebouncedIn QEI TextLCD_encoder mbed
Fork of PID_Encoder by
Diff: main.cpp
- Revision:
- 5:ad88703dc6d3
- Parent:
- 4:d42fe3777735
diff -r d42fe3777735 -r ad88703dc6d3 main.cpp --- a/main.cpp Sat May 24 15:05:40 2014 +0000 +++ b/main.cpp Thu Jun 12 16:43:28 2014 +0000 @@ -1,248 +1,517 @@ #include "mbed.h" #include "DebouncedIn.h" #include "TextLCD.h" -#include "QEI.h" +#include "QEI.h" -TextLCD lcd(PTB10, PTB11, PTE2, PTE3, PTE4, PTE5); // rs, e, d4-d7 -QEI wheel (PTD5, PTD0, NC, 100); -AnalogIn y(PTB1); -AnalogOut u(PTE30); -DigitalOut led1(LED1); -DigitalOut led2(LED2); -DigitalOut led3(LED3); -DebouncedIn button1(PTC12); -DebouncedIn button2(PTC13); -DebouncedIn button3(PTC16); -DebouncedIn button4(PTC17); +TextLCD lcd(PTB10, PTB11, PTE2, PTE3, PTE4, PTE5); // rs, e, d4-d7 entradas del LCD +QEI wheel (PTD5, PTD0, NC, 100); // entradas para el ENCODER +AnalogIn LM(PTB1); // temperatura leida por un LM35 +PwmOut bomb(PTD4); //salida para activar un bombillo +PwmOut vent(PTA12); //salida para activar un ventilador +DigitalOut led3(LED3); // Led para indicar que los botones se presionan +DebouncedIn button3(PTC16); //boton 3 es el pulsador del ENCODER +DebouncedIn button4(PTA13); // boton 4 es para la configuración de las constantes del pid, de tiempo de rampa y de temperatura del horno - //codigos movimiento del curzor - //18 para izquierda - //1A para derecha - -//int C1=0x0E; // solo muestra el curzor +//codigos movimiento del curzor LCD int C2=0x18; // desplaza izquierda int C3=0x1A; // desplaza derecha int C4=0x0C; // quito cursor bajo -int C1=0x0F; +int C1=0x0F; // solo muestra el curzor + -int i; // indice de la variable -int j; //variable controla cambio 4 posiciones -int kp, ki, kd, sp; -float yr, ap, ai, ad, err, med, err_v, cycle, pid; -int b=0; +//definicion de varibles +int i=1; // i controla cambio de "modo" del boton 4. i=1 -> (constantes PID), i=2 -> (Tiempo y temperatura) +int j=1; //j controla cambio de posiciones para cambiar variable (con el boton del ENCODER) +int kp=40, ki=40, kd=40, sp; //constantes del pid y del setpoint +int t1=60, t2=60, t3=60; //tiempos de la rapmpa de subida, temperatura estable y tiempo de bajada t1=t2=t3 [segundos] +int temp=45; // temp:temperatura final a la que llega el horno[ºC] +float ta, avg, a[10]; // ta: temperatura ambiente que se lee con el LM35, antes de empezar control, avg, promedio de temperatura para minimizar error +float yr, ap, ai, ad, err, med, err_v, cycle, pid; // +float dt1, dt2, dt3,c=0; // variables para ciclos de control en tiempos t1, t2 y t3 +int b=0; // Se usa para imprimir datos en la LCD float pidn; Timer t; -int main() { - lcd.cls(); - lcd.writeCommand(C1);//escribimos un comando segun el manual del modulo LCD - lcd.locate(0,0); - lcd.printf("Sp%d",sp); - lcd.locate(8,0); - lcd.printf("Kp%d",kp); - lcd.locate(0,1); - lcd.printf("Ki%d",ki); - lcd.locate(8,1); - lcd.printf("Kd%d",kd); - +// Inicia el código +int main() +{ while(1) { - - led3 =1; - if (button3.falling()) { //INCREMENTA POSICION DEL MENU CON BOTON 3 (Switche encoder) - led3 =!led3; - ++j; - } - - if (j==0){ - sp=sp+wheel.getPulses(); - wheel.reset(); - if (sp>999){ - sp=999; - } - if (sp<0){ - sp=0; - } - lcd.locate(2,0); - lcd.printf(" ",sp); - lcd.locate(2,0); - lcd.printf("%d",sp); - wait(0.2); - - if(button3.falling()){ - j=1; - led3=0; - wait(0.3); - wheel.reset(); - } - - } - - if (j==1) { - kp=kp+wheel.getPulses(); - wheel.reset(); - if (kp>999){ - kp=999; - } - if (kp<0){ - kp=0; - } - lcd.locate(10,0); - lcd.printf(" "); - lcd.locate(10,0); - lcd.printf("%d",kp); - wait(0.2); - - if(button3.falling()){ - j=2; - led3=0; - wait(0.3); - wheel.reset(); - } - - } - - if (j==2) { - ki=ki+wheel.getPulses(); - wheel.reset(); - if (ki>999){ - ki=999; - } - if (ki<0){ - ki=0; - } - lcd.locate(2,1); - lcd.printf(" "); - lcd.locate(2,1); - lcd.printf("%d",ki); - wait(0.2); - - if(button3.falling()){ - j=3; - led3=0; - wait(0.3); - wheel.reset(); - } - - } - - if (j==3) { - kd=kd+wheel.getPulses(); - wheel.reset(); - if (kd>999){ - kd=999; - } - if (kd<0){ - kd=0; - } - lcd.locate(10,1); - lcd.printf(" "); - lcd.locate(10,1); - lcd.printf("%d",kd); - wait(0.2); - - if(button3.falling()){ - j=0; - led3=0; - wait(0.3); - wheel.reset(); - } - - } - - if (j==4) { - j=0; - } - - if (!button4){ - break; //sale del bucle si pisan suiche4 - } - } //cierro while(1) -//%--------------------------------------------------------------------- - - - lcd.writeCommand(C4);//escribimos un comando segun el manual del modulo LCD para quitar cursor bajo - lcd.cls(); //borra la pantalla - lcd.printf("GUARDAMOS \nVALORES |m|"); - wait(2); - - // se imprimen los parches del control ***************************************** - lcd.cls(); - lcd.printf("Er%d",err); - lcd.locate(8,0); - lcd.printf("Me%d",med); - lcd.locate(0,1); - lcd.printf("Sp%d",sp); - lcd.locate(8,1); - lcd.printf("Co%d",pid); - wait(1); - - - // CICLO PRINCIPAL CONTROLADOR PID - b=0; - while(1) { - med=1000*y.read(); //leer puerto analogo y asignar a med - err = (sp-med); - ap = kp*err; - - // se verifica que la accion integral no sea muy grande - if(ai<100) - { - ai =(ki*err)+ai; //calculo de la integral del error - } - //else{ - //Dejo de sumar la accion integral - // } - - ad = kd*(err-err_v); //calculo de la accion derivativa - pid = (ap+ai+ad); - - - - // se verifica que pid sea positivo ************************************** - if(pid<=0){pid=0;} - // se verifica que pid sea menor o igual la valor maximo ***************** - if(pid>=1000){pid=1000;} - - // se actualizan las variables ******************************************* - err_v = err; - - //se muestran las variables****************************************** - - if (b==0) - { - t.start(); - b=1; - } - if(t>=0.01) - { - wait(0.2); - lcd.locate(2,0); - lcd.printf(" "); - lcd.locate(2,0); - lcd.printf("%d",err); - lcd.locate(10,0); - lcd.printf(" "); - lcd.locate(10,0); - lcd.printf("%d",med); - lcd.locate(2,1); - lcd.printf(" "); - lcd.locate(2,1); - lcd.printf("%d",sp); - lcd.locate(10,1); - lcd.printf(" "); - lcd.locate(10,1); - lcd.printf("%d",pid); - } - - //Normalizacion de la salida - pidn=pid/1000; - // se envia el valor pid a puerto analogico de salida (D/A) ************** - u.write(pidn); - - // se repite el ciclo - wait(0.1); - } - - + if(i==1) { + lcd.cls(); + lcd.writeCommand(C1);//escribimos un comando segun el manual del modulo LCD + lcd.locate(0,0); + lcd.printf(" PID"); + lcd.locate(8,0); + lcd.printf("Kp:%d",kp); + lcd.locate(0,1); + lcd.printf("Ki:%d",ki); + lcd.locate(8,1); + lcd.printf("Kd:%d",kd); + + led3 =1; + if (button3.falling()) { //INCREMENTA POSICION DEL MENU CON BOTON 3 (Switche encoder) + led3 =!led3; + } + + if (j==1) { + kp=kp+wheel.getPulses(); + wheel.reset(); + if (kp>999) { + kp=999; + } + if (kp<0) { + kp=0; + } + lcd.locate(11,0); + lcd.printf(" "); + lcd.locate(11,0); + lcd.printf("%d",kp); + wait(0.2); + + if(button3.falling()) { + j=2; + led3=0; + wait(0.3); + wheel.reset(); + } + } + if (j==2) { + ki=ki+wheel.getPulses(); + wheel.reset(); + if (ki>999) { + ki=999; + } + if (ki<0) { + ki=0; + } + lcd.locate(3,1); + lcd.printf(" "); + lcd.locate(3,1); + lcd.printf("%d",ki); + wait(0.2); + + if(button3.falling()) { + j=3; + led3=0; + wait(0.3); + wheel.reset(); + } + } + if (j==3) { + kd=kd+wheel.getPulses(); + wheel.reset(); + if (kd>999) { + kd=999; + } + if (kd<0) { + kd=0; + } + lcd.locate(11,1); + lcd.printf(" "); + lcd.locate(11,1); + lcd.printf("%d",kd); + wait(0.2); + + if(button3.falling()) { + j=1; + led3=0; + wait(0.3); + wheel.reset(); + } + } + if (j==4) { + j=1; + } + if(button4.falling()) { + i=2; + j=0; + } + }//CIERRA EL MODO i=1 -> constantes PID + if(i==2) { //INICIA EL MODO i=2 -> tiempos y temperatura + lcd.cls(); + lcd.writeCommand(C1);//escribimos un comando segun el manual del modulo LCD + lcd.locate(0,0); + lcd.printf("T1:%d",t1); + lcd.locate(8,0); + lcd.printf("T2:%d",t2); + lcd.locate(0,1); + lcd.printf("T3:%d",t3); + lcd.locate(8,1); + lcd.printf("Tm:%d",temp); + + + led3 =1; + if (button3.falling()) { //INCREMENTA POSICION DEL MENU CON BOTON 3 (Switche encoder) + led3 =!led3; + } + if (j==0) { + t1=t1+wheel.getPulses(); + wheel.reset(); + if (t1>5*60) { // Tiempos no mayores a 6 minutos + t1=5*60; + } + if (t1<60) { + t1=60; + } + lcd.locate(3,0); + lcd.printf(" ",t1); + lcd.locate(3,0); + lcd.printf("%d",t1); + wait(0.2); + + if(button3.falling()) { + j=1; + led3=0; + wait(0.3); + wheel.reset(); + } + } + + if (j==1) { + t2=t2+wheel.getPulses(); + wheel.reset(); + if (t2>5*60) { + t2=5*60; + } + if (t2<60) { + t2=60; + } + lcd.locate(11,0); + lcd.printf(" "); + lcd.locate(11,0); + lcd.printf("%d",t2); + wait(0.2); + + if(button3.falling()) { + j=2; + led3=0; + wait(0.3); + wheel.reset(); + } + } + if (j==2) { + t3=t3+wheel.getPulses(); + wheel.reset(); + if (t3>5*60) { + t3=5*60; + } + if (t3<60) { + t3=60; + } + lcd.locate(3,1); + lcd.printf(" "); + lcd.locate(3,1); + lcd.printf("%d",t3); + wait(0.2); + + if(button3.falling()) { + j=3; + led3=0; + wait(0.3); + wheel.reset(); + } + } + if (j==3) { + temp=temp+wheel.getPulses(); + wheel.reset(); + if (temp>60) { + temp=60; + } + if (temp<20) { + temp=20; + } + lcd.locate(11,1); + lcd.printf(" "); + lcd.locate(11,1); + lcd.printf("%d",temp); + wait(0.2); + + if(button3.falling()) { + j=0; + led3=0; + wait(0.3); + wheel.reset(); + } + } + if (j==4) { + j=0; + } + if (button4.falling()) { + break; + } + }//CIERRE MODO i=2 -> tiempo y temperatura + }// Cierre del while(1) +//%--------------------------------------------------------------------- + + + lcd.writeCommand(C4);//escribimos un comando segun el manual del modulo LCD para quitar cursor bajo + lcd.cls(); //borra la pantalla + lcd.printf("Valores \nGuardados"); + wait(1); + + avg=0; + for(i=0; i<10; i++) { + a[i]=LM.read(); + wait(.001); + } + for(i=0; i<10; i++) { + avg=avg+(a[i]/10); + } + + ta=(avg*3.10143686*100); + + lcd.cls(); //borra la pantalla + lcd.printf("T Ambiente:%.2f",ta); + wait(2); + + // se imprimen los parches del control ***************************************** + lcd.cls(); + lcd.printf("Er:%.2f",err); + lcd.locate(8,0); + lcd.printf("Me:%.2f",med); + lcd.locate(0,1); + lcd.printf("dt:%.2f",dt1); + lcd.locate(10,1); + lcd.printf("t:%.0f",0); + wait(1); + + // CICLO PARA CONTROL DE RAMPA ASCENDENTE (T1) + b=0; + t.start(); + // Comienza el ciclo for para la primera parte del control(Rampa ascendente) + for(dt1=ta; dt1<=temp; dt1+=(temp-ta)/t1) { + avg=0; + for(i=0; i<10; i++) { + a[i]=LM.read(); + wait(.001); } - \ No newline at end of file + for(i=0; i<10; i++) { + avg=avg+(a[i]/10); + } + med=(avg*3.10143686*100); //leer puerto analogo y asignar a med (*100 ya que LM35 da 10mV/ºC) + err = (dt1-med); + // Para activar la bombilla en el tiempo de ascenso + if(err>=0) { + vent=0; + ap = kp*err; //calculo de la acción proporcional + // se verifica que la accion integral no sea muy grande + if(ai<100) { + ai =(ki*err)+ai; //calculo de la integral del error + } + ad = kd*(err-err_v); //calculo de la accion derivativa + pid = (ap+ai+ad); + // se verifica que pid sea positivo ************************************** + if(pid<=0) { + pid=0; + } + // se verifica que pid sea menor o igual la valor maximo ***************** + if(pid>=100) { + pid=100; + } + err_v = err; + //Normalizacion de la salida + pidn=pid/100; + // se envia el valor pid a puerto analogico de salida (D/A) ************** + bomb.write(pidn); + } + // Para activar ventilador en el tiempo de ascenso + if(err<0) { + bomb=0; + err=-1*err; + ap = kp*err; + if(ai<100) { + ai =(ki*err)+ai; + } + ad = kd*(err-err_v); + pid = (ap+ai+ad); + if(pid<=0) { + pid=0; + } + if(pid>=100) { + pid=100; + } + err_v = err; + pidn=pid/100; + vent.write(pidn); + } + // se repite el ciclo + lcd.cls(); + lcd.locate(0,0); + lcd.printf("Er:%.2f",err); + lcd.locate(8,0); + lcd.printf("Me:%.2f",med); + lcd.locate(0,1); + lcd.printf("dt:%.2f",dt1); + lcd.locate(10,1); + lcd.printf("t1:%.0f",t.read()); + wait(1); + } + bomb=0; + vent=0; + // Comienza el segundo ciclo para la segunda parte del control (Temperatura estable) + t.start(); + while(t<=t2) { + avg=0; + for(i=0; i<10; i++) { + a[i]=LM.read(); + wait(.001); + } + for(i=0; i<10; i++) { + avg=avg+(a[i]/10); + } + + med=(avg*3.10143686*100); //leer puerto analogo y asignar a med (*100 ya que LM35 da 10mV/ºC) + err = (temp-med); + // Para activar la bombilla en el tiempo de ascenso + if(err>=0) { + vent=0; + ap = kp*err; //calculo de la acción proporcional + // se verifica que la accion integral no sea muy grande + if(ai<100) { + ai =(ki*err)+ai; //calculo de la integral del error + } + ad = kd*(err-err_v); //calculo de la accion derivativa + pid = (ap+ai+ad); + // se verifica que pid sea positivo ************************************** + if(pid<=0) { + pid=0; + } + // se verifica que pid sea menor o igual la valor maximo ***************** + if(pid>=100) { + pid=100; + } + err_v = err; + //Normalizacion de la salida + pidn=pid/100; + // se envia el valor pid a puerto analogico de salida (D/A) ************** + bomb.write(pidn); + } + // Para activar ventilador en el tiempo de ascenso + if(err<0) { + bomb=0; + err=-1*err; + ap = kp*err; + if(ai<100) { + ai =(ki*err)+ai; + } + ad = kd*(err-err_v); + pid = (ap+ai+ad); + if(pid<=0) { + pid=0; + } + if(pid>=100) { + pid=100; + } + err_v = err; + //Normalizacion de la salida + pidn=pid/100; + // se envia el valor pid a puerto analogico de salida (D/A) ************** + vent.write(pidn); + } + lcd.cls(); + lcd.locate(0,0); + lcd.printf("Er:%.2f",err); + lcd.locate(8,0); + lcd.printf("Me:%.2f",med); + lcd.locate(0,1); + lcd.printf("Tm:%.2d",temp); + lcd.locate(10,1); + lcd.printf("t2:%.0f",t.read()); + wait(1); + } + bomb=0; + vent=0; + // Comienza el tercer ciclo para la ultima parte del control (Descenso de rampa) + t.start(); + for(dt3=temp; dt3>=ta; dt3-=((temp-ta)/t3)) { + avg=0; + for(i=0; i<10; i++) { + a[i]=LM.read(); + wait(.001); + } + for(i=0; i<10; i++) { + avg=avg+(a[i]/10); + } + + med=(avg*3.10143686*100);//leer puerto analogo y asignar a med (*100 ya que LM35 da 10mV/ºC) + err = (med-dt3); + if(err>=0) { + bomb=0; + ap = kp*err; //calculo de la acción proporcional + // se verifica que la accion integral no sea muy grande + if(ai<100) { + ai =(ki*err)+ai; //calculo de la integral del error + } + ad = kd*(err-err_v); //calculo de la accion derivativa + pid = (ap+ai+ad); + // se verifica que pid sea positivo ************************************** + if(pid<=0) { + pid=0; + } + // se verifica que pid sea menor o igual la valor maximo ***************** + if(pid>=100) { + pid=100; + } + // se actualizan las variables ******************************************* + err_v = err; + lcd.cls(); + lcd.locate(0,0); + lcd.printf("Er:%.2f",err); + lcd.locate(8,0); + lcd.printf("Me:%.2f",med); + lcd.locate(0,1); + lcd.printf("dt:%.2f",dt3); + lcd.locate(10,1); + lcd.printf("t3:%.0f",t.read()); + + //Normalizacion de la salida + pidn=pid/100; + // se envia el valor pid a puerto analogico de salida (D/A) ************** + vent.write(pidn); + // se repite el ciclo + wait(1); + } + if(err<0) { + err=-1*err; + vent=0; + ap = kp*err; //calculo de la acción proporcional + // se verifica que la accion integral no sea muy grande + if(ai<100) { + ai =(ki*err)+ai; //calculo de la integral del error + } + ad = kd*(err-err_v); //calculo de la accion derivativa + pid = (ap+ai+ad); + // se verifica que pid sea positivo ************************************** + if(pid<=0) { + pid=0; + } + // se verifica que pid sea menor o igual la valor maximo ***************** + if(pid>=100) { + pid=100; + } + // se actualizan las variables ******************************************* + err_v = err; + lcd.cls(); + lcd.locate(0,0); + lcd.printf("Er:%.2f",err); + lcd.locate(8,0); + lcd.printf("Me:%.2f",med); + lcd.locate(0,1); + lcd.printf("dt:%.2f",dt3); + lcd.locate(10,1); + lcd.printf("t3:%.0f",t.read()); + + //Normalizacion de la salida + pidn=pid/100; + // se envia el valor pid a puerto analogico de salida (D/A) ************** + bomb.write(pidn); + // se repite el ciclo + wait(1); + } + + } + bomb=0; + vent=0; + lcd.cls(); + lcd.printf("Control\nTreminado"); +}