duan123 发表于 2013-11-2 11:38:04

标准PID处理例子


/*====================================================================================================
    这是从网上找来的一个比较典型的PID处理程序,在使用单片机作为控制cpu时,请稍作简化,具体的PID
参数必须由具体对象通过实验确定。由于单片机的处理速度和ram资源的限制,一般不采用浮点数运算,
而将所有参数全部用整数,运算到最后再除以一个2的N次方数据(相当于移位),作类似定点数运算,可
大大提高运算速度,根据控制精度的不同要求,当精度要求很高时,注意保留移位引起的“余数”,做好余
数补偿。这个程序只是一般常用pid算法的基本架构,没有包含输入输出处理部分。
=====================================================================================================*/
#include <string.h>
#include <stdio.h>
/*====================================================================================================
    PID Function
   
    The PID (比例、积分、微分) function is used in mainly
    control applications. PIDCalc performs one iteration of the PID
    algorithm.

    While the PID function works, main is just a dummy program showing
    a typical usage.
=====================================================================================================*/

typedef struct PID {

      doubleSetPoint;         //设定目标 Desired Value

      doubleProportion;         //比例常数 Proportional Const
      doubleIntegral;         //积分常数 Integral Const
      doubleDerivative;         //微分常数 Derivative Const

      doubleLastError;          //Error[-1]
      doublePrevError;          //Error[-2]
      doubleSumError;         //Sums of Errors

} PID;

/*====================================================================================================
   PID计算部分
=====================================================================================================*/

double PIDCalc( PID *pp, double NextPoint )
{
    doubledError,
            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             // 微分项
      );
}

/*====================================================================================================
   Initialize PID Structure
=====================================================================================================*/

void PIDInit (PID *pp)
{
    memset ( pp,0,sizeof(PID));
}

/*====================================================================================================
    Main Program
=====================================================================================================*/

double sensor (void)                  //Dummy Sensor Function
{
    return 100.0;
}

void actuator(double rDelta)            //Dummy Actuator Function
{}

void main(void)
{
    PID         sPID;                   //PID Control Structure
    double      rOut;                   //PID Response (Output)
    double      rIn;                  //PID Feedback (Input)

    PIDInit ( &sPID );                  //Initialize Structure
    sPID.Proportion = 0.5;            //Set PID Coefficients
    sPID.Integral   = 0.5;
    sPID.Derivative = 0.0;
    sPID.SetPoint   = 100.0;            //Set PID Setpoint

    for (;;) {                        //Mock Up of PID Processing

      rIn = sensor ();                //Read Input
      rOut = PIDCalc ( &sPID,rIn );   //Perform PID Interation
      actuator ( rOut );            //Effect Needed Changes
    }
}

请问大伙这个什么意思
doubleSetPoint;         //设定目标 Desired Value
#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));         //全部初始化为0
}
      /*====================================================================================================
      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);                // 微分项
}
      /***********************************************************
      温度比较处理子程序
      ***********************************************************/
void compare_temper()
{
      unsigned char i;
      if(set_temper>temper)      //是否设置的温度大于实际温度
      {
         if(set_temper-temper>1)         //设置的温度比实际的温度是否是大于1度
          {
         high_time=100;                     //如果是,则全速加热
         low_time=0;
          }
       else                                       //如果是在1度范围内,则运行PID计算
          {
            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)
{
      unsigned char n,a,m;
      for(n=0;n<6;n++)
      {
      // k=disp_num1;
         for(a=0;a<8;a++)
         {
            clk=0;
          m=(disp_num1&1);
          disp_num1=disp_num1>>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;
      unsigned int k,k1;
      k=high_time;
      k=k%1000;
      k1=k/100;
      if(k1==0)
      disp_num=0;
      else
      disp_num=0x60;
      k=k%100;
      disp_num=number;
      disp_num=number;
      k=temper;
      k=k%100;
      disp_num=number;
      disp_num=number+1;
      disp_num=number;
      disp_1(disp_num);
}
      /***********************************************************
      主程序
      ***********************************************************/
void 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比例常数 Proportional Const
      spid.Integral = 8;    //积分常数 Integral Const
      spid.Derivative =6;   //微分常数 Derivative Const
      spid.SetPoint = 100; // Set PID Setpoint 设定目标 Desired Value
      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;
}
}


这个程序spid.SetPoint = 100; // Set PID Setpoint 设定目标 Desired Value是什么意思,上面的eet_temper=35;难道这个spid.SetPoint = 100是指35-34=1度的温差扩大100倍?

灵魂腐蚀 发表于 2014-3-16 17:52:41

穿过黑夜 发表于 2014-3-16 17:52:51

为毛老子总也抢不到沙发?!!

loonfe1 发表于 2015-6-4 23:17:12

标记学习!!!
页: [1]
查看完整版本: 标准PID处理例子