首页>>科技 >>内容

温控pid算法实例c语言,pid算法温度控制c语言程序

发布时间:2023-08-13 11:42:39编辑:温柔的背包来源:

很多朋友对温控pid算法实例c语言,pid算法温度控制c语言程序不是很了解,每日小编刚好整理了这方面的知识,今天就来带大家一探究竟。

温控pid算法实例c语言,pid算法温度控制c语言程序

介绍了温度控制PID自整定的原理。调谐PID(三模式)控制器调谐温度控制器包括设置比例、积分和微分值,以获得特定过程的最佳控制。如果控制器不包括自动设置算法,或者自动设置算法不能提供足够的适合于特定应用的控制,则必须通过反复试验来设置该设备。

以下是温度控制器的标准设置步骤。也可以使用其他调整步骤,但使用类似的试错法。请注意,如果控制器使用机械继电器(而不是固态继电器),应在开始时使用长周期时间(20秒)。可能需要以下定义:

周期时间也称为占空比,是控制器完成一个开关周期所用的总时间。例如:对于20秒的周期时间,10秒的开启时间和10秒的关闭时间代表50%的功率输出。当处于比例带时,控制器将循环开启和关闭。

比例带——以满量程的%或度表示的温度范围,在此范围内控制器发生比例动作。比例带越宽,设定值周围发生比例动作的区域就越大。有时也用增益表示,增益是比例带的倒数。积分,也称复位,是根据设定值调整比例带宽以补偿与设定值的偏移(固定偏差)的功能,即在系统稳定后将被控温度调整到设定值。

差分,也称为速率,检测系统温度上升或下降的速率,并自动调整比例带,以尽量减少欠调或过调。

如果设置和使用正确,PID(三模)控制器可以有很好的控制稳定性。通过仔细遵循这些说明,操作员可以实现最快的响应时间和最小的超调量。设置此三模式控制器的信息可能与其他控制器设置步骤不同。对于主输出,通过使用自设定功能,通常不需要使用这种手动设定步骤,但必要时可以调整自设定值。a .设置加热控制的输出,以启用输出并启动过程。

该过程应该在设定点运行,并且温度将随着所需的热量输入而稳定。速度和复位关闭时,温度会比较稳定,设定值和实际温度之间存在稳态偏差或固定偏差。通过观察显示屏上的测量值,密切注意该温度是否有规律的循环或振荡。(振荡可持续30分钟。)

4.如果温度没有规律地振荡,将PB除以2(见图1)。让过程稳定,然后检查是否有温度振荡。如果仍然没有振荡,将PB除以2。重复此操作,直到获得一个周期或振荡。转到步骤5。5.如果立即观察到振荡,将PB乘以2。观察温度几分钟。如果振荡继续,将PB乘以系数2,直到振荡停止。

此时,PB非常接近其临界设置。小心地增加或减少PB设置,直到温度记录中出现一个循环或振荡。如果过程温度即使在最小PB设置为1%时也不波动,请跳过以下步骤6至11,转到条款B.在已经达到的“临界”BP设置下,读取设置值和实际温度之间的稳态偏差或固定偏差。既然温度有一点周期,请用平均温度。)

以单位测量相邻峰或谷之间的振荡时间(见图2)。这种测量最容易用图表记录器进行,但是你可以每分钟读取测量值来记录时间。此时,增加PB设置,直到温度偏差(或固定偏差)增加65%。

所需的最终温度偏差可以通过将在“临界”BP设置下获得的初始温度偏差乘以1.65或方便的线图I(见图4)来计算。通过反复试验,多次尝试PB控制的设置,直到获得所需的最终温度偏差。此时,您已经完成了获得控制器最佳性能所需的所有测量。只需再做两个调整——速度和重置。使用在步骤7中测量的振荡时间,以每分钟重复次数为单位计算重置值,如下所示。

将该值输入复位1。然后,使用步骤7中测量的振荡时间,按如下单位计算速度值。将该值输入到比率1中。如果出现过冲,可以通过减少复位时间来消除。当重置值改变时,速率调整也应相应改变,使速率值等于:即如果重置=2 R/M,则速率=0.08分钟。

