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

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

[复制链接]
nyszx 发布时间:2017-12-26 15:40
本帖最后由 nyszx 于 2017-12-26 19:31 编辑
" r* g3 l# ?" F' c% Q
' n6 j# o+ F: d/ u! L8 L原帖:【分享】增量式PID的stm32实现,整定过程
0 h0 ]! e  u! G$ z, \原文网址:http://www.amobbs.com/thread-5575823-1-1.html
( r" }8 C  h" H6 v+ m出处:阿莫电子论坛
( S& c6 _$ @: `作者:tim4146
, i& R3 K9 `4 t感谢大家最近的帮忙,让我顺利做完增量PID功能,虽然PID不是什么牛逼的东西,但是真心希望以后刚刚接触这块的人能尽快进入状态。
8 c" e# Y* u! Q' A也下面我分享一下近期的这些工作吧。欢迎大家批评指点~ : v( V. g8 p- N- R! E- l9 D, @7 e# V

5 a7 M; O+ y8 r$ E& f首先说说增量式PID的公式,这个关系到MCU算法公式的书写,实际上两个公式的写法是同一个公式变换来得,不同的是系数的差异。9 Z0 A# d" N7 i9 l
资料上比较多的是:/ O' |. F& x4 o: M# U0 c
1.jpg
1 l7 _$ P! I5 V. a% K还有一种是:
+ o6 T3 u; X, F 2.jpg
! w  r3 s' e. [感觉第二种的Kp Ki Kd比较清楚,更好理解,下面介绍的就以第二种来吧。(比例、积分、微分三个环节的作用这里就详细展开,百度会有很多)4 i$ S& g1 v. ~) x3 a
. A; ?. X- W1 p5 @
硬件部分:7 m( o9 L& ?* H+ Y
控制系统的控制对象是4个空心杯直流电机,电机带光电编码器,可以反馈转速大小的波形。电机驱动模块是普通的L298N模块。
& O  K, H. ^' l1 l芯片型号,STM32F103ZET6
  z  d6 r: w- Q4 n; U- w
; h: J1 C" `% s- Z* g软件部分:
0 N: W) w3 a! l8 G% E0 hPWM输出:TIM3,可以直接输出4路不通占空比的PWM波
6 ]' j& @. P% p7 R  F& [. tPWM捕获:STM32除了TIM6 TIM7其余的都有捕获功能,使用TIM1 TIM2 TIM4 TIM5四个定时器捕获四个反馈信号4 y' i) D; H2 e2 r% I5 q/ _
PID的采样和处理:使用了基本定时器TIM6,溢出时间就是我的采样周期,理论上T越小效果会越好,这里我取20ms,依据控制对象吧,如果控制水温什么的采样周期会是几秒几分钟什么的。/ ]2 m" G) A: E/ R7 m. \% D- W

