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

电子常识

2585人已加入

描述

  温度控制PID自整定原理介绍

  整定PID(三模式)控制器

  整定温度控制器涉及设置比例、积分和微分值,以得到对特定过 程的可能的最佳控制。如果控制器不包含自动整定算法,或者自 动整定算法未提供适合特定应用的足够控制,则必须用试误法对 装置进行整定。

  下面是温度控制器的标准整定步骤。也可以采用其他整定步骤, 但都使用类似的试误法。请注意,如果控制器使用机械式继电器 (而非固态继电器),开始时应使用较长的循环时间(20秒)。

  可能需要用到以下定义 :

  循环时间 – 也称为工作周期,是控制器完成一个通断循环所 用的总时间长度。示例: 对于20秒的循环时间,10秒接通时 间和10秒切断时间代表50%的功率输出。在比例带内时,控 制器将循环接通和切断。

  比例带 – 以满量程的%或度表示的温度范围,控制器的比例 作用发生在此范围内。比例带越宽,在其内发生比例作用的 围绕设定值的区域越大。有时也用增益表示,增益是比例带 的倒数。

  积分,又称为复位,是根据设定值调节比例带宽以补偿偏离 设定值的偏移量(固定偏差)的一个函数,也就是说,它在 系统稳定后将控制的温度调节到设定值。

  微分,又称为速率,感应系统温度上升或下降的速率,并自 动调节比例带,从而将下冲或过冲降到最小。

  PID(三模式)控制器如果正确整定和使用的话,能具有优异的 控制稳定性。通过认真遵守这些指示,操作人员便可实现最快的 响应时间和最小的过冲。整定这种三模式控制器的信息可能不同 于其它控制器整定步骤。对于主输出,通常用自整定功能就可省 去使用此手动整定步骤的需要,但是,需要时可对自整定值进 行调整。

  A.整定加热控制的输出

  启用输出并启动过程。

  过程应在设定值处运行,将用所需热量输入让温度稳定。

  在速率和复位断开的情况下,温度将稳定,并在设定值和实际 温度之间存在稳态偏差,或固定偏差。通过观察显示屏上的测 量值,密切注意此温度是否存在规则的循环或振荡。(振荡可 长达30分钟。)

  温度控制

  4.如果温度没有规则的振荡,将PB除以2(见图1)。让过程 稳定下来,然后再检查是否有温度振荡。如果仍无振荡, 再将PB除以2。重复此操作,直到得到循环或振荡。转至 第5步。

  5.如果马上观察到振荡,将PB乘以2。观察得到的温度几分 钟。如果振荡持续,以系数2不断乘PB,直到振荡停止。

  此时,PB非常接近其临界设置。小心地增大或减小PB设 置,直到温度记录中刚刚出现循环或振荡为止。

  如果甚至在1%的最小PB设置时过程温度仍不发生振荡, 请跳过下面的第6步到第11步,转至第B条。

  在已经达到的“临界”BP设置下,读取设定值与实际温度 之间的稳态偏差,或固定偏差。(由于温度有一点循环, 请使用平均温度。)

  测量相邻波峰或波谷之间的振荡时间,以分为单位 (见图2)。使用图表记录仪最容易进行这种测量,但可每 隔一分钟读取一次测量值,以掌握时间。

  此时,增大PB设置,直到温度偏差(或固定偏差)增大 65%。

  温度控制

  用在“临界”BP设置下得到的初始温度偏差乘以1.65或者 使用方便的线列图I(见图4)就可计算出所需的最终温度偏 差。用试误法尝试几次PB控制的设置,直到得到所需的最终 温度偏差。

  温度控制

  此时您已经完成了得到控制器最佳性能所需的所有测量。 只需再做两项调整 – 速率和复位。

  使用第7步中测得的振荡时间,按以下方法计算复位值, 以每分钟重复次数为单位。

  温度控制

  将此值输入给RESET 1。

  再使用第7步中测得的振荡时间,按以下方法计算速率的 值,以分为单位。

  温度控制

  将此值输入给RATE 1。

  如果出现过冲,可通过减少复位时间来消除。当对复位值 进行了更改时,也应对速率调整进行相应的更改,使速率值 等于:

  温度控制

  即:如果复位 = 2 R/M,则速率= 0.08分钟

  若想在对系统扰动的“响应时间”和“设置时间”之间得到 正确的平衡,可能需要进行多次设定值更改和随之发生的复 位和速率控制时间调整。快速响应常常伴随着较大的过冲, 过程“稳定下来”所需的时间也较短。相反,如果响应较 慢,过程趋向于慢慢滑行到最终值,过冲很小或者没有过 冲。应由系统的要求决定采取哪种动作。

  当得到满意的整定时,应增大循环时间以节省接触器的寿命 (适用于只有时间比例输出的装置(TPRI))。在不造成测量 值因负载循环而振荡的情况下,应尽量增大循环时间。

  转至第C节。

  B. 未观察到振荡时的整定步骤

  在最小PB设置下,测量设定值与实际温度之间的稳态偏 差,或固定偏差。

  增大PB设置,直到温度偏差(固定偏差)增大65%。线列 图I(见图4)提供了计算所需最终温度偏差的简便方法。

  将RESET 1设置为一个较高的值(10 R/M)。将RATE 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中的图表记录是在以最大功率给加热炉供电时获 得的。图表比例尺为10°F/cm和5分/cm。控制器范围为 100 ~ 600°F,或者说500°F的量程。

  最大斜率 = 18°F/5分

  = 3.6°F/分

  延时 = Td = 大约7分

  比例带 = 7分x3.6°F/分 x 100/500°F = 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晶振为准,延时时间为30us×time

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

  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; /*拉低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;i《8;i++) /*写一字节数据,一次写一位*/

  {

  temp=val》》i; /*移位操作,将本次要写的位移到最低位*/

  temp=temp&1;

  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;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); /*延时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=(i《《4)&0x7f;

  s=(unsigned int)(j&0x0f);

  s=(s*100)/16;

  j=j》》4;

  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_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

  {

  /* 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;n《6;n++)

  {

  // k=disp_num1[n];

  for(a=0;a《8;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;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=val&0x01;

  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;

  }

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分