如果我们想要在系统扰动的“响应时间”和“设置时间”之间获得正确的平衡,可能需要多次更改设置值,并相应地调整复位和速率控制时间。快速响应往往伴随着较大的超调,过程达到“稳定”所需的时间也较短。相反,如果响应较慢,过程倾向于缓慢滑向最终值,很少或没有超调。由系统的要求来决定采取哪种行动。

当获得令人满意的定时时,应增加周期时间以节省接触器的寿命(适用于只有时间比例输出(TPRI)的设备)。在不导致测量值因负载循环而振荡的情况下,应尽可能增加循环时间。当没有观察到振动时,转到章节C. B .设置步骤。在最小PB设置下,测量设定值和实际温度之间的稳态偏差或固定偏差。

增加PB设置,直到温度偏差(固定偏差)增加65%。线图I(见图4)提供了一种简单的方法来计算所需的最终温度偏差。将复位1设置为高值(10转/分)。将比率1设置为相应的值(0.02点)。此时,由于复位功能,测量值应稳定在设定温度。

因为我们无法确定临界振荡时间,所以必须通过试错法来确定复合位置和速率调整的最优设置。温度稳定在设定值后,将设定温度增加10度。观察伴随实际温度上升的过冲。然后将设定温度的设定值恢复到初始值,然后观察伴随实际温度上升的超调量。过大的过冲表明复位和/或速率值设置得太高。过阻尼响应(无过冲)表示复位和/或速率值设置得太低。请参考图7。

当性能需要提高时,一次改变一个设置参数,观察设置值改变时该参数对性能的影响。让参数逐渐变化,直到性能达到最佳。

当获得令人满意的定时时,应增加周期时间以节省接触器的寿命(适用于只有时间比例输出(TPRI)的设备)。在不导致测量值因负载循环而振荡的情况下,应尽可能增加循环时间。图7:设置重置和/或速率c。设置冷却控制的主输出使用与加热相同的步骤。该过程应该在设定点运行,这需要在温度稳定之前进行冷却控制。d .简化PID控制器的整定步骤。

以下步骤是分析过程对阶跃输入的响应曲线的图解方法。用长图表记录器读取过程变量(PV)更容易。从冷启动(室温下的PV)开始,当控制器不在回路中时(即当回路打开时),过程以最大功率供电。记录这个开始时间。

经过一段时间的延迟(让热量到达传感器),PV将开始上升。延迟后,PV将达到最大变化率(斜率)。记录最大斜率出现的时间和此时的PV。记录最大斜率,单位为度/分钟。关闭系统电源。

从最大斜率点画一条线回到环境温度轴,得到总系统延迟Td(见图8)。延迟也可以通过以下公式获得:Td=达到最大斜率时的时间-(最大斜率时的PV-环境温度)/最大斜率S. PID参数可以通过应用以下公式获得:比例范围=Td x最大斜率x 100/范围=%范围的重置=0.4/Td=次数/分钟速率=0.4 x Td=分钟。

重启系统,在控制器处于回路中的情况下将过程带到设定点,并观察响应。如果响应超调过大或振荡,可以从以下几个方向改变PID参数(稍微改变,一次改变一个参数,观察过程响应):加宽比例带,降低复位值,增加速度值。图8中的图表记录是在加热炉以最大功率运行时获得的。图表比例尺是10?F/cm和5分钟/cm。控制器范围100 ~ 600?f,还是500?f的范围。

示例: 图8中的图表记录是在以最大功率给加热炉供电时获得的。图表比例尺为10F/cm和5分/cm。控制器范围为100 ~ 600F,或者说500F的量程。

最大斜率=18F/5分

=3.6F/分

延时=Td=大约7分

比例带=7分x3.6F/分x 100/500F=5%。

复位=0.4 /7分=0.06次/分

速率=0.4 x 7分=2.8分

图8:系统延时

pid算法温度控制c语言程序基于PID算法的温度控制系统89C51单片机,通过键盘输入预设值,与DS18B20测得的实际值做比较,然后驱动制冷或加热电路。用keil C语言来实现PID的控制。

#include 《reg51.h》

#include 《intrins.h》

#include 《math.h》

#include 《string.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晶振为准,延时时间为30ustime

***********************************************************/

void delay(unsigned char time)

