Controlador PID

Dependencies:   Debounced Pulse1 QEI RTC-DS1307 TextLCD_1 mbed

Fork of grafica_PID_android by Nicolás Villegas Echavarría

/media/uploads/seccastanova/whatsapp_image_2018-06-05_at_10.25.03_am.jpeg

main.cpp

Committer:
seccastanova
Date:
2018-06-05
Revision:
5:f39e8f190857
Parent:
4:82ac4b34c3d9

File content as of revision 5:f39e8f190857:

/*
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 "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
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 red(LED1);
DigitalOut green(LED2);
DigitalOut blue(LED3);

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 = 15, kpnum = 50 ,kdnum = 3;
int j,k; 
long t_pid = 0, t_btn = 0;

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){ 
    
    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();
    
    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);
    
    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;
                
                case 1:
                    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("%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;
            }
        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("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 > 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;
    
    }
    }
}