大红鹰葡京会娱乐PID控制器的数字实现同C语法讲解。PID控制器的数字实现和C语法讲解。

PID控制器的数字实现与C语法讲解

PID控制器的数字实现同C语法讲解

  • 概述  
  • 概述  

  也方便学习与交流,根据自己的知和经历写了立即卖教程,有荒唐的远在请求各位读者给予指出,具体包含以下三有内容:

  为好学习及交流,根据自己的了解和经历写了立即卖教程,有误的远在请求各位读者给予指出,具体包含以下三片情节:

  (1)
 PID数字化的演绎过程(实质:微积分的近似计算);

  (1)
 PID数字化的演绎过程(实质:微积分的近似计算);

  (2)
 程序风格介绍(程序风格来TI官方案例);

  (2)
 程序风格介绍(程序风格来TI官方案例);

  (3)
 C有关语法简述(语法会结合实例进行教学)。

  (3)
 C有关语法简述(语法会结合实例进行讲解)。

==========================================================================================================================================

==========================================================================================================================================

  • PID控制器的数字化
  • PID控制器的数字化

  PID控制器是工业经过控制着广大应用的一致栽控制器,其中,P、I、D分别吗比例(Proportion)、积分(Integral)、微分(Differential)的简写;将错误的比重、积分及微分通过线性组合成控制量,用该控制量对受控对象进行控制,称为PID算法

  PID控制器是工业经过控制中普遍采用的一律种植控制器,其中,P、I、D分别吗比例(Proportion)、积分(Integral)、微分(Differential)的简写;将病的百分比、积分及微分通过线性组合成控制量,用该控制量对受控对象进行控制,称为PID算法

  为了用软件实现PID算法,需将PID控制器离散化。

  为了用软件实现PID算法,需将PID控制器离散化。

  1. 完思路
  1. 完思路

        大红鹰葡京会娱乐 1

        大红鹰葡京会娱乐 2

  2. 方框图

  2. 方框图

  PID控制器的方框图如图所示:

  PID控制器的方框图如图所示:

          大红鹰葡京会娱乐 3 

          大红鹰葡京会娱乐 4 

  3. 牵连氏域的表达式

  3. 牵连氏域的表达式

  根据方框图,可写有PID控制器对应的传递函数:

  根据方框图,可写有PID控制器对应之传递函数:

            大红鹰葡京会娱乐 5  

            大红鹰葡京会娱乐 6  

         中,Kp为比例系数,ki为积分系数,Kd为微分系数

         中间,Kp为比例系数,ki为积分系数,Kd为微分系数

 

 

  4. 时域的表达式

  4. 时域的表达式

  在分析时,通常借助于拉氏空间,例如判断系的安居和相对稳定;而现咱们关注的凡时域里的题材,因此对上式进行拉普拉斯逆变换,得到时域里之表达式:

  于条分缕析时,通常借助于拉氏空间,例如判断系的康乐和相对稳定;而现行咱们关注的是时域里的题材,因此对上式进行拉普拉斯逆变换,得到时域里的表达式:

             大红鹰葡京会娱乐 7

             大红鹰葡京会娱乐 8

       其相应的组织框图如图所示:

       其相应的组织框图如图所示:

              大红鹰葡京会娱乐 9

              大红鹰葡京会娱乐 10

  5. 差分方程

  5. 差分方程

  该时域里的表达式不便民编程处理,因此待对该式进行离散化处理,从而取得可编程实现的差分方程,解析过程如下:

  该时域里之表达式不便宜编程处理,因此用对该式进行离散化处理,从而获得可编程实现之差分方程,浅析过程如下:

  (说明:PID离散化的本来面目为微积分的离散化(数值化处理),由于是推导过程很多课本及且发介绍,因而有些去演绎过程,只受来最终表达式,程序的算法就是根据这个表达式而写的)

  (说明:PID离散化的实质为微积分的离散化(数值化处理),由于这推导过程很多课本及且发出介绍,因而有些去演绎过程,只为起终极表达式,程序的算法就是基于这个表达式而写的)

  数字PID控制器的增量式算法:

  数字PID控制器的增量式算法:

      大红鹰葡京会娱乐 11

      大红鹰葡京会娱乐 12

      其间,T为宽度,即采样周期(是因为微控制器的定时器确定

      里,T为宽度,即采样周期(出于微控制器的定时器确定

  u(kT)=u(k),便得到PID控制器增量式算法的差分方程:

  u(kT)=u(k),便得到PID控制器增量式算法的差分方程:

      大红鹰葡京会娱乐 13

      大红鹰葡京会娱乐 14

  这样尽管不过编程实现了或有人会咨询,为什么差分方程就不过编程实现呢?这是坐解差分方程的貌似解法就是迭代法,而迭代法只待新值和通项公式,这当电脑编程中好爱实现 

  这样尽管可编程实现了想必有人会问,为什么差分方程就只是编程实现啊?这是盖解差分方程的一般解法就是迭代法,而迭代法只需要新值和通项公式,这当处理器编程中甚容易实现 

  为要编程方便,可引入中变量,定义如下:

  也要编程方便,可引入中变量,定义如下:

             大红鹰葡京会娱乐 15

             大红鹰葡京会娱乐 16

  则,PID控制器增量式算法的差分方程变为:

  则,PID控制器增量式算法的差分方程变为:

      大红鹰葡京会娱乐 17

      大红鹰葡京会娱乐 18

  说明:

  说明:

   (1)在PID增量式算法中就待对输出u(t)作限幅处理

   (1)在PID增量式算法中单单待对输出u(t)作限幅处理

   (2)当微分系数 Kd=0 时,PID控制器就成了PI控制器(在编写**PID程序时默认使其为PI调节器**)

   (2)当微分系数 Kd=0 时,PID控制器就成为了PI控制器(在编写**PID程序时默认使该为PI调节器**)

       当积分系数 Ki=0 时,PID控制器就改成了PD控制器。

       当积分系数 Ki=0 时,PID控制器就变成了PD控制器。

=======================================================================================

=======================================================================================

  •  冲微控制器的算法实现
  •  据悉微控制器的算法实现

  我形容的数字PID程序如图所示(当最后之附件部分),有少拟代码,一模仿是直函数调用**(C/C++通用),另一样模拟是使用函数指针进行函数调用单纯适用于C**),现于点滴个方面针对该次召开教授:

  我勾勒的数字PID程序如图所示(每当末的附件部分),有少数模拟代码,一模拟是直白函数调用**(C/C++通用),另一样仿是采取函数指针进行函数调用特适用于C**),现由零星单方面针对拖欠次召开教授:

