Programa en lenguaje C de algoritmo PID para control de temperatura
//Algoritmo PID control de temperatura lenguaje C 2008-08-17 18:58
#includelt;reg51.hgt
#includelt;intrins.hgt;
#includelt;math.hgt;
#includelt;string.hgt;
struct PID {
unsigned int SetPoint; // Establece el valor deseado objetivo
unsigned int Proportion; // Const proporcional
unsigned int Integral; // Constante integral Const integral
unsigned int Derivative; // Constante diferencial Const derivada
unsigned int LastError; // Error[-1]
unsigned int PrevError; // Error[-2]
unsigned int SumError; // Sumas de errores
};
struct PID spid; // Estructura de control PID
unsigned int rout; )
unsigned int rin; // Retroalimentación PID (entrada)
sbit data1=P1^0
sbit clk=P1^1; >
sbit plus=P2^0;
sbit subs=P2^1;
sbit parada=P2^2
sbit salida =P3; ^4;
sbit DQ=P3^3;
indicador de caracteres sin firmar, flag_1=0;
tiempo_alto, tiempo_bajo, recuento = 0; /Parámetro de ajuste del ciclo de trabajo
unsigned char set_temper=35;
unsigned char temperament
unsigned char i
unsigned char j; =0;
int sin signo
/**************************** ** **********************************
Subrutina de retardo, el tiempo de retardo es Prevalecerá el oscilador de cristal de 12M, el tiempo de retardo es 30us×time
****************************** ****** ****************************/
retraso nulo (tiempo de carácter sin firmar)
{
carácter sin firmar m, n;
for(n=0;nlt;time;n)
for(m= 0;mlt;
2;m ){}
}
/****************************** ** *******************************
Escribe una subrutina de datos de un bit
************************************************ ****** **********/
void write_bit(unsigned char bitval)
{
EA=0;
DQ=0; /*Baja DQ para iniciar una secuencia de escritura*/
if(bitval==1)
{
_nop_();
DQ=1; /*Si quieres escribir 1, configura el bus en alto*/
}
delay(5
DQ=1 /*Liberar bus DQ*/
_nop_()
_nop_(); ;
EA=1
}
/************************ ****** *******************************
Escribir subrutina de datos de un byte p>
********************************************* *** ***********/
void write_byte(unsigned char val)
{
unsigned char i
p>
temperatura de carácter sin firmar;
EA=0; /*Desactivar interrupción*/
TR0=0; ; ilt; 8 ;i) /*Escribe un byte de datos, un bit a la vez*/
{
temp=valgt;gt;i; cambiar esta vez Mueve el bit escrito al bit más bajo*/
temp=tempamp 1
write_bit(temp /*Escribe el bit en el bus*/
p>
}
delay(7); /*Después del retraso 120us*/
// TR0=1
EA=1; *Habilitar interrupción*/
}
/****************************** ******* *************************
Lectura de subrutina de datos de un bit
* ************************************************* ***** ****/
carácter sin firmar read_bit()
{
carácter sin firmar i, valor_bit
EA=0;
DQ=0; /*Baja DQ y comienza a leer el tiempo*/
_nop_();
_nop_(); p>
DQ=1; /*Liberar el bus*/
for(i=0;ilt;2;i){}
value_bit=DQ; p>
EA =1;
ret
urna(valor_bit);
}
/****************************** * ****************************
Subrutina de lectura de datos de un byte
** ************************************************** ** **********/
carácter sin firmar read_byte()
{
carácter sin firmar i, valor=0 ; p>
EA=0;
for(i=0;ilt;8;i)
{
if(read_bit()) / *leer Un byte de datos se lee una vez en una secuencia y se desplaza*/
value|=0x01lt;lt;i;
delay(4); este momento y luego lea los siguientes datos*/
}
EA=1
return(value);
/*************************************** ***** *******************
Restablecer subrutina
****************** * ***********************************************/
restablecimiento de caracteres sin firmar()
{
presencia de caracteres sin firmar
EA=0
DQ; = 0; /*Baja el bus DQ para comenzar a restablecer*/
delay(30); /*Mantiene el nivel bajo durante 480us*/
DQ=1; Liberar el bus*/
delay(3);
presence=DQ /*Obtener la señal de respuesta*/
delay(28); Retraso para completar toda la secuencia */
EA=1;
return(presence); /*Devuelve la señal de respuesta, si hay un chip, devuelve 0, si lo hay. no es chip, devuelve 1*/
}
/*************************** ***************** **********************
Obtener subrutina de temperatura p>
************************************************ *****************/
void get_temper()
{
unsigned char i, j;
hacer
{
i=reset() /*Reset*/
} while(i!=0); /*1 no hay señal de retroalimentación*/
i=0xcc; / *Enviar comando de posicionamiento del dispositivo*/
write_byte(i); ; /*Enviar comando de inicio de conversión*/
write_byte(i
delay(180);
{
i=reiniciar(); /*reiniciar */
} while(i!=0);
i=0xcc /*Ubicación del dispositivo*/
write_byte(i); p>i=0xbe; /*Leer contenido del buffer*/
write_byte(i
j=read_byte()
i=read_byte ()
i=(ilt;lt;4)amp;0x7f;
s=(unsigned int)(jamp;0x0f); s*100)/16;
j=jgt;gt;4;
temper=i|j; /*La temperatura obtenida se coloca en temperatura*/
p>}
/*==================================== = =================================================== = ===============
Inicializar estructura PID
================== = =================================================== = =================================*/
void PIDInit (struct PID *pp )
{
memset (pp, 0, sizeof(struct PID)
}
/*==== = =================================================== = ==============================================
Parte de cálculo de PID
====================================== === ================================================= === =============*/
unsigned int PIDCalc( estructura PID *pp, unsigned int NextPoint )
{
unsigned int dError, Error
Error = pp-gt; SetPoint - NextPoint; // Desviación
SumError = Error; >
dError = pp-gt; LastError - pp-gt; PrevError; // Diferencial actual
pp-gt; gt; LastError = Error;
return (pp-gt;Proporción * Error//Proporción
pp-gt;Integral * pp-gt;SumError //Término integral
pp-gt;Derivada * dError); // Término diferencial
}
/****************** *
**********************************************
Subrutina de procesamiento de comparación de temperaturas
*************************************** ***** *************************/
compare_temper()
{ p>
carácter sin firmar i;
if(set_tempergt;temper)
{
if(set_temper-tempergt; 1)
{
tiempo_alto=100;
tiempo_bajo=0;
}
else
{
for (i=0;ilt;10;i)
{ get_temper();
rin = s; p>rout = PIDCalc ( amp ; spid, rin ); // Realizar interacción PID
}
if (high_timelt;=100)
high_time=( char sin firmar)(rout/800 );
else
high_time=100;
low_time= (100-high_time
); }
}
else if(set_temperlt;=temper)
{
if(temper-set_tempergt;0)
{
p>
high_time=0
low_time=100
}
else p>
{
for(i=0; ilt; 10; i )
{ get_temper();
rin = s; Leer entrada
rout = PIDCalc (amp; spid, rin); // Realizar interacción PID
}
if (high_timelt; 100)
high_time=(unsigned char)(rout/ 10000);
else
high_time=0
low_time= (100-high_time); /p>
}
}
// más
// {}
}
/************ ************************************* *****
Subrutina de servicio de interrupción T0, utilizada para controlar el cambio de nivel, período de 40us*100=4ms
************** ************** *******************************/
void save_T0() interrumpe 1 usando 1
{
if( count
lt;=(high_time))
salida=1
else if(countlt;=100)
{
salida= 0;
}
de lo contrario
cuenta=0
TH0=0x2f
TL0=0xe0; ;
}
/********************************* *** **********************
Rutina de servicio de interrupción del puerto serie, utilizada para la comunicación con la computadora host
************************************************* ***** /
void save_sio() interrumpe 4 usando 2
{
/* EA=0
RI; =0;
p>
i=SBUF;
if(i==2)
{
mientras( RI==0){}
RI=0;
set_temper=SBUF;
SBUF=0x02; ==0){}
TI=0;
}
si no(i==3)
{ p>
TI=0;
SBUF=temperamento;
mientras(TI==0){}
TI=0; >
}
EA=1; */
}
void disp_1(unsigned char disp_num1[6])
{
carácter sin firmar n, a, m
for(n=0;nlt;6;n)
{
// k=disp_num1[n];
for(a=0; alt; 8; a )
{
clk=0; >
m=(disp_num1[n ]amp;1);
disp_num1[n]=disp_num1[n]gt;gt;1
if(m== 1)
datos1 =1
de lo contrario
datos1=0
_nop_(); clk=1;
_nop_();
}
}
}
/*** ************* ************************************* *****
Mostrar subrutina
Función: convierte la temperatura del ciclo de trabajo en un solo carácter, muestra el ciclo de trabajo y la temperatura medida
*** *************** ************************************* ****/
visualización nula ( )
{
número de código de carácter sin firmar[]={0xfc, 0x60, 0xda, 0xf2, 0x66, 0xb6 , 0xbe, 0xe0, 0xfe, 0xf6};
d char disp_num[6];
unsigned int k, k1
k=high_time
k=k1000; =k/100;
if(k1==0)
disp_num[0]=0
si no
disp_num[; 0]=0x60;
k=k100;
num_disp[1]=número[k/10]; ];
k=temperamento;
k=k100;
disp_num[3]=número[k/10]; disp_num[4]=número[k10] 1
disp_num[5]=número[s/10];
/****************************************** *******************
Programa principal
****************** ******* *******************************************/
main()
{
carácter sin firmar z;
carácter sin firmar a, b, flag_2=1, count1=0;
char phil sin firmar[]={2, 0xce, 0x6e, 0x60, 0x1c, 2};
TMOD=0x21;
TH0=0x2f; /p>
TL0 =0x40;
SCON=0x50;
PCON=0x00;
TH1=0xfd; TL1=0xfd;
PS=1;
EA=1;
EX1=0; p>
ES= 1;
TR0=1;
TR1=1;
tiempo_alto=50; =50;
PIDInit (amp; spid); // Inicializar estructura
spid.Proportion = 10; // Establecer coeficientes PID
spid.Integral = 8;
spid.Derivative =6;
spid.SetPoint = 100; // Establecer punto de ajuste PID
mientras(1)
{
if(plus==0)
{
EA=0
for(a=0; alt;5;a)
for(b=0;blt;102;b){}
if(plus==0)
{
set_temper;
flag=0;
}
}
si no
bs==0)
{
for(a=0;alt;5;a)
for(b=0;alt;102 ;b ){}
if(subs==0)
{
set_temper--
flag=0; ;
}
}
si(parada==0)
{
para(a =0; alt ;5;a)
for(b=0;blt;102;b){}
if(stop==0)
{ p>
bandera=0;
romper;
}
EA=1; /p>
get_temper();
b=temperamento;
if(flag_2==1)
a=b;
if ((abs(a-b))gt; 5)
temperamento=a
else
temperamento=b; p>a= temperamento;
flag_2=0;
if( count1gt; 30)
{
display(); /p>
count1=0;
}
compare_temper();
}
TR0=0; p>
z=1;
mientras(1)
{
EA=0; =0)
{
para(a=0; alt; 5; a )
para(b=0; blt; 102; b ){ }
if(stop==0)
disp_1(phil);
// descanso;
EA =1;
}
}
//subrutina DS18b20
#include lt; /p>
sbit DQ=P2^1; //Definir puerto
typedef unsigned char byte;
typedef unsigned int word;
// Retraso
retraso nulo(palabra usegundos)
{
for(;usegundosgt;0;usegundos--);
}
//Restablecer
byte ow_reset(void)
{
presencia de bytes;
DQ=0; // nivel bajo DQ
retraso(29); //480us
DQ=1; //nivel alto DQ
retraso(3);
//Espera
presencia=DQ; //señal de presencia
retraso(25);
retorno(presencia
} //0 permite, 1 prohíbe
//Leer un byte del bus de 1 cable
byte read_byte(viod)
{
byte i;
valor de byte=0;
para (i=8; igt; 0; i--)
{ p>
valorgt;gt;=1;
DQ=0;
DQ=1;
retraso(1);
if(DQ)valor|=0x80;
retraso(6);
}
retorno(valor);
}
//Escribe un byte en el bus de 1 cable
void write_byte(char val)
{
byte i; /p>
for (i=8; igt; 0; i--) //Escribe un byte a la vez
{
DQ=0;
DQ=valamp;0x01;
retraso(5);
DQ=1;
val=val/2;
p>
}
retraso(5);
}
//Leer temperatura
char Read_Temperature( vacío)
{
unión{
byte c[2]
int x
} temp;
ow_reset();
write_byte(0xcc);
write_byte(0xBE); =read_byte();
temp.c[0]=read_byte();
ow_reset()
write_byte(0xCC);
escribir_byte(0x44);
devolver temp.x/2;
}