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

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

[复制链接]
nyszx 发布时间:2017-12-26 15:40
本帖最后由 nyszx 于 2017-12-26 19:31 编辑
, X8 K5 {: E& l# A" i, K+ D
5 Y6 r; x* s4 ]8 ~原帖:【分享】增量式PID的stm32实现,整定过程& x) P- \, ^3 J0 u2 \
原文网址:http://www.amobbs.com/thread-5575823-1-1.html" l* e7 v( y0 p! w* [, b
出处:阿莫电子论坛
2 K% Y+ G9 t! I7 J作者:tim4146
' Y4 C9 K+ W8 c3 F" v9 h% i感谢大家最近的帮忙,让我顺利做完增量PID功能,虽然PID不是什么牛逼的东西,但是真心希望以后刚刚接触这块的人能尽快进入状态。
; g+ E8 x9 D9 E, ?也下面我分享一下近期的这些工作吧。欢迎大家批评指点~
1 |5 m+ ^- Z- w, {9 G
7 h% ~9 C- ^1 d: w# u8 Y$ b首先说说增量式PID的公式,这个关系到MCU算法公式的书写,实际上两个公式的写法是同一个公式变换来得,不同的是系数的差异。5 R9 F! l8 t7 G
资料上比较多的是:1 U$ S0 n* s3 ~* C& e
1.jpg
3 ?: A7 ]% s2 D; X还有一种是:- i; O- n% X% d& F6 D+ ^4 m' b
2.jpg
3 a0 i* H2 E' Y* v感觉第二种的Kp Ki Kd比较清楚,更好理解,下面介绍的就以第二种来吧。(比例、积分、微分三个环节的作用这里就详细展开,百度会有很多)
0 ]3 E* _7 w! G1 ?$ h$ P, k2 I! Z! Z2 a2 o
硬件部分:
9 w: M( {: C6 L2 s# s控制系统的控制对象是4个空心杯直流电机,电机带光电编码器,可以反馈转速大小的波形。电机驱动模块是普通的L298N模块。: o. c: R; R: b# z: C
芯片型号,STM32F103ZET6
, p! E, j) ]6 l9 ~: ~9 E4 s* b) v, d5 `" {
软件部分:
' S1 _8 O" y3 B0 H% z3 f- TPWM输出:TIM3,可以直接输出4路不通占空比的PWM波
3 _1 X' [, }* Q. K6 V0 F0 [2 KPWM捕获:STM32除了TIM6 TIM7其余的都有捕获功能,使用TIM1 TIM2 TIM4 TIM5四个定时器捕获四个反馈信号
4 }  E3 O' R6 K) L  {2 ], YPID的采样和处理:使用了基本定时器TIM6,溢出时间就是我的采样周期,理论上T越小效果会越好,这里我取20ms,依据控制对象吧,如果控制水温什么的采样周期会是几秒几分钟什么的。/ g+ Z. r1 T; |5 d5 n: B

0 {( B: Z5 r, P; ]9 ]1 H- t上面的PWM输出和捕获关于定时器的设置都有例程,我这里是这样的:. P& U7 w+ N( [* I. ]
TIM3输出四路PWM,在引脚 C 的 GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9输出% a8 e6 A# A! ?
四路捕获分别是TIM4  TIM1  TIM2  TIM5   ,对应引脚是:  PB7 PE11 PB3 PA1

6 y6 q0 U5 p' _' V# d4 Y高级定时器tim1的初始化略不同,它的中断”名称“和通用定时器不同,见代码:
0 f9 W/ H: q2 W1 ?" t; N
  1. /*功能名称IM3_PWM_Init(u16 arr,u16 psc)
      l: M+ M' \( p( m  n! l4 F4 M+ \7 a
  2.         描述      TIM3产生四路PWM
    $ K; l  e9 X7 h+ Z
  3. */
    2 M; t: ^' U( G# I6 a  C; g
  4. void TIM3_PWM_Init(u16 arr,u16 psc)
    / P( g+ T. ~/ c* D
  5. {4 K1 w' I8 M, t$ T2 f# D
  6.         GPIO_InitTypeDef GPIO_InitStructure;- X5 C$ f4 Q; K! Y7 T0 F( A' |' Y
  7.         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    - R2 w4 V+ T  @: |& _$ ]2 W- a2 d  q
  8.         TIM_OCInitTypeDef  TIM_OCInitStructure;/ p" ^- m- t8 X- [
  9.   G( m% z6 D# o) x$ R* _" X# y
  10. 2 c+ J2 x* t* B; f, H% {
  11.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    # z7 M* b* _7 I
  12.          RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC  | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟使能' C" f  n3 I2 u5 z3 J! |' v$ z
  13.   N4 y6 R& V2 p' C  M. R8 W
  14.   GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE); //Timer3全映射 GPIOC-> 6,7,8,9                                                                             //用于TIM3的CH2输出的PWM通过该LED显示
    + @3 v1 ?( m  a! K5 i
  15. * S, a# `- }1 [$ K. w1 P; z8 d0 D
  16.    //设置该引脚为复用输出功能,输出TIM3 CH1 CH2 CH3 CH4 的PWM脉冲波形
    9 K5 G1 z4 W1 L1 b
  17.         GPIO_InitStructure.GPIO_Pin =GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9; //初始化GPIO
    9 s) q; p- a* s4 C: J0 d
  18.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出" t' {+ W( q" Z0 U( x, p% ?
  19.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    ' h( a" Y4 U; w" x
  20.         GPIO_Init(GPIOC, &GPIO_InitStructure);/ G8 W2 U# b9 K
  21.         GPIO_ResetBits(GPIOC,GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9);//默认电机使能端状态:不使能, `4 w# ~6 J3 {5 f( }$ V
  22. ' y3 _6 X5 ~! v1 |7 }1 _/ d
  23.         TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
    " o9 u3 i% ?0 M, R0 E6 [
  24.         TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  这里是72分频,那么时钟频率就是1M
    ) S2 s' d/ P* f: H
  25.         TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
    ' _4 A+ W& }! X5 o( u0 _# r! ^
  26.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    4 E7 J& a) z" M
  27.         TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位3 S6 w2 d. \" {* J$ A4 y  s# t  @
  28. # @6 x7 s: g1 U! c
  29. 5 o) z8 f3 G( G, S% }- n) K
  30.         TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
    # r. X$ a( ~! a! B% E% n( u
  31.         TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能3 K8 S4 o4 k4 [7 c4 S0 C
  32.         TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值
    & n# J& L( }- N: z0 h' D# s6 ^
  33.         TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高! _) D; w$ q5 Z8 @0 D

  34. 1 F5 P  S/ ?: n4 C
  35.         TIM_OC1Init(TIM3, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx4 R" \: W6 Y# p9 ^% B
  36.         TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIMx在CCR1上的预装载寄存器
    ( M$ F8 x) R* ]4 \6 ^
  37. ; y" }2 U9 [( Z4 a2 F: g$ o
  38. 6 o- {! B, c  J% R+ \
  39.         TIM_OC2Init(TIM3, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx) G1 J/ C7 D) ]- [% s( A: a
  40.         TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIMx在CCR2上的预装载寄存器% g* o  }7 x" C% C; s
  41. ) Z1 Z/ l5 R% x" q& y& w
  42.         TIM_OC3Init(TIM3, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx) \* T& E& E8 ~
  43.         TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIMx在CCR3上的预装载寄存器; F/ Q& J" s- J" D: w  y
  44. - `+ Q3 t" F( w. B, U
  45.         TIM_OC4Init(TIM3, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx4 w% a% x5 n  c0 E7 @+ o1 B
  46.         TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIMx在CCR4上的预装载寄存器
    - o" |  d9 U) z4 I$ E! _

  47. ( B  e9 O* u7 d+ H9 E& v
  48.         TIM_ARRPreloadConfig(TIM3, ENABLE); //使能TIMx在ARR上的预装载寄存器) b1 ]% @* o( N% P8 n' m

  49.   X9 \$ F) s+ T

  50. " o! n; F1 p- ?: |9 {# z. z$ X
  51.         TIM_Cmd(TIM3, ENABLE);  //使能TIMx外设
    / i3 H" U% Q/ j! V% T+ R: o

  52. : c7 }; R6 U" B2 s+ M! K
  53. % \4 C8 n4 J- {7 R0 P
  54. }( g  F/ Z( n9 ?

  55. 8 L7 C. b" F: p  R0 h3 p, `

  56. * _7 b0 p  z( H; W4 g0 i! v( `
  57. 1 N7 V8 U4 Z3 y3 i, `9 @
  58. /*功能名称TIM4_PWMINPUT_INIT(u16 arr,u16 psc)+ U! x! S' h4 R% x6 H; m9 b5 Y
  59.   描述      PWM输入初始化*/
    / c' E/ f: F3 `+ z
  60. , ]6 o  \; b* o8 A1 c7 t0 n+ L
  61. void TIM4_PWMINPUT_INIT(u16 arr,u16 psc)2 J, k( t, B: B, `
  62. {
    : I" u5 ?, m) {* q6 S  d* q
  63. $ k0 H* A) n( p9 D
  64.         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;        //TIM的初始化结构体- N) e9 F. V3 ]- P8 A2 T1 c
  65.         NVIC_InitTypeDef NVIC_InitStructure;                        //中断配置! A" @6 y* ~7 g# i5 s6 y1 A) V! C
  66.         TIM_ICInitTypeDef  TIM4_ICInitStructure;                 //TIM4  PWM配置结构体/ c6 D" X7 y: z4 z
  67.         GPIO_InitTypeDef GPIO_InitStructure;                         //IO口配置结构体' V5 ^7 F  K5 U- _! J
  68. 8 A9 z" F* v% c) c" W' H$ `
  69.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);     //Open TIM4 clock" p+ K& G) f2 N- a2 B
  70.   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  //open gpioB clock
    / I! x  y8 n' K' T

  71. : w) r) w4 y- T
  72.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;             //GPIO 7- w; c6 a, u) a4 d2 ~8 b/ ?1 F7 X
  73.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;          //上拉输入2 q6 o" f. W# H* y0 }, g
  74.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    & k. N0 h$ d8 ?
  75.   GPIO_Init(GPIOB, &GPIO_InitStructure);5 f7 v7 ?0 u& ?" O7 E* h0 u  t
  76. ) U" O4 m# X! z/ l& p# p
  77.         TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
    ' h2 [; k: s# J
  78.         TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
    7 h) E5 o1 T# C6 C/ ^
  79.         TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim" |2 F2 T& }/ L
  80.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式" @# {/ m* r' w4 R  y
  81.         TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
    4 M5 b: X3 z; P2 O! V$ P& g

  82. # J/ ?2 H/ I% O4 ~- |

  83. 6 X, l- q1 l+ ?
  84.         /*配置中断优先级*/9 o5 w& x- G$ P
  85.         NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;1 C6 B+ Q! m1 u8 H6 t/ ~8 M
  86.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    . d+ {% V, P' E
  87.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    ; m5 l2 W9 ~  p) b
  88.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;( ~2 s) W. f) [+ e: `, _) w$ q8 d$ Q9 `
  89.   NVIC_Init(&NVIC_InitStructure);
    ' Q! H2 u5 h* O1 T# o

  90. $ P. P& K" {/ [0 k: T
  91.   TIM4_ICInitStructure.TIM_Channel = TIM_Channel_2;4 l! w7 k! O8 i" ?6 u
  92.   TIM4_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;" G# G) W( x1 O2 e6 F5 y- v
  93.   TIM4_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
    9 K4 L( z' Q; `) Q4 v0 P; G1 B; y
  94.   TIM4_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    & @1 ?: x1 G; }* l9 d- B8 g, z9 q
  95.   TIM4_ICInitStructure.TIM_ICFilter = 0x3;   //Filter:过滤
    3 G% N! E3 k  w% e

  96. 6 l8 R1 v) s$ F% j: G7 D" `
  97.   TIM_PWMIConfig(TIM4, &TIM4_ICInitStructure);     //PWM输入配置& e1 x, B2 l4 I8 k+ ~  L
  98.   TIM_SelectInputTrigger(TIM4, TIM_TS_TI2FP2);     //选择有效输入端
    # _" i) R  Q3 j, o
  99.   TIM_SelectSlaveMode(TIM4, TIM_SlaveMode_Reset);  //配置为主从复位模式
    . T; o5 ^4 V( g9 I9 t1 w5 ]
  100.   TIM_SelectMasterSlaveMode(TIM4, TIM_MasterSlaveMode_Enable);//启动定时器的被动触发
    2 K* y* Z& d$ Y, M" j0 F0 j9 S
  101.   TIM_ITConfig(TIM4, TIM_IT_CC2|TIM_IT_Update, ENABLE);          //中断配置; U5 C0 \% D+ k. L0 \( ^+ H) p
  102.   TIM_ClearITPendingBit(TIM4, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位
    1 S9 c: Z+ }: o6 z
  103.   TIM_Cmd(TIM4, ENABLE);
    : q! q/ J2 f& q/ R$ D" p8 V8 V& ^- ]
  104. }
    2 U& F2 n* _: g" F

  105. * d- N  p' Y! L

  106. / w+ j+ [! c  C7 c1 n
  107. void TIM4_IRQHandler(void)
    6 E+ K5 T$ c, `
  108. {- Y: X. G; M7 d9 u6 j, W6 L
  109. 1 U, B0 r3 u  d: _
  110.                 if (TIM_GetITStatus(TIM4, TIM_IT_CC2) != RESET)//捕获1发生捕获事件
    : @: Q, ~  [/ X/ h3 N6 z8 q
  111.                         {6 b# g3 A- q6 Q& h( o
  112.                                 duty_TIM4    =   TIM_GetCapture1(TIM4);          //采集占空比
    3 p  L: E" F4 d: D  S
  113.                if  (TIM_GetCapture2(TIM4)>600)         period_TIM4        =        TIM_GetCapture2(TIM4);//简单的处理
    $ G$ q5 t- w7 S# K4 l' s5 A$ d: D7 P- t
  114.                                 CollectFlag_TIM4 = 0;
    5 i$ f6 h+ o& Y9 n- F8 h+ a
  115.         }
    2 F; q# @! h2 P' A
  116.                 TIM_ClearITPendingBit(TIM4, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位
    5 e& J' i' G( S
  117. }& [9 ]. l/ y, B, K) V
  118. 2 P  U/ C5 l6 b9 X
  119. % I! {4 G2 A2 S: z3 G3 z
  120. /*功能名称TIM1_PWMINPUT_INIT(u16 arr,u16 psc)) I  J2 g1 R2 Y* c) d. k0 t7 d2 o
  121.   描述      PWM输入初始化*/! n, [% y" S, Q4 A0 D4 O; _- V

  122. 4 |! y9 N/ g- Z8 T5 q7 {
  123. void TIM1_PWMINPUT_INIT(u16 arr,u16 psc)
    ) K6 a, @6 c& J- I
  124. {
    $ n3 F1 E+ s' R: ~
  125. ( g# r3 H' D  f' S; i" f3 `
  126.         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;        //TIM的初始化结构体
    ( X4 [# Q% s1 A2 V- O5 N% b" M
  127.         NVIC_InitTypeDef NVIC_InitStructure;                        //中断配置! I: x; S. T1 S% i4 p7 T4 }
  128.         TIM_ICInitTypeDef  TIM1_ICInitStructure;                 //PWM配置结构体
    % [. S; R; [, @
  129.         GPIO_InitTypeDef GPIO_InitStructure;                         //IO口配置结构体
    / H' B" g  V  m- z6 `% A
  130. ( L) j* c0 |/ A' G! N  ^
  131.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);     //Open TIM1 clock
    * o; \; X  U* h1 z% g& t
  132.   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);  //open gpioE clock
    1 }  z1 j* I9 H! x7 X: f; y2 u
  133.    GPIO_PinRemapConfig(GPIO_FullRemap_TIM1, ENABLE); //Timer1完全重映射  TIM1_CH2->PE11
    : U0 T6 f* F, Q- v: B0 H
  134.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;             //GPIO 112 H! L5 M" k6 X' }& {3 v7 l
  135.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;          //上拉输入) @3 g- X+ m/ f6 P
  136.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;7 ]2 t( ?1 ~1 c& m8 c
  137.   GPIO_Init(GPIOE, &GPIO_InitStructure);
    # K6 z* k" u/ S: Y- }9 K
  138. - }( `6 x% @& L/ w
  139.         TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
    ) l6 @2 Z5 w* U7 m
  140.         TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
    # {  {, M8 F/ u3 |3 @2 G
  141.         TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim. X! a/ R; ^6 f
  142.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    ; h( G  A; b$ z
  143.         TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位0 G  z# T, |% r' W9 z
  144. & Q4 E' E1 Y5 F! w! }

  145. + F- O" u/ }' u, F0 Z" C4 y" Z* F3 u
  146.         /*配置中断优先级*/
    6 w* |0 v. z7 G
  147.   NVIC_InitStructure.NVIC_IRQChannel =  TIM1_CC_IRQn;   //TIM1捕获中断
    3 `) Y) S" H# R8 _
  148.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;8 Z2 _$ l  x( }2 K& V+ Z; I5 E
  149.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;2 O. a' m# A1 }1 v* D% k+ d. o
  150.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;; M- p( }4 `: {) s2 [: D
  151.   NVIC_Init(&NVIC_InitStructure);
    8 O8 ~: e. j; a# r9 \. F

  152. 5 n$ ~1 u6 X! P0 ?" x
  153.   TIM1_ICInitStructure.TIM_Channel = TIM_Channel_2;
    ) R, {, Y: U  L8 ]* F8 w  n. ?
  154.   TIM1_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
    $ ^2 {: A" ~2 l7 }
  155.   TIM1_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
    # _+ b/ U9 y; ~7 w0 c2 g7 ~! g
  156.   TIM1_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    " i) Z" i" _) x7 r
  157.   TIM1_ICInitStructure.TIM_ICFilter = 0x03;   //Filter:过滤1 m$ T. a3 W1 n* L

  158. $ N% z# B9 p& @( a5 }
  159.   TIM_PWMIConfig(TIM1, &TIM1_ICInitStructure);     //PWM输入配置8 J" p! _7 D3 h( k. L( O8 i
  160.   TIM_SelectInputTrigger(TIM1, TIM_TS_TI2FP2);     //选择有效输入端0 b- O* x! T! u" z' R
  161.   TIM_SelectSlaveMode(TIM1, TIM_SlaveMode_Reset);  //配置为主从复位模式! t$ ]1 |7 {2 |5 P9 A9 f7 g; Z
  162.   TIM_SelectMasterSlaveMode(TIM1, TIM_MasterSlaveMode_Enable);//启动定时器的被动触发# Q0 _0 t) F. n  O  j$ ?
  163. // TIM_ITConfig(TIM1, TIM_IT_CC2|TIM_IT_Update, ENABLE);          //中断配置. i# e' ~: O" b  T1 r9 P
  164.   TIM_ITConfig(TIM1, TIM_IT_CC2, ENABLE); //通道2 捕获中断打开
    % r0 c. I5 m8 `) \( k
  165.   //TIM_ClearITPendingBit(TIM1, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位
    ( P4 X4 q0 W! v2 B5 Z
  166.   TIM_Cmd(TIM1, ENABLE);
    2 [. x! ~+ t; n. M, A4 C
  167. }0 |0 U1 O5 [# d

  168. : Z5 `6 d; v8 x+ b  r1 M. y

  169. * @6 E" q1 J( [% Y9 o. s+ R
  170. void TIM1_CC_IRQHandler(void)" G  R( m& p- P2 O
  171. {/ \" ^& I5 V4 j; j" y. W; w

  172. ! ?" I# ?% q/ y. \2 Q3 L! {/ Y- s
  173.         {: V( O1 b4 T4 `) I( h# S4 |3 P
  174.                 if (TIM_GetITStatus(TIM1, TIM_IT_CC2) != RESET)//捕获1发生捕获事件0 u3 W) H: I  i) q- L. v
  175.                         {3 s, T5 ]" S9 D0 H. I
  176.                                 duty_TIM1    =   TIM_GetCapture1(TIM1);          //采集占空比  k' u7 o, I# g: r9 z! f% E
  177.                            if  (TIM_GetCapture2(TIM1)>600)         period_TIM1        =        TIM_GetCapture2(TIM1);) ?% P+ `6 f( {" B7 P# v
  178.                                 CollectFlag_TIM1 = 0;
    . ~" V+ [+ G9 {. }0 M: C+ m3 M
  179.                         }( g2 w) r* S9 \
  180.         }
    & E* ~5 y! Y2 H$ i$ \
  181.                 TIM_ClearITPendingBit(TIM1, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位
    / @/ G' a. q1 j0 m' w7 }  t
  182. }$ Q% I7 D: s3 F
  183.   A# B( U) I3 V6 R; I3 ~

  184. & {! a. p2 V) C" k' o5 b$ B. X1 C
  185. /*功能名称TIM2_PWMINPUT_INIT(u16 arr,u16 psc)! ?, B' x2 \4 s$ O
  186.   描述      PWM输入初始化*/& c' V( |  t1 n7 I8 F, F
  187. / m$ B" C; L" c5 h/ e' N
  188. void TIM2_PWMINPUT_INIT(u16 arr,u16 psc)
    ! i$ q0 X7 |" y6 w4 W* g6 Y; z
  189. {
    : K- ]0 Y/ _( l! |) M# \4 D5 T

  190. , d  z) n  Z: l& K  ]
  191.         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;        //TIM的初始化结构体/ W. Z/ Y4 X" c2 l) n/ c" l
  192.         NVIC_InitTypeDef NVIC_InitStructure;                        //中断配置
    / y  o1 `9 l5 v+ l6 l
  193.         TIM_ICInitTypeDef  TIM2_ICInitStructure;                 //TIM2  PWM配置结构体: \. w# o! U& c! D6 l) R* g7 q
  194.         GPIO_InitTypeDef GPIO_InitStructure;                         //IO口配置结构体
    ' X4 q4 Q  h) u( N3 y( k8 d# m
  195. : K4 @8 k9 `( G$ [+ h
  196.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);     //Open TIM2 clock
    ) J' ]0 d! J) x2 C
  197. // RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  //open gpioB clock
    + ]2 m  i0 Z6 r- T% n# n5 r6 e) k
  198. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB  | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟
    / F; p6 B% A7 I  M8 {3 L$ B1 t
  199. GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);          //关闭JTAG; u% d! J/ B0 o; l5 g- G
  200.          GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE); //Timer2完全重映射  TIM2_CH2->PB35 j! w+ K  F0 r8 h# E
  201. * ^7 ^' l7 o: ^9 p" K8 M
  202.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;             //GPIO 3
    $ I3 x9 V: J$ h/ y' Y1 }
  203.         GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_IPU;          //浮空输入 上拉输入
    ' N: u6 q) R" i( o
  204.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    2 `1 r$ f1 o$ S5 e
  205.         GPIO_Init(GPIOB, &GPIO_InitStructure);0 o( Z! a; I8 @0 h, L7 C4 B
  206. + L" P( N, d2 n/ Y+ H  D
  207.         TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
    * ^& v7 Y5 H2 G) E; q) y
  208.         TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值% ?% r% H* P$ f/ O/ }& k. f! _4 z
  209.         TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim( O2 R8 P& T+ a: C& L' H$ y4 o
  210.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式; |/ L1 p  ?( [: j" ~9 y. W
  211.         TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位2 I$ |: z1 _' Z) Z! E3 X0 l
  212. 2 r- _) G0 Y. i0 i6 P
  213. * V7 \0 O( _( X& x$ P2 Y2 `% B! V8 T
  214.         /*配置中断优先级*/% {! p% S% y' e2 U
  215.         NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    7 N4 Z9 C8 @6 r, s6 w4 E
  216.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    $ y7 }. c8 [; d, W# q) B
  217.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    4 W. Q& m' o) j# Z* r) k2 Z  ~4 H
  218.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    ( e  e0 u1 T+ d6 R( I# ]7 j
  219.   NVIC_Init(&NVIC_InitStructure);
    8 w3 Q5 j  q- c. i9 H* F
  220. + C6 A' D. r6 R: m" E
  221.   TIM2_ICInitStructure.TIM_Channel = TIM_Channel_2;. r. ~+ Y$ n/ l1 v6 A% o/ _& O
  222.   TIM2_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
    # y7 P1 d: g, n2 {) I. F# o* [
  223.   TIM2_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
      W( N( [; v( `1 N
  224.   TIM2_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    & e. n8 h2 f2 x/ V+ z( J
  225.   TIM2_ICInitStructure.TIM_ICFilter = 0x3;   //Filter:过滤
    : u- m) l6 M  d$ t+ E. u8 U
  226. . g( d- e7 b# v  F0 I( D
  227.   TIM_PWMIConfig(TIM2, &TIM2_ICInitStructure);     //PWM输入配置
    " `% N' G: D0 O2 o
  228.   TIM_SelectInputTrigger(TIM2, TIM_TS_TI2FP2);     //选择有效输入端
    4 [( m6 e2 ?+ Z2 m4 B' H& @8 l7 g0 \
  229.   TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset);  //配置为主从复位模式* W4 A0 ?' g) ^5 y9 V
  230.   TIM_SelectMasterSlaveMode(TIM2, TIM_MasterSlaveMode_Enable);//启动定时器的被动触发
    0 L0 a$ `7 i' B  C
  231.   TIM_ITConfig(TIM2, TIM_IT_CC2|TIM_IT_Update, ENABLE);          //中断配置% T7 _8 b( E" W5 w
  232.   TIM_ClearITPendingBit(TIM2, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位" M9 E* t" A! p7 m- [
  233.   TIM_Cmd(TIM2, ENABLE);
    - d. R& H( z2 y0 e# a. m% `
  234. }" C" o  ?' x9 z" f5 Q  ]1 J

  235. " }: `& m8 o' O) q& }7 y
  236. & \8 Q3 c2 s9 p, W1 b
  237. void TIM2_IRQHandler(void)
    1 t7 x  N2 D5 O
  238. {0 ^  m, e" R; e2 @- U# {5 ~" T7 l
  239.         {
      d9 B$ Z# v# q- @
  240.                 if (TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET)//捕获1发生捕获事件: I0 D" ]4 x( Y9 X
  241.                         {+ C+ F5 |1 q/ ?# r6 T0 |* [
  242.                                 duty_TIM2    =   TIM_GetCapture1(TIM2);          //采集占空比
    # O3 ?) `: {5 y% U2 K: `' C
  243.                            if  (TIM_GetCapture2(TIM2)>600)         period_TIM2        =        TIM_GetCapture2(TIM2);
    7 Z* W7 F6 y0 m! R. B2 k; I
  244.                                 CollectFlag_TIM2 = 0;9 c6 N: \# b3 Z: C/ _# T
  245.                         }4 d  Q0 r, G% e2 e
  246.         }
    * W; ~% {: i! M9 g8 o& C
  247.                 TIM_ClearITPendingBit(TIM2, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位7 I' T% H, M1 g1 w: y
  248. }
    # I. v9 [) W3 y6 g6 a

  249. " G# g1 c, l5 _. v( }& }
  250. /*功能名称TIM5_PWMINPUT_INIT(u16 arr,u16 psc)
    ; d% r* Q- u+ `) C
  251.   描述      PWM输入初始化*/
    5 t  m: s: @) q+ a7 x3 V
  252. 8 K( S8 V) o/ U
  253. void TIM5_PWMINPUT_INIT(u16 arr,u16 psc)% x$ o" T! L" i1 i2 t6 x
  254. {
    : q6 H7 @  @5 w& @2 [3 Z

  255. 7 t# S1 I3 N, a1 u. E* t& `: d
  256.         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;        //TIM的初始化结构体2 }  p# _: ^- B
  257.         NVIC_InitTypeDef NVIC_InitStructure;                        //中断配置
    6 f( r4 ^( M  \1 o! W* E4 A: ~
  258.         TIM_ICInitTypeDef  TIM5_ICInitStructure;                 //TIM4  PWM配置结构体, j! a/ i: o) O" q# g+ a) P- Z) X
  259.         GPIO_InitTypeDef GPIO_InitStructure;                         //IO口配置结构体
    3 D' X" w% s/ B$ Z
  260. * O! p" U9 @6 S. g/ Z/ \( p
  261.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);     //Open TIM4 clock
    ! e7 y+ N* z  |
  262.   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  //open gpioB clock3 y/ U# Q# ]- C  ?! H

  263. 3 v1 k5 E' D" z3 _
  264.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;             //GPIO 12 w7 h% d6 R- _8 `3 }" ]1 W
  265.   GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_IPU;          //浮空输入 上拉输入$ k) f' O  P# g( T! _" u' r
  266.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    % d4 I2 H1 C4 Y  G$ b8 }4 z& K7 N: z
  267.   GPIO_Init(GPIOA, &GPIO_InitStructure);
    ! c7 |5 y* o/ h" C
  268. ; c- a# Q2 }  b4 p% o) E
  269.         TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值' A1 F* K% u$ O
  270.         TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值: }. J2 V3 ^6 ?  t. K! M# ^# i) \% T, J
  271.         TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim# N8 V4 p/ `. D0 |2 d/ h3 n& _
  272.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    - l; u/ q: r+ z8 a
  273.         TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位& g& p; L" _( L, L

  274. ( F( p$ }3 o) c1 f: x  L" [

  275. ( ^% m! R2 E% }
  276.         /*配置中断优先级*/
      N$ |4 h; P; s. z, g9 G
  277.         NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
    : h& S1 N: q8 F) c1 f
  278.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;( Z2 G0 E9 f: C3 Y, t
  279.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    + n( p# W* f; {
  280.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;& }* V* \$ I, u3 Y6 N6 Z
  281.   NVIC_Init(&NVIC_InitStructure);" \, y9 g, s* _9 W* y1 J2 D
  282. . M$ V2 {0 t' K, F! u
  283.   TIM5_ICInitStructure.TIM_Channel = TIM_Channel_2;
      [4 Y" Z/ L# q; X) d
  284.   TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
    ) H+ [7 O7 |5 W9 j
  285.   TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;* N! X0 h0 ~3 `/ \4 c
  286.   TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    : ?7 \) ]( v4 J6 i1 _; t! v  t
  287.   TIM5_ICInitStructure.TIM_ICFilter = 0x3;   //Filter:过滤5 M; E) h# [) T
  288. ) M+ c# j$ `. o9 n
  289.   TIM_PWMIConfig(TIM5, &TIM5_ICInitStructure);     //PWM输入配置
    : @! T7 X1 `0 h
  290.   TIM_SelectInputTrigger(TIM5, TIM_TS_TI2FP2);     //选择有效输入端- x% y1 Y- {: y+ H& v6 r9 X
  291.   TIM_SelectSlaveMode(TIM5, TIM_SlaveMode_Reset);  //配置为主从复位模式
    4 w+ Q6 T6 ^+ D7 y# W
  292.   TIM_SelectMasterSlaveMode(TIM5, TIM_MasterSlaveMode_Enable);//启动定时器的被动触发
    * N7 n. S" }$ ~3 H) D
  293.   TIM_ITConfig(TIM5, TIM_IT_CC2|TIM_IT_Update, ENABLE);          //中断配置
    ( q  @3 {: C4 [) l
  294.   TIM_ClearITPendingBit(TIM5, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位
      \  N8 I( [# W3 b, x/ A, L: ?$ E- J
  295.   TIM_Cmd(TIM5, ENABLE);
    # Z7 L; M" H( q, l% i9 R! j
  296. }3 R. S2 N7 P2 C( A1 J) }8 W  ~

  297. / u; a- t' C  }% d/ R

  298. " r8 S$ _" v$ f7 ]5 P
  299. void TIM5_IRQHandler(void)
    ( b7 Y3 g; c5 d5 d0 R& M
  300. {
    9 B" x$ w% s! q+ U4 ^" r
  301.         {8 \+ |" `4 _: H7 E
  302.                 if (TIM_GetITStatus(TIM5, TIM_IT_CC2) != RESET)//捕获1发生捕获事件4 r& \( L* Y, k5 y1 N8 q( C8 U
  303.                         {* R7 `8 O, D% R  s5 \
  304.                                 duty_TIM5    =   TIM_GetCapture1(TIM5);          //采集占空比
    9 s, ~% V$ W5 u! o$ D& w6 }' [
  305.                         if  (TIM_GetCapture2(TIM5)>600)         period_TIM5        =        TIM_GetCapture2(TIM5);- W8 \) |$ R) |) q- Q
  306.                                 CollectFlag_TIM5 = 0;
    ! [8 q8 M: K# ^
  307.                         }8 m" j) ~! Q& H, ~% @
  308.         }8 p/ M% \4 N7 w$ B8 P6 G, Z
  309.                 TIM_ClearITPendingBit(TIM5, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位
    3 Y7 v6 o2 H& R# ?$ H  O7 {( S
  310. }
复制代码

8 W/ \) L  ~! e1 d' d" w1 U' m$ ?1 U0 E% i
PID部分:. {' z3 g$ V+ Z, f% k# B
准备部分:先定义PID结构体:
& @/ U: T6 S6 \) U8 Z

  1. : I/ @5 v- U- M. ?
  2.     typedef struct% ?' O9 d$ O# e: _" {
  3.     {
    + I/ ~) W* Z: B2 L9 _
  4.     int setpoint;//设定目标
    ( x/ Y; ]2 W2 }2 c) D
  5.     int sum_error;//误差累计
    1 P6 y+ n' S2 `( y
  6.     float proportion ;//比例常数
    1 b& @4 V. V. P% Z3 p) O% S( |
  7.     float integral ;//积分常数4 e- J$ e, N2 J( Y' S; n
  8.     float derivative;//微分常数7 K8 ?! e& x- k- i5 e
  9.     int last_error;//e[-1]
      `$ `; A. u$ L$ `. L0 @2 w
  10.     int prev_error;//e[-2]; d( f3 g; l+ n- O) V
  11.     }PIDtypedef;
复制代码
/ l( s3 a; f. T. K0 ]3 j) W3 a
1 y1 e, Y' {$ q( \

, Q5 W7 o- F+ ]2 y* r" e这里注意一下成员的数据类型,依据实际需要来定的。/ ?7 D: ]: w" M9 Z
在文件中定义几个关键变量:
4 x5 |6 o1 u  y: _* b
  1. float  Kp =     0.32  ; //比例常数
    6 p# }: i/ O. \, b
  2. float  Ti =                0.09 ; //积分时间常数
    $ X% k6 u) {2 q2 |' f
  3. float Td =                0.0028 ;  //微分时间常数. K+ i5 V3 Y4 e4 b
  4. #define T                  0.02 //采样周期. x  T% C/ \1 S4 W1 J; D
  5. #define Ki     Kp*(T/Ti)        // Kp Ki Kd 三个主要参数9 V* W  }5 X2 x* k
  6. #define Kd                Kp*(Td/T)
复制代码

) z' k+ Y! b* ^# q# ^+ i8 }+ b
! u3 a- G$ r: r" Y+ n$ |C语言好像用#define 什么什么对程序不太好,各位帮忙写个优化办法看看呢? 用const?8 t$ N. q' S7 H! F3 W

) E/ U( U$ j! x# g9 G8 IPID.H里面主要的几个函数:
4 K& R0 c6 j; n3 f! `( k+ h7 P6 W1 m
  1. void PIDperiodinit(u16 arr,u16 psc);        //PID 采样定时器设定2 ?. e0 C1 i+ }9 T% }0 r9 z7 J
  2. void incPIDinit(void);                //初始化,参数清零清零
    ' S( T0 K9 H' _1 e
  3. int incPIDcalc(PIDtypedef*PIDx,u16 nextpoint);           //PID计算
    / h  K1 r6 D! S
  4. void PID_setpoint(PIDtypedef*PIDx,u16 setvalue);  //设定 PID预期值
    $ N  G, g/ A; B: e0 ^
  5. void PID_set(float pp,float ii,float dd);//设定PID  kp ki kd三个参数* g$ p% Z; e- u8 e- G* X, t1 r
  6. void set_speed(float W1,float W2,float W3,float W4);//设定四个电机的目标转速
复制代码

2 H+ r# \2 ?) s" W0 k" u# G8 o# b6 O8 v# a  i* c8 |" `9 z6 F
PID处理过程:# T/ |0 d1 T. {& n; V
岔开一下:这里我控制的是电机的转速w,实际上电机的反馈波形的频率f、电机转速w、控制信号PWM的占空比a三者是大致线性的正比的关系,这里强调这个的目的是
% ~. e* D4 F: o5 i因为楼主在前期一直搞不懂我控制的转速怎么和TIM4输出的PWM的占空比联系起来,后来想清楚里面的联系之后通过公式把各个系数算出来了。
6 }; N9 o2 i7 l7 Z

! v9 v) i, u& H9 M/ n$ W$ f正题:控制流程是这样的,首先我设定我需要的车速(对应四个轮子的转速),然后PID就是开始响应了,它先采样电机转速,得到偏差值E,带入PID计算公式,得到调整量也就是最终更改了PWM的占空比,不断调节,直到转速在稳态的一个小范围上下浮动。' c2 q* k/ @- y$ x0 o" @) V+ d# i
上面讲到的“得到调整量”就是增量PID的公式:
& z) q2 m4 r4 @
  1.     int incPIDcalc(PIDtypedef *PIDx,u16 nextpoint)
    1 f- ^- u! {2 H+ e" A$ o
  2.     {
    2 U  x0 X$ F' ~" _
  3.     int iError,iincpid;
    7 V" ?# V# n$ G: g( A$ U6 R
  4.     iError=PIDx->setpoint-nextpoint;  //当前误差
    2 m7 L" U- l. S! j: z0 W' Q# q
  5.     /*iincpid=                                               //增量计算
    : i+ P1 ?$ P, Y; U$ {1 C  F
  6.     PIDx->proportion*iError                //e[k]项' s1 f# O+ x; i! @2 h
  7.     -PIDx->integral*PIDx->last_error          //e[k-1]# _: c  \% t9 s. l( V# ]
  8.     +PIDx->derivative*PIDx->prev_error;//e[k-2]: C1 R8 X0 y% B- m7 ^
  9.     */
    4 x: ?8 A0 L6 j$ q$ ~
  10.     iincpid=                                                          //增量计算* e2 i& F8 |  t/ [! @. f, h3 _
  11.     PIDx->proportion*(iError-PIDx->last_error). g5 ^9 l. |/ q8 h1 ]) c  l# F
  12.     +PIDx->integral*iError
    1 L( h: W& F4 P5 M; V9 g0 S
  13.     +PIDx->derivative*(iError-2*PIDx->last_error+PIDx->prev_error);
    3 W: C3 ^* f' {
  14. ) d. \4 M  ~. D) V
  15.     PIDx->prev_error=PIDx->last_error; //存储误差,便于下次计算
    1 O1 S4 c; B0 a& U" M* ^" n& s
  16.     PIDx->last_error=iError;
    % l" |4 K2 q7 M1 _3 E
  17.     return(iincpid) ;- w# u, T6 x, y1 C) y; X
  18.     }& O& K4 g& |3 m! X2 a9 q* V

  19. 0 |& W) S$ z6 J+ u

  20. 6 l1 h# C+ h7 {, o1 D' B
  21. 复制代码
    ! [$ R! t- a2 |" Z( F

  22. ) k  l5 H) n4 }; p- F4 {
  23. 注释掉的是第一种写法,没注释的是第二种以Kp KI kd为系数的写法,实际结果是一样的。0 n( Q. R6 T! E  X$ d
  24. 处理过程放在了TIM6,溢出周期时间就是是PID里面采样周期(区分于反馈信号的采样,反馈信号采样是1M的频率)
    , s& q. z( Z5 t( w( o, k- G
  25. 相关代码:
      k! b% x) I$ ]  }
  26. 4 j* ^) q7 i- {3 k
  27. $ i, j2 M- C8 z4 D
  28.     void TIM6_IRQHandler(void)        //        采样时间到,中断处理函数
    * z4 b$ n. O9 ^, Z" ]
  29.     {
    $ f9 s$ L! P1 i) J( t) `
  30. ' F0 N3 i& u9 l+ J* D: X1 k* }
  31.     if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET)//更新中断
    4 Q3 v6 Y; n/ T9 s
  32.             {: w7 u; _* i9 T
  33.             frequency1=1000000/period_TIM4        ; //通过捕获的波形的周期算出频率
    : V3 ^$ a6 j9 K6 x7 V  m0 V7 h
  34.             frequency2=1000000/period_TIM1        ;
    , e6 B+ K1 i& H$ x
  35.             frequency3=1000000/period_TIM2        ;" }9 |$ q& i; Z
  36.             frequency4=1000000/period_TIM5        ;
    2 l( W( B- s7 s6 F' ~, ~
  37.     /********PID1处理**********/( X9 \+ x- o' e5 B  q$ P& e, M9 A
  38.             PID1.sum_error+=(incPIDcalc(&PID1,frequency1));         //计算增量并累加3 c9 u1 v) D1 U2 B$ c7 E
  39.            pwm1=PID1.sum_error*4.6875  ;   //pwm1 代表将要输出PWM的占空比2 ?$ Y, R8 g& n# r3 |
  40.               frequency1=0; //清零0 T" G* e# m& Q2 w
  41.          period_TIM4=0;
    , h$ W+ U& B" s
  42.     /********PID2处理**********/
    5 o0 |- ^% P- Q2 D* ^0 v" E- g$ S, l
  43.              PID2.sum_error+=(incPIDcalc(&PID2,frequency2));         //计算增量并累加  Y=Y+Y'1 B3 k3 b% _9 L- G* X
  44.              pwm2=PID2.sum_error*4.6875 ;   //将要输出PWM的占空比
    0 @& P' x3 ^* z$ y
  45.             frequency2=0;
    2 ?0 g% r! N( g# p
  46.             period_TIM1=0;
    9 J; C8 i; }5 t* X8 z  A' O
  47.     /********PID3处理**********/: i% n7 @, y9 M; o0 L# Y. Z; |
  48.              PID3.sum_error+=(incPIDcalc(&PID3,frequency3));          //常规PID控制7 {8 ~' F% f! }0 S8 ?6 u
  49.             pwm3=PID3.sum_error*4.6875 ;   //将要输出PWM的占空比  I3 Z0 H& _$ h$ f2 m- K3 B
  50.             frequency3=0;. r% m  P' H  ]
  51.             period_TIM2=0;
    9 F' u) M5 d8 ^+ `. e$ O, m
  52.     /********PID4处理**********/
    ; e0 H5 u* E' u
  53.                 PID4.sum_error+=(incPIDcalc(&PID4,frequency4));         //计算增量并累加
    ! E$ R& X1 C  x8 z8 q3 ?
  54.              pwm4=PID4.sum_error*4.6875 ;   //将要输出PWM的占空比
    % ^1 I' n; z; `3 j6 G
  55.             frequency4=0;
    0 U! I, ~/ t: t# ]
  56.             period_TIM5=0;0 j" N" p8 J/ y: P
  57.               }
    3 k) N/ B* M' h2 C% r
  58.     TIM_SetCompare(pwm1,pwm2,pwm3,pwm4);             //重新设定PWM值
    8 U/ P1 F7 m- F  Y. \. w% Q" I
  59.     TIM_ClearITPendingBit(TIM6, TIM_IT_Update); //清除中断标志位# K( g5 v) t' U  e
  60.     }
复制代码

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

举报

17个回答
zero99 回答时间:2017-12-26 16:11:12
大佬,这样插代码效果更加哦
0 Y: @1 p9 U5 G5 j1 o4 ^9 \' P
/ w  }, C5 B: C
  1. 测试代码. k; O5 ^- Z+ `3 t8 `6 W: N
  2. 测试代码
    4 V. K: g, f; l5 {3 n: m
  3. 测试代码/ a1 m9 D! b* a2 q3 i4 @8 V
  4. 测试代码
复制代码
7 D1 D0 r: s: L; S( e" W
$ n+ d, u$ I. V, Z9 _2 M% N  g. [. S
333333.png
2 b  U2 r$ _- L7 _
二子 回答时间:2018-10-3 11:10:48
nyszx 发表于 2017-12-26 15:410 P* `" v  B/ }( q. N! b. G
再付个网上的资料

' \" }) w: b1 Y0 M9 P$ Y9 m* u* G3 K这是个好东西3 w- T' d& s- {8 Z
书到用时方恨少
1 \/ o' o/ D/ P果断收藏
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 M0 _% |! t3 M4 R  p& o+ G
板子粉丝 回答时间: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管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版