(一)程序风格

(一)程序风格

  次第行使了模块化编程的想,这样做的目的加强代码的可移植性及顺序的可读性

  次下了模块化编程的思辨,这样做的目的加强代码的可移植性及程序的可读性

  程序被拆分化为三个模块:

  程序被拆分化三只模块:

  一个凡是PID的条文件’PID.h’:主要是概念算法实现有关的数据类型;

  一个是PID的条文件’PID.h’:主要是概念算法实现有关的数据类型;

  一个凡是PID的源文件’PID.c’:主要是概念算法实现之函数;

  一个凡PID的源文件’PID.c’:主要是概念算法实现之函数;

  一个是主函数文件’amain.c’:PID程序的动办法,即当主程序中做相应的初始化工作,在刹车服务程序中开展PID的计。

  一个凡主函数文件’amain.c’:PID程序的运用方法,即当主程序中做相应的初始化工作,在刹车服务程序中开展PID的计。

说明:**念之序时可能有硌困难,不过当下属于合理的从业,毕竟刚刚接触这种作风的童鞋不顶能够领悟这种作风的出(为什么如此做)及作用(这么做的好处);我的提议是:在亮算法的规律后,根据自己之编程风格尝试在写一下,然后再度同这套程序对比着来掌握,推敲一下别人干什么要这样做;当熟悉了一切流程后,你才会体味这种程序风格的优势,再将这种编程风格慢慢转化为自己的编程风格。**

说明:**念之顺序时或者有硌困难,不过当下属于情理之中的从业,毕竟刚刚点这种作风的童鞋不绝能够明了这种风格的产生(为什么这么做)及作用(这么做的裨益);我的建议是:在明亮算法的规律后,根据自己之编程风格尝试在写一下,然后再度跟这套程序对比着来明,推敲一下人家怎么要这样做;当熟悉了通工艺流程后,你才能够体味这种程序风格的优势,再用这种编程风格慢慢转化为和谐的编程风格。**

(二)程序中涉嫌的C语法讲解

(二)程序中涉及的C语法讲解

  这里,我单讲述缘何而以这些语法以及动用这些语法所带动的益处,至于细枝末节的题材,就请各位童鞋自行查阅有关材料,顺带给大家推荐一遵照科学的C语言教材:C Primer
Plus
,毕竟上之趣味浓度及书籍的编排也有关。

  这里,我不过讲述干什么要采用这些语法以及动这些语法所带的好处,至于细枝末节的题目,就伸手各位童鞋自行查阅有关资料,顺带给大家推荐一比照科学的C语言教材:C Primer
Plus
,毕竟上的志趣浓度与书籍的编也有关。

  1. 尺度编译指令

  1. 标准编译指令

  第一处:#ifndef PID_H语句

  第一处:#ifndef PID_H语句

  使用该语句之目的举凡避造成把更定义语句(如,结构体类型定义)添加到工程被,而令编译出错

  使用该语句的目的凡是避造成把还定义语句(如,结构体类型定义)添加到工程被,而使得编译出错

  说明:实质上呢不过不用#ifndef语句,因为每个定义的变量都持有一定的物理意义,不见面导致重复定义现象。

  说明:实际上呢只是不要#ifndef语句,因为每个定义之变量都装有一定的物理意义,不会见招致重复定义现象。

  第二处:#if (PID_DEBUG) 语句

  第二处:#if (PID_DEBUG) 语句

  使用该语句之目的落实效益切换注意了:举凡于校正PID参数后手动切换,通过转宏定义语句#define