6 J7 y8 _( m/ I5 \上面的PWM输出和捕获关于定时器的设置都有例程,我这里是这样的:5 s  N( G7 N9 H5 I2 R$ P% W# [# S
TIM3输出四路PWM,在引脚 C 的 GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9输出$ @& D$ S, `- G% {! K+ F  A
四路捕获分别是TIM4  TIM1  TIM2  TIM5   ,对应引脚是:  PB7 PE11 PB3 PA1

; {5 `  o: C; H7 T9 `高级定时器tim1的初始化略不同,它的中断”名称“和通用定时器不同,见代码:
6 [7 ]3 O- \) q
  1. /*功能名称IM3_PWM_Init(u16 arr,u16 psc)
    , @! c: I7 J/ ~9 z: T1 X' y
  2.         描述      TIM3产生四路PWM/ ~* e* c0 ~8 H% m/ F1 z
  3. */6 ?& _: J, Y6 I& B, T* J
  4. void TIM3_PWM_Init(u16 arr,u16 psc)* B$ P+ ^  ~  D- ?/ a
  5. {
    ' `+ e% ?& |8 W( T
  6.         GPIO_InitTypeDef GPIO_InitStructure;1 j' {1 a/ O+ F! o+ a+ G( a
  7.         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;" Y" H" ^" f+ u% Y1 e* d# o
  8.         TIM_OCInitTypeDef  TIM_OCInitStructure;
    / b. Z2 s" s( ]
  9. . K- U! _9 w$ F8 T& y2 y" P4 Y
  10. 1 k$ h' y7 _, H& j3 m
  11.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);5 Z' S3 p  u+ T6 r6 G9 p7 M
  12.          RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC  | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟使能
    * S( Y4 ^: S* k% P

  13. # f3 n6 x4 i6 ~% D( x# z! Y
  14.   GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE); //Timer3全映射 GPIOC-> 6,7,8,9                                                                             //用于TIM3的CH2输出的PWM通过该LED显示
    1 h2 ]6 B* C9 `8 o- V: P

  15. 2 Y. j0 q' j; L& q2 K
  16.    //设置该引脚为复用输出功能,输出TIM3 CH1 CH2 CH3 CH4 的PWM脉冲波形/ I, {; {3 f  h5 r. [$ m
  17.         GPIO_InitStructure.GPIO_Pin =GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9; //初始化GPIO8 f1 Y# W% n/ S) T
  18.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出# R5 {' N& r: A
  19.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;: V/ v7 ?2 X; Q! d1 b3 ^5 p
  20.         GPIO_Init(GPIOC, &GPIO_InitStructure);
    1 g6 a( ^8 A+ N6 ^8 K2 S6 n  C1 U; q" [
  21.         GPIO_ResetBits(GPIOC,GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9);//默认电机使能端状态:不使能
    % @. G! P, S5 B2 h! g
  22. / B/ f  U+ F* r. C6 A0 u
  23.         TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值4 h! K: t+ M9 h% h2 w- G2 X
  24.         TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  这里是72分频,那么时钟频率就是1M
    , V: [3 U/ T( a
  25.         TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim$ R5 J) D) o/ v2 B" E
  26.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    ' f3 L7 g% |7 ?& q. ^/ i9 r
  27.         TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
    # w: M9 v6 y! \4 d! r" H

  28. ) C. Y% K/ s) C% V3 _

  29. 9 F$ P- i! {  B9 m2 V2 L% g: _& ]
  30.         TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
    8 v8 C, }5 q. k
  31.         TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能- O* l6 x/ f$ R
  32.         TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值6 X4 N) V% \3 N# y0 e
  33.         TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高1 ^  j' b0 S3 g, s: M
  34. & H: O0 k1 R8 ^' j. l
  35.         TIM_OC1Init(TIM3, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
    & L4 N8 R2 e' }' r3 X
  36.         TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIMx在CCR1上的预装载寄存器
    ' m8 b  s8 @0 H
  37. 0 r7 N" Y" `* L* j& \  Y# _
  38. 0 n+ g( A2 U3 v. p( L  f
  39.         TIM_OC2Init(TIM3, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx- k5 s; }- \/ S: t/ ]- y, C0 {
  40.         TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIMx在CCR2上的预装载寄存器, W( m* q" Z8 j1 j% u; W1 i
  41. 2 G& E/ o$ ?: U; z: r& b
  42.         TIM_OC3Init(TIM3, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx/ D# N( S0 l9 d+ y
  43.         TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIMx在CCR3上的预装载寄存器1 x# e+ g, f( `% @; Z$ ]- L
  44. $ H* ?3 e* N. f: |9 _- r
  45.         TIM_OC4Init(TIM3, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
    5 A: N+ Q/ a6 `3 B) X
  46.         TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIMx在CCR4上的预装载寄存器) y* C/ H7 I& g

  47. * j  y& F. C1 O
  48.         TIM_ARRPreloadConfig(TIM3, ENABLE); //使能TIMx在ARR上的预装载寄存器
    3 B6 _% [2 l7 }; K) Z/ O

  49. # A( s; E4 O" u/ {2 i! z' i* @' G
  50. . K5 c$ S) R+ O+ H
  51.         TIM_Cmd(TIM3, ENABLE);  //使能TIMx外设
    , O# S( S  |" L" S* H

  52. ( v" I: m: G1 _  u

  53. + ^; [: P( x1 o8 [9 T
  54. }$ [) b0 a/ }& f: W; Q, r0 I

  55. * j: R6 q; a% `- f
  56. & M3 k0 ?: B; n" [
  57. $ f6 s+ E( {4 r; q% n9 w
  58. /*功能名称TIM4_PWMINPUT_INIT(u16 arr,u16 psc)
    , z) Z6 O8 c, _, O
  59.   描述      PWM输入初始化*/
    ( d1 X! ]# O. a% l

  60. 5 n, S4 R  h+ [0 m: ?
  61. void TIM4_PWMINPUT_INIT(u16 arr,u16 psc)
    9 B( Q* H. m3 n  s* n' m. s
  62. {
    4 E1 `! t" L- I- z9 v
  63. 8 X5 m" Y/ c  `( l: ~
  64.         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;        //TIM的初始化结构体
    # s' Z* I& d2 F: N* d* Z
  65.         NVIC_InitTypeDef NVIC_InitStructure;                        //中断配置
    $ A% D' F* l" {- B
  66.         TIM_ICInitTypeDef  TIM4_ICInitStructure;                 //TIM4  PWM配置结构体
    " L$ @$ n# {* ~5 q
  67.         GPIO_InitTypeDef GPIO_InitStructure;                         //IO口配置结构体- a% a+ ^7 b2 [& S

  68. & ]8 y: {8 @, m5 V% Y5 s$ U
  69.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);     //Open TIM4 clock
    3 ^4 d! y- s0 h8 s1 @* X% w8 L- ~
  70.   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  //open gpioB clock
    " o; g0 a8 ?% f
  71. . O2 V; \6 J% E; U3 W2 y
  72.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;             //GPIO 7, v- E  U0 K3 M2 ^- J
  73.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;          //上拉输入
    ( k6 b0 O8 u8 C5 j
  74.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;" e$ O6 w3 j7 @
  75.   GPIO_Init(GPIOB, &GPIO_InitStructure);- _- z6 I, h) t) n/ K
  76. 5 s* i3 y3 s2 |1 K% S
  77.         TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值7 \' \4 p2 Y7 l, [
  78.         TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
    ) n4 W( C1 `# b" Y% h
  79.         TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
    ; {5 v9 D: S3 d5 L$ n$ J1 d* \8 V
  80.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    ) D! x2 n, g% \# |, C! {' i
  81.         TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位+ t+ \# `% `2 @! T# ~

  82. & l% A( Q, i) f# X5 B2 y+ c% j) V
  83. : y& d" K: e( F3 Z, V; B  |
  84.         /*配置中断优先级*/. E" ?* r( h+ m, c$ j
  85.         NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;7 ?) ^7 O) v/ N7 W0 M
  86.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;# A( [% i( n" v5 c- @, G+ W+ p6 U  j1 K
  87.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    8 w( j! \* s$ e# f) Q) d. e
  88.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;5 v9 b5 d( R' d; C( }
  89.   NVIC_Init(&NVIC_InitStructure);; a, E  J: A  O3 y
  90. ( w9 s. d+ _6 O" m$ W+ E
  91.   TIM4_ICInitStructure.TIM_Channel = TIM_Channel_2;5 z4 I. u& R1 Z- m3 H4 t
  92.   TIM4_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;' Z/ n8 z2 Q/ ~% m, U! r
  93.   TIM4_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
    ( C# s9 F- F+ s$ B! o
  94.   TIM4_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;# R9 v. L2 [. B. \' m6 K7 z
  95.   TIM4_ICInitStructure.TIM_ICFilter = 0x3;   //Filter:过滤
    % I0 \0 U5 u$ O$ B
  96. * M3 d) [4 O' P8 U- Z
  97.   TIM_PWMIConfig(TIM4, &TIM4_ICInitStructure);     //PWM输入配置
    ) P* h& k) `, `" ^% ^
  98.   TIM_SelectInputTrigger(TIM4, TIM_TS_TI2FP2);     //选择有效输入端# l( [  y; k$ t2 @6 Y; C
  99.   TIM_SelectSlaveMode(TIM4, TIM_SlaveMode_Reset);  //配置为主从复位模式
    9 G+ I# I* ?! S0 g  `0 v% D
  100.   TIM_SelectMasterSlaveMode(TIM4, TIM_MasterSlaveMode_Enable);//启动定时器的被动触发
    : z# V/ |0 L9 N% G6 X
  101.   TIM_ITConfig(TIM4, TIM_IT_CC2|TIM_IT_Update, ENABLE);          //中断配置
    0 P, M# A4 K6 h7 B
  102.   TIM_ClearITPendingBit(TIM4, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位
    / d. D$ v+ t" ^% e( x* a8 t
  103.   TIM_Cmd(TIM4, ENABLE);7 n4 R' m+ L/ O; B$ V! v
  104. }$ ~( y9 t- b; n! k* q+ Y! K

  105. , g$ _0 v' ?/ J6 X
  106. 0 G4 x4 R; o: l4 q# f* t
  107. void TIM4_IRQHandler(void)
    + r1 N& M4 f  P3 ~' t$ f
  108. {4 R6 c3 Q" r( y+ M, @: h

  109. - t$ m7 s4 ~* [' q
  110.                 if (TIM_GetITStatus(TIM4, TIM_IT_CC2) != RESET)//捕获1发生捕获事件6 G1 V) F# B0 n
  111.                         {5 y. j  o' p, z# X
  112.                                 duty_TIM4    =   TIM_GetCapture1(TIM4);          //采集占空比
    ' y* b# |8 W4 S* K
  113.                if  (TIM_GetCapture2(TIM4)>600)         period_TIM4        =        TIM_GetCapture2(TIM4);//简单的处理
    * s: ]4 b( B7 d. A
  114.                                 CollectFlag_TIM4 = 0;
      e, W0 ^) ~$ {( r1 L- b5 i8 b$ ?  d/ @
  115.         }, \' m) U  Q( k8 P
  116.                 TIM_ClearITPendingBit(TIM4, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位
    , p! w# z$ f. o9 Q! N8 a2 }1 [$ ^5 V9 y
  117. }+ e% H! j5 t- K. \1 E

  118. # `( C1 L: `! [$ c4 |
  119. ) ^5 F2 v* j0 Y2 N
  120. /*功能名称TIM1_PWMINPUT_INIT(u16 arr,u16 psc)) Q8 u3 z( @3 X2 s" `
  121.   描述      PWM输入初始化*/
    1 G6 Y% w0 V: [& t
  122. : ]0 @# D' V4 g1 D
  123. void TIM1_PWMINPUT_INIT(u16 arr,u16 psc)( q0 ]. P: Z& }* y" k) W- i" {  D
  124. {# V, G6 J' K6 Q' E5 a

  125. 5 F& b7 U" f$ Q/ l4 F- g" t, _
  126.         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;        //TIM的初始化结构体8 f) u- M. a& W4 q- ^4 ~$ d8 u
  127.         NVIC_InitTypeDef NVIC_InitStructure;                        //中断配置  u3 b6 |' S8 E
  128.         TIM_ICInitTypeDef  TIM1_ICInitStructure;                 //PWM配置结构体+ n4 G7 P, i; `$ v$ `& `
  129.         GPIO_InitTypeDef GPIO_InitStructure;                         //IO口配置结构体6 H- M9 p9 n' G; R: m
  130. 0 I1 s) Y/ ~; h' j' B
  131.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);     //Open TIM1 clock
    / e& Y/ p% W! ^. j
  132.   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);  //open gpioE clock  k  N* F! e  Q6 T" V" v+ A
  133.    GPIO_PinRemapConfig(GPIO_FullRemap_TIM1, ENABLE); //Timer1完全重映射  TIM1_CH2->PE11" j: G  O4 |8 ?: |# e) @6 I# @
  134.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;             //GPIO 11! @7 d8 f, ^3 h6 J% y
  135.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;          //上拉输入: \1 x) B, [( [3 U+ ?' r+ c
  136.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;) o* v- ]# y+ J4 B
  137.   GPIO_Init(GPIOE, &GPIO_InitStructure);
    7 v% o1 o, E9 f% ?
  138. + T4 N) H/ j: P/ D+ v, x: r
  139.         TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值0 M+ u% U" c* F) U& C% h
  140.         TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
    ) g+ ^$ t$ K0 f: ^5 @7 W* Z& f
  141.         TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
    - E- J$ k" p  D" ^) L; z& [
  142.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式" c% o6 O# P8 d$ g( e* L0 q
  143.         TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位+ C" l+ h+ d) K$ ^" ^5 X

  144. ; v6 j* u! E5 \: Q
  145. 5 D. j" @; a+ a4 I6 L
  146.         /*配置中断优先级*/9 M7 e- }& L$ e+ W
  147.   NVIC_InitStructure.NVIC_IRQChannel =  TIM1_CC_IRQn;   //TIM1捕获中断2 c: {. k1 [, j) b+ i. L
  148.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;/ x4 p! z$ {5 Y
  149.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;. A$ I* e2 O; }8 C, c) R
  150.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    $ A$ J  A3 N# F% _& ^
  151.   NVIC_Init(&NVIC_InitStructure);
    - x* i+ W) F+ X# O2 R
  152. ) p5 {" o( Q( v" V2 V3 q
  153.   TIM1_ICInitStructure.TIM_Channel = TIM_Channel_2;& m1 n3 [' @8 H  v. N
  154.   TIM1_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;5 \1 V5 [9 _$ a9 @3 P
  155.   TIM1_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;- r* r# {) c+ j3 N7 d+ |7 N" q
  156.   TIM1_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;; s7 w5 m# L% m1 H  R
  157.   TIM1_ICInitStructure.TIM_ICFilter = 0x03;   //Filter:过滤
    : X$ m5 n: `* M4 V. X

  158. 5 i# t+ [. e6 V, @
  159.   TIM_PWMIConfig(TIM1, &TIM1_ICInitStructure);     //PWM输入配置0 O+ I, e* s" Y2 ?1 c' ]# Z, S/ F+ d
  160.   TIM_SelectInputTrigger(TIM1, TIM_TS_TI2FP2);     //选择有效输入端) y1 e1 e2 s9 z& J4 r5 [1 C
  161.   TIM_SelectSlaveMode(TIM1, TIM_SlaveMode_Reset);  //配置为主从复位模式
    * x# G; C# |: Y7 _, s
  162.   TIM_SelectMasterSlaveMode(TIM1, TIM_MasterSlaveMode_Enable);//启动定时器的被动触发! }: e) ~1 b- \0 h. ~7 P- y8 C
  163. // TIM_ITConfig(TIM1, TIM_IT_CC2|TIM_IT_Update, ENABLE);          //中断配置; |1 v; O) F9 k. I1 D. P7 j
  164.   TIM_ITConfig(TIM1, TIM_IT_CC2, ENABLE); //通道2 捕获中断打开
    ! s$ L; q9 P( y& [* a7 k' X3 j
  165.   //TIM_ClearITPendingBit(TIM1, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位4 |1 k! H: N& X% E; m# O
  166.   TIM_Cmd(TIM1, ENABLE);
    + ^4 i2 @- S8 z% ^! ~+ c1 r2 u
  167. }
    , h% d8 i# X3 r( U/ m7 B
  168. / Y0 p1 }2 V) g

  169. 0 m/ }7 Y4 e& q3 C, p0 ?
  170. void TIM1_CC_IRQHandler(void)$ R6 {9 Z. ^0 p) z4 i# ]7 P  l
  171. {4 x: s& D) O% H; q, Y, Q& ~! O

  172. : o( d  K- m3 x# _5 J" o: s% l8 L9 |
  173.         {" G; |, f& ~6 {2 m
  174.                 if (TIM_GetITStatus(TIM1, TIM_IT_CC2) != RESET)//捕获1发生捕获事件
    * P" [; p5 D# e# x. B, g
  175.                         {3 s5 o0 J1 X5 N3 I; |
  176.                                 duty_TIM1    =   TIM_GetCapture1(TIM1);          //采集占空比
    7 b; z% o7 `/ S/ k! |. {7 Y. k$ e  l
  177.                            if  (TIM_GetCapture2(TIM1)>600)         period_TIM1        =        TIM_GetCapture2(TIM1);" y7 s' t% x: b  Q! ?5 _$ y) C+ h& D
  178.                                 CollectFlag_TIM1 = 0;
    ) h3 p) v* ?' h' O# N3 d
  179.                         }7 \! x$ T% m' A- u7 ?: D& a
  180.         }) ~* y- X: G2 e8 ?3 C
  181.                 TIM_ClearITPendingBit(TIM1, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位- M& M! {" Z) D4 c+ p. m' u( e
  182. }
    1 }* ~; o4 s  e4 y& x

  183.   @, X' Y5 Z2 k  S4 @

  184. 0 ^8 b+ \4 |4 m0 G, @
  185. /*功能名称TIM2_PWMINPUT_INIT(u16 arr,u16 psc)' k* T) e5 ~4 x
  186.   描述      PWM输入初始化*// `5 a) ]; C7 x2 |, [5 Z+ b8 U
  187. / H: z4 U; P1 X" W  V3 b1 m
  188. void TIM2_PWMINPUT_INIT(u16 arr,u16 psc)
    7 d6 \& @6 Y( G+ W
  189. {% ]/ O7 z! W" a& \, J- t

  190. 6 R5 p/ ?* e; A# ?
  191.         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;        //TIM的初始化结构体) x" H6 o8 u3 C* A( M
  192.         NVIC_InitTypeDef NVIC_InitStructure;                        //中断配置9 q3 R5 h- V4 |- F) \
  193.         TIM_ICInitTypeDef  TIM2_ICInitStructure;                 //TIM2  PWM配置结构体8 I& R& h! \  r. i, e( H$ K
  194.         GPIO_InitTypeDef GPIO_InitStructure;                         //IO口配置结构体
    & k, Y% X& Q: }2 ?
  195. ( D9 q. J0 S) B# c9 t8 d4 ^$ y
  196.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);     //Open TIM2 clock4 ?( r$ t/ z" r8 h
  197. // RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  //open gpioB clock8 h2 Z1 v4 X' `6 K$ w+ Z0 X
  198. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB  | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟% F% @3 y( g. u4 {/ H1 `) V
  199. GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);          //关闭JTAG
    3 S( k! \  A2 c4 @$ g7 E
  200.          GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE); //Timer2完全重映射  TIM2_CH2->PB3
    * |* R8 v4 m3 f, z1 W
  201. , }% c4 c/ [. e
  202.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;             //GPIO 3
    6 `6 h; j- L6 ~. H% H$ Y4 Q  N- I0 `
  203.         GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_IPU;          //浮空输入 上拉输入& R+ ?/ q) S; v8 |5 y
  204.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;5 J+ ]  M9 P7 h! P
  205.         GPIO_Init(GPIOB, &GPIO_InitStructure);' F. }: B9 n3 b( s; w- v. l
  206. % u1 L9 _4 n- }& f2 `- Q
  207.         TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
    + j2 }* ^& r, l2 f  w9 P' P
  208.         TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
    : e. o' f( k; c7 u: b% ]
  209.         TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
    ( \, t1 u" e" s  p: D
  210.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式; Y6 Y& Y  ^5 ^
  211.         TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位- w/ k- \% N4 S! h  @( o/ c
  212. " b, z. F& N* ?/ G6 o$ E; u8 e( q

  213. : l- X3 Y: A/ w$ \. x( G' f. M- [! P
  214.         /*配置中断优先级*/1 U0 V* p( b( u/ v7 `
  215.         NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;: x  B' a) m" i  k* g
  216.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    ; d1 c  m) O0 I) ~
  217.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    6 T1 Y, g% M; g9 ~9 z
  218.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    % v" h0 ?/ s( k
  219.   NVIC_Init(&NVIC_InitStructure);2 v* I6 J7 t$ V% @/ h7 R3 i

  220. % A! w& [4 P, A; P) n' l0 ?
  221.   TIM2_ICInitStructure.TIM_Channel = TIM_Channel_2;
    " y1 z8 O% o# e# ]) l% X
  222.   TIM2_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
    ! h; E9 h" @5 p9 Q2 d
  223.   TIM2_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;+ X* n# r6 T  N3 I  W6 E' n+ a
  224.   TIM2_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    " U1 p% N( u9 M
  225.   TIM2_ICInitStructure.TIM_ICFilter = 0x3;   //Filter:过滤! Z' P. h8 L. X! `1 p7 J* }
  226. 6 t7 Z- M" W, {0 C# N+ L4 B2 E3 x
  227.   TIM_PWMIConfig(TIM2, &TIM2_ICInitStructure);     //PWM输入配置3 {* ?  ]: E; f% b% D
  228.   TIM_SelectInputTrigger(TIM2, TIM_TS_TI2FP2);     //选择有效输入端4 T- b9 C" w# z( p
  229.   TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset);  //配置为主从复位模式, _+ `0 P6 C+ j) Y
  230.   TIM_SelectMasterSlaveMode(TIM2, TIM_MasterSlaveMode_Enable);//启动定时器的被动触发
    1 p; v: d8 s& T% X  p8 V
  231.   TIM_ITConfig(TIM2, TIM_IT_CC2|TIM_IT_Update, ENABLE);          //中断配置
    8 U4 T! \+ `) g' G. c1 V0 }( }2 k
  232.   TIM_ClearITPendingBit(TIM2, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位# w% o9 a5 I5 ^! W  e: B
  233.   TIM_Cmd(TIM2, ENABLE);& \0 ]$ `! t$ v7 Q3 o" t: V, N+ c& F3 C
  234. }
    , g( B/ f' D4 p- G6 c5 P/ _0 P2 v( ?

  235. . H. t3 c# G- u* N0 d* b$ B( ^! F

  236. 5 A. ?# P) r7 z0 X$ c" i
  237. void TIM2_IRQHandler(void)
    # B3 M8 \. [# Y
  238. {, e# V* E+ E* o: l& D4 `! S
  239.         {
    5 y5 _* G- [; Y; [3 w9 T
  240.                 if (TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET)//捕获1发生捕获事件
    & t& s1 x. ?6 k
  241.                         {, m7 }3 D" u5 S5 }; f
  242.                                 duty_TIM2    =   TIM_GetCapture1(TIM2);          //采集占空比+ m6 f0 Y& K  v& F8 s1 _- e
  243.                            if  (TIM_GetCapture2(TIM2)>600)         period_TIM2        =        TIM_GetCapture2(TIM2);
    ) }9 w. r! \: y  z' V* Y
  244.                                 CollectFlag_TIM2 = 0;/ I8 c3 X' P/ Z) l" _2 p6 q
  245.                         }
    , j5 F( O3 W9 i; K1 J4 ]
  246.         }2 U; V0 G* W7 U6 ]
  247.                 TIM_ClearITPendingBit(TIM2, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位
    # G0 `+ l! Y% f6 M2 q3 V
  248. }7 e7 g  Z/ R. m
  249. " \$ U+ L  i. R. F/ s3 B' ?
  250. /*功能名称TIM5_PWMINPUT_INIT(u16 arr,u16 psc)
    ( P3 T: Z! P% q+ n
  251.   描述      PWM输入初始化*/
    , ?& a" U7 I# i9 Z1 C$ s+ N9 `

  252. 6 P- _9 {3 ^# `4 k+ t  u
  253. void TIM5_PWMINPUT_INIT(u16 arr,u16 psc)
    0 x$ B7 F  k0 E4 S6 Y2 R5 H
  254. {+ q. k3 C* n7 J$ D# Z% {
  255. 0 _. `% f# ?$ y: I
  256.         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;        //TIM的初始化结构体; n- |/ y  B3 D
  257.         NVIC_InitTypeDef NVIC_InitStructure;                        //中断配置/ j# ~* b# r1 B% t* T- a6 J& {3 B" Z
  258.         TIM_ICInitTypeDef  TIM5_ICInitStructure;                 //TIM4  PWM配置结构体
    " D+ x' D8 [6 e. K" q
  259.         GPIO_InitTypeDef GPIO_InitStructure;                         //IO口配置结构体" w5 H( W2 k5 s& W8 g' _
  260. . r. ~+ V9 k( \# t% d4 T
  261.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);     //Open TIM4 clock) a8 G6 S  I5 R9 \* ]
  262.   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  //open gpioB clock* ^: O# U3 U1 f- f) v" A; c# @* X

  263. * W4 `' N7 U' D) q+ B
  264.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;             //GPIO 1
    6 P: f+ a' N+ E( r# p
  265.   GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_IPU;          //浮空输入 上拉输入' Y' c/ W0 C4 i# J. E  y
  266.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;& C9 @( x  G' P6 ]6 v3 b
  267.   GPIO_Init(GPIOA, &GPIO_InitStructure);6 o* s& \3 n$ n; [2 Z  J+ w- a. r
  268. 0 ?0 O$ Q1 A4 F3 x. v8 T9 A
  269.         TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
    ! ]* |% i/ E& j* G& B" |  p
  270.         TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
    # e/ R8 F, E- D" @& \7 g
  271.         TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
    # Y/ V' M& t0 ^& D3 J1 ?
  272.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    ' }! d/ ^' ]: n5 M7 U
  273.         TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位/ s& Y  R" i4 D  d. p

  274.   F3 z+ r+ q$ [5 U& f

  275. 9 \, p% N) o8 R7 [) W' k
  276.         /*配置中断优先级*/* [# @/ O% e' D3 v+ [: ]1 h
  277.         NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
    & k$ i/ ~9 `3 G( g& x
  278.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    / }  I: O" S: f" F! g6 _) G
  279.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;* Z4 C. I5 q- A' r) ^
  280.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;1 \0 u. t/ U9 \
  281.   NVIC_Init(&NVIC_InitStructure);  v# m! D! d. O+ s, d1 B( w

  282. / q4 |! y: B/ s" U  o  C
  283.   TIM5_ICInitStructure.TIM_Channel = TIM_Channel_2;
    % W: Z6 L, ?# |3 u9 L
  284.   TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;4 F  ~& b; E# ^( `3 g
  285.   TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;9 M; z: z" ~* O
  286.   TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    * o5 Q, _! Y+ K) z* |; Q; Z1 k
  287.   TIM5_ICInitStructure.TIM_ICFilter = 0x3;   //Filter:过滤! e: m0 s0 ]5 }! J: O5 r0 n( B
  288. , W+ }) Y4 @4 B/ t
  289.   TIM_PWMIConfig(TIM5, &TIM5_ICInitStructure);     //PWM输入配置
    9 T  P8 s! O+ N0 }
  290.   TIM_SelectInputTrigger(TIM5, TIM_TS_TI2FP2);     //选择有效输入端( o0 I4 ]$ J# n9 U% q0 j8 R$ E
  291.   TIM_SelectSlaveMode(TIM5, TIM_SlaveMode_Reset);  //配置为主从复位模式
    5 q7 L! Z6 N+ o
  292.   TIM_SelectMasterSlaveMode(TIM5, TIM_MasterSlaveMode_Enable);//启动定时器的被动触发8 Y2 |5 \% E; C" y
  293.   TIM_ITConfig(TIM5, TIM_IT_CC2|TIM_IT_Update, ENABLE);          //中断配置
    4 n& A3 q  Y# s$ D
  294.   TIM_ClearITPendingBit(TIM5, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位: U3 r. U! k- _! F) i* D$ i, r
  295.   TIM_Cmd(TIM5, ENABLE);& [7 E' b5 A8 @8 O
  296. }
    # O' g/ |, ^! Z; _

  297. + J3 [- g2 X) S' q" ]- ]
  298. ; v. x3 I) M8 T# s" ]  R" v
  299. void TIM5_IRQHandler(void)% ^+ L2 h1 X7 n& v/ b  G
  300. {/ f' t% C+ k# n
  301.         {3 D& R5 ~; m2 ~
  302.                 if (TIM_GetITStatus(TIM5, TIM_IT_CC2) != RESET)//捕获1发生捕获事件: l, |8 {7 s6 t
  303.                         {+ R" L4 K$ ~% [9 X# z1 U' Z
  304.                                 duty_TIM5    =   TIM_GetCapture1(TIM5);          //采集占空比4 a4 i6 @$ A# N$ G0 Q: S. y
  305.                         if  (TIM_GetCapture2(TIM5)>600)         period_TIM5        =        TIM_GetCapture2(TIM5);
    3 v& k' S1 i7 X& |" D
  306.                                 CollectFlag_TIM5 = 0;
    8 `. y; s' V  c7 C" A- S- {
  307.                         }% U& h/ T5 b& V
  308.         }( @0 }# k7 I: |7 Q; R
  309.                 TIM_ClearITPendingBit(TIM5, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位, u" S+ m8 e' @' ~
  310. }
复制代码
: O% H0 {( Q7 u4 D* ~6 V
( C9 h: z/ ^, Z, f0 b! D
PID部分:3 |4 _5 H6 |* f" F5 \: P7 O2 w
准备部分:先定义PID结构体:* j& R% _/ w- J

  1. 0 s8 F! v( i- t7 Q5 d
  2.     typedef struct! w; c* f6 V5 h+ e+ o: x
  3.     {$ ~1 P1 @& R6 T& i$ |5 Q- q
  4.     int setpoint;//设定目标
    ! B/ I5 A! K3 `, }% R+ I
  5.     int sum_error;//误差累计
    5 ~; K+ [" ?  o
  6.     float proportion ;//比例常数
    , P* f* U; u! I7 ~3 \' L
  7.     float integral ;//积分常数
    ; K; X$ j. E+ T3 T( t1 c: j
  8.     float derivative;//微分常数% j- M  D/ p( e  O8 S9 C
  9.     int last_error;//e[-1]
    2 ~3 f" |- b4 b7 T! \
  10.     int prev_error;//e[-2]+ L* q( k0 u* d2 G
  11.     }PIDtypedef;
复制代码
0 `0 J4 I# R& W4 w( k! p

# M0 Y3 Q- I; x) Y8 g6 }2 |! w) g- f% \# H- V) I( G0 l
这里注意一下成员的数据类型,依据实际需要来定的。
; N' z2 ?( ~4 n: i1 ~在文件中定义几个关键变量:
. p) M/ U: ?# b2 h/ J5 ~$ J
  1. float  Kp =     0.32  ; //比例常数
    & Y5 a3 I& E7 e/ K2 ?. n* ^
  2. float  Ti =                0.09 ; //积分时间常数
    1 S3 }# v& |: E6 I
  3. float Td =                0.0028 ;  //微分时间常数$ c5 Y2 k  A0 R& J* ^9 H) C3 ]
  4. #define T                  0.02 //采样周期
    , T& |# F/ D2 X; {" w' z
  5. #define Ki     Kp*(T/Ti)        // Kp Ki Kd 三个主要参数1 x; b, C* F* [, h" U- R
  6. #define Kd                Kp*(Td/T)
复制代码

! e! C9 B5 b* p- Y* b+ p& @: {( F8 ~- V, _1 P
C语言好像用#define 什么什么对程序不太好,各位帮忙写个优化办法看看呢? 用const?
' j& Q+ E# m9 O6 U4 U' q3 Z) N3 u  F% u6 D8 Z
PID.H里面主要的几个函数:
% Q0 r; ?' `6 T( M4 u
  1. void PIDperiodinit(u16 arr,u16 psc);        //PID 采样定时器设定
    + a7 R9 J* r; V7 O! n. P/ K- J/ L
  2. void incPIDinit(void);                //初始化,参数清零清零
    " q- m6 j0 H( _. t4 j
  3. int incPIDcalc(PIDtypedef*PIDx,u16 nextpoint);           //PID计算3 Y8 @- W6 Q5 ]4 X+ P! g
  4. void PID_setpoint(PIDtypedef*PIDx,u16 setvalue);  //设定 PID预期值0 b0 _* {7 ]( U, {* g- @2 G9 n
  5. void PID_set(float pp,float ii,float dd);//设定PID  kp ki kd三个参数
    . i6 L1 t# }* d% F! c$ ]1 R
  6. void set_speed(float W1,float W2,float W3,float W4);//设定四个电机的目标转速
复制代码

0 W8 ~- n4 R; K. D7 u
! }/ X) l1 Z0 @0 R( ~PID处理过程:
! _  E0 u$ z- s/ X& ?岔开一下:这里我控制的是电机的转速w,实际上电机的反馈波形的频率f、电机转速w、控制信号PWM的占空比a三者是大致线性的正比的关系,这里强调这个的目的是
# ?4 r9 ^8 C# R" v* k+ D! W因为楼主在前期一直搞不懂我控制的转速怎么和TIM4输出的PWM的占空比联系起来,后来想清楚里面的联系之后通过公式把各个系数算出来了。

; a, M% \/ C& G7 k8 z( }* e( c
3 z4 ?7 x2 g' n8 Q正题:控制流程是这样的,首先我设定我需要的车速(对应四个轮子的转速),然后PID就是开始响应了,它先采样电机转速,得到偏差值E,带入PID计算公式,得到调整量也就是最终更改了PWM的占空比,不断调节,直到转速在稳态的一个小范围上下浮动。
: w4 T2 \8 j, b9 k上面讲到的“得到调整量”就是增量PID的公式:$ D# G9 x# N. S5 g# `
  1.     int incPIDcalc(PIDtypedef *PIDx,u16 nextpoint)
    6 e& h1 V  r7 [( X9 @4 g% P
  2.     {
    / M  A6 @: @1 e" ]
  3.     int iError,iincpid;7 }  r8 d7 `6 H
  4.     iError=PIDx->setpoint-nextpoint;  //当前误差
    % p. @/ T1 H' n& q
  5.     /*iincpid=                                               //增量计算' H; ?7 s% o0 s/ j$ K1 C
  6.     PIDx->proportion*iError                //e[k]项
    4 P# Q7 s6 N0 z7 k. n9 K+ m; i- s
  7.     -PIDx->integral*PIDx->last_error          //e[k-1]4 q* W; l4 Z/ q( M% a( S" p
  8.     +PIDx->derivative*PIDx->prev_error;//e[k-2]
      w! ]( \1 u+ G% h; _% K* @7 c
  9.     */
    ) }% B7 r0 P! X6 k7 d8 u
  10.     iincpid=                                                          //增量计算
    9 z9 |! Y7 d# J0 E  r% w. {
  11.     PIDx->proportion*(iError-PIDx->last_error)
    ! Q% D6 e4 Q6 L) N
  12.     +PIDx->integral*iError
    2 W8 B  e+ P# c- I7 I" O
  13.     +PIDx->derivative*(iError-2*PIDx->last_error+PIDx->prev_error);
    ! m- _( J( g& C7 {! d+ i
  14. / @3 U5 e4 _- e
  15.     PIDx->prev_error=PIDx->last_error; //存储误差,便于下次计算
    ! x$ P, s+ `% o# {' t
  16.     PIDx->last_error=iError;
    2 ?( B/ X( ?4 v- U0 N
  17.     return(iincpid) ;7 }3 S  f, y* J( _" s3 |( Q
  18.     }
    7 f: F* i+ ~* L1 A

  19.   M. T# q( c- M' v' M

  20. 3 y# Y, \4 b* S! z$ [3 K
  21. 复制代码
    * i1 J& b( W( [
  22. # e8 l6 @  _; z; C
  23. 注释掉的是第一种写法,没注释的是第二种以Kp KI kd为系数的写法,实际结果是一样的。
    ; V5 x0 g- s3 V! E1 M, z6 w6 A
  24. 处理过程放在了TIM6,溢出周期时间就是是PID里面采样周期(区分于反馈信号的采样,反馈信号采样是1M的频率)7 |9 v+ `" V5 Y- k! \" E8 J
  25. 相关代码:
    - G9 X& I: b$ P% d# w# i# m

  26. / V, w) V+ H$ J5 ]$ r

  27. # G7 c/ r& [, k* ~; q& d
  28.     void TIM6_IRQHandler(void)        //        采样时间到,中断处理函数
    1 l. T, g  t2 H( u$ m' ^& s
  29.     {( `. P8 Z- p. C1 X

  30. 6 q% R* h( w# H
  31.     if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET)//更新中断
    ; [  a* j$ F# S- T4 m$ J# e$ H9 ]4 W
  32.             {
    2 h/ @4 J3 c: Z
  33.             frequency1=1000000/period_TIM4        ; //通过捕获的波形的周期算出频率  R  a% t1 W" B: V" A+ u, u
  34.             frequency2=1000000/period_TIM1        ;
    # ~5 t2 W4 [6 g, b! o# G7 S
  35.             frequency3=1000000/period_TIM2        ;
    9 U- U, B9 E8 W5 C
  36.             frequency4=1000000/period_TIM5        ;, x; t+ C+ L* i9 |: g
  37.     /********PID1处理**********/
    8 f; m' b2 A8 f3 O
  38.             PID1.sum_error+=(incPIDcalc(&PID1,frequency1));         //计算增量并累加. N7 V/ u0 r, [7 h
  39.            pwm1=PID1.sum_error*4.6875  ;   //pwm1 代表将要输出PWM的占空比1 {2 F. A3 V- }) _) `4 |
  40.               frequency1=0; //清零0 R4 X8 `, s2 {. M" V6 P
  41.          period_TIM4=0;
    - o0 p( `& S. j5 l
  42.     /********PID2处理**********/; z0 [% g/ m$ r: x
  43.              PID2.sum_error+=(incPIDcalc(&PID2,frequency2));         //计算增量并累加  Y=Y+Y'0 ^9 q2 ]! N' N# m4 u4 V' z0 i) N
  44.              pwm2=PID2.sum_error*4.6875 ;   //将要输出PWM的占空比* a* E( {+ I7 s& c6 V' ^/ ~
  45.             frequency2=0;
      C. Y+ Q3 q4 v9 H8 g
  46.             period_TIM1=0;
    $ A: l( o2 P& L2 {$ C  h, K
  47.     /********PID3处理**********/2 r1 c2 {9 B! q" S/ t: h6 {
  48.              PID3.sum_error+=(incPIDcalc(&PID3,frequency3));          //常规PID控制
    + f( S  k3 ^; |" O! J
  49.             pwm3=PID3.sum_error*4.6875 ;   //将要输出PWM的占空比
    5 D+ s% o6 ~  o8 K4 h
  50.             frequency3=0;) M3 i: s9 V8 K6 K) l
  51.             period_TIM2=0;5 v5 X( H1 a' B
  52.     /********PID4处理**********/3 U4 W, z8 B; H7 T- o' _: x
  53.                 PID4.sum_error+=(incPIDcalc(&PID4,frequency4));         //计算增量并累加; |, n4 C, |% O( ~
  54.              pwm4=PID4.sum_error*4.6875 ;   //将要输出PWM的占空比1 F' y' ~+ P, \
  55.             frequency4=0;
    . L2 S+ A$ b/ z, i" J0 K# \3 ^9 B
  56.             period_TIM5=0;
    ! ^) ]5 p8 Q3 d& X( w# {7 k& L
  57.               }
    5 E, t4 r" A* O0 @9 H3 g. G
  58.     TIM_SetCompare(pwm1,pwm2,pwm3,pwm4);             //重新设定PWM值
    1 h; h% H, D% P' h
  59.     TIM_ClearITPendingBit(TIM6, TIM_IT_Update); //清除中断标志位
    / S; g; N' c$ p/ H/ _
  60.     }
复制代码

1 d8 R( r" _& j# _+ G# s+ {9 \0 i6 B7 k! [+ Y
上面几个代码是PID实现的关键部分
7 U7 i; ]% x- B, Q# m6 r
- t6 E/ u1 [: @+ |整定过程:" x9 L6 h7 h% ]) ?7 g
办法有不少,这里用的是先KP,再TI,再TD,在微调。其他的办法特别是有个尼古拉斯法我发现不适合我这个控制对象。6 w5 B. K5 H0 r+ n$ U7 T
先Kp,就是消除积分和微分部分的影响,这里我纠结过到底是让Ti 等于一个很大的值让Ki=Kp*(T/Ti)里面的KI接近零,还是直接定义KI=0,TI=0.
  f. C# q! \8 x) D6 a& g然后发现前者没法找到KP使系统震荡的临界值,第二个办法可以得到预期的效果:即KP大了会产生震荡,小了会让系统稳定下来,当然这个时候是有稳态误差的。
; r, O) A% o6 b随后把积分部分加进去,KI=Kp*(T/Ti)这个公式用起来,并且不断调节TI 。TI太大系统稳定时间比较长。# g& ~/ X& Y  Y1 |' R9 _
然后加上Kd        =Kp*(Td/T),对于系统响应比较滞后的情况效果好像好一些,我这里的电机反映挺快的,所以Td值很小。' I8 h7 x; r* D( ~
最后就是几个参数调节一下,让波形好看一点。这里的波形实际反映的是采集回来的转速值,用STM32的DAC功能输出和转速对应的电压,用示波器采集的。
( p1 F: T* p  u( N% e最后的波形是这样的:: Z/ [2 J0 r5 }' g
3.jpg
/ n/ T  g: g7 u; T最后欢迎大家拍砖,有批评才会让我更加进步!8 t7 t7 p7 x, p& v6 I' k
最后把PID文件放上来 pid.zip (2.88 KB, 下载次数: 134)
收藏 5 评论17 发布时间:2017-12-26 15:40

举报

17个回答
zero99 回答时间:2017-12-26 16:11:12
大佬,这样插代码效果更加哦
9 x" f8 k+ s' U3 y. d
) A  G* a! `! s1 i
  1. 测试代码( ]3 A6 X/ ]* n6 U& D
  2. 测试代码
    * N6 r. ]" L- w* t( w, f! c' @
  3. 测试代码
    + T9 K% F) Z. \1 s% G
  4. 测试代码
复制代码

" K5 k5 w0 ~8 {( G# W$ K' u" E4 i, p' U- \4 T
333333.png 5 G5 w+ ]% ~/ t0 c7 Y$ Q; f
二子 回答时间:2018-10-3 11:10:48
nyszx 发表于 2017-12-26 15:415 D- \! p! e6 F: E
再付个网上的资料
9 Y8 U( N6 a+ c  H0 t9 a
这是个好东西
$ D* i* [: r: y) X, i书到用时方恨少
4 _6 S2 J5 ]5 Y2 p/ s0 c9 S& y. O果断收藏
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
学习了,谢谢!/ p& g4 Y4 Y2 }% Z5 V& T6 b" l2 F
板子粉丝 回答时间: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 手机版