研发埠

标题: 怎样用C程序能实现PID倒立摆系统? [打印本页]

作者: 徐依淼    时间: 2014-2-24 13:55
标题: 怎样用C程序能实现PID倒立摆系统?

作者: 杨鹏飞    时间: 2014-2-24 13:59
#include "stc12.h" #include <intrins.h>#include"pid.h" typedef  unsigned  char  uint8;   typedef  unsigned  int  uint16;   typedef  unsigned  long int  uint32; /*********************************函数声明******************   结构体设定***********************************************************/ typedef struct PIDValue { uint32  Ek_Uint32[3];  //差值保存,给定和反馈的差值 uint8  EkFlag_Uint8[3];  //差值标志位符号,1则对应的为负数,0为对应的为正数   uint8  KP_Uint8;  //比例系数uint8  KI_Uint8;  //积分系数uint8  KD_Uint8;  //微分显示uint16  Uk_Uint16;  //上一时刻的控制电压 uint16  RK_Uint16;  //设定值 uint16  CK_Uint16;  //实际值  uint8  Vaule_Flag;  //输出的值正负标志位,0为正,1为负}PIDValueStr; PIDValueStr  PID;  //定义一个结P构体uint16  out ;  // 加热输出(PID运算后的输出值)  /*********************************************************************************** 增量型PID算式ID :Uk=KP*[E(k)-E(k-1)]+KI*E(k)+KD*[E(k)-2E(k-1)+E(k-2)]函数入口: RK(设定值),CK(实际值),KP,KI,KD  PID比例参数函数出口: U(K) PID运算函数 **************************************************************************************/ uint16 PID_Calc(uint16 PIDinput)   {    uint32  Temp[3];  //中间临时变量   uint32  PostSum;  //正数和   uint32  NegSum;  //负数和   Temp[0] = 0;  //给储存中间临时变量赋初值  Temp[1] = 0;     Temp[2] = 0;     PostSum = 0;  //给存储所有的正数变量赋初值  NegSum  = 0;  //给存储所有的负值变量赋初值  PID.RK_Uint16=180;  //设定值为180  PID.CK_Uint16=PIDinput;  //输入值 if( PID.RK_Uint16 > PID.CK_Uint16 )  //如果设定值大于实际值,就是当前的值比设定值小  {  if( PID.RK_Uint16 - PID.CK_Uint16 >10 )  //计算偏差是否大于 piancha=10 ( 这里的10由 piancha 来设定大小,根据实际情况设定) //if( PID.RK_Uint16 - PID.CK_Uint16 >piancha )  {  //如果偏差大于 piancha=10 不在设定的PID调控范围之内就全速加热  out = 100;  //偏差大于piancha=10为上限幅值输出(全速加热)   // PID.Uk_Uint16 = full_speed;  //全速时的加热值,更具实际情况可自由设定 这里full_speed=100; }     else  //如果偏差小于 piancha=10 再调节的范围内就计算储存起来  {  //下面就是PID算法     Temp[0] = PID.RK_Uint16 - PID.CK_Uint16;  // 计算出当前偏差值E(k)    PID.EkFlag_Uint8[1]=0;  //E(k)为正数 的标志位 0为正,1为负  //数值移位   PID.Ek_Uint32[2] = PID.Ek_Uint32[1];  //存储E(k-2)  PID.Ek_Uint32[1] = PID.Ek_Uint32[0];  //储存E(k-1)  PID.Ek_Uint32[0] = Temp[0];  //存储E(k)/****************************************************************************************/   if( PID.Ek_Uint32[0] &gtID.Ek_Uint32[1] )  //E(k)>E(k-1) 为正数  {   Temp[0]=PID.Ek_Uint32[0] - PID.Ek_Uint32[1];  //E(k)-E(k-1) 保存  PID.EkFlag_Uint8[0]=0;  // 设定标志位 0为正,1为负  }     else  //E(k)<E(k-1)   {   Temp[0]=PID.Ek_Uint32[1] - PID.Ek_Uint32[0];  //E(k)-E(k-1)为负数   PID.EkFlag_Uint8[0]=1;    }   /*****************************************************************************************/   Temp[2]=PID.Ek_Uint32[1]*2 ;  // 2E(k-1)      if( (PID.Ek_Uint32[0]+ PID.Ek_Uint32[2])>Temp[2] )  //E(k-2)+E(k)>2E(k-1)   {   Temp[2]=(PID.Ek_Uint32[0]+ PID.Ek_Uint32[2])-Temp[2];  //E(k-2)+E(k)-2E(k-1)为正数   PID.EkFlag_Uint8[2]=0;    }     else  //E(k-2)+E(k)-2E(k-1)为负数   {   Temp[2]=Temp[2]-(PID.Ek_Uint32[0]+ PID.Ek_Uint32[2]);  //2E(k-1)-(E(k-2)+E(k))  PID.EkFlag_Uint8[2]=1;   }   /**********************************************************************************************/     Temp[0] = (uint32)PID.KP_Uint8 * Temp[0];  // KP*[E(k)-E(k-1)]   Temp[1] = (uint32)PID.KI_Uint8 * PID.Ek_Uint32[0];  // KI*E(k)   Temp[2] = (uint32)PID.KD_Uint8 * Temp[2];  // KD*[E(k-2)+E(k)-2E(k-1)] /************************以下部分代码是讲所有的正数项叠加,负数项叠加**************************/   /**************************************KP*[E(k)-E(k-1)]********************************************/   if(PID.EkFlag_Uint8[0]==0)   PostSum += Temp[0];  //正数和   else     NegSum += Temp[0];  //负数和 /*************************************** KI*E(k)*************************************************/    if(PID.EkFlag_Uint8[1]==0)     PostSum += Temp[1];  //正数和   else   ;  //空操作,E(K)>0 /************************************KD*[E(k-2)+E(k)-2E(k-1)]*************************************/     if(PID.EkFlag_Uint8[2]==0)   PostSum += Temp[2];  //正数和   else   NegSum += Temp[2];  //负数和 /**********************************************U(K)*************************************************/     //PostSum += (uint32)PID.Uk_Uint16;        if(PostSum > NegSum )  // 是否控制量为正数   {   out= PostSum - NegSum;  PID.Vaule_Flag=0;  //PID调节值是正值  }        else  //控制量输出为负数   {  out=NegSum-PostSum;   PID.Vaule_Flag=1;  //PID调节值是负值  }     }  //return out; }  else  //如果设定值小于实际值,就是当前的值大于设定值,就不进行PID计算直接输出 0 {   out = 0;  }    return out;}




欢迎光临 研发埠 (http://bbs.yanfabu.com/) Powered by Discuz! X3.2