PID_DEBUG 1中的宏体实现),具体要圈程序清单。

  使用该语句的目的兑现效益切换注意了:是在校正PID参数后手动切换,通过反宏定义语词#define
PID_DEBUG 1中的宏体实现),具体要圈程序清单。

  2. 结构体及结构体指针

  2. 结构体及结构体指针

  动结构体类型的好处:可也贯彻有平等效能的每变量进行“打包”处理

  利用结构体类型的好处:可为兑现有平效果的诸变量进行“打包”处理

  使用结构体指针的好处:通过传址调用,对有利于对结构体变量本身进行操作

  使用结构体指针的好处:通过传址调用,对好对结构体变量本身进行操作

  3. typedef数据类型定义

  3. typedef数据类型定义

  利用typedef数据类型定义之好处是方便超平台进行代码移植操作;但由教材的缘由,造成多童鞋都停留在外表层次上之懂得(typedef
数据类型 别名)
,因而这里作重要讲解。

  采取typedef数据类型定义的好处是方便跳平台拓展代码移植操作;但鉴于教材的缘故,造成过多童鞋都留于表面层次上的知情(typedef
数据类型 别名)
,因而此作重要讲解。

       我的理解:任何一个typedef声明遭的标识符不再是一个变量,而是表示一个数据类型,其象征的数据类型为常规变量声明(去掉typedef)的坏标识符的数据类型。

       自之喻:任何一个typedef声明中之标识符不再是一个变量,而是意味着一个数据类型,其象征的数据类型为正常变量声明(去掉typedef)的充分标识符的数据类型。



  理解起来也许发生硌困难,现做实例来讲学:

  理解起来或来硌困难,现做实例来讲课:

       [例1]

       [例1]

  typedef int Myint;
  typedef int Myint;

  分析:

  分析:

  **第一步:正常变量声明(去丢typedef)**

  **首先步:正常变量声明(去丢typedef)**

    int Myint; 
    int Myint; 

  该语句表示定义一个int型变量Myint这里,Myint为变量名

  该语句表示定义一个int型变量Myint此间,Myint为变量名

  其次步:整体分析

  老二步:整体分析

    typedef int Myint;
    typedef int Myint;

  该语句表示定义一个Myint类型这时候,Myint为数列标识符,其切实所代表的路:int型;

  该语句表示定义一个Myint类型这时,Myint为多少类标识符,其实际所表示的类型:int型;

  应用:

  应用:

    Myint a; //声明整型变量a
    Myint a; //声明整型变量a

       [**例2]    **

       [**例2]    **

  typedef struct
  {
      //省略成员
  }PID;
  typedef struct
  {
      //省略成员
  }PID;

  分析:

  分析:

  第一步:正常变量声明(去掉typedef)**

  第一步:健康变量声明(去掉typedef)**

    struct
    {
        //省略成员
    }PID;
    struct
    {
        //省略成员
    }PID;

  该语句表示定义一个结构体变量PID此,PID为变量名

  该语句表示定义一个结构体变量PID此地,PID为变量名

  第二步:一体化分析**

  第二步:一体化分析**

    typedef struct
    {
        //省略成员
    }PID;
    typedef struct
    {
        //省略成员
    }PID;

  该语句表示定义一个PID类型这,PID为多少列标识符,其实际所代表的项目:结构体类型,且其具有的积极分子以及结构体变量PID这里,PID为变量名

  该语句表示定义一个PID类型此刻,PID为数量类标识符,其现实所表示的种类:结构体类型,且该有的积极分子和结构体变量PID此间,PID为变量名

  应用:

  应用:

      PID ASR; //定义结构体变量ASR
      PID ASR; //定义结构体变量ASR

       [例3]

       [例3]

  typedef void (*PFun)(int );
  typedef void (*PFun)(int );

  分析:

  分析:

  **第一步:例行变量声明(去掉typedef)**

  **第一步:正常变量声明(去掉typedef)**

    void (*PFun)(int );
    void (*PFun)(int );

  该语句表示定义一个函数指针PFun此间,PFun为变量名

  该语句表示定义一个函数指针PFun这里,PFun为变量名

  第二步:整分析**

  第二步:完分析**

    typedef void (*PFun)(int );
    typedef void (*PFun)(int );

  该语句表示定义一个PFun类型这,PFun为数据列标识符,其现实所代表的品种:函数指针类型,且该指向形参为int型,无返回值的同等类函数;

  该语句表示定义一个PFun类型此时,PFun为数据列标识符,其现实所代表的种类:函数指针类型,且该指向形参为int型,无返回值的同样类函数;

  应用:

  应用:

    PFun  pf; //定义函数指针pf
    PFun  pf; //定义函数指针pf


  说明:typedef的用法及宏定义#define的用法类似,但以闹区别,体现在以下简单触及:

  说明:typedef的用法及宏定义#define的用法类似,但以发生区别,体现于偏下简单触及:

  (a)
 typedef是指向数据类型的概念,而#define是对准数值的概念;

  (a)
 typedef是本着数据类型的概念,而#define是针对性数值的概念;

  (b)
 typedef由编译器解释,而#define由预处理器执行。

  (b)
 typedef由编译器解释,而#define由预处理器执行。

  4. 空形参函数和展示参带(void)函数

  4. 空形参函数和显示参带(void)函数

  这是在C/C++中相当好模糊的地方,因此这里要介绍一下,若是这知识点没来明白,那么这个顺序你就是无法看懂为什么会如此定义函数指针及运用函数指针来进行函数调用。

  这是在C/C++中相当易模糊的地方,因此这里关键介绍一下,若是者知识点没打明白,那么这个序你不怕无法看懂为什么会如此定义函数指针及运用函数指针来拓展函数调用。

  void本身便是平等种植多少类(空类型),把void作为形参时,表示此函数不待参数。

  void本身即是均等栽多少类(空类型),把void作为形参时,表示是函数不需要参数。

  于C++中,空形参表与新参为void是相当价格的,这是C++中明确规定的;但以C中虽是两码事:C中的空形参表仅代表函数的形参个数和类型不确定,并非无参数,这会少挂于编译器的类型检查机制,从而导致类型安全隐患,所以于C中要表示函数无形参时,最好用void,此时编译器将进行函数参数类型验证。

  以C++中,空形参表与新参为void是相当价格的,这是C++中明确规定的;但以C中虽是两码事:C中的空形参表仅代表函数的形参个数和类型不确定,并非无参数,这会少挂于编译器的种检查机制,从而造成类型安全隐患,所以在C中要表示函数无形参时,最好用void,此时编译器将进行函数参数类型验证。

  [例]

  [例]