{

unsigned char m,n;

for(n=0;n《time;n++)

for(m=0;m《2;m++){}

}

/***********************************************************

写一位数据子程序

***********************************************************/

void write_bit(unsigned char bitval)

{

EA=0;

DQ=0;

if(bitval==1)

{

_nop_();

DQ=1;

}

delay(5);

DQ=1;

_nop_();

_nop_();

EA=1;

}

/***********************************************************

写一字节数据子程序

***********************************************************/

void write_byte(unsigned char val)

{

unsigned char i;

unsigned char temp;

EA=0;

TR0=0;

for(i=0;i《8;i++)

{

temp=val》i;

temp=temp1;

write_bit(temp);

}

delay(7);

//TR0=1;

EA=1;

}

/***********************************************************

读一位数据子程序

***********************************************************/

unsigned char read_bit()

{

unsigned char i,value_bit;

EA=0;

DQ=0;

_nop_();

_nop_();

DQ=1;

for(i=0;i《2;i++){}

value_bit=DQ;

EA=1;

return(value_bit);

}

/***********************************************************

读一字节数据子程序

***********************************************************/

unsigned char read_byte()

{

unsigned char i,value=0;

EA=0;

for(i=0;i《8;i++)

{

if(read_bit())

value|=0x01《i;

delay(4);

}

EA=1;

return(value);

}

/***********************************************************

复位子程序

***********************************************************/

unsigned char reset()

{

unsigned char presence;

EA=0;

DQ=0;

delay(30);

DQ=1;

delay(3);

presence=DQ;

delay(28);

EA=1;

return(presence);

}

/***********************************************************

获取温度子程序

***********************************************************/

void get_temper()

{

unsigned char i,j;

do

{

i=reset();

}while(i!=0);

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=(i《4)0x7f;

s=(unsigned int)(j0x0f);

s=(s*100)/16;

j=j》4;

temper=i|j;

}

void PIDInit (struct PID *pp)

{

memset ( pp,0,sizeof(struct 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_temper》temper)

{

if(set_temper-temper》1)

{

high_time=100;

low_time=0;

}

else

{

for(i=0;i《10;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_temper》0)

{

high_time=0;

low_time=100;

}

else

{

for(i=0;i《10;i++)

{ get_temper();

rin=s; //Read Input

rout=PIDCalc ( spid,rin ); //Perform PID Interation

}

if (high_time《100)

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

{

}

void disp_1(unsigned char disp_num16)

{

unsigned char n,a,m;

for(n=0;n《6;n++)

{

//k=disp_num1n;

for(a=0;a《8;a++)

{

clk=0;

m=(disp_num1n1);

disp_num1n=disp_num1n》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_num6;

unsigned int k,k1;

k=high_time;

k=k%1000;

k1=k/100;

if(k1==0)

disp_num0=0;

else

disp_num0=0x60;

k=k%100;

disp_num1=numberk/10;

disp_num2=numberk%10;

k=temper;

k=k%100;

disp_num3=numberk/10;

disp_num4=numberk%10+1;

disp_num5=numbers/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;a《5;a++)

for(b=0;b《102;b++){}

if(plus==0)

{

set_temper++;

flag=0;

}

}

else if(subs==0)

{

for(a=0;a《5;a++)

for(b=0;a《102;b++){}

if(subs==0)

{

set_temper--;

flag=0;

}

}

else if(stop==0)

{

for(a=0;a《5;a++)

for(b=0;b《102;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(++count1》30)

{

display();

count1=0;

}

compare_temper();

}

TR0=0;

z=1;

while(1)

{

EA=0;

if(stop==0)

{

for(a=0;a《5;a++)

for(b=0;b《102;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(;useconds》0;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;i》0;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;i》0;i--) //一次写一个字节

{

DQ=0;

DQ=val0x01;

delay(5);

DQ=1;

val=val/2;

}

delay(5);

}

//读取温度

char Read_Temperature(void)

{

union{

byte c2;

int x;

}temp;

ow_reset();

write_byte(0xcc);

write_byte(0xBE);

temp.c1=read_byte();

temp.c0=read_byte();

ow_reset();

write_byte(0xCC);

write_byte(0x44);

return temp.x/2;

}

以上知识分享希望能够帮助到大家!