你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

(转载)增量式PID的stm32实现,整定过程

[复制链接]
nyszx 发布时间:2017-12-26 15:40
本帖最后由 nyszx 于 2017-12-26 19:31 编辑 1 v  Q' Q- G: X1 Y+ e
3 t- E4 d$ R$ G3 J% l) Z2 k
原帖:【分享】增量式PID的stm32实现,整定过程) g( T' @8 W" J1 ]+ x- V$ g
原文网址:http://www.amobbs.com/thread-5575823-1-1.html% D' ]7 K4 j2 D, M
出处:阿莫电子论坛
* d* r- O5 _* P. b, V: d0 J作者:tim4146
1 q" Q3 @, |  G7 O感谢大家最近的帮忙,让我顺利做完增量PID功能,虽然PID不是什么牛逼的东西,但是真心希望以后刚刚接触这块的人能尽快进入状态。
, O7 f3 p5 r3 a+ n, s1 Q7 P/ ^" S也下面我分享一下近期的这些工作吧。欢迎大家批评指点~
4 ~$ ]/ t1 |. F' o" S/ n- e( b1 M7 M9 V) u' q0 B( O6 s
首先说说增量式PID的公式,这个关系到MCU算法公式的书写,实际上两个公式的写法是同一个公式变换来得,不同的是系数的差异。
0 W# h1 ^( O% Q+ r+ f3 R资料上比较多的是:+ E6 F% \0 ]. G9 z  ~3 `( Y
1.jpg
, \$ ]* f  R% ]. N4 D还有一种是:& b2 `% b# }- _% m
2.jpg ; U+ \! Y3 ^7 N% i3 T
感觉第二种的Kp Ki Kd比较清楚,更好理解,下面介绍的就以第二种来吧。(比例、积分、微分三个环节的作用这里就详细展开,百度会有很多)7 ~$ n9 b% [0 V$ ~. e' {
8 E! e( F2 v8 v" D: a5 d/ B
硬件部分:5 a: M+ S# N  J$ H! T
控制系统的控制对象是4个空心杯直流电机,电机带光电编码器,可以反馈转速大小的波形。电机驱动模块是普通的L298N模块。
3 d& c& L" W% C芯片型号,STM32F103ZET65 K5 d7 ~3 j" b. F, N( I1 |
8 d# ~' J9 {! }' ]
软件部分:
% f0 v+ f, x6 Z! I& u7 e9 HPWM输出:TIM3,可以直接输出4路不通占空比的PWM波$ x& B5 T7 p1 e; f7 x2 [4 x
PWM捕获:STM32除了TIM6 TIM7其余的都有捕获功能,使用TIM1 TIM2 TIM4 TIM5四个定时器捕获四个反馈信号1 [" N" {6 A: R3 u
PID的采样和处理:使用了基本定时器TIM6,溢出时间就是我的采样周期,理论上T越小效果会越好,这里我取20ms,依据控制对象吧,如果控制水温什么的采样周期会是几秒几分钟什么的。; q7 L4 K2 ?2 N) h4 V- b

) x% m" u: Y  ]5 o* K9 `4 \3 @上面的PWM输出和捕获关于定时器的设置都有例程,我这里是这样的:
& S- V3 B, W$ l  N# ?: m2 _: FTIM3输出四路PWM,在引脚 C 的 GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9输出( l, j. i% `/ n  h
四路捕获分别是TIM4  TIM1  TIM2  TIM5   ,对应引脚是:  PB7 PE11 PB3 PA1
6 Z6 p& I4 |+ f( {
高级定时器tim1的初始化略不同,它的中断”名称“和通用定时器不同,见代码:7 _# Q9 e  P$ n
  1. /*功能名称IM3_PWM_Init(u16 arr,u16 psc)
    2 }& S9 I$ Z' D! v0 t. j
  2.         描述      TIM3产生四路PWM- R, m2 v4 R4 c2 _2 A. _
  3. */
    5 N5 S2 i; V9 ]3 Q; p% c
  4. void TIM3_PWM_Init(u16 arr,u16 psc)* `0 n) K. x0 F7 k) M) U8 q' ~
  5. {
    5 {( I7 n* B  @
  6.         GPIO_InitTypeDef GPIO_InitStructure;. r$ P1 I! D5 b% O- p1 w
  7.         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    ( Y: @* h% [( z8 c6 v$ ]! v1 S, p, `
  8.         TIM_OCInitTypeDef  TIM_OCInitStructure;
    . n5 K; D, v. ]! y0 V4 ?
  9. 8 g% W% \- g7 G1 l: F6 m% i
  10. + {( O' c$ A  s8 b* f# J5 o
  11.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    2 u# s7 m7 T+ h( O8 e
  12.          RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC  | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟使能
    ; h" m5 u$ Z$ J/ u: `0 Z
  13. & H( j& n3 x: O! T$ V& g2 f
  14.   GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE); //Timer3全映射 GPIOC-> 6,7,8,9                                                                             //用于TIM3的CH2输出的PWM通过该LED显示
    3 [# m8 M; x$ \% m3 A
  15. 3 {5 b! m" C, @
  16.    //设置该引脚为复用输出功能,输出TIM3 CH1 CH2 CH3 CH4 的PWM脉冲波形; I  @+ s1 L: X
  17.         GPIO_InitStructure.GPIO_Pin =GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9; //初始化GPIO
      R6 ~( k) B' _4 G# y9 U' l
  18.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
    ! C# U2 n7 p. @
  19.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;& D5 x3 z/ c, o4 K+ T' J
  20.         GPIO_Init(GPIOC, &GPIO_InitStructure);
    ) U" k7 G) u- K! m0 L: E1 O2 {
  21.         GPIO_ResetBits(GPIOC,GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9);//默认电机使能端状态:不使能' [7 I2 [9 d* j/ P; g

  22. ) N& v7 _% _  Y! n- c- l% C" d% M$ H
  23.         TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
    ! V4 y+ ^7 o+ x+ v
  24.         TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  这里是72分频,那么时钟频率就是1M
    4 ?3 f  i$ \, _4 }. B% \, D
  25.         TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
    9 p2 m0 \$ T8 x- s0 f1 B& }: H2 T5 @" w
  26.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式: H8 D$ ~, \2 l' q# N2 E0 [$ O2 ^7 v
  27.         TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位) H& e3 f. L4 z1 {' s% ?) w" \

  28. 3 b" e7 Q+ Y2 o

  29. & u' z+ q3 o7 x5 t9 v, x6 _, {
  30.         TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
    + o6 g$ x# F6 U! Y
  31.         TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能# r: t' T& i9 \% C' P
  32.         TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值8 {- Z' d3 t" \, B% k# n- m
  33.         TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
    1 ~9 D- c6 j. K0 L0 m
  34. ; [; F, b& H- g; l
  35.         TIM_OC1Init(TIM3, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx! N  q3 E6 k* L, z' c! a1 I$ }
  36.         TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIMx在CCR1上的预装载寄存器; g" x, ?3 K4 b4 U, e  k& k5 [9 g

  37. 3 K2 ?! G. d$ c7 d" w8 z5 X3 B% h

  38. " G0 ^  r5 k: t6 B% P
  39.         TIM_OC2Init(TIM3, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
    / o2 X" O/ J6 w: }8 u, G% `
  40.         TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIMx在CCR2上的预装载寄存器
    " V1 z# u3 r- [

  41. - {/ [3 y$ D$ ?4 [
  42.         TIM_OC3Init(TIM3, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
    4 n: l& L: q/ J5 {: N
  43.         TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIMx在CCR3上的预装载寄存器5 b+ I) E' k% C  \

  44. 1 b- T/ p; r8 S7 l* u: o
  45.         TIM_OC4Init(TIM3, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx! n" k1 P9 }. M* H0 v
  46.         TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIMx在CCR4上的预装载寄存器4 P1 ~8 B: B+ b+ g1 R

  47. + L5 y  L" u( M5 v0 e7 _
  48.         TIM_ARRPreloadConfig(TIM3, ENABLE); //使能TIMx在ARR上的预装载寄存器: Y  l; l8 s9 D* _

  49. $ S" [/ h, P. V! |  n  {; c3 R

  50. 1 B* Q7 K3 X: c6 u  I3 @) `( X
  51.         TIM_Cmd(TIM3, ENABLE);  //使能TIMx外设; W4 G) P0 W4 N9 t

  52. " W9 y2 f1 z, C# d

  53. $ b% x& A/ ~$ a$ ?/ C$ g* D
  54. }
    : E& J, k" r5 K$ V
  55. / E7 C% c( e& X0 ~" _
  56. 3 o& S* n2 w9 o
  57. 4 @& R0 X. B! v
  58. /*功能名称TIM4_PWMINPUT_INIT(u16 arr,u16 psc)
    0 R/ M& N8 x7 H8 h' b( M8 D
  59.   描述      PWM输入初始化*/
    : J' g) b1 W! y& p) T! y. Y
  60. & r( R" t$ O0 p! s8 G. U
  61. void TIM4_PWMINPUT_INIT(u16 arr,u16 psc)
    2 [7 Q& B- |' Z; A; o  p- B
  62. {0 t5 I$ Y; ~! H1 P, g8 J7 m
  63. 4 k. b' R9 t0 d
  64.         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;        //TIM的初始化结构体" Z, n0 [: s1 q4 r
  65.         NVIC_InitTypeDef NVIC_InitStructure;                        //中断配置
    $ ~2 c; t! k8 F, [
  66.         TIM_ICInitTypeDef  TIM4_ICInitStructure;                 //TIM4  PWM配置结构体( w3 {" |) S" ~" H. _
  67.         GPIO_InitTypeDef GPIO_InitStructure;                         //IO口配置结构体' |% K4 y* S$ L4 h: u
  68. & K; F7 }' g4 u: b& i1 q3 A
  69.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);     //Open TIM4 clock
    1 N. T. m* X5 G+ l7 w5 K3 W) t
  70.   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  //open gpioB clock. Z+ A7 y$ D( g: K: A9 j4 E

  71. % u' l( @( e  s* H
  72.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;             //GPIO 7
    ! T' s' J7 `; I" [2 L
  73.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;          //上拉输入2 n/ C) {. x$ a0 \4 Y, {% v2 \) V
  74.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;: v0 h. \6 P& d/ y5 _
  75.   GPIO_Init(GPIOB, &GPIO_InitStructure);
    ; j1 N& ~8 [; u$ v
  76. 4 P$ t0 h6 X' `9 F% F
  77.         TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值3 ]4 F6 c8 `- E- ~, o4 ^
  78.         TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
    " o% _5 l# @" E
  79.         TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim2 a8 s9 s! ^4 l; |
  80.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式' W* J7 N0 m  f4 F: W. W- k
  81.         TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
    ! K. o1 Q7 a2 \1 D) _- _# W4 I

  82. , b7 T: a& C4 M* L# t6 q
  83. & _: g; f8 I0 w/ T# [
  84.         /*配置中断优先级*/; e8 U0 E0 ]3 `5 H
  85.         NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
    8 z6 O6 R% X9 h  v3 h$ Z
  86.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    $ b" D  J% G8 S- ^
  87.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    % N7 X, `8 a7 x2 W; r5 L
  88.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    * M6 Y+ E/ a( B
  89.   NVIC_Init(&NVIC_InitStructure);5 s$ h7 N: o, f

  90. 8 {. r* G4 ]1 h2 S
  91.   TIM4_ICInitStructure.TIM_Channel = TIM_Channel_2;9 R& K0 }, d# d  ?+ m. _+ [9 ?
  92.   TIM4_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
      ?/ n$ V: C0 ]( n4 C4 v7 ~! ?
  93.   TIM4_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;7 c' q8 e1 r8 x6 w3 X: Y, @
  94.   TIM4_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;: S2 s/ [5 Q6 G; o, W  t/ q
  95.   TIM4_ICInitStructure.TIM_ICFilter = 0x3;   //Filter:过滤/ ]' }' D- ], \/ h. F+ G) n
  96. 0 r* P4 F  Q* F1 @
  97.   TIM_PWMIConfig(TIM4, &TIM4_ICInitStructure);     //PWM输入配置! g- u1 K+ u. E0 C8 y3 {5 ^, J( C! C
  98.   TIM_SelectInputTrigger(TIM4, TIM_TS_TI2FP2);     //选择有效输入端& ^& |! X7 e/ v& @  ?
  99.   TIM_SelectSlaveMode(TIM4, TIM_SlaveMode_Reset);  //配置为主从复位模式  X1 g' `! `* O7 y6 |- E3 \
  100.   TIM_SelectMasterSlaveMode(TIM4, TIM_MasterSlaveMode_Enable);//启动定时器的被动触发  K0 N& o: J- e  B  g: r9 r
  101.   TIM_ITConfig(TIM4, TIM_IT_CC2|TIM_IT_Update, ENABLE);          //中断配置% a9 Z) ^6 r0 }: C2 i3 @  a
  102.   TIM_ClearITPendingBit(TIM4, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位
    1 M* y/ e. F. S( q2 X4 a
  103.   TIM_Cmd(TIM4, ENABLE);6 y( ?1 w0 @6 }% n. t( p* \
  104. }' u8 F7 _7 l1 x
  105. 6 R' M) D! G; I8 G4 x/ y8 F
  106. ! k9 x; q* Z2 }/ g7 ?  X, q2 \1 F
  107. void TIM4_IRQHandler(void)
    , F2 f* L- S$ S7 H" g; S) _8 m6 T
  108. {7 e! X! m9 P, |  u; s+ \  e) s6 J  z

  109.   G  I( L# Y; |, M6 R' n
  110.                 if (TIM_GetITStatus(TIM4, TIM_IT_CC2) != RESET)//捕获1发生捕获事件$ D2 z  ]9 Q$ k' ]" ~0 t/ V9 c
  111.                         {; t8 m2 ^4 o; j" W" U! r7 ^
  112.                                 duty_TIM4    =   TIM_GetCapture1(TIM4);          //采集占空比
      w) m6 d: t0 q) W* l/ \
  113.                if  (TIM_GetCapture2(TIM4)>600)         period_TIM4        =        TIM_GetCapture2(TIM4);//简单的处理# @+ |. i# X( E& g8 X4 U
  114.                                 CollectFlag_TIM4 = 0;& J, B! h9 f4 o1 c3 I. m; l
  115.         }
      a( o. K$ l( f# B4 F
  116.                 TIM_ClearITPendingBit(TIM4, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位. O, K. A: |  H
  117. }
    % W  N; g0 k' O* U
  118. ; h  Z  y! C  {( Q" F+ B' v3 F
  119. ) {# n1 D# a4 G6 f" m
  120. /*功能名称TIM1_PWMINPUT_INIT(u16 arr,u16 psc)' ^' X) n- z' F6 b: K+ N
  121.   描述      PWM输入初始化*/
    9 j4 N* x" K6 K. r. j1 c- b$ W0 A

  122. $ ~0 B$ }* k7 |. f$ b5 u; h
  123. void TIM1_PWMINPUT_INIT(u16 arr,u16 psc), Z4 H  k+ o2 ^. \; \' f+ D. `
  124. {6 {5 q/ E: O1 A9 l

  125. . `. G, V: }0 B+ t8 ?! ^# o
  126.         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;        //TIM的初始化结构体  e/ j* H  `! W3 t% c
  127.         NVIC_InitTypeDef NVIC_InitStructure;                        //中断配置2 Z& z3 T4 [$ ]% `# l: L
  128.         TIM_ICInitTypeDef  TIM1_ICInitStructure;                 //PWM配置结构体! N) i% a$ W& t, F9 H5 w
  129.         GPIO_InitTypeDef GPIO_InitStructure;                         //IO口配置结构体- y$ B4 C- z& o& k
  130. ; L+ I  [& K9 ?' H, r* |1 z0 ?
  131.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);     //Open TIM1 clock
    * Z" b0 h& H( T% |
  132.   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);  //open gpioE clock3 Q, T' \$ E' M- I
  133.    GPIO_PinRemapConfig(GPIO_FullRemap_TIM1, ENABLE); //Timer1完全重映射  TIM1_CH2->PE11
    ' C4 B1 P% Y6 E. H1 W# d
  134.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;             //GPIO 11
    4 J; b1 B( n8 \7 Q1 {/ P
  135.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;          //上拉输入
    , g+ n8 m, M2 t0 U
  136.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    3 z3 r1 Y# ~2 v5 p
  137.   GPIO_Init(GPIOE, &GPIO_InitStructure);* @& Z2 B8 |7 P

  138. # \! [7 ?7 e9 ?1 O- \  ]
  139.         TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
    " m  C6 T: ?6 `  O5 M1 j7 n" L! g* G
  140.         TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
    ( t+ X6 h/ S. e
  141.         TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
    1 z3 c  {4 U6 V% X. w2 i
  142.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    ' f; O& _  c2 e' k
  143.         TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
    $ y& d" Q  Z9 G5 _4 m  G  C
  144. * k: v; Q( y1 F" |$ i" h- t

  145. 9 a8 }, P; \- m  f
  146.         /*配置中断优先级*/" S4 I5 e' M1 c% C3 R
  147.   NVIC_InitStructure.NVIC_IRQChannel =  TIM1_CC_IRQn;   //TIM1捕获中断* }  Q; k2 f% V& k. W
  148.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    ' U/ V+ a: Y5 _$ n, n, R  c6 ^
  149.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;' Z% N6 g9 ?4 w, v
  150.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;6 Y% ^% ~2 N8 U* X/ r
  151.   NVIC_Init(&NVIC_InitStructure);1 ~6 X# d$ ]; G8 r9 A

  152. ) h) o9 ^5 H! Y# r! ~1 ?- E
  153.   TIM1_ICInitStructure.TIM_Channel = TIM_Channel_2;* N; @( m9 G) a9 P' ?$ F
  154.   TIM1_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;3 R. U/ t# L8 y& F
  155.   TIM1_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;# f, U: y7 v8 m$ M! X
  156.   TIM1_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    9 m1 d& D9 y! I. @3 r% t: f/ @5 ]0 h
  157.   TIM1_ICInitStructure.TIM_ICFilter = 0x03;   //Filter:过滤
    1 {$ J* \/ |8 \. F( c$ a- G
  158. & m6 X6 J& h5 k5 P
  159.   TIM_PWMIConfig(TIM1, &TIM1_ICInitStructure);     //PWM输入配置* `+ P. I! T/ C! x+ i
  160.   TIM_SelectInputTrigger(TIM1, TIM_TS_TI2FP2);     //选择有效输入端4 h' {; H6 ?. c9 v/ z
  161.   TIM_SelectSlaveMode(TIM1, TIM_SlaveMode_Reset);  //配置为主从复位模式) ^% Y# h4 n' D+ K+ @
  162.   TIM_SelectMasterSlaveMode(TIM1, TIM_MasterSlaveMode_Enable);//启动定时器的被动触发
    2 t9 ^$ b( B7 a  {  V
  163. // TIM_ITConfig(TIM1, TIM_IT_CC2|TIM_IT_Update, ENABLE);          //中断配置. ^6 g4 m  O; f8 Q4 O! ?
  164.   TIM_ITConfig(TIM1, TIM_IT_CC2, ENABLE); //通道2 捕获中断打开
    & z% e  V" H4 z( V5 x
  165.   //TIM_ClearITPendingBit(TIM1, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位
    ' K. g+ @# _1 ~( f# _1 o
  166.   TIM_Cmd(TIM1, ENABLE);0 w3 v8 f7 H. i' \( [; }0 q* `
  167. }
    $ h; y9 k7 k/ H6 Z' R: b

  168. 5 ?: g: u: M( s

  169. 2 N' A# s, L  Y( n
  170. void TIM1_CC_IRQHandler(void)
    ' u7 I" P. Q, l1 L% h% |) A. G* C
  171. {/ ~) Y9 y' Q& Z5 I% {6 h
  172. + m+ G3 w8 v' y! w( N
  173.         {
    4 g+ L" Q' G" A* Q) U) T
  174.                 if (TIM_GetITStatus(TIM1, TIM_IT_CC2) != RESET)//捕获1发生捕获事件& C" b  q7 D0 h3 Q5 E0 B
  175.                         {* u( e! a' H0 x: X
  176.                                 duty_TIM1    =   TIM_GetCapture1(TIM1);          //采集占空比
      I/ h/ X( a. k$ n
  177.                            if  (TIM_GetCapture2(TIM1)>600)         period_TIM1        =        TIM_GetCapture2(TIM1);
    1 }# F$ ^' }3 u9 \' J' G* U5 R
  178.                                 CollectFlag_TIM1 = 0;- U# Q$ g- d7 I  `( y
  179.                         }
    , E5 f2 h: t0 }8 O. E" B, N
  180.         }
    $ B1 \  I2 U7 c
  181.                 TIM_ClearITPendingBit(TIM1, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位
    . e3 _4 ]& ]# t# V# U
  182. }' t( r7 }2 ]3 ^, G6 i9 s

  183. : S7 s5 i  Y, f  w

  184. ' ~0 T' i1 G+ r, k' w
  185. /*功能名称TIM2_PWMINPUT_INIT(u16 arr,u16 psc)1 L! O, l7 s% {7 H4 F
  186.   描述      PWM输入初始化*/
    % p( [6 j1 n% M. \( `; h2 n

  187. ' i: @1 l5 L5 r, Z; S" c0 c
  188. void TIM2_PWMINPUT_INIT(u16 arr,u16 psc)8 @3 h0 g" n* f) _
  189. {, _$ S7 f6 c$ o) S( l/ D) C; m
  190. 3 p6 ^, @# k# c: P; ^
  191.         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;        //TIM的初始化结构体1 S9 i2 |5 u% o8 t, ~* a
  192.         NVIC_InitTypeDef NVIC_InitStructure;                        //中断配置' i/ C. V( z+ \; k- V
  193.         TIM_ICInitTypeDef  TIM2_ICInitStructure;                 //TIM2  PWM配置结构体
    " x9 ^4 P4 Q! ?2 e
  194.         GPIO_InitTypeDef GPIO_InitStructure;                         //IO口配置结构体
    # y# b6 c  I+ x$ u! E/ X; i& N
  195. 8 H5 [( `2 f. K- \6 X% |, u9 f
  196.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);     //Open TIM2 clock: H% A; i# P' v1 ~; x1 n4 [: N
  197. // RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  //open gpioB clock
    7 R# `6 q" h3 \* ~( [. R  ~
  198. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB  | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟* e! i0 n  o% S; V
  199. GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);          //关闭JTAG+ z" t2 }, T! u0 i8 o" m
  200.          GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE); //Timer2完全重映射  TIM2_CH2->PB3. a' O/ i0 R+ H9 U# q7 P% g
  201. ) E% c+ n3 w( L# i5 R( N- p
  202.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;             //GPIO 3  n" I& i4 _2 i  ?" T, R6 N% L
  203.         GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_IPU;          //浮空输入 上拉输入
    5 h2 V$ M9 h' g7 v) H
  204.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;6 l! y' ]. ~$ K6 t3 d: c
  205.         GPIO_Init(GPIOB, &GPIO_InitStructure);
    ! b0 H5 A/ b  W3 O8 U
  206. & N( }/ X1 F2 G6 a
  207.         TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
    6 k- F2 W7 C8 z+ D) I+ p8 |3 O+ r
  208.         TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
    4 D) z) m* ~' ~8 B
  209.         TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
    0 s3 o2 a. n6 m, `# o  r
  210.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式/ o: p. {! X2 n- e) I7 @
  211.         TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位# F* H. @* J0 T& \/ v
  212. 0 z  X8 M3 ~. F2 G$ L* @

  213. % H- B" t+ O# A* q4 P
  214.         /*配置中断优先级*/1 E5 L% J' u1 t
  215.         NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    2 r) M6 y! L, K; u( k# X
  216.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    * k: S- V' S0 C% ~7 W
  217.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    3 X; _% _* m( h) T9 Q! l  h, V
  218.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    % U7 R7 y* O$ d1 h
  219.   NVIC_Init(&NVIC_InitStructure);
    8 @# J0 D# x. ~5 U& q0 N- b9 K
  220. 8 k6 Z: ~' R8 U( S0 _: T2 n
  221.   TIM2_ICInitStructure.TIM_Channel = TIM_Channel_2;/ a" B" Z( z. g! g1 B2 @" }  a
  222.   TIM2_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;4 E$ T8 V9 O# b9 }2 {8 @* v
  223.   TIM2_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;  O( P3 R7 S) T# |
  224.   TIM2_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    7 ?5 ?2 g- w* a
  225.   TIM2_ICInitStructure.TIM_ICFilter = 0x3;   //Filter:过滤
    ; w* `  F- g! C$ ?0 C
  226. / i4 K- ^$ ~' s; N1 v! u
  227.   TIM_PWMIConfig(TIM2, &TIM2_ICInitStructure);     //PWM输入配置- a. j1 s* w  r3 ~
  228.   TIM_SelectInputTrigger(TIM2, TIM_TS_TI2FP2);     //选择有效输入端
    $ W( u# I; v, Z$ x5 L3 [4 W, [
  229.   TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset);  //配置为主从复位模式
    7 z" B% Z" e: g6 \
  230.   TIM_SelectMasterSlaveMode(TIM2, TIM_MasterSlaveMode_Enable);//启动定时器的被动触发
    / z& j$ E( N1 E+ u7 ^
  231.   TIM_ITConfig(TIM2, TIM_IT_CC2|TIM_IT_Update, ENABLE);          //中断配置$ `- j7 G3 c' u: g# Z
  232.   TIM_ClearITPendingBit(TIM2, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位
    1 n# q  \" U! N3 U0 A0 I+ ]/ k
  233.   TIM_Cmd(TIM2, ENABLE);
    7 n! j' Y8 I2 X7 Q3 m- H: l2 }
  234. }- h) Z; V5 b4 J; j6 F# D1 C6 `. N
  235. * m/ F: V0 L: E' a

  236. ! Z" g4 a, L4 ?+ y5 T) a2 }5 u
  237. void TIM2_IRQHandler(void), R3 z' v$ n$ D) X( v, O
  238. {
    : u* r0 k9 O4 D( Z/ @+ z1 }" _
  239.         {
    , Z6 i: c3 D& g' z
  240.                 if (TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET)//捕获1发生捕获事件
    3 ~) l- v8 w2 L$ i5 Y4 t+ B) P
  241.                         {
    & |: ^. _5 c; l# L
  242.                                 duty_TIM2    =   TIM_GetCapture1(TIM2);          //采集占空比& W; ?# l. b# X4 k$ n5 b8 w
  243.                            if  (TIM_GetCapture2(TIM2)>600)         period_TIM2        =        TIM_GetCapture2(TIM2);
    / v3 S9 {. Y% ?9 _' e8 ]! M( d: g
  244.                                 CollectFlag_TIM2 = 0;( d; u1 v1 J# s( s( _) v- D$ v1 A+ D- H
  245.                         }
    : @2 \+ o: Q* ^" F) ^! r/ C" Z
  246.         }, D( w& U- Z* C: U) m: d3 c' x( }- W
  247.                 TIM_ClearITPendingBit(TIM2, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位" y* O! w5 j: h' ~* q
  248. }
    & c- W: B6 ~$ V8 w' E
  249. , x) ?8 d2 e( z8 Z
  250. /*功能名称TIM5_PWMINPUT_INIT(u16 arr,u16 psc)* F- d, x; s+ S: c7 G/ e
  251.   描述      PWM输入初始化*/  r! T* r8 s5 z3 S5 z

  252. 0 |3 O9 t* [; D4 B( R
  253. void TIM5_PWMINPUT_INIT(u16 arr,u16 psc)2 u& U; ?0 r0 f1 G8 L6 l7 a
  254. {5 U4 H7 Q8 z4 H7 s, X. u& @/ z

  255. 7 l6 f1 W7 V# f& Y7 d6 [$ S: i
  256.         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;        //TIM的初始化结构体
    & ?. S$ @- z5 ]  H: g$ O
  257.         NVIC_InitTypeDef NVIC_InitStructure;                        //中断配置
    ' Z& {* ]" {8 C* D
  258.         TIM_ICInitTypeDef  TIM5_ICInitStructure;                 //TIM4  PWM配置结构体
    ' a, K% R( m# ^% h: Z1 D( T& y/ G
  259.         GPIO_InitTypeDef GPIO_InitStructure;                         //IO口配置结构体
    7 n" h+ t- `/ j9 y: F* n. n! W+ o

  260. , v6 m7 m! Z3 ]* I$ ~: ~! {
  261.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);     //Open TIM4 clock: ]+ M: T0 G) |
  262.   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  //open gpioB clock
    0 {% p' v) I$ ^
  263. * H8 ~/ \8 y" }% T* w2 d
  264.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;             //GPIO 1
    1 m& x8 B8 Z! X2 y
  265.   GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_IPU;          //浮空输入 上拉输入
    ! W5 i% f6 o; C* m0 H
  266.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    2 b: ~6 B, N$ ]2 d6 L
  267.   GPIO_Init(GPIOA, &GPIO_InitStructure);
    2 j+ t0 Q- c$ h

  268. ! B' Y- ~) V: {% U& L
  269.         TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值3 o& P! V# V; y1 v% y( H
  270.         TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值% V& q% c' P  b8 c: P
  271.         TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim' [0 [7 b: c6 t2 e8 I* M% b  |' c- w
  272.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
      C  y: d, z/ w% B/ X+ m# V& O& y
  273.         TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位6 J. s0 i/ o- c* {- H3 Y6 t' a

  274. / N% h' N/ n# O, h! R. D- @' o

  275. 0 E/ q; N5 P0 x9 r/ z4 u5 c3 h
  276.         /*配置中断优先级*/
    6 p  a+ [/ ~' Q+ `# ]$ x
  277.         NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
    $ k8 S7 v! K- F" S3 t: w' Q) |- ]1 T
  278.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;* Q' A* V& A5 T2 G6 w- f" t  w
  279.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    - K6 J. p( C3 ?, X5 i: Q
  280.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    / \4 J- Y! M; S- y, W4 j
  281.   NVIC_Init(&NVIC_InitStructure);
    + ^0 y1 G0 r9 ]/ E# I

  282. . t: P" p' @* Y9 L4 ^+ q
  283.   TIM5_ICInitStructure.TIM_Channel = TIM_Channel_2;& h4 u3 L6 R, R2 c  @2 A4 b
  284.   TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;. }' B. [" u* X. |" r, p5 s
  285.   TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;' c) {; q$ v  g
  286.   TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    & j# F6 ~/ ^( `4 z0 U0 M
  287.   TIM5_ICInitStructure.TIM_ICFilter = 0x3;   //Filter:过滤
      P  p! r6 v4 d7 I+ F
  288. 4 T" f9 r4 Z  l* c' Z
  289.   TIM_PWMIConfig(TIM5, &TIM5_ICInitStructure);     //PWM输入配置
    . F/ v& G- B! f- V
  290.   TIM_SelectInputTrigger(TIM5, TIM_TS_TI2FP2);     //选择有效输入端
    . R) A+ C7 R9 j6 r  Y
  291.   TIM_SelectSlaveMode(TIM5, TIM_SlaveMode_Reset);  //配置为主从复位模式# H% Q- H9 A" s8 F" _# L
  292.   TIM_SelectMasterSlaveMode(TIM5, TIM_MasterSlaveMode_Enable);//启动定时器的被动触发
    ( y0 L: K8 h, _  {& ^7 Y* o& J4 `' S
  293.   TIM_ITConfig(TIM5, TIM_IT_CC2|TIM_IT_Update, ENABLE);          //中断配置( U6 x7 D8 d/ n" I, Z
  294.   TIM_ClearITPendingBit(TIM5, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位& e  q2 H) o3 \1 Z  P7 r. }
  295.   TIM_Cmd(TIM5, ENABLE);$ e" x  q2 A3 L9 ~
  296. }
    / T- B% J5 }* \, }
  297.   q/ n- p! X+ e/ S2 b% h& a
  298. ) E6 x  A0 Z3 \$ I# {
  299. void TIM5_IRQHandler(void)
    9 D# O5 Q( o4 y8 d+ [
  300. {
    % x9 {' W4 T/ i6 t5 ?) A
  301.         {
    - |/ L+ U9 i8 b6 y
  302.                 if (TIM_GetITStatus(TIM5, TIM_IT_CC2) != RESET)//捕获1发生捕获事件
    1 \1 w( I3 y" r" Z3 X2 x
  303.                         {
    ! N1 @3 _% k& b3 q
  304.                                 duty_TIM5    =   TIM_GetCapture1(TIM5);          //采集占空比& L9 i; U5 j  p5 P9 Q6 X* i# [# P
  305.                         if  (TIM_GetCapture2(TIM5)>600)         period_TIM5        =        TIM_GetCapture2(TIM5);) _% ?$ q% @% F
  306.                                 CollectFlag_TIM5 = 0;) l7 q4 }: y/ C! t% ^
  307.                         }
    ! \4 I( B9 w0 h4 r3 a" D+ V; p
  308.         }
    8 @3 o. @6 m7 }5 H0 \( h: ?
  309.                 TIM_ClearITPendingBit(TIM5, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位& j" v& q1 f' M. ~1 t3 O& v
  310. }
复制代码

( ?9 L6 w# z) M1 j0 x" B  ~
, P" J9 S7 Z. d, O, ], m, R; DPID部分:# S1 s! Y. k7 |
准备部分:先定义PID结构体:# ]! b/ L4 x# l2 `
  1. ' ?2 b/ e/ q# H0 O0 R
  2.     typedef struct
    " K$ s0 s3 n; f7 Z
  3.     {
    & D4 K% ^8 X/ b8 `7 c
  4.     int setpoint;//设定目标
    ' ]( _9 A) d* h0 @
  5.     int sum_error;//误差累计0 D5 @. b3 ~4 I' r
  6.     float proportion ;//比例常数0 Q+ u6 Y' e* n7 t7 |& ~
  7.     float integral ;//积分常数/ S) G- c0 A" |4 K
  8.     float derivative;//微分常数7 r5 \1 c5 @7 n) O4 d
  9.     int last_error;//e[-1]
    ; c4 L$ f) [! g/ e: E2 F" ~/ ]! t5 O
  10.     int prev_error;//e[-2]; F; F% u, b7 Q' ?/ w; ^
  11.     }PIDtypedef;
复制代码

) l0 J9 P: [. c  i' N1 |; T; e! v7 U# a" H2 t  B! T8 O% Y

3 X3 h" N: O8 z/ {9 S) l这里注意一下成员的数据类型,依据实际需要来定的。. t+ b- ]+ v3 g+ T/ g$ L
在文件中定义几个关键变量:
" j! p" s' e6 w; s
  1. float  Kp =     0.32  ; //比例常数
    / \* h% _7 i, o7 [
  2. float  Ti =                0.09 ; //积分时间常数& p4 a; q) P4 ?) g  O  P( V! I
  3. float Td =                0.0028 ;  //微分时间常数2 S9 {8 U. w; N
  4. #define T                  0.02 //采样周期5 \" U' ]3 s1 J+ x3 Y+ k  G
  5. #define Ki     Kp*(T/Ti)        // Kp Ki Kd 三个主要参数
    ! U. u! m7 }- s, F3 f1 Z/ C
  6. #define Kd                Kp*(Td/T)
复制代码
. G4 q* z% k8 D, D+ n
6 ^. N8 x" t+ S  d1 {0 f; I
C语言好像用#define 什么什么对程序不太好,各位帮忙写个优化办法看看呢? 用const?
- k- G6 U9 m. v  P, m6 o! y* k3 }( W7 N  }
PID.H里面主要的几个函数:. S* k9 [( q2 x4 j* z
  1. void PIDperiodinit(u16 arr,u16 psc);        //PID 采样定时器设定
    3 J1 p: X$ T% u9 @
  2. void incPIDinit(void);                //初始化,参数清零清零3 q% J' F1 p. ^3 U0 e
  3. int incPIDcalc(PIDtypedef*PIDx,u16 nextpoint);           //PID计算! b# ?/ |( s7 ]7 r- x/ B6 j
  4. void PID_setpoint(PIDtypedef*PIDx,u16 setvalue);  //设定 PID预期值
    9 X4 H# c' Q) E& e. `1 _0 ]1 M" ^
  5. void PID_set(float pp,float ii,float dd);//设定PID  kp ki kd三个参数
    + q. M  v7 [" ?& Y8 ^, x
  6. void set_speed(float W1,float W2,float W3,float W4);//设定四个电机的目标转速
复制代码

  _8 n. ?+ ^2 t: L" S9 B+ n
' x! Y( d' k# M- \0 ?: Z4 }PID处理过程:
  _1 g9 ^  |' D岔开一下:这里我控制的是电机的转速w,实际上电机的反馈波形的频率f、电机转速w、控制信号PWM的占空比a三者是大致线性的正比的关系,这里强调这个的目的是
: J+ ^! _9 M( p因为楼主在前期一直搞不懂我控制的转速怎么和TIM4输出的PWM的占空比联系起来,后来想清楚里面的联系之后通过公式把各个系数算出来了。
* `' M4 {  F, c- a

( q% g4 W0 t( c6 M% e6 o. h" c% W正题:控制流程是这样的,首先我设定我需要的车速(对应四个轮子的转速),然后PID就是开始响应了,它先采样电机转速,得到偏差值E,带入PID计算公式,得到调整量也就是最终更改了PWM的占空比,不断调节,直到转速在稳态的一个小范围上下浮动。& {, b/ J  N% d: y0 v# U7 h3 i
上面讲到的“得到调整量”就是增量PID的公式:
+ N2 u7 H* s. e8 Z
  1.     int incPIDcalc(PIDtypedef *PIDx,u16 nextpoint)8 o+ R5 o' _& u' ^# i# E$ h
  2.     {
    % f- X5 t0 t: N0 x/ X  X
  3.     int iError,iincpid;- h: N. n( I0 Y: v/ Y/ y  L" f
  4.     iError=PIDx->setpoint-nextpoint;  //当前误差
    ) A9 a5 d. B2 h- Z" R
  5.     /*iincpid=                                               //增量计算
    ' g0 `$ e$ |# F5 K' i
  6.     PIDx->proportion*iError                //e[k]项5 E% m% a! i% Q! x" |
  7.     -PIDx->integral*PIDx->last_error          //e[k-1]
    ( z7 x- U4 x0 x7 ?: y: t+ }
  8.     +PIDx->derivative*PIDx->prev_error;//e[k-2]9 m/ \- E& |) y& a" J3 Z
  9.     */
    8 _5 g1 S1 G  Y( j2 z: B' y5 A$ j
  10.     iincpid=                                                          //增量计算
    # X! @5 G; k: u$ Z/ a
  11.     PIDx->proportion*(iError-PIDx->last_error). @/ n* |2 L- g
  12.     +PIDx->integral*iError
    & ^, `  L! r2 u2 r
  13.     +PIDx->derivative*(iError-2*PIDx->last_error+PIDx->prev_error);. j5 r; l, A- a' X6 ^

  14. / {8 s, T) {7 r
  15.     PIDx->prev_error=PIDx->last_error; //存储误差,便于下次计算
      |$ D7 L1 }. R, \, \
  16.     PIDx->last_error=iError;- M% q1 ]7 Z. G9 M- k3 \9 ]
  17.     return(iincpid) ;
    ; j+ Y; X5 W3 P" B; k$ D
  18.     }2 }$ q2 q: u. K& @7 U
  19. . d- L) w! Q1 i& s; k. U

  20. ( I8 Z% y! J! c: e& }8 K
  21. 复制代码2 d) G- P+ x3 ^4 G
  22. ! I- G: h! _0 ~4 R
  23. 注释掉的是第一种写法,没注释的是第二种以Kp KI kd为系数的写法,实际结果是一样的。
    + Y+ k) h$ \! {5 ~$ l
  24. 处理过程放在了TIM6,溢出周期时间就是是PID里面采样周期(区分于反馈信号的采样,反馈信号采样是1M的频率)6 h. N$ V: e/ H3 A/ W
  25. 相关代码:
    ! B& X2 X6 k# h6 i, x
  26. ! |8 w# S) @( a+ o1 a' v# i& {3 N. L4 f

  27. 7 |+ v( X" X6 c2 d+ _  [% d
  28.     void TIM6_IRQHandler(void)        //        采样时间到,中断处理函数7 O+ w1 |; U% Z! I. q
  29.     {
    ; c  \. Q3 Y* |5 H

  30. 9 ?4 e7 q8 u, f- w7 V
  31.     if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET)//更新中断- j9 }4 k( z/ f7 m
  32.             {
    0 Z: D. l) u% X; L4 f
  33.             frequency1=1000000/period_TIM4        ; //通过捕获的波形的周期算出频率* X! Y8 [6 G. B
  34.             frequency2=1000000/period_TIM1        ;7 y1 L) B* k& c1 S' D
  35.             frequency3=1000000/period_TIM2        ;
    6 n4 c+ o4 D( D3 A& H
  36.             frequency4=1000000/period_TIM5        ;$ h& V4 F  h3 ^- b/ x! D
  37.     /********PID1处理**********/
    ! d/ C! @1 _) |0 b' {" Z
  38.             PID1.sum_error+=(incPIDcalc(&PID1,frequency1));         //计算增量并累加
    ' X$ a$ ~5 B& @/ m  P7 H+ e
  39.            pwm1=PID1.sum_error*4.6875  ;   //pwm1 代表将要输出PWM的占空比) _. f4 P' b( J. X6 J* M' A
  40.               frequency1=0; //清零+ M# E2 k* N7 `" o6 [0 D7 i. p6 j
  41.          period_TIM4=0;
    ' W* C# k& |3 @7 L
  42.     /********PID2处理**********/- w. L+ \- i0 x5 Q  v
  43.              PID2.sum_error+=(incPIDcalc(&PID2,frequency2));         //计算增量并累加  Y=Y+Y'
    - n! C5 r! c# b( X7 Q0 j
  44.              pwm2=PID2.sum_error*4.6875 ;   //将要输出PWM的占空比- f$ }1 }, ]% R/ h$ ?7 [
  45.             frequency2=0;
    2 C, E" Q1 v0 A2 {& Q* y
  46.             period_TIM1=0;# m6 R0 o& P- C, k; V6 @) i3 G0 I# ?
  47.     /********PID3处理**********/( {/ R) d$ j9 h: n% t/ Z# u
  48.              PID3.sum_error+=(incPIDcalc(&PID3,frequency3));          //常规PID控制
    ) n9 Q& @+ B1 `1 h
  49.             pwm3=PID3.sum_error*4.6875 ;   //将要输出PWM的占空比8 ]- I% ?$ M6 U. m
  50.             frequency3=0;
    0 c5 k+ T$ q+ K3 i/ C# k
  51.             period_TIM2=0;
    $ W8 y. b9 g$ M" r" L9 c+ U: Z
  52.     /********PID4处理**********/1 j) W# F  _2 G1 T
  53.                 PID4.sum_error+=(incPIDcalc(&PID4,frequency4));         //计算增量并累加" Q; n' v- ?% y5 @1 U. N
  54.              pwm4=PID4.sum_error*4.6875 ;   //将要输出PWM的占空比
    * h" b; A1 [5 g
  55.             frequency4=0;
    8 c- D5 q9 P" ]) L5 _
  56.             period_TIM5=0;% `) o! h( r0 Y! f+ V9 D: D
  57.               }
    - F- u, f2 N9 W" Q3 a' v
  58.     TIM_SetCompare(pwm1,pwm2,pwm3,pwm4);             //重新设定PWM值
    6 i0 E' ~7 D0 h% ~
  59.     TIM_ClearITPendingBit(TIM6, TIM_IT_Update); //清除中断标志位
    " w* P, _. |0 E
  60.     }
复制代码
2 m8 [) _) G3 |! ~& N9 c& l) |$ {
8 b* A# K: M; n
上面几个代码是PID实现的关键部分
% f. L8 x- h7 Z! A$ C' S6 S* i* x" ?5 a$ W8 o; r
整定过程:
. Y1 C4 C) w' d# e8 ?7 W  x3 s' J% c办法有不少,这里用的是先KP,再TI,再TD,在微调。其他的办法特别是有个尼古拉斯法我发现不适合我这个控制对象。: c* e' K  ~1 F% h; w; j" z; [& O
先Kp,就是消除积分和微分部分的影响,这里我纠结过到底是让Ti 等于一个很大的值让Ki=Kp*(T/Ti)里面的KI接近零,还是直接定义KI=0,TI=0.) t: f' s' y3 q# W) u3 ]+ s* D
然后发现前者没法找到KP使系统震荡的临界值,第二个办法可以得到预期的效果:即KP大了会产生震荡,小了会让系统稳定下来,当然这个时候是有稳态误差的。
! w- u0 g( M$ s$ t6 S随后把积分部分加进去,KI=Kp*(T/Ti)这个公式用起来,并且不断调节TI 。TI太大系统稳定时间比较长。
. W4 m- ^; w& `: `9 x$ F7 _& ]* N; h然后加上Kd        =Kp*(Td/T),对于系统响应比较滞后的情况效果好像好一些,我这里的电机反映挺快的,所以Td值很小。
  l) ~/ {/ C+ K- d2 g最后就是几个参数调节一下,让波形好看一点。这里的波形实际反映的是采集回来的转速值,用STM32的DAC功能输出和转速对应的电压,用示波器采集的。: |0 d) P% v  B6 A4 @& W
最后的波形是这样的:
& A6 Y7 K' O+ d' v$ b 3.jpg
+ K$ B( t4 B# j1 S/ M* J最后欢迎大家拍砖,有批评才会让我更加进步!
1 x, r: m7 n. J3 B* ^8 v6 V最后把PID文件放上来 pid.zip (2.88 KB, 下载次数: 134)
收藏 5 评论17 发布时间:2017-12-26 15:40

举报

17个回答
zero99 回答时间:2017-12-26 16:11:12
大佬,这样插代码效果更加哦
3 j3 b0 Z9 S% I# U: s8 j: U8 }5 b/ f" ?, @5 Y0 w
  1. 测试代码4 c9 {% r0 K; _( b% U
  2. 测试代码
    8 I+ e9 a) B6 M) \
  3. 测试代码
    ( P% H: A' f" y3 c& v/ v/ R- h
  4. 测试代码
复制代码
( C+ E6 [& F' D( g# h

4 G. C' e8 K5 y 333333.png : Q" w7 {6 h6 n$ e0 o
二子 回答时间:2018-10-3 11:10:48
nyszx 发表于 2017-12-26 15:41- D8 r" |+ T: B+ g( c; Z& j
再付个网上的资料
& B6 \7 A  E9 Q  t, F$ V
这是个好东西( w0 x! j5 {+ n+ o7 F
书到用时方恨少
8 }1 R# i5 X0 @0 F果断收藏
tlj1b455c 回答时间:2020-8-16 12:15:37
我想问一下,那个编码器得到的脉冲数和占空比有啥关系呀
nyszx 回答时间:2017-12-26 15:41:49
再付个网上的资料 PID控制经典培训教程.pdf (406.07 KB, 下载次数: 183)
nyszx 回答时间:2017-12-26 19:24:38
我马上改过来
东方惑思 回答时间:2017-12-26 20:48:07
学习了,谢谢!
" [5 A6 [+ f9 }1 R2 m
板子粉丝 回答时间:2018-5-12 12:58:31
不错,学习了
西点钟灵毓秀 回答时间:2018-7-22 02:13:36
学习了,正好需要
libin1009 回答时间:2018-7-22 15:44:52
学习一下!
shwp 回答时间:2018-8-20 14:08:14
学习
wjwjwjwj997 回答时间:2018-8-21 08:14:50
学习了,正好需要
coobakl 回答时间:2018-8-21 16:10:40
学习了,正好需要
chao2018 回答时间:2018-9-20 09:48:26
谢谢分享!!
gengkeju 回答时间:2018-10-8 14:32:36
赞,学习一下
zjczm 回答时间:2018-10-9 17:31:58
有空学习。
12下一页

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版