void pid_calc(int); //函数声明
void (*calc_1)(int); //函数指针声明
void (*calc_2)(); //函数指针声明

void main()
{
    //将函数的入口地址赋给函数指针
    calc_1=pid_calc; //C编译通过;C++编译通过
    calc_2=pid_calc; //C编译通过;C++编译失败
}
void pid_calc(int); //函数声明
void (*calc_1)(int); //函数指针声明
void (*calc_2)(); //函数指针声明

void main()
{
    //将函数的入口地址赋给函数指针
    calc_1=pid_calc; //C编译通过;C++编译通过
    calc_2=pid_calc; //C编译通过;C++编译失败
}

  5. 函数指针及其函数调用

  5. 函数指针及其函数调用

  函数调用,除了直接调用”函数名为(实参)”这种语法外,还可经函数指针来贯彻,两者并随便别,但以代码的紧凑性及美观性,建议大家以函数指针来开展函数调用。

  函数调用,除了直接调用”函数称呼(实参)”这种语法外,还而经函数指针大红鹰葡京会娱乐来贯彻,两者并任区别,但为了代码的紧凑性及美观性,建议大家利用函数指针来开展函数调用。

  以自身放的片仿代码中,一法是直函数调用C/C++通用),另一样套是使用函数指针进行函数调用唯有适用于C),大家可咀嚼这片栽用法的分别。

  在自放的个别仿代码中,一法是直接函数调用C/C++通用),另一样套是使函数指针进行函数调用光适用于C),大家而咀嚼这片种植用法的区分。

  6. 数据类型转换

  6. 数据类型转换

  C语言中之数据类型分为自动类型转换与强制类型转换

  C语言中之数据类型分为自动类型转换与强制类型转换

  (1) 自动类型转换(**是因为编译器完成**)

  (1) 自动类型转换(**鉴于编译器完成**)

  自行转换的适用场合及其转换规则,请读者查阅有关材料

  电动转换的适用场合及其转换规则,请读者查阅有关材料

  (2) 强制类型转换通过类型转换运算实现

  (2) 强制类型转换经类型转换运算实现

  于本程序中,即好用从今定义函数的函数名pid_calc(**函数称呼代表针对承诺函数的输入地址**)直赋值给函数指针calc,也可将从今定义函数的函数名pid_calc先强制类型转换换为函数指针继,再赋值给函数指针calc;这有限栽办法尽管能达成平等的效益,但该所反映的考虑却大相径庭。

  于本程序中,即可以将从今定义函数的函数名pid_calc(**函数叫作代表对承诺函数的入口地址**)直白赋值给函数指针calc,也只是将从今定义函数的函数名pid_calc先强制类型转换改换为函数指针继,再赋值给函数指针calc;这半栽方式尽管能落得相同的法力,但彼所体现的琢磨却悬殊。

  现把代码截取出来,方便大家对待:

  现把代码截取出来,方便大家对待:

void pid_calc(PID *p); //函数声明
void (*calc)(); //函数指针:指向PID计算函数

void main()
{
    //将函数的入口地址赋给指针变量
    calc=(void (*)(unsigned long))pid_calc; //编译通过(强制类型转换)
    calc=pid_calc; //编译通过
}
void pid_calc(PID *p); //函数声明
void (*calc)(); //函数指针:指向PID计算函数

void main()
{
    //将函数的入口地址赋给指针变量
    calc=(void (*)(unsigned long))pid_calc; //编译通过(强制类型转换)
    calc=pid_calc; //编译通过
}

  7. 代码换行问题

  7. 代码换行问题

  为了代码的美调节好,需涉及到代码换行问题

  为了代码的姣好调剂好,需涉及到代码换行问题

  以本程序的宏定义语句被运用了”\”,这是宏定义中连接达下行的连接符,表示该宏定义还未竣工。

  以本程序的宏定义语句被使用了”\”,这是宏定义中连接上下行的连接符,表示该宏定义还不终止。

//定义PID控制器的初始值
#define PID_DEFAULTS {0,0, \
                      0,0,0, \
                      0.0002, \
                      0,0,0, \
                      0,0,0, \
                      0,0,0,0, \
                      (void (*)(unsigned long))pid_calc}
//定义PID控制器的初始值
#define PID_DEFAULTS {0,0, \
                      0,0,0, \
                      0.0002, \
                      0,0,0, \
                      0,0,0, \
                      0,0,0,0, \
                      (void (*)(unsigned long))pid_calc}

=======================================================================================

=======================================================================================

附件一:直接函数调用(C/C++通用)

附件一:直接函数调用(C/C++通用)

PID.h文件

PID.h文件

//===================================================
//PID.h
//===================================================
#ifndef PID_H
#define PID_H

//定义PID计算用到的结构体类型
typedef struct
{
    float Ref;         //输入:系统待调节量的给定值
    float Fdb;         //输入:系统待调节量的反馈值

    //PID控制器部分
    float Kp;          //参数:比例系数
    float Ki;          //参数:积分系数
    float Kd;          //参数:微分系数

    float T;           //参数:离散化系统的采样周期

    float a0;          //变量:a0
    float a1;          //变量: a1
    float a2;          //变量: a2

    float Err;          //变量:当前的偏差e(k)
    float Err_1;           //历史:前一步的偏差e(k-1)
    float Err_2;          //历史:前前一步的偏差e(k-2)

    float Out;           //输出:PID控制器的输出u(k)
    float Out_1;            //历史:PID控制器前一步的输出u(k-1)
    float OutMax;          //参数:PID控制器的最大输出
    float OutMin;          //参数:PID控制器的最小输出

}PID;

//定义PID控制器的初始值
#define PID_DEFAULTS {0,0, \
                      0,0,0, \
                      0.0002, \
                      0,0,0, \
                      0,0,0, \
                      0,0,0,0}

//条件编译的判别条件
#define PID_DEBUG 1                     

//函数声明
void pid_calc(PID *p);

#endif

//===================================================
//End of file.
//===================================================
//===================================================
//PID.h
//===================================================
#ifndef PID_H
#define PID_H

//定义PID计算用到的结构体类型
typedef struct
{
    float Ref;         //输入:系统待调节量的给定值
    float Fdb;         //输入:系统待调节量的反馈值

    //PID控制器部分
    float Kp;          //参数:比例系数
    float Ki;          //参数:积分系数
    float Kd;          //参数:微分系数

    float T;           //参数:离散化系统的采样周期

    float a0;          //变量:a0
    float a1;          //变量: a1
    float a2;          //变量: a2

    float Err;          //变量:当前的偏差e(k)
    float Err_1;           //历史:前一步的偏差e(k-1)
    float Err_2;          //历史:前前一步的偏差e(k-2)

    float Out;           //输出:PID控制器的输出u(k)
    float Out_1;            //历史:PID控制器前一步的输出u(k-1)
    float OutMax;          //参数:PID控制器的最大输出
    float OutMin;          //参数:PID控制器的最小输出

}PID;

//定义PID控制器的初始值
#define PID_DEFAULTS {0,0, \
                      0,0,0, \
                      0.0002, \
                      0,0,0, \
                      0,0,0, \
                      0,0,0,0}

//条件编译的判别条件
#define PID_DEBUG 1                     

//函数声明
void pid_calc(PID *p);

#endif

//===================================================
//End of file.
//===================================================

 

 

