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 Gustavo Ramirez

main.cpp

Committer:
Gregorio
Date:
2014-06-12
Revision:
5:ad88703dc6d3
Parent:
4:d42fe3777735

File content as of revision 5:ad88703dc6d3:

#include "mbed.h"
#include "DebouncedIn.h"
#include "TextLCD.h"
#include "QEI.h"

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 LCD
int C2=0x18; // desplaza izquierda
int C3=0x1A; // desplaza derecha
int C4=0x0C; // quito cursor bajo
int C1=0x0F; // solo muestra el curzor


//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;

// Inicia el código
int main()
{
    while(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);
        }
        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");
}