查看: 548|回复: 0

[经验] 软件PID控温

[复制链接]

该用户从未签到

发表于 2021-1-19 19:21:08 | 显示全部楼层 |阅读模式
分享到:
跟大家分享一下我对PID的理解:在控温中比例控制占主导,积分和微分都是辅助性的,在参数整定时先去掉微分和积分的作用,单独整定比例参数使温度能停止波动后比例参数即确定(此时由于没有积分作用允许与目标温度存在温差),再打开积分并调试其参数使温度无限接近目标温,注意积分周期宜长不宜短,积分周期必须大于热惯性作用时间,如果积分周期太短温度会始终在目标温附近波动,积分时间长只会使恒温过程变长。对于负载经常更换的控温体应使用热惯性最大的负载做积分参数整定。微分参数整定需放到比例和积分参数确定之后来做,微分的原则是:微分周期越短控温效果越好但是要能减小传感器的采样干扰,在不引起温度波动的前提下尽量加大微分作用。以下是一款热风枪的控温程序:
//======================
//MCU:S3F94C4
//系统晶振:3200000Hz
//======================
#include
//========宏定义========
#define uchar unsigned char
#define uint unsigned int

uchar tmr=0,tmr_sec=0,adc_cnt=0,com_duty;
uchar tmr_delay,dig0_p2=0,dig1_p2=0,dig2_p2=0;
uchar dig0_p0=0,dig1_p0=0,dig2_p0=0;
uchar Periods_cnt,ip_cnt=0,delay_sleep;
signed char d_tab[10]={0,0,0,0,0,0,0,0,0,0};//i_pid,d_pid=0,
int d_sum=0,p_pid;
uint sen_val=0,vr_val=0xFFFF,last_sev;//
uint tar_adv,tar_temp,cur_temp,ip_sum=0;
uchar ip_tab[8]={0,0,0,0,0,0,0,0};

#define NOP asm("NOP")
#define DI asm("DI")
#define EI asm("EI")

#define wdt_feed (BTCON |= 0x02)
#define Power_on (P1 |= 0x01)
#define Power_off (P1 &= 0xfe)
#define Relay_on (P1 |= 0x02)
#define Relay_off (P1 &= 0xfd)
#define sw_power (P1&4|flag.d_slp)
//#define sw_sleep (P2 & 0x01)
#define ad1c 64

//========SMART OPTION========
__root const uchar SmartOption[4] @ 0x003C ={0x00,0x00,0xB0,0x03};
__code const uint DigCode[];
__code const uint temp_tab[];
union a
    {
      struct
      {
        uchar h;
        uchar l;
      }u8r;
      uint u16r;
    };
struct b
    {
      unsigned t_stb:1;
      unsigned d_slp:1;
    };
static struct b flag;

