023_STM32之PID算法原理及应用

发布时间:2024-08-16  

(一)PID控制算法(P:比例     I:积分    D:微分)

(二)首先先说明原理,使用的是数字PID算法,模拟PID算法在计算机这样的系统中是不能够直接使用的,数字PID算法又分为位置式PID控制算法和增量式PID控制算法,那么下面从原理上说明这两种算法

(三)原理分析如图

(四)从上面图中我们可以得到定义


定义变量

用户设定值:         SV

当前值(实际值):    PV

偏差:              E = SV - PV       

 

(五)如果我们在一段时间内就从传感器读取一个值,那么我们就可以得到一个实际值的数据序列,,那么我们也会得到一个偏差值的序列


读取时间:  t(1)    t(2)    ------  t(k-1)    t(k)

读取到的值:  X(1)    X(2)    ------  X(k-1)  X(k)

偏差值:     E(1)    E(2)    ------  E(k-1)  E(k)


那么我们从偏差值中可以知道:  E(X)  > 0     说明未达标

                E(X) = 0      说明正好达标

                E(X) < 0        说明超标


(六)比例控制(P),作用:对偏差起到及时反映的作用,一旦产生偏差,控制器立即做出反映.............


定义:

比例系数:Kp    (根据系统进行调节)

比例输出:POUT  = Kp * E(k) 

     POUT   = Kp * E(k) + OUT0


OUT0说明:OUT0是防止E(K) = 0 时候比例控制不作用,所以添加个OUT0进去,OUT0可以根据系统定义大小

Kp说明:如果我们得到一个偏差之后,将偏差进行放大或者缩小来让控制器进行控制


(七)积分控制(I),作用:消除静差............


从上面我们得到偏差序列:

偏差值:     E(1)    E(2)    ------  E(k-1)  E(k)


定义,历史偏差值之和:S(k) = E(1) + E(2) + .... + E(k-1) + E(K)

定义,积分输出:   IOUT = Kp * S(k) + OUT0


(八)微分控制(D),作用:反映偏差信号的变化趋势.............


从上面我们得到偏差序列:

偏差值:     E(1)    E(2)    ------  E(k-1)  E(k)

定义,偏差之差:D(k) = E(k) - E(k-1)

定义,微分输出:DOUT  =  Kp * D(k) + OUT0

 


(九)那么我们从上面就能得出PID的控制算法


PIDOUT = POUT + IOUT + DOUT

            = (Kp * E(k) + OUT0) + (Kp * S(k) + OUT0) + (Kp * D(k) +OUT0)

       = Kp * (E(k) + S(k) + D(k)) + OUT0


OUT0防止PIDOUT = 0 时候算法还有输出,防止失去控控制

比例(P):考虑当前

积分(I):考虑历史

微分(D):考虑未来


(十)位置式PID,上面只是简单的说明了一下原理,那么实际的数字PID控制算法中,额,那个变换公式打不出来,自行百度,这里就直接打出结果

Ti:积分常数
TD:微分常数
T:计算周期

上面两个是变化后的积分和微分的那个,那么我们把上面的两个替换到第九点中,我们就得到位置上PIDOUT的公式,两个式子是一样的

 

(十一)增量式PID,本次基础上加上多少偏差:△OUT

 

/**********************分割线************************/

(十二)上面的只是PID的原理说明,那么数字PID的公式是

(十三)那么我们将上面的公式通过通过C语言写出来


1. 位置式PID


#ifndef _pid_

#define _pid_

#include 'stm32f10x_conf.h'

#define     MODEL_P         1

#define     MODEL_PI         2

#define     MODEL_PID     3



typedef struct

{

    u8 choose_model;        //使用哪个模式调节

    

    float Sv;     //用户设定值

    float Pv;        //当前值,实际值

 

    float Kp;        //比例系数

    float T;      //PID计算周期--采样周期

    u16   Tdata;    //判断PID周期到没到

    float Ti;        //积分时间常数

    float Td;       //微分系数

    

    

    

    float Ek;          //本次偏差

    float Ek_1;        //上次偏差

    float SEk;         //历史偏差之和

    

    float Iout;        //积分输出

    float Pout;        //比例输出    

    float Dout;        //微分输出

    

    float OUT0;        //一个维持的输出,防止失控


    float OUT;        //计数最终得到的值

    

    

    u16 pwmcycle;//pwm周期

    

    

}PID;


extern PID pid; //存放PID算法所需要的数据

void PID_Calc(void); //pid计算

void PID_Init(void);        //PID初始化    


#endif


#include 'pid.h'

