为了提高温控的速度,减少温控所需要的时间,所以该增加式PID算法常与BangBang算法、大林算法相结合使用。以上是对几种常用PID算法的比较和总结,在实际的项目中用的比较多的是增量式PID算法和分段式PID算法,分段式PID算比单一的增量式PID算法控温速度快,精度更高,虽然分段PID算法参数整定比较繁琐些,但鉴于它的控制速度快、精度高,还是推荐使用分段PID算法应用于温度控制、电机控制等领域或项目中。控制恒温恒湿的算法
最近在做一个有关大气VOCs实时监测的项目,由于该项目要求控温精度在0.1度之内,所以就研究了一下有关温控的算法,我们知道对于一些大惯性的系统,比如加热炉、智能小车中都会用到PID(比例、积分和微分)算法,而PID算法分为二值式、位置式、增量式和分段式,当然也有模糊式等。现根据在实际项目中的应用情况将其总结如下:
(1)二值式
二值式温控算法只存在两个状态,不是开,就是关。常用在一些控温精度不高的场合。
(2)位置式
位置式PID算法由于计算量比较大,降低了单片机的运行速度,需要单片机比较大的内存,所以在实际应用中应用的比较少,除非有特除要求的场合。
(3)增量式
增量式PID算法相比二值式控温精度比较高,相比位置式计算量减少了许多,提高了单片机的运行速度,也增大了单片机的选择余地(内存要求降低)。为了提高温控的速度,减少温控所需要的时间,所以该增加式PID算法常与BangBang算法、大林算法相结合使用。BangBang算法和大林算法即是全功率加热,比如BangBang-PID算法通过会有一个阈值,一旦采用BangBang或大林算法升温到阈值时,就会自动切换到增量式PID算法进行控温。另外该阈值的选择是个难点,阈值小了,升温时间比较长,阈值大了,过冲量比较大,所以说该阈值的选择需要从以下两个方面去确定:升温速率、距离设定值的差值大小等方面。
(4)分段式
分段式PID算法虽然比模糊PID算法差一些,但是模糊PID控制大多数还停留在理论阶段,应用到实际系统的还比较少,控制效果如何还不是很确定。分段式PID算法在某些方面与模糊式PID算法有很多相近的地方,也是对信号进行阈值的划分,然后在不同的阈值阶段采用不同的控制参数。分段PID优于模糊PID的地方在于我们现有的工控机在编辑控制算法时是数字式的,模糊PID算法要想实现其功能除了要进行数据的离散化外,其用到的数据参数也比较多导致统计起来比较麻烦,经过以上对比分析,从系统的可实现性方面考虑,还是采用分段式PID算法的比较多些。
根据项目的实际控制结果表明单纯的采用单一的PID参数进行调节要想达到较为理想的控制效果是不容易的。所以可以根据控制对象的实际情况及偏差的大小,在不同的控制阶段给定不同的PID调节参数,这样可以在偏差大的时候加大比例调节,降低积分作用,偏差小的时候减少比例作用,加大积分作用。这样既可以增加响应速度,超调量也不会太大,这就是分段PID的控制思想。 下面对普通PID与分段PID在同一控制变量下做出的反应做一下对比,他们的输出曲线如下图:
在上图输出曲线中可以看出在目标值情况相同的情况下,分段PID的响应速度更快,达到目标值时分段PID比普通PID所用的时间少一半,所用控制系统的快速性被分段PID明显提高了。采用分段PID即是将一个控制过程进行分段控制,可以避免采用单一PID控制时对误差积累较多的缺点(采用单一PID算法时,刚开始启动时目标值与实际值的差值会很大,如果有积分变量的话,积分变量大了会导致较大的积累偏差,导致消除困难,造成系统较大的系统超调;积分变量小了会导致精差消除较慢。),这样在每一阶段都对误差进行消除,最后误差结果会小很多。分段PID算法的实现步骤:这里假定阈值a为偏差的50%,阈值b为偏差的30%。
a、根据工程需要设置阈值ab0;
b、当偏差较大,且偏差大于等于a时,采用PD控制,可加快系统响应;
c、当偏差较小,且大于b,小于a时采用PI控制;
d、当偏差小于b时,采用PID控制(P设的小些,I设的大些),可减少系统精差。
以上是对几种常用PID算法的比较和总结,在实际的项目中用的比较多的是增量式PID算法和分段式PID算法,分段式PID算比单一的增量式PID算法控温速度快,精度更高,虽然分段PID算法参数整定比较繁琐些,但鉴于它的控制速度快、精度高,还是推荐使用分段PID算法应用于温度控制、电机控制等领域或项目中。
目前,恒温恒湿空调系统的应用场合越来越多,例如在电子、医院、计量、纺织和光学仪器等领域,以保证一些产品或操作处于恒温恒湿的环境。
一种恒温恒湿系统的控制方法,包括:
测量恒温恒湿室内的实际室温T1测和实际室内露点温度T2测;
根据实际室温T1测与恒温恒湿系统的送风部的设定送风温度T1设的差值△T1对T1设进行校正:T1校=T1设+f(△T1),其中,△T1=T1测-T1设,△T10时,f(△T1)0,△T10时,f(△T1)0,T1校为所述送风部的校正后的设定送风温度;
根据实际室内露点温度T2测与恒温恒湿系统的送风部的设定送风露点温度T2设的差值△T2对T2设进行校正:T2校=T2设+F(△T2),其中,△T2=T2测-T2设,△T20时,F(△T2)0,△T20时,F(△T2)0,T2校为所述送风部的校正后的设定送风露点温度。
进一步地,f(△T1)和F(△T2)分别由控制器通过PID计算得到。
进一步地,恒温恒湿系统制冷时,送风部校正后的设定送风温度为T1校,
恒温恒湿系统制热时,所述送风部校正后的设定送风温度为T1’校,T1’校=T1校-第一死区温度,0第一死区温度≦1℃;
恒温恒湿系统除湿时,所述送风部校正后的设定送风露点温度为T2校,
恒温恒湿系统加湿时,所述送风部校正后的设定送风露点温度为T2’,T2’校=T2校-第二死区温度,0第二死区温度≦1℃。
进一步地,恒温恒湿系统包括冷却单元,当所述恒温恒湿系统用于降温和除湿时,所述恒温恒湿系统通过所述冷却单元进行降温和除湿;所述冷却单元包括第一换热管和设置于所述第一换热管上的第一控制阀,当根据所述T1校和所述T2校的控制所述第一控制阀具有不同的开度变化值时,所述控制器以所述T1校和所述T2校中令所述第一控制阀开度变化值更大的一个来控制所述第一控制阀的开度变化。
//PID算法温控C语言2008-08-17 18:58
#includereg51.h
#includeintrins.h
#includemath.h
#includestring.h
struct PID {
unsigned int SetPoint; // 设定目标 Desired Value
unsigned int Proportion; // 比例常数 Proportional Const
unsigned int Integral; // 积分常数 Integral Const
unsigned int Derivative; // 微分常数 Derivative Const
unsigned int LastError; // Error[-1]
unsigned int PrevError; // Error[-2]
unsigned int SumError; // Sums of Errors
};
struct PID spid; // PID Control Structure
unsigned int rout; // PID Response (Output)
unsigned int rin; // PID Feedback (Input)
sbit data1=P1^0;
sbit clk=P1^1;
sbit plus=P2^0;
sbit subs=P2^1;
sbit stop=P2^2;
sbit output=P3^4;
sbit DQ=P3^3;
unsigned char flag,flag_1=0;
unsigned char high_time,low_time,count=0;//占空比调节参数
unsigned char set_temper=35;
unsigned char temper;
unsigned char i;
unsigned char j=0;
unsigned int s;
/***********************************************************
延时子程序,延时时间以12M晶振为准,延时时间为30us×time
***********************************************************/
void delay(unsigned char time)
{
unsigned char m,n;
for(n=0;ntime;n++)
for(m=0;m2;m++){}
}
/***********************************************************
写一位数据子程序
***********************************************************/
void write_bit(unsigned char bitval)
{
EA=0;
DQ=0; /*拉低DQ以开始一个写时序*/
if(bitval==1)
{
_nop_();
DQ=1; /*如要写1,则将总线置高*/
}
delay(5); /*延时90us供DA18B20采样*/
DQ=1; /*释放DQ总线*/
_nop_();
_nop_();
EA=1;
}
/***********************************************************
写一字节数据子程序
***********************************************************/
void write_byte(unsigned char val)
{
unsigned char i;
unsigned char temp;
EA=0; /*关中断*/
TR0=0;
for(i=0;i8;i++) /*写一字节数据,一次写一位*/
{
temp=vali; /*移位操作,将本次要写的位移到最低位*/
temp=temp1;
write_bit(temp); /*向总线写该位*/
}
delay(7); /*延时120us后*/
// TR0=1;
EA=1; /*开中断*/
}
/***********************************************************
读一位数据子程序
***********************************************************/
unsigned char read_bit()
{
unsigned char i,value_bit;
EA=0;
DQ=0; /*拉低DQ,开始读时序*/
_nop_();
_nop_();
DQ=1; /*释放总线*/
for(i=0;i2;i++){}
value_bit=DQ;
EA=1;
return(value_bit);
}
/***********************************************************
读一字节数据子程序
***********************************************************/
unsigned char read_byte()
{
unsigned char i,value=0;
EA=0;
for(i=0;i8;i++)
{
if(read_bit()) /*读一字节数据,一个时序中读一次,并作移位处理*/
value|=0x01i;
delay(4); /*延时80us以完成此次都时序,之后再读下一数据*/
}
EA=1;
return(value);
}
/***********************************************************
复位子程序
***********************************************************/
unsigned char reset()
{
unsigned char presence;
EA=0;
DQ=0; /*拉低DQ总线开始复位*/
delay(30); /*保持低电平480us*/
DQ=1; /*释放总线*/
delay(3);
presence=DQ; /*获取应答信号*/
delay(28); /*延时以完成整个时序*/
EA=1;
return(presence); /*返回应答信号,有芯片应答返回0,无芯片则返回1*/
}
/***********************************************************
获取温度子程序
***********************************************************/
void get_temper()
{
unsigned char i,j;
do
{
i=reset(); /*复位*/
}while(i!=0); /*1为无反馈信号*/
i=0xcc; /*发送设备定位命令*/
write_byte(i);
i=0x44; /*发送开始转换命令*/
write_byte(i);
delay(180); /*延时*/
do
{
i=reset(); /*复位*/
}while(i!=0);
i=0xcc; /*设备定位*/
write_byte(i);
i=0xbe; /*读出缓冲区内容*/
write_byte(i);
j=read_byte();
i=read_byte();
i=(i4)0x7f;
s=(unsigned int)(j0x0f);
s=(s*100)/16;
j=j4;
temper=i|j; /*获取的温度放在temper中*/
}
/*====================================================================================================
Initialize PID Structure
=====================================================================================================*/
void PIDInit (struct PID *pp)
{
memset ( pp,0,sizeof(struct PID));
}
/*====================================================================================================
PID计算部分
=====================================================================================================*/
unsigned int PIDCalc( struct PID *pp, unsigned int NextPoint )
{
unsigned int dError,Error;
Error = pp-SetPoint - NextPoint; // 偏差
pp-SumError += Error; // 积分
dError = pp-LastError - pp-PrevError; // 当前微分
pp-PrevError = pp-LastError;
pp-LastError = Error;
return (pp-Proportion * Error//比例
+ pp-Integral * pp-SumError //积分项
+ pp-Derivative * dError); // 微分项
}
/***********************************************************
温度比较处理子程序
***********************************************************/
compare_temper()
{
unsigned char i;
if(set_tempertemper)
{
if(set_temper-temper1)
{
high_time=100;
low_time=0;
}
else
{
for(i=0;i10;i++)
{ get_temper();
rin = s; // Read Input
rout = PIDCalc ( spid,rin ); // Perform PID Interation
}
if (high_time=100)
high_time=(unsigned char)(rout/800);
else
high_time=100;
low_time= (100-high_time);
}
}
else if(set_temper=temper)
{
if(temper-set_temper0)
{
high_time=0;
low_time=100;
}
else
{
for(i=0;i10;i++)
{ get_temper();
rin = s; // Read Input
rout = PIDCalc ( spid,rin ); // Perform PID Interation
}
if (high_time100)
high_time=(unsigned char)(rout/10000);
else
high_time=0;
low_time= (100-high_time);
}
}
// else
// {}
}
/*****************************************************
T0中断服务子程序,用于控制电平的翻转 ,40us*100=4ms周期
******************************************************/
void serve_T0() interrupt 1 using 1
{
if(++count=(high_time))
output=1;
else if(count=100)
{
output=0;
}
else
count=0;
TH0=0x2f;
TL0=0xe0;
}
/*****************************************************
串行口中断服务程序,用于上位机通讯
******************************************************/
void serve_sio() interrupt 4 using 2
{
/* EA=0;
RI=0;
i=SBUF;
if(i==2)
{
while(RI==0){}
RI=0;
set_temper=SBUF;
SBUF=0x02;
while(TI==0){}
TI=0;
}
else if(i==3)
{
TI=0;
SBUF=temper;
while(TI==0){}
TI=0;
}
EA=1; */
}
void disp_1(unsigned char disp_num1[6])
{
unsigned char n,a,m;
for(n=0;n6;n++)
{
// k=disp_num1[n];
for(a=0;a8;a++)
{
clk=0;
m=(disp_num1[n]1);
disp_num1[n]=disp_num1[n]1;
if(m==1)
data1=1;
else
data1=0;
_nop_();
clk=1;
_nop_();
}
}
}
/*****************************************************
显示子程序
功能:将占空比温度转化为单个字符,显示占空比和测得到的温度
******************************************************/
void display()
{
unsigned char code number[]={0xfc,0x60,0xda,0xf2,0x66,0xb6,0xbe,0xe0,0xfe,0xf6};
unsigned char disp_num[6];
unsigned int k,k1;
k=high_time;
k=k%1000;
k1=k/100;
if(k1==0)
disp_num[0]=0;
else
disp_num[0]=0x60;
k=k%100;
disp_num[1]=number[k/10];
disp_num[2]=number[k%10];
k=temper;
k=k%100;
disp_num[3]=number[k/10];
disp_num[4]=number[k%10]+1;
disp_num[5]=number[s/10];
disp_1(disp_num);
}
/***********************************************************
主程序
***********************************************************/
main()
{
unsigned char z;
unsigned char a,b,flag_2=1,count1=0;
unsigned char phil[]={2,0xce,0x6e,0x60,0x1c,2};
TMOD=0x21;
TH0=0x2f;
TL0=0x40;
SCON=0x50;
PCON=0x00;
TH1=0xfd;
TL1=0xfd;
PS=1;
EA=1;
EX1=0;
ET0=1;
ES=1;
TR0=1;
TR1=1;
high_time=50;
low_time=50;
PIDInit ( spid ); // Initialize Structure
spid.Proportion = 10; // Set PID Coefficients
spid.Integral = 8;
spid.Derivative =6;
spid.SetPoint = 100; // Set PID Setpoint
while(1)
{
if(plus==0)
{
EA=0;
for(a=0;a5;a++)
for(b=0;b102;b++){}
if(plus==0)
{
set_temper++;
flag=0;
}
}
else if(subs==0)
{
for(a=0;a5;a++)
for(b=0;a102;b++){}
if(subs==0)
{
set_temper--;
flag=0;
}
}
else if(stop==0)
{
for(a=0;a5;a++)
for(b=0;b102;b++){}
if(stop==0)
{
flag=0;
break;
}
EA=1;
}
get_temper();
b=temper;
if(flag_2==1)
a=b;
if((abs(a-b))5)
temper=a;
else
temper=b;
a=temper;
flag_2=0;
if(++count130)
{
display();
count1=0;
}
compare_temper();
}
TR0=0;
z=1;
while(1)
{
EA=0;
if(stop==0)
{
for(a=0;a5;a++)
for(b=0;b102;b++){}
if(stop==0)
disp_1(phil);
// break;
}
EA=1;
}
}
//DS18b20 子程序
#include REG52.H
sbit DQ=P2^1; //定义端口
typedef unsigned char byte;
typedef unsigned int word;
//延时
void delay(word useconds)
{
for(;useconds0;useconds--);
}
//复位
byte ow_reset(void)
{
byte presence;
DQ=0; //DQ低电平
delay(29); //480us
DQ=1; //DQ高电平
delay(3); //等待
presence=DQ; //presence信号
delay(25);
return(presence);
} //0允许,1禁止
//从1-wire 总线上读取一个字节
byte read_byte(viod)
{
byte i;
byte value=0;
for (i=8;i0;i--)
{
value=1;
DQ=0;
DQ=1;
delay(1);
if(DQ)value|=0x80;
delay(6);
}
return(value);
}
//向1-wire总线上写一个字节
void write_byte(char val)
{
byte i;
for (i=8;i0;i--) //一次写一个字节
{
DQ=0;
DQ=val0x01;
delay(5);
DQ=1;
val=val/2;
}
delay(5);
}
//读取温度
char Read_Temperature(void)
{
union{
byte c[2];
int x;
}temp;
ow_reset();
write_byte(0xcc);
write_byte(0xBE);
temp.c[1]=read_byte();
temp.c[0]=read_byte();
ow_reset();
write_byte(0xCC);
write_byte(0x44);
return temp.x/2;
}
这个的看型号,西门子200的PLC你就得自己编算法,自己算PID参数,而三菱FX或台达DVP的PLC,PID里本身就有自整定功能,直接使用就行了,不过自整定后控温精度不是很好,毕竟不是专门控温的,和温控表差的还是很多。
望采纳。。。。
第一步:把器件等各种实物连上...
第二步:开环,对PWM的控温信号加阶跃(改变PWM的占空比),由输入输出的结果大致得出加热器的数学模型
第三部:由理论公式整定出PID参数
第四部:根据实际结果调节PID以达到你想要的指标
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。
E-mail:langhai8@163.com
本文链接:https://www.wumai.net/tianqi/20221217225009.html