void InitMCU(void)
{
    BTCON=0xA3;
    CLKCON=0x18;//fcpu=fosc/1
    P0=0x00;
    P1=0x00;
    P2=0x00;
    P0CONH=0xAA;//P0 口控制寄存器 (高字节)
    P0CONL=0x8F;//P0 口控制寄存器 (低字节)
    P0PND=0x00;//P0 中断标志位寄存器
    P1CON=0x0A;
    P2CONH=0x4A;
    P2CONL=0xA8;//0xAA
    T0DATA=0x7d;//10ms*125/125=10ms
    T0CON=0x4A;//FOSC/256=3200000/256=12500
    PWMDATA=0x00;
    PWMCON=0x00;
    ADCON=0x01;//ADC0 fosc/16 start A/D Convert//0.25ms
    BTCON=0x00;
}
void Display(void)
{
   uchar i;
    if (com_duty)com_duty--;
    if (com_duty==0)
    {
      uchar dat_p0,dat_p2;
      if (!(P2 & 0x40))//last dig0
      {
        dat_p0=dig1_p0 & 0xEF;
        dat_p2=dig1_p2;
        dat_p0|=0x40;dat_p2|=0x40;
      }
      else
      {
        if (!(P0 & 0x10))//last dig1
        {
          dat_p0=dig2_p0 & 0xBF;
          dat_p2=dig2_p2;
          dat_p0|=0x10;dat_p2|=0x40;
        }
        else//last dig2
        {
          dat_p0=dig0_p0;
          dat_p2=dig0_p2 & 0xBF;
          dat_p0|=0x50;
        }
      }
      P2 |= 0x40;
      P0 |= 0xf8;
      P2 |= 0x7e;
      P2 &= dat_p2|0xC1;
      P0 &= dat_p0|0x07;
      P2 &= dat_p2|0x81;
      //GetDutyValue
      dat_p0 &= 0xA8;
      dat_p2 &= 0x3e;
      for (i=3;i>0;i--)
      {
        if (dat_p0 & 0x80)com_duty++;
        dat_p0 <<= 2;
      }
      dat_p2>>=1;
      for (i=5;i>0;i--)
      {
        if (dat_p2 & 0x01)com_duty++;
        dat_p2>>=1;
      }
    }
}
void DispValue(uint val1)
{
    if (val1>600)
    {
      dig0_p0=0xF0;
      dig0_p2=0x74;
      dig1_p0=0;
      dig1_p2=0x20;
      dig2_p0=0xF0;
      dig2_p2=0x66;
    }
    /*
    else if (tmr_delay&1)//ray
    {
      dig0_p0=0x50;dig0_p2=0x40;
      dig1_p0=0x50;dig1_p2=0x40;
      dig2_p0=0x50;dig2_p2=0x40;
    }
    */
    else
    {
      union a buf;
      uchar b0=0,b1=0,b2=0;
      while (val1>=100){val1-=100;b0++;}//uchar i=val1/100;
      buf.u16r = DigCode[b0];
      dig0_p0=buf.u8r.h;
      dig0_p2=buf.u8r.l;
      while (val1>=10){val1-=10;b1++;}b2=val1;//i=val1%100/10;
      buf.u16r = DigCode[b1];
      dig1_p0=buf.u8r.h;
      dig1_p2=buf.u8r.l;
      //i=val1%10;
      buf.u16r = DigCode[b2];
      dig2_p0=buf.u8r.h;
      dig2_p2=buf.u8r.l;
    }
}
//===============================================================================================
void main(void)
{
   uint adc_val_buf=0;   
    DI;
    SP=0xc0;//add by sp
    InitMCU();
    EI;
    tmr = 0;
    Relay_on;
    while(1)
    {
      //主程序
      wdt_feed;
    //=============================================
      while ((ADCON & 0x08)==0);//A/D Convertion done!
      Display();
      adc_val_buf += ((uint)ADDATAH<<2) + (ADDATAL & 0x03);
      adc_cnt++;

      if (ADCON & 0x10)//ADC1
      {
        if (adc_cnt & 0xc0)//adc_cnt>63
        {
          ADCON = 0x01;
          adc_cnt = 0;
          sen_val = adc_val_buf;
          //delay wait for A/D channel to be stable

          cur_temp=(int)tar_temp+(int)(adc_val_buf>>6)-(int)(tar_adv>>6);
          if (flag.t_stb==0 && tmr_delay==0)
          {
             if (cur_temp42)cur_temp++;
             else if (cur_temp>cur_temp && (sen_val&63)<21)cur_temp--;
             DispValue(cur_temp);
             if (tar_temp==cur_temp)flag.t_stb=1;
          }
          else if (cur_temp>tar_temp+5 || cur_temp<tar_temp-5)
           {
            flag.t_stb=0;
          }
          //Calculate the P of PID
          p_pid=(int)(tar_adv>>4)-(int)(sen_val>>4);
          adc_val_buf=0;
        }
        else ADCON |= 0x01;//Start A/D Convert
      }
      else//ADC0
      {
        if (adc_cnt & 0xf0)//adc_cnt>15
        {
          uint buf16;
          ADCON=0x11;//ADCON ^= 0x10;
          adc_cnt = 0;
          buf16 = adc_val_buf>>4;
          //delay wait for A/D channel to be stable
          if (vr_val>buf16+2 || vr_val+2<buf16)
           {
            vr_val=buf16;
            buf16=( (buf16<<4)+(buf16<<3)+buf16+(buf16>>3)>>6 )+100;//( (vr_val>>1)+(vr_val>>2)+(vr_val>>4)>>1 )
            if (buf16>500)buf16=500;
            tar_temp=buf16;
            DispValue(buf16);
            buf16-=100;
            if ( (buf16&31)<16 )tar_adv=temp_tab[buf16>>5]+((buf16&31)<<6);
            else tar_adv=temp_tab[buf16+32>>5]-(32-(buf16&31)<<6);
            tmr_delay=4;
            flag.t_stb=0;
          }
          adc_val_buf=0;
        }
        else ADCON |= 0x01;//Start A/D Convert
      }
    //=================================================

      if (sw_power!=0 && sen_val<0x21E5)
      {
        union a period;uchar p2_buf=0x20;
        P0=02=0x20;
        Relay_off;
        while (sw_power)
        {
            wdt_feed;
            if (++period.u16r==0)p2_buf ^= 0x20;
            if (period.u8r.l<period.u8r.h)p2 =="" p2_buf;
             else P2 = p2_buf^0x20;
        }
        flag.t_stb=0;
        Relay_on;
      }
    }
}
//======================
#pragma vector=0x00
__interrupt void int_9454()//T0 10ms/cycle
{
  int Heat_duty,s16buf,d_pid;//
  signed char s8buf,i_pid;
    //中断服务程序
    T0CON = T0CON & 0xfe;
    //BTCON = 0x2;

    if (++tmr>4)//50ms
    {
      tmr=0;
      tmr_sec++;
      if (tmr_sec>9)//0.5s
      {
        tmr_sec=0;
        if (tmr_delay>0)tmr_delay--;
        if ((P2&1)==0)
        {
          if (flag.t_stb!=0 && ++delay_sleep>119)//60/0.5=120
          {
            flag.d_slp=1;
            flag.t_stb=0;
          }
        }
        else {delay_sleep=0;flag.d_slp=0;}
        //Calculate the I of PID
        s8buf = ip_sum>>3;
        if (s8buf+p_pid>100)s8buf=100;
        else if (s8buf+p_pid<0)s8buf=0;
        else s8buf += p_pid;
        ip_sum = ip_sum + s8buf - ip_tab[ip_cnt];
        ip_tab[ip_cnt++]=s8buf;
        ip_cnt &= 7;
      }
      //Calculate the D of PID
      if (last_sev<sen_val){s16buf=sen_val-last_sev;s8buf=1;}
       else {s16buf=last_sev-sen_val;s8buf=0;}
      if (s16buf>127)s16buf=127;
      if (s8buf)s8buf = -(signed char)s16buf;
      else s8buf = (signed char)s16buf;

      d_sum -= d_tab[tmr_sec];
      d_sum += s8buf;
      d_tab[tmr_sec] = s8buf;
      last_sev=sen_val;
    }
    i_pid = ip_sum>>3;

    //if (d_pid&0x80)flag.t_stb=0;
    d_pid = d_sum>>5;

    if (sw_power)Heat_duty=0;//
    else Heat_duty=p_pid+i_pid+d_pid;//
    if (Heat_duty>100)Heat_duty=100;
    else if (Heat_duty<0)Heat_duty=0;
    Heat_duty>>=2;
    Periods_cnt++;
    if (Periods_cnt>24)Periods_cnt=0;
    if (Periods_cnt<heat_duty)power_on;
     else Power_off;
}