#include 'PWM_Config.h'

#include 'USART_Config.h'   //USART设置


PID pid; //存放PID算法所需要的数据

void PID_Init()            

{

    pid.choose_model = MODEL_PID;

    

    pid.T=330;                //采样周期,定时器使用1ms,则最小执行PID的周期为330ms

    

  pid.Sv=280;                //用户设定值

    pid.Kp=0.5;                //比例系数

  pid.Ti=180;            //积分时间

    pid.Td=1;                    //微分时间

    pid.OUT0=0;                //一个维持的输出

    

    pid.pwmcycle = 330;    //PWM的周期

}

    

void PID_Calc()  //pid计算

{

    float DelEk;            //本次和上次偏差,最近两次偏差之差

    float ti,ki;

    float td;

    float kd;

    float out;


    if(pid.Tdata < (pid.T))  //最小计算周期未到

     {

            return ;

     }

    pid.Tdata = 0;

    pid.Ek=pid.Sv-pid.Pv;               //得到当前的偏差值

    pid.Pout=pid.Kp*pid.Ek;          //比例输出

 

    pid.SEk+=pid.Ek;                    //历史偏差总和

 

    DelEk=pid.Ek-pid.Ek_1;              //最近两次偏差之差

 

    ti=pid.T/pid.Ti;

    ki=ti*pid.Kp;

 

    pid.Iout=ki*pid.SEk*pid.Kp;  //积分输出

    /*注意:上面程序中多了个pid.Kp,原程序中有,请自动删除,正确的应该是pid.Iout=ki*pid.SEK */



    td=pid.Td/pid.T;

 

    kd=pid.Kp*td;

 

  pid.Dout=kd*DelEk;                //微分输出

 

    

     switch(pid.choose_model)

     {

         case MODEL_P:     out= pid.Pout;                                                printf('使用P运算rn') ;

             break;

         

         case MODEL_PI:  out= pid.Pout+ pid.Iout;                            printf('使用PI运算rn') ;

             break;

                 

         case MODEL_PID: out= pid.Pout+ pid.Iout+ pid.Dout;        printf('使用PID运算rn') ;

             break;

     }

    printf('PID算得的OUT:t%drn',(int)out) ;

 

 //////////////////////////////////////////////////////////

 

        /*判断算出的数是否符合控制要求*/

     if(out>pid.pwmcycle)        //不能比PWM周期大,最大就是全高吗

     {

        pid.OUT=pid.pwmcycle;

     }

     else if(out<0)             //值不能为负数

     {

        pid.OUT=pid.OUT0; 

     }

     else 

     {

        pid.OUT=out;

     }

     printf('实际输出使用的pid.OUT:t%drn',(int)pid.OUT) ;

     pid.Ek_1=pid.Ek;  //更新偏差

     

     Turn_Angle((int)pid.OUT);        //输出PWM

     

}


2.增量式PID


#ifndef _pid_

#define _pid_

#include 'stm32f10x_conf.h'

#define     MODEL_P         1

#define     MODEL_PI         2

#define     MODEL_PID     3


typedef struct

{

    u8 choose_model;    //使用哪个模式调节

    

  float curr;              //当前值

    float set;               //设定值

    


    float En;                    //当前时刻

    float En_1;                //前一时刻

    float En_2;                //前二时刻

        

    float Kp;               //比例系数

    float T;                     //采样周期---控制周期,每隔T控制器输出一次PID运算结果

    u16   Tdata;            //判断PID周期到没到

    float Ti;               //积分时间常数

    float Td;               //微分时间常数

    

    float Dout;                //增量PID计算本次应该输出的增量值--本次计算的结果

    float OUT0;                //一个维持的输出,防止失控

    

    short currpwm;      //当前的pwm宽度

    u16 pwmcycle;       //pwm周期


}PID;



extern u8 STATUS;

extern PID pid;

void PIDParament_Init(void);  /*增量式PID初始化*/

void pid_calc(void);                  /*pid计算 并输出*/


#endif


#include 'pid.h'

#include 'PWM_Config.h'

#include 'USART_Config.h'   //USART设置


PID pid;


void PIDParament_Init()  //

{

    pid.choose_model = MODEL_PID;

    pid.T=330;                //采样周期,定时器使用1ms,则最小执行PID的周期为330ms

    

  pid.set =280;            //用户设定值

    pid.Kp=0.5;                //比例系数

    pid.Ti=40;                //微分系数常数

    pid.Td=10;                //积分时间常数

    pid.OUT0=0;                //一个维持的输出


    pid.pwmcycle = 330;    //PWM的周期

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>