网站导航: 首页 > 设计参考 > 正文 文章搜索
用C51实现PID算法
 
文章编号:
090106144802
文章分类: EDA技术 Keil C
点 击:
...
关 键 词: PID,浮点,小数,整数,定点数
文章来源:
网络
摘 要:
关于PID的算法实现,很多书上都讲了。但是,最近真正要用PID算法的时候,发现书上的代码在我们51上来实现还不是那么容易的事情。简单的说来,就是不能直接调用。仔细分析你可以发现,教材上的、网上现行的PID实现的C

关于PID的算法实现,很多书上都讲了。
 
但是,最近真正要用PID算法的时候,发现书上的代码在我们51上来实现还不是那么容易的事情。简单的说来,就是不能直接调用。仔细分析你可以发现,教材上的、网上现行的PID实现的C语言代码几乎都是用浮点型的数据来做的,可以想象,如果我们的计算使用浮点数据,那我们的51单片机来运行的话会有多痛苦。
 
所以,本人自己琢磨着弄了一个整型变量来实现了PID算法,由于是用整型数来做的,所以也不是很精确,但是对于很多的使用场合,这个精度也够了。关于系数和采样电压全部是放大10倍处理的。所以精度不是很高,但是也不是那么低,大部分的场合都够用了。实在觉得精度不够,可以再放大10倍或者100倍处理,但是要注意不超出整个数据类型的范围就可以了。
 
    本人做的是带死区控制的PID算法。
 
具体的参考代码参见下面:
 

 
  1. typedef struct PIDValue   
  2. {   
  3.     uint32 Ek_Uint32[3];         //差值保存,给定和反馈的差值   
  4.     uint8  EkFlag_Uint8[3];     //符号,1则对应的Ek[i]为负数,0为对应的Ek[i]为正数   
  5.     uint8   KP_Uint8;   
  6.     uint8   KI_Uint8;   
  7.     uint8   KD_Uint8;   
  8.     uint8   B_Uint8;     //死区电压   
  9.        
  10.     uint8   KP;      //显示修改的时候用   
  11.     uint8   KI;      //   
  12.     uint8   KD;      //   
  13.     uint8   B;       //   
  14.     uint16  Uk_Uint16;    //上一时刻的控制电压   
  15. }PIDValueStr;   
  16.   
  17. PIDValueStr xdata PID;   
  18. /*******************************  
  19. **PID = Uk + (KP*E(k) - KI*E(k-1) + KD*E(k-2));  
  20. ********************************/  
  21. void    PIDProcess(void)   
  22. {   
  23.     uint32 idata Temp[3];  //   
  24.     uint32 idata PostSum;  //正数和   
  25.     uint32 idata NegSum;   //负数和   
  26.     Temp[0] = 0;   
  27.     Temp[1] = 0;   
  28.     Temp[2] = 0;   
  29.     PostSum = 0;   
  30.     NegSum = 0;   
  31.     if( ADPool.Value_Uint16[UINADCH] > ADPool.Value_Uint16[UFADCH] )  //给定大于反馈,则EK为正数   
  32.     {   
  33.         Temp[0] = ADPool.Value_Uint16[UINADCH] - ADPool.Value_Uint16[UFADCH];   //计算Ek[0]   
  34.         if( Temp[0] > PID.B_Uint8 )   
  35.         {   
  36.             //数值移位   
  37.             PID.Ek_Uint32[2] = PID.Ek_Uint32[1];   
  38.             PID.Ek_Uint32[1] = PID.Ek_Uint32[0];   
  39.             PID.Ek_Uint32[0] = Temp[0];   
  40.             //符号移位   
  41.             PID.EkFlag_Uint8[2] = PID.EkFlag_Uint8[1];   
  42.             PID.EkFlag_Uint8[1] = PID.EkFlag_Uint8[0];   
  43.             PID.EkFlag_Uint8[0] = 0;                       //当前EK为正数   
  44.             Temp[0] = (uint32)PID.KP_Uint8 * PID.Ek_Uint32[0];    // KP*EK0   
  45.             Temp[1] = (uint32)PID.KI_Uint8 * PID.Ek_Uint32[1];    // KI*EK1   
  46.             Temp[2] = (uint32)PID.KD_Uint8 * PID.Ek_Uint32[2];    // KD*EK2   
  47.         }   
  48.     }   
  49.     else   //反馈大于给定   
  50.     {   
  51.         Temp[0] = ADPool.Value_Uint16[UFADCH] - ADPool.Value_Uint16[UINADCH];   //计算Ek[0]   
  52.         if( Temp[0] > PID.B_Uint8 )   
  53.         {   
  54.             //数值移位   
  55.             PID.Ek_Uint32[2] = PID.Ek_Uint32[1];   
  56.             PID.Ek_Uint32[1] = PID.Ek_Uint32[0];   
  57.             PID.Ek_Uint32[0] = Temp[0];   
  58.             //符号移位   
  59.             PID.EkFlag_Uint8[2] = PID.EkFlag_Uint8[1];   
  60.             PID.EkFlag_Uint8[1] = PID.EkFlag_Uint8[0];   
  61.             PID.EkFlag_Uint8[0] = 1;                       //当前EK为负数   
  62.             Temp[0] = (uint32)PID.KP_Uint8 * PID.Ek_Uint32[0];    // KP*EK0   
  63.             Temp[1] = (uint32)PID.KI_Uint8 * PID.Ek_Uint32[1];    // KI*EK1   
  64.             Temp[2] = (uint32)PID.KD_Uint8 * PID.Ek_Uint32[2];    // KD*EK2   
  65.         }   
  66.     }   
  67.        
  68.     /*以下部分代码是讲所有的正数项叠加,负数项叠加*/  
  69.     if(PID.EkFlag_Uint8[0]==0)   
  70.     {   
  71.         PostSum += Temp[0];   //正数和   
  72.     }   
  73.     else  
  74.     {   
  75.         NegSum += Temp[0];    //负数和   
  76.     }                         // KP*EK0   
  77.     if(PID.EkFlag_Uint8[1]!=0)        
  78.     {   
  79.         PostSum += Temp[1];   //正数和   
  80.     }   
  81.     else  
  82.     {   
  83.         NegSum += Temp[1];    //负数和   
  84.     }                         // - kI * EK1   
  85.     if(PID.EkFlag_Uint8[2]==0)   
  86.     {   
  87.         PostSum += Temp[2];   //正数和   
  88.     }   
  89.     else  
  90.     {   
  91.         NegSum += Temp[2];    //负数和   
  92.     }                         // KD * EK2   
  93.     PostSum += (uint32)PID.Uk_Uint16;        //   
  94.     if( PostSum > NegSum )             // 是否控制量为正数   
  95.     {   
  96.         Temp[0] = PostSum - NegSum;   
  97.         if( Temp[0] < (uint32)ADPool.Value_Uint16[UMAXADCH] )   //小于限幅值则为计算值输出   
  98.         {   
  99.             PID.Uk_Uint16 = (uint16)Temp[0];   
  100.         }   
  101.         else  
  102.         {   
  103.             PID.Uk_Uint16 = ADPool.Value_Uint16[UMAXADCH];    //否则为限幅值输出   
  104.         }   
  105.     }   
  106.     else               //控制量输出为负数,则输出0   
  107.     {   
  108.         PID.Uk_Uint16 = 0;   
  109.     }   
  110. }   

 

 
相关文章:

 
最新开源项目
 
 
  查看更多...  
 
本站相关产品   淘宝网店
 



 
  查看更多...  

 

本站程序由百合电子工作室开发和维护
Copyright @ baihe electric studio
渝ICP备09006681号-4