Autor Tema: Control PID 16f877  (Leído 4545 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado mariacontenis

  • PIC16
  • ***
  • Mensajes: 114
Control PID 16f877
« en: 22 de Diciembre de 2014, 21:42:29 »
Saludosn amigos.

Aquí les dejo el código de un control PID de temperatura, espero les sea útil.


Código: ActionScript
  1. #include <16F877a.h>
  2. #device adc=10
  3. #use delay(clock=4000000)        
  4. #fuses XT,NOWDT
  5.  
  6. #define WireTX PIN_C6
  7. #define WireRX PIN_C7
  8.  
  9. #use rs232 (baud = 9600, xmit=WireTX, rcv=WireRX, ERRORS, STREAM=serial)
  10. #USE TIMER(TIMER=1,TICK=1ms,BITS=16,NOISR)
  11.  
  12. int16 valor;                  //lectura de temperatura
  13. int control;                //valor del PWM
  14. double temp_limit;            //temperatura a alcanzar
  15. double rT,yt;     //variables de ecuaciones
  16. double out = 10;
  17. double errSum, lastErr;
  18. double kp, ki, kd;
  19. int16 sampletime = 1000;
  20.  unsigned int16 current_tick, previous_tick;
  21.  
  22. unsigned int16 tick_difference(unsigned int16 current, unsigned int16 previous)
  23. {
  24.    return(current - previous);
  25. }
  26.  
  27. void Compute()
  28. {
  29.    current_tick = get_ticks();
  30.  
  31.    if(tick_difference(current_tick, previous_tick) > SampleTime)
  32.    {
  33.       previous_tick = current_tick;
  34.    
  35.       /*Compute all the working error variables*/
  36.       double error = temp_limit - yT;
  37.       printf("\n\rerror: %f",error);
  38.       errSum += error;
  39.       printf("\n\rerrSum: %f",errSum);
  40.       double dErr = (error - lastErr);
  41.       printf("\n\rdErr: %f",dErr);
  42.      
  43.       /*Compute PID Output*/
  44.       out = kp * error + ki * errSum + kd * dErr;
  45.       printf("\n\rout: %f",out);
  46.      
  47.       /*Remember some variables for next time*/
  48.       lastErr = error;
  49.       printf("\n\rlastErr: %f",lastErr);      
  50.    }
  51. }
  52.  
  53. void SetTunings(double Kp, double Ki, double Kd)
  54. {
  55.    double SampleTimeInSec = ((double)SampleTime)/1000;
  56.    kp = Kp;
  57.    ki = Ki * SampleTimeInSec;
  58.    kd = Kd / SampleTimeInSec;
  59. }
  60.  
  61. void SetSampleTime(int NewSampleTime)
  62. {
  63.    if (NewSampleTime > 0)
  64.    {
  65.       double ratio  = (double)NewSampleTime
  66.                       / (double)SampleTime;
  67.       ki *= ratio;
  68.       kd /= ratio;
  69.       SampleTime = (unsigned long)NewSampleTime;
  70.    }
  71. }
  72.              
  73.                                      
  74. void main()
  75. {
  76.    current_tick = previous_tick = get_ticks();
  77.    
  78.    printf("\fReady...\n");  
  79.    kp=80.75;                     //constantes del PID
  80.    ki=3.375;
  81.    kd=150.375;
  82.    temp_limit=0.33;          //Temperatura a alcanzar
  83.    
  84.    setup_timer_1(t1_internal|t1_div_by_1);
  85.    setup_timer_2(t2_div_by_16,249,1);     //periodo de la señal PWM a 1ms  
  86.    setup_ccp1(ccp_pwm);                  //Módulo CCP a modo PWM
  87.    setup_adc_ports(all_analog);         //Puerto A analógico
  88.    setup_adc(ADC_CLOCK_INTERNAL);       //reloj convertidor AD interno
  89.    set_adc_channel(0);                  //Lectura por el canal 0
  90.    delay_us (20);
  91.    
  92.    while(true)
  93.    {                                    
  94.      valor=read_adc();                 //Lectura de la temperatura
  95.      printf("\n\rAD: %lu",valor);
  96.      
  97.      yT=valor*5.0/1024.0;           //conversión a mV (0.25V a 250mV)
  98.      printf("\n\ryt: %f",yT);
  99.      rT=temp_limit;
  100.      
  101.      SetTunings(kp,ki,kd);
  102.      
  103.      compute();
  104.      control = (int)(out);
  105.      printf("\n\rcontrol: %u",control);
  106.      set_pwm1_duty(control);
  107.                                                                    
  108.      //delay_ms(10);                //Tiempo de muestreo
  109.      }
  110. }
« Última modificación: 22 de Diciembre de 2014, 21:48:26 por mariacontenis »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Control PID 16f877
« Respuesta #1 en: 22 de Diciembre de 2014, 23:13:13 »
Al final conseguiste hacer funcionar el PID, felicidades

Desconectado jeremylf

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1341
Re: Control PID 16f877
« Respuesta #2 en: 26 de Diciembre de 2014, 14:27:37 »
Se ve bien

Desconectado mariacontenis

  • PIC16
  • ***
  • Mensajes: 114
Re: Control PID 16f877
« Respuesta #3 en: 26 de Diciembre de 2014, 15:22:16 »
Se ve bien y funciona. Solo que me gustaría que el control fuera por angulo de fase para un foco de 127 volts/60 hrz.

Me podrían apoyar en eso?.


Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Control PID 16f877
« Respuesta #4 en: 26 de Diciembre de 2014, 18:01:36 »
Código: [Seleccionar]
     control = (int)(out);
     printf("\n\rcontrol: %u",control);
     set_pwm1_duty(control);


Imagino que deberias cambiar eso... detectacto cuando cruze por 0 de la tension AC y usando un timer para contar donde control seria el valor que determine el angulo.

Desconectado soymoe

  • PIC18
  • ****
  • Mensajes: 456
    • El blog de Moe
Re: Control PID 16f877
« Respuesta #5 en: 26 de Diciembre de 2014, 20:13:59 »
Tendrias que explicar como se usa y como sensa la temperatura...

Desconectado Darkman_A

  • PIC18
  • ****
  • Mensajes: 288
Re: Control PID 16f877
« Respuesta #6 en: 26 de Diciembre de 2014, 20:33:53 »
Se ve bien y funciona. Solo que me gustaría que el control fuera por angulo de fase para un foco de 127 volts/60 hrz.

Me podrían apoyar en eso?.



Hola Maria.
Tengo entendido que el sistema de control seria controlador PID mas la planta (que es lo que queres estabilizar).
¿Este controlador lo hicistes vos?. Si es asi,¿podrias subir un esquema o diagrama de bloques del sistema en lazo cerrado?. Es para entender lo que has hecho.
No estoy del todo seguro, pero si lo que queres controlar es la intensidad de la luz de la lampara, como estan suponiendo otros miembros del foro, lo que tendrias que modificar es la parte que corresponde a la planta (normalmente llamada G(s) o G(z)).
Voy a estudiar el codigo que has hecho y luego comento.
Nota: no he nombrado el ROC para facilitar la lectura.

Saludos

Edito: No entiendo cual es la funcion de tranferencia de la planta. ¿Podrias escribirla?.
¿El codigo funciona?. Estas usando una variable errSum que nunca inicializas. En particular estas haciendo
 errSum += error; que significa  errSum =errSum + error; o sea le sumo a error "cualquier banana" porque nunca inicializas errSum.
Si me estoy equivocando, decime donde esta inicializada esa variable porque no lo encuentro.
De ser asi el programa no funcionaria, porque tengo un error que es cualquier cosa.
Por favor, trata de poner toda la informacion que puedas, ya sea el gráfico de la planta, formula de la funcion de transferencia, comentar las lineas del codigo, nombrar si estas usando un modelo (como el de Ziegler/Nichols, por ejemplo) y porque lo estas usando etc, etc.
Toda la informacion que puedas agregar es siempre bienvenida ( y sobretodo necesaria ).
Gracias.

Saludos.
 
« Última modificación: 27 de Diciembre de 2014, 00:08:28 por Darkman_A »