//EJEMPLO 16. CONTROL DIGITAL.
//Guia del Compilador C. PIC16C74A. 4 de marzo del 2001.
//Realizar un controlador PID digital.
//Solucion:
//Se utilizara el algoritmo de control PID tipo posicion que maneja el libro
//"Sistemas de Control en Tiempo Discreto", de K. Ogata (capitulo 3, Funcion
//de transferencia de pulsos de un controlador PID digital, en forma de posicion).
//Funcion de transferencia de pulsos, forma de posicion:
//Gd(z) = Kp + Ki/(1-z-1) + Kd(1-z-1)
//donde:
// Kp = K - KT/2Ti = Ganancia proporcional (controlador digital).
// Ki = KT/Ti = Ganancia integral.
// Kd = KTd/T = Ganancia derivativa.
// Ti = Tiempo integral (o tiempo de restablecimiento, segundos).
// Td = Tiempo derivativo (o tasa de tiempo, segundos).
// K = Ganancia proporcional (controlador analogico).
// T = Periodo de muestreo (segundos).
//Los parametros anteriores, junto con otras se¤ales, seran capturados
//utilizando los canales de entrada analogica de los puertos A y E en el
//siguiente orden:
//Ti Canal A/D 0 (Tiempo integral, segundos, PA0).
//Td Canal A/D 1 (Tiempo derivativo, segundos, PA1).
//K Canal A/D 2 (Constante proporcional, segundos, PA2).
//SP Canal A/D 3 (Set Point, PA3).
//RETRO Canal A/D 4 (Retroalimentacion, PA5).
//T Canal A/D 5 (Periodo de muestreo, segundos, PE0).
//Para la salida de control del PID, se utilizara la operacion PWM del modulo CCP1
//(pin PC2). Esta salida nos indica la magnitud en 8 bits de la accion de control.
//El signo de la accion de control se muestra en el pin PC0 (0 positivo, 1 negativo).
//Directivas.
#include <16C74.H> //Especificando dispositivo a utilizar y constantes generales (pag. 47).
#fuses XT,NOWDT,NOPROTECT,PUT //Fusibles de configuracion de hardware (pag. 31).
#use delay(clock = 4000000) //Base de tiempo para retardos (pag. 17).
#use fast_io(C) //Directiva para el manejo normal de puertos (pag. 13).
#byte portc = 0x07 //Declarando la direccion del puerto C.
#bit PC0 = 0x07.0 //Apuntando como una constante al bit de un puerto (pag. 30).
#bit PC2 = 0x07.2
//Variables globales:
int Ti, Td, K, SP, RETRO, T; //Variables de 8 bits sin signo.
float m0,m1,e0,e1,e2; //Variables en punto flotante de 32 bits (pag. 7).
int magnitud; //Variable de 8 bits sin signo. Magnitud accion de control.
short signo; //Variable tipo bit. Signo accion de control.
//Funcion de inicializacion.
inicializar() {
//Inicializando la operacion analogica del puerto A.
setup_port_a(ALL_ANALOG); //Especificando operacion analogica de puertos A y E, Vref = Vdd. (pag. 13).
set_tris_a(0b00111111); //Configurando puerto A como entrada (pag. 13).
set_tris_e(0b00000111); //Configurando puerto E como entrada (pag. 13).
setup_adc(ADC_CLOCK_INTERNAL); //Habilitando el convertidor A/D con reloj interno (pag. 16).
//Inicializando el modo PWM del modulo CCP1.
portc = 0; //Valor inicial del puerto C.
set_tris_c(0b11111010); //Configurando PC0 y PC2 como salidas (pag. 13).
setup_ccp1(CCP_PWM); //Configurando el modulo CCP1 en modo PWM (pag. 15).
setup_timer_2(T2_DIV_BY_4, 167, 0); //Definiendo el periodo del PWM con la configuracion
//del temporizador 2 (para es te caso periodo
//pwm = (167)(4)/(4000000/4) = 668 us (pag. 15).
//Ver tambien ejemplo 14.
set_pwm1_duty(0); //Valor inicial salida PWM.
m1 = 0; //Valor inicial parametros PID.
e1 = 0;
e2 = 0;
} //Fin inicializar.
//Funcion de adquisicion de datos.
adquisicion_datos() {
set_adc_channel(0); //Adquisicion canal 0, Ti.
delay_cycles(3);
Ti = read_adc();
set_adc_channel(1); //Adquisicion canal 1, Td.
delay_cycles(3);
Td = read_adc();
set_adc_channel(2); //Adquisicion canal 2, K.
delay_cycles(3);
K = read_adc();
set_adc_channel(3); //Adquisicion canal 3, SP.
delay_cycles(3);
SP = read_adc();
set_adc_channel(4); //Adquisicion canal 4, RETRO.
delay_cycles(3);
RETRO = read_adc();
set_adc_channel(5); //Adquisicion canal 5, T, en segundos.
delay_cycles(3);
T = read_adc();
} //Fin adquisicion.
//Funcion del controlador PID digital de posicion (algoritmo del libro de Control Discreto de K. Ogata).
control_PID() {
float Ts, Kp, Ki, Kd, salida_PID; //Variables locales en punto flotante de 32 bits.
Ts = T/1000; //Convirtiendo el periodo T de segundos a milisegundos.
Kp = K - (K*Ts/2*Ti); //Calculo de los parametros Kp, Ki y Kd segun algoritmo.
Ki = K*Ts/Ti;
Kd = K*Td/Ts;
m0 = m1+(Kp+Ki+Kd)*e0-(Kp+2*Kd)*e1+Kd*e2;//Calculo de la accion de control m(kT).
if( m0<0 ) { //Detectando el signo de la accion de control.
signo = 1; //m0 negativo, signo = 1, m0 positivo, signo = 0.
salida_PID = -m0; //Calculando valor absoluto de m0.
}
else {
signo = 0;
salida_PID = m0;
}
if(salida_PID>255) salida_PID = 255; //Limitando la magnitud de la accion de control a 255.
magnitud = (int)salida_PID; //Cambiando de tipo de dato float a
//8 bits sin signo.
e2 = e1; //Actualizando e(k-2).
e1 = e0; //Actualizando e(k-1).
if(signo == 1) m1 = -salida_PID; //Actualizando m(k-1).
else m1 = salida_PID;
} //fin control PID.
//Funcion principal.
main() { //Inicio programa principal.
inicializar(); //Llamada a funcion inicializar.
while(TRUE) { //Inicio ciclo continuo.
adquisicion_datos(); //Llamada a funcion de adquisicion de datos.
e0 = SP - RETRO; //Calculo del error actual.
control_PID(); //Llamada al controlador PID.
set_pwm1_duty(magnitud);//Actuacion del PWM en funcion de la magnitud
//de la accion de control calculada.
PC0 = signo; //Salida del signo de la accion de control.
delay_ms(T); //Retardo segun periodo de muestreo.
} //Fin while.
} //Fin main.