您现在所在的是:

单片机论坛

回帖:0个,阅读:1298 [上一页] [1] [下一页]
* 帖子主题:

用C51实现PID算法

1006
mahuaqiang
文章数:39
年度积分:49
历史总积分:1006
注册时间:2005/6/27
发站内信
08年博客人气奖
发表于:2008/10/24 17:27:00
#0楼
用c51实现pid算法
关于pid的算法实现,很多书上都讲了。

但是,最近真正要用pid算法的时候,发现书上的代码在我们51上来实现还不是那么容易的事情。简单的说来,就是不能直接调用。仔细分析你可以发现,教材上的、网上现行的pid实现的c语言代码几乎都是用浮点型的数据来做的,可以想象,如果我们的计算使用浮点数据,那我们的51单片机来运行的话会有多痛苦。

所以,本人自己琢磨着弄了一个整型变量来实现了pid算法,由于是用整型数来做的,所以也不是很精确,但是对于很多的使用场合,这个精度也够了。关于系数和采样电压全部是放大10倍处理的。所以精度不是很高,但是也不是那么低,大部分的场合都够用了。实在觉得精度不够,可以再放大10倍或者100倍处理,但是要注意不超出整个数据类型的范围就可以了。

   本人做的是带死区控制的pid算法。

具体的参考代码参见下面:

typedef struct pidvalue
{
   uint32 ek_uint32[3];         //差值保存,给定和反馈的差值
   uint8  ekflag_uint8[3];     //符号,1则对应的ek[i]为负数,0为对应的ek[i]为正数
   uint8   kp_uint8;
uint8   ki_uint8;
uint8   kd_uint8;
uint8   b_uint8;     //死区电压

uint8   kp;      //显示修改的时候用
uint8   ki;      //
uint8   kd;      //
uint8   b;       //
uint16  uk_uint16;    //上一时刻的控制电压
}pidvaluestr;

pidvaluestr xdata pid;
/*******************************
**pid = uk + (kp*e(k) - ki*e(k-1) + kd*e(k-2));
********************************/
void    pidprocess(void)
{
uint32 idata temp[3];  //
uint32 idata postsum;  //正数和
uint32 idata negsum;   //负数和
temp[0] = 0;
   temp[1] = 0;
   temp[2] = 0;
postsum = 0;
negsum = 0;
if( adpool.value_uint16[uinadch] > adpool.value_uint16[ufadch] )  //给定大于反馈,则ek为正数
{
    temp[0] = adpool.value_uint16[uinadch] - adpool.value_uint16[ufadch];   //计算ek[0]
       if( temp[0] > pid.b_uint8 )
       {
     //数值移位
           pid.ek_uint32[2] = pid.ek_uint32[1];
           pid.ek_uint32[1] = pid.ek_uint32[0];
           pid.ek_uint32[0] = temp[0];
           //符号移位
  pid.ekflag_uint8[2] = pid.ekflag_uint8[1];
  pid.ekflag_uint8[1] = pid.ekflag_uint8[0];
  pid.ekflag_uint8[0] = 0;                       //当前ek为正数
           temp[0] = (uint32)pid.kp_uint8 * pid.ek_uint32[0];    // kp*ek0
           temp[1] = (uint32)pid.ki_uint8 * pid.ek_uint32[1];    // ki*ek1
           temp[2] = (uint32)pid.kd_uint8 * pid.ek_uint32[2];    // kd*ek2
       }
}
else   //反馈大于给定
{
    temp[0] = adpool.value_uint16[ufadch] - adpool.value_uint16[uinadch];   //计算ek[0]
       if( temp[0] > pid.b_uint8 )
       {
     //数值移位
           pid.ek_uint32[2] = pid.ek_uint32[1];
           pid.ek_uint32[1] = pid.ek_uint32[0];
           pid.ek_uint32[0] = temp[0];
           //符号移位
  pid.ekflag_uint8[2] = pid.ekflag_uint8[1];
  pid.ekflag_uint8[1] = pid.ekflag_uint8[0];
  pid.ekflag_uint8[0] = 1;                       //当前ek为负数
           temp[0] = (uint32)pid.kp_uint8 * pid.ek_uint32[0];    // kp*ek0
           temp[1] = (uint32)pid.ki_uint8 * pid.ek_uint32[1];    // ki*ek1
           temp[2] = (uint32)pid.kd_uint8 * pid.ek_uint32[2];    // kd*ek2
       }
}

/*以下部分代码是讲所有的正数项叠加,负数项叠加*/
   if(pid.ekflag_uint8[0]==0)
   {
       postsum += temp[0];   //正数和
}
   else
{
       negsum += temp[0];    //负数和
}                         // kp*ek0
   if(pid.ekflag_uint8[1]!=0)    
   {
       postsum += temp[1];   //正数和
}
else
{
       negsum += temp[1];    //负数和
}                         // - ki * ek1
   if(pid.ekflag_uint8[2]==0)
   {
       postsum += temp[2];   //正数和
   }
else
{
       negsum += temp[2];    //负数和
}                         // kd * ek2
   postsum += (uint32)pid.uk_uint16;        //
   if( postsum > negsum )             // 是否控制量为正数
   {
       temp[0] = postsum - negsum;
       if( temp[0]
----------------------------------------------
此篇文章从博客转发
原文地址: Http://blog.gkong.com/more.asp?id=65373&Name=mahuaqiang

关于我们 | 联系我们 | 广告服务 | 本站动态 | 友情链接 | 法律声明 | 非法和不良信息举报

工控网客服热线:0755-86369299
版权所有 工控网 Copyright©2024 Gkong.com, All Rights Reserved

31.2002