PID.c文件 

PID.c文件 

//===================================================
//PID.c
//===================================================
#include "PID.h"
//===================函数定义========================
/****************************************************
*说    明:
*    (1)PID控制器默认为PI调节器
*    (2)使用了条件编译进行功能切换:节省计算时间
*        在校正PID参数时,使用宏定义将PID_DEBUG设为1;
*        当参数校正完成后,使用宏定义将PID_DEBUG设为0,同时,在初始化时
*    直接为p->a0、p->a1、p->a2赋值
****************************************************/
void pid_calc(PID *p)
{
    //使用条件编译进行功能切换
    #if (PID_DEBUG)
    float a0,a1,a2;
    //计算中间变量a0、a1、a2
    a0=p->Kp+p->Ki*p->T+p->Kd/p->T;
    a1=p->Kp+2*p->Kd/p->T;
    a2=p->Kd/p->T;
    //计算PID控制器的输出
    p->Out=p->Out_1+a0*p->Err-a1*p->Err_1+a2*p->Err_2;
    #else
    //计算PID控制器的输出
    p->Out=p->Out_1+p->a0*p->Err-p->a1*p->Err_1+p->a2*p->Err_2;
    #endif

    //输出限幅
    if(p->Out>p->OutMax)
        p->Out=p->OutMax;
    if(p->Out<p->OutMin)
        p->Out=p->OutMin;

    //为下步计算做准备
    p->Out_1=p->Out;
    p->Err_2=p->Err_1;
    p->Err_1=p->Err;

}

//===================================================
//End of file.
//===================================================
//===================================================
//PID.c
//===================================================
#include "PID.h"
//===================函数定义========================
/****************************************************
*说    明:
*    (1)PID控制器默认为PI调节器
*    (2)使用了条件编译进行功能切换:节省计算时间
*        在校正PID参数时,使用宏定义将PID_DEBUG设为1;
*        当参数校正完成后,使用宏定义将PID_DEBUG设为0,同时,在初始化时
*    直接为p->a0、p->a1、p->a2赋值
****************************************************/
void pid_calc(PID *p)
{
    //使用条件编译进行功能切换
    #if (PID_DEBUG)
    float a0,a1,a2;
    //计算中间变量a0、a1、a2
    a0=p->Kp+p->Ki*p->T+p->Kd/p->T;
    a1=p->Kp+2*p->Kd/p->T;
    a2=p->Kd/p->T;
    //计算PID控制器的输出
    p->Out=p->Out_1+a0*p->Err-a1*p->Err_1+a2*p->Err_2;
    #else
    //计算PID控制器的输出
    p->Out=p->Out_1+p->a0*p->Err-p->a1*p->Err_1+p->a2*p->Err_2;
    #endif

    //输出限幅
    if(p->Out>p->OutMax)
        p->Out=p->OutMax;
    if(p->Out<p->OutMin)
        p->Out=p->OutMin;

    //为下步计算做准备
    p->Out_1=p->Out;
    p->Err_2=p->Err_1;
    p->Err_1=p->Err;

}

//===================================================
//End of file.
//===================================================

 

 

amain.c主函数文件

amain.c主函数文件

//===================================================
//amain.c
//===================================================

//将用户定义的头文件包含进来
#include "PID.h"

//=============宏定义=====================
#define T0   0.0002       //离散化采样周期,单位s

//============全局变量========================
//定义PID控制器对应的结构体变量
PID ASR=PID_DEFAULTS;       //速度PI调节器ASR

//定义PID控制器的参数及输出限幅值
float SpeedKp=2,SpeedKi=1,SpeedLimit=10;  //速度PI调节器ASR

//===============主程序=======================
void main()
{
    //初始化PID控制器
    ASR.Kp=SpeedKp;
    ASR.Ki=SpeedKi;
    ASR.T=T0;
    ASR.OutMax=SpeedLimit;
    ASR.OutMin=-SpeedLimit;

}

//============中断服务程序====================
interrupt void T1UFINT_ISR(void)
{
    //转速调节ASR
    ASR.Ref=input1;         //速度给定
    ASR.Fdb=input2;         //速度反馈
    ASR.Err=ASR.Ref-ASR.Fdb;    //偏差
    pid_calc(&ASR);         //函数调用:启动PID计算
    output=ASR.Out;         //读取PID控制器的输出

}

//===================================================
//End of file.
//===================================================
//===================================================
//amain.c
//===================================================

//将用户定义的头文件包含进来
#include "PID.h"

//=============宏定义=====================
#define T0   0.0002       //离散化采样周期,单位s

//============全局变量========================
//定义PID控制器对应的结构体变量
PID ASR=PID_DEFAULTS;       //速度PI调节器ASR

//定义PID控制器的参数及输出限幅值
float SpeedKp=2,SpeedKi=1,SpeedLimit=10;  //速度PI调节器ASR