__code const uint DigCode[16] @ 0x0002 =
{// P0 P2
  0xF856,        //0
  0x5850,        //1
  0x7866,        //2
  0x7874,        //3
  0xD870,        //4
  0xF074,        //5
  0xF076,        //6
  0x7850,        //7
  0xF876,        //8
  0xF874,        //9
  0xF872,        //A
  0xD076,        //B
  0xF046,        //C
  0x5876,        //D
  0xF066,        //E
  0xF062,        //F
//  0x5040,        //NOP
};
__code const uint temp_tab[14] @ 0x0040=
{
  0x1556,        //100
0x1D60,        //132
0x256B,        //164
0x2DCD,        //196
0x3609,        //228
0x3DEB,        //260
0x46BA,        //292
0x4F65,        //324
0x579A,        //356
0x6093,        //388
0x6973,        //420
0x6FF0,        //452
0x798C,        //484
0x8328,        //516
};
</heat_duty)power_on;
</sen_val){s16buf=sen_val-last_sev;s8buf=1;}
</buf16)
</tar_temp-5)

回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /4 下一条



手机版|小黑屋|与非网

GMT+8, 2024-11-23 22:24 , Processed in 0.102099 second(s), 14 queries , MemCache On.

ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

苏公网安备 32059002001037号

Powered by Discuz! X3.4

Copyright © 2001-2024, Tencent Cloud.