//===============主程序=======================
void main()
{
    //初始化PID控制器
    ASR.Kp=SpeedKp;
    ASR.Ki=SpeedKi;
    ASR.T=T0;
    ASR.OutMax=SpeedLimit;
    ASR.OutMin=-SpeedLimit;

}

//============中断服务程序====================
interrupt void T1UFINT_ISR(void)
{
    //转速调节ASR
    ASR.Ref=input1;         //速度给定
    ASR.Fdb=input2;         //速度反馈
    ASR.Err=ASR.Ref-ASR.Fdb;    //偏差
    pid_calc(&ASR);         //函数调用:启动PID计算
    output=ASR.Out;         //读取PID控制器的输出

}

//===================================================
//End of file.
//===================================================

=======================================================================================

=======================================================================================

附件二:使用函数指针进行函数调用(仅适用于C)

附件二:使用函数指针进行函数调用(仅适用于C)

PID.h文件

PID.h文件

//===================================================
//PID.h
//===================================================
#ifndef PID_H
#define PID_H

//定义PID计算用到的结构体类型
typedef struct
{
    float Ref;       //输入:系统待调节量的给定值
    float Fdb;       //输入:系统待调节量的反馈值

    //PID控制器部分
    float Kp;        //参数:比例系数
    float Ki;        //参数:积分系数
    float Kd;        //参数:微分系数

    float T;         //参数:离散化系统的采样周期

    float a0;        //变量:a0
    float a1;        //变量: a1
    float a2;        //变量: a2

    float Err;       //变量:当前的偏差e(k)
    float Err_1;      //历史:前一步的偏差e(k-1)
    float Err_2;        //历史:前前一步的偏差e(k-2)

    float Out;       //输出:PID控制器的输出u(k)
    float Out_1;        //历史:PID控制器前一步的输出u(k-1)
    float OutMax;     //参数:PID控制器的最大输出
    float OutMin;     //参数:PID控制器的最小输出

    void (*calc)();    //函数指针:指向PID计算函数

}PID;

//定义PID控制器的初始值
#define PID_DEFAULTS {0,0, \
                      0,0,0, \
                      0.0002, \
                      0,0,0, \
                      0,0,0, \
                      0,0,0,0, \
                      (void (*)(unsigned long))pid_calc} //加与不加强制类型转换都没影响

//条件编译的判别条件
#define PID_DEBUG 1                     

//函数声明
void pid_calc(PID *p);

#endif

//===================================================
//End of file.
//===================================================
//===================================================
//PID.h
//===================================================
#ifndef PID_H
#define PID_H

//定义PID计算用到的结构体类型
typedef struct
{
    float Ref;       //输入:系统待调节量的给定值
    float Fdb;       //输入:系统待调节量的反馈值

    //PID控制器部分
    float Kp;        //参数:比例系数
    float Ki;        //参数:积分系数
    float Kd;        //参数:微分系数

    float T;         //参数:离散化系统的采样周期

    float a0;        //变量:a0
    float a1;        //变量: a1
    float a2;        //变量: a2

    float Err;       //变量:当前的偏差e(k)
    float Err_1;      //历史:前一步的偏差e(k-1)
    float Err_2;        //历史:前前一步的偏差e(k-2)

    float Out;       //输出:PID控制器的输出u(k)
    float Out_1;        //历史:PID控制器前一步的输出u(k-1)
    float OutMax;     //参数:PID控制器的最大输出
    float OutMin;     //参数:PID控制器的最小输出

    void (*calc)();    //函数指针:指向PID计算函数

}PID;

//定义PID控制器的初始值
#define PID_DEFAULTS {0,0, \
                      0,0,0, \
                      0.0002, \
                      0,0,0, \
                      0,0,0, \
                      0,0,0,0, \
                      (void (*)(unsigned long))pid_calc} //加与不加强制类型转换都没影响

//条件编译的判别条件
#define PID_DEBUG 1                     

//函数声明
void pid_calc(PID *p);

#endif

//===================================================
//End of file.
//===================================================

 

 

PID.c文件

PID.c文件

//===================================================
//PID.c
//===================================================
#include "PID.h"
//===================函数定义========================
/****************************************************
*说    明:
*    (1)PID控制器默认为PI调节器
*    (2)使用了条件编译进行功能切换:节省计算时间
*        在校正PID参数时,使用宏定义将PID_DEBUG设为1;
*        当参数校正完成后,使用宏定义将PID_DEBUG设为0,同时,在初始化时
*    直接为p->a0、p->a1、p->a2赋值
****************************************************/
void pid_calc(PID *p)
{
    //使用条件编译进行功能切换
    #if (PID_DEBUG)
    float a0,a1,a2;
    //计算中间变量a0、a1、a2
    a0=p->Kp+p->Ki*p->T+p->Kd/p->T;
    a1=p->Kp+2*p->Kd/p->T;
    a2=p->Kd/p->T;
    //计算PID控制器的输出
    p->Out=p->Out_1+a0*p->Err-a1*p->Err_1+a2*p->Err_2;
    #else
    //计算PID控制器的输出
    p->Out=p->Out_1+p->a0*p->Err-p->a1*p->Err_1+p->a2*p->Err_2;
    #endif

    //输出限幅
    if(p->Out>p->OutMax)
        p->Out=p->OutMax;
    if(p->Out<p->OutMin)
        p->Out=p->OutMin;

    //为下步计算做准备
    p->Out_1=p->Out;
    p->Err_2=p->Err_1;
    p->Err_1=p->Err;

}

//===================================================
//End of file.
//===================================================
//===================================================
//PID.c
//===================================================
#include "PID.h"
//===================函数定义========================
/****************************************************
*说    明:
*    (1)PID控制器默认为PI调节器
*    (2)使用了条件编译进行功能切换:节省计算时间
*        在校正PID参数时,使用宏定义将PID_DEBUG设为1;
*        当参数校正完成后,使用宏定义将PID_DEBUG设为0,同时,在初始化时
*    直接为p->a0、p->a1、p->a2赋值
****************************************************/
void pid_calc(PID *p)
{
    //使用条件编译进行功能切换
    #if (PID_DEBUG)
    float a0,a1,a2;
    //计算中间变量a0、a1、a2
    a0=p->Kp+p->Ki*p->T+p->Kd/p->T;
    a1=p->Kp+2*p->Kd/p->T;
    a2=p->Kd/p->T;
    //计算PID控制器的输出
    p->Out=p->Out_1+a0*p->Err-a1*p->Err_1+a2*p->Err_2;
    #else
    //计算PID控制器的输出
    p->Out=p->Out_1+p->a0*p->Err-p->a1*p->Err_1+p->a2*p->Err_2;
    #endif

    //输出限幅
    if(p->Out>p->OutMax)
        p->Out=p->OutMax;
    if(p->Out<p->OutMin)
        p->Out=p->OutMin;

    //为下步计算做准备
    p->Out_1=p->Out;
    p->Err_2=p->Err_1;
    p->Err_1=p->Err;

}

//===================================================
//End of file.
//===================================================

 

 

amain.c主函数文件

amain.c主函数文件

//===================================================
//amain.c
//===================================================

//将用户定义的头文件包含进来
#include "PID.h"

//=============宏定义=====================
#define T0   0.0002     //离散化采样周期,单位s

//============全局变量========================
//定义PID控制器对应的结构体变量
PID ASR=PID_DEFAULTS;     //速度PI调节器ASR

//定义PID控制器的参数及输出限幅值
float SpeedKp=2,SpeedKi=1,SpeedLimit=10;   //速度PI调节器ASR

//===============主程序=======================
void main()
{
    //初始化PID控制器
    ASR.Kp=SpeedKp;
    ASR.Ki=SpeedKi;
    ASR.T=T0;
    ASR.OutMax=SpeedLimit;
    ASR.OutMin=-SpeedLimit;

}

//============中断服务程序====================
interrupt void T1UFINT_ISR(void)
{
    //转速调节ASR
    ASR.Ref=input1;         //速度给定
    ASR.Fdb=input2;         //速度反馈
    ASR.Err=ASR.Ref-ASR.Fdb;    //偏差
    ASR.calc(&ASR);         //函数调用:启动PID计算
    output=ASR.Out;         //读取PID控制器的输出

}

//===================================================
//End of file.
//===================================================
//===================================================
//amain.c
//===================================================

//将用户定义的头文件包含进来
#include "PID.h"

//=============宏定义=====================
#define T0   0.0002     //离散化采样周期,单位s

//============全局变量========================
//定义PID控制器对应的结构体变量
PID ASR=PID_DEFAULTS;     //速度PI调节器ASR

//定义PID控制器的参数及输出限幅值
float SpeedKp=2,SpeedKi=1,SpeedLimit=10;   //速度PI调节器ASR

//===============主程序=======================
void main()
{
    //初始化PID控制器
    ASR.Kp=SpeedKp;
    ASR.Ki=SpeedKi;
    ASR.T=T0;
    ASR.OutMax=SpeedLimit;
    ASR.OutMin=-SpeedLimit;

}

//============中断服务程序====================
interrupt void T1UFINT_ISR(void)
{
    //转速调节ASR
    ASR.Ref=input1;         //速度给定
    ASR.Fdb=input2;         //速度反馈
    ASR.Err=ASR.Ref-ASR.Fdb;    //偏差
    ASR.calc(&ASR);         //函数调用:启动PID计算
    output=ASR.Out;         //读取PID控制器的输出

}

//===================================================
//End of file.
//===================================================

 

 

相关文章

admin

网站地图xml地图