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

STM32定时器pwm模式输入捕获方法解析

[复制链接]
STMCU-管管 发布时间:2021-6-18 12:57
STM32定时器pwm模式输入捕获##( t' c: `# N5 Y# P1 X
STM32中的定时器,除了TIM6和TIM7,其他定时器都有输入捕获功能。这种模式通常用在对输入信号频率frequency、占空比duty、高低脉宽的计算中,具有很广泛的用途。
' C, L. U$ Y5 Q4 s  w
! R7 e/ N0 i$ c: f% g6 k; a2 e& d! [& K
* P$ ~( h) y! E" f  I" I
STM32的输入捕获,简单的说就是通过检测TIMx_CHx上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存(TIMx_CCRx)里面,完成一次捕获。同时还可以配置捕获时是否触发中断/DMA 等。$ E& A( M, W/ C! Q
' B5 e. ^0 T' E! y/ P0 ~

* A7 S- S# i% q1 }PWM模式捕获方法:利用TIM3_CH1作PWM输出,TIM2_CH2捕获上述PWM信号,并测出频率和占空比。设置PWM频率为1KHz,占空比50%。* T7 V3 y. ^6 G  ]5 X& r
具体步骤:
9 ]0 y$ t  J# i9 y9 \# f# q# U2 \. R7 x; {
2 z8 W+ g+ k2 U' S" M1 u2 J- }
1、为了实现PWM输入捕获,TIM2占用了2个通道。第2通道的电平变化会被第一通道和第二通道引脚检测到,其中第一通道被设置为从机模式(如何快速判别主从机模式,规则如下:如果设置的是第二通道作为PWM输入捕获,则剩余的第一通道都为从机,反之亦然)。+ e. J/ C# W$ }% H; |0 `7 j
2、假设输入的PWM从低电平开始跳变,在第一个上升沿到来时,1,2通道同时检测到上升沿。而从机设置为复位模式,所以将TIM2的计数值复位至0,此时不会产生一个中断请求。+ s7 ^, q- Z/ b- O* j
3、下一个到来的电平是下降沿,此时通道1发生捕获事件,将计数值存入通道1的CCR1里。
5 R- D7 D( X1 {4 ^' U# b然后是第二个上升沿到来后,此时通道2发生捕获事件,将此时的计数值存入通道2的CCR2里。复位模式此时又将TIM2计数值复位至0,等待第二个下降沿到来。
2 ^1 N, N! S; p7 L4、一次捕获过程完成,则PWM的频率f=72M/CCR2;占空比:duty=(CCR1/CCR2) X100%; i9 O/ e$ h7 Q4 q- U
12.png
注:) w4 m, {8 ~. x9 r+ M& H+ h
PWM输入模式时,用到两个通道(一般用TIMx_CH1或TIMx_CH2),只给其中一个通道分配gpio时钟即可,另一个在内部使用。给一个通道分配gpio时钟后,需要设置另一个为从机且复位模式。(例如使用ch2,ch1就得设置成从机模式)。当一个输入信号(TI1或TI2)来临时,主通道捕获上升沿,从机捕获下降沿。
* }6 D* y- \5 ^8 a在CH2通道中:5 k% B- |2 K/ u, @
TI2FP1和TI2FP2都来自同一信号TI2 的边沿检测,信号相同,同一个TIx输入映射了两个ICx信号。
  D# R( J* K% W9 O: LTI2FP1和TI2FP2可以分别由连接到的ICx (IC1或是IC2)相对应的控制寄存器设为上升沿或是下降沿触发,这两个ICx信号分别在相反的极性边沿有效。如果TI2FP2设置为上升沿触发,则TI2FP1设置为下降沿触发,二者极性相反。
0 {8 [3 m+ z; Q* z6 W. [CH1,3,4相同。/ T: H0 l" r* A+ K1 a* H$ O

1 \1 }; W3 R/ u2 L8 W$ X; E7 w
/ A1 U, v# L0 k% F' S
具体程序:: \( E5 Z2 b4 w) t# l
  1. include “pbdata.h”2 L! k- ]. @: {: }+ l$ L4 U

  2. 1 X  w  g" D, m3 ]. B' g5 {
  3. void RCC_Configuration(void);9 L) @( @' A! K
  4. void GPIO_Configuration(void);5 a% l6 m/ m; J; c8 k! y7 P
  5. void NVIC_Configuration(void);
    2 \6 x1 h5 Y" K2 u4 M) n0 B- I
  6. void TIM2_Configuration(void);2 ?% N& W* V" ^( p" t0 A6 _  n# C% r" \
  7. void TIM3_Configuration(void);
    , r2 q. z/ `" @; e* @4 r
  8. void USART_Configuration(void);2 m1 }/ \! l" Q% m  u) N# c3 x! M
  9. # M1 q8 |- s& m3 ]+ M# p8 S4 O
  10. int fputc(int ch,FILE *f)' \/ ~) S) O8 x7 ?) N
  11. {" w  ]5 _6 P( {- H
  12. USART_SendData(USART1,(u8)ch);
    - H* N' K5 d& B2 z. Z4 O! ^2 F# Z! e
  13. while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);0 W3 X2 d% H0 v4 w' j2 r
  14. return ch;
    ! _0 u. z  [6 Y. Z
  15. }
    * E# ]7 D; S9 a' \7 h7 x

  16. " D! |9 ~% a5 z# ~. ?
  17. int main(void)' }( g* h1 f8 W) q# Y
  18. {
    4 [3 W8 @9 w& v/ Z7 Z( J) O+ X
  19. RCC_Configuration(); //配置时钟- V$ d0 w# N1 Y% H7 \4 A# {# E# ~3 N+ p
  20. GPIO_Configuration();//IO口配置
    + d2 d1 q0 B8 C% b! p
  21. TIM3_Configuration();
    2 H. w5 Y  q$ L3 s7 H2 S
  22. TIM2_Configuration();5 X5 k8 h% V4 }' x" V$ A( d! T
  23. NVIC_Configuration();" Z2 k; R. H- X% Q) ]' p
  24. USART_Configuration();9 n& ^! m4 H% z5 G

  25. ! y7 H0 |& Z9 q2 J$ [. @
  26. while(1)
    0 J7 d0 r3 n& H6 @1 P( J" G
  27. {! c- d- B* N  j5 f! z+ ]
  28. if(flag==1)
    " Q' U/ C0 ]' H( u! H$ M6 s: X5 S
  29. {1 {5 `4 u4 h9 H% U: _& j1 z
  30. flag=0;3 w4 X+ p) R5 ?$ Q$ W
  31. printf(“the duty is %d/r/n”,duty);
    $ r8 x6 [  A1 W
  32. printf(“the frequency is %.2fKHz /r/n”,freq);, u! l# J# p) @4 v4 x+ E' Q. U
  33. }' b' k/ [# m/ H% K6 e
  34. }  M% o1 z' |% x* c6 O3 t2 C
  35. }. q& _) f. P8 w# d! T2 q" q4 s
  36. & _! B+ l6 B% l) m% G9 {
  37. void RCC_Configuration(void)
      c! h  Q- p" N9 T5 Y7 l$ O; q
  38. {1 o' i( [7 w/ w$ x4 {
  39. SystemInit();) j0 C: `3 j) @* C
  40. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);) K* X8 n3 a( a; F6 c" s! X- ^
  41. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2|RCC_APB1Periph_TIM3,ENABLE);
    + ~9 z* j" @1 r' I
  42. RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
    # k# I1 I3 B' N- E
  43. }- z' t, n' ^( g# V  ]) S) p7 W

  44. , I5 ?$ H! b2 Z0 p& K
  45. void GPIO_Configuration(void). N0 ]8 x; U' g! [
  46. {8 R& A/ g2 t  h
  47. GPIO_InitTypeDef GPIO_InitStructure;% @3 b) ~( }7 E8 S
  48. //LED
    2 H) r  c6 _. i7 x5 @9 d) g1 d: e
  49. GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//TX
    ( b6 O3 d- O5 D, G
  50. GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;: w7 a  I9 B: z! i9 |
  51. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;/ c( L# A3 {) \0 I! l
  52. GPIO_Init(GPIOA,&GPIO_InitStructure);
    8 [. {( r( D7 v- d6 Z: Y

  53. ! i) b  Y; B8 Q- M) Q
  54. GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//RX  m' [9 P$ I: |" Q) @. E8 G  h
  55. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;0 o- |) h7 o/ q5 S. d+ {
  56. GPIO_Init(GPIOA,&GPIO_InitStructure);
    & Z7 M+ O7 z1 ~& J
  57. ; {* M! v+ D6 M1 r/ J1 B3 f3 x
  58. GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;//PWM,TIM3_CH1
    ; q/ B" W9 X( `
  59. GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;& F: F* \1 G# P. Q: \
  60. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
    ' v0 t2 y2 Z0 O! m; c( Q. i' C/ `
  61. GPIO_Init(GPIOA,&GPIO_InitStructure);- T7 B3 p& h9 M" @! T. s
  62. . ~  O$ H1 G% J9 T7 J" q
  63. GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;//TIM2_CH2% V% y  o4 X. Z1 [, ~
  64. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
    6 l( Y( |0 u; \/ Y; \. h
  65. GPIO_Init(GPIOA,&GPIO_InitStructure);# {' s3 q# G4 h3 w) H
  66. }
    7 e$ F) z5 l9 J2 q; M' O
  67. ; O1 Z6 Q2 l: n, [+ @
  68. void TIM2_Configuration(void)9 m4 e- j7 \. M
  69. {( Y" h4 N  Q* |2 F) D/ h! J1 @' Q( Y
  70. TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;$ ^: b) E7 ]2 A- S
  71. TIM_ICInitTypeDef TIM_ICInitStructure;& _  A% K! u/ P; j! Y  ~  Z/ f$ J8 u+ |

  72. ; n' r& I) {. O2 ?, o7 c
  73. TIM_ICInitStructure.TIM_Channel=TIM_Channel_2;//选择TIM2_CH2,选择输入端 IC2映射到TI2上* C9 Y* `3 \- ~, ~. H+ u
  74. TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//上升沿捕获
    ' X) T* U* s1 G; p& Q* |% U
  75. TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//映射到TI2上/ M/ s7 J0 e+ u$ K! d: ^  s
  76. TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;//在捕获输入上每探测到一个边沿执行一次捕获3 D4 A' e8 G4 t/ I( W* ?; {5 K
  77. TIM_ICInitStructure.TIM_ICFilter=0;//滤波设置,经历几个周期跳变认定波形稳定。(采样高电平,只有连续采集到N个电平是高电平时才认为是有效的,否则低于N个时认为是无效的,N取0x0-0xF)" t. \" y; ]! k* @
  78. TIM_PWMIConfig(TIM2,&TIM_ICInitStructure);//以上是输入捕获配置: A* D) c' A' R" _! F  E- E- A
  79. TIM_SelectInputTrigger(TIM2,TIM_TS_TI2FP2);//选择滤波后的TI2FP2输入作为触发源,触发下面程序的复位
    ' L% w) p$ T+ ^: d4 V
  80. TIM_SelectSlaveMode(TIM2,TIM_SlaveMode_Reset);//从模式控制器被设置为复位模式-选中的触发信号上升沿重新初始化计数器并产生一个更新信号(上升沿一到,TIM2->CNT被清零,每次上升沿来到,CNT都会被清零)
    9 R9 r+ N: D+ B7 _4 t: o
  81. TIM_SelectMasterSlaveMode(TIM2,TIM_MasterSlaveMode_Enable);//启动定时器的被动触发; F/ P. w/ c! Q' m
  82. TIM_ITConfig(TIM2,TIM_IT_CC2,ENABLE);//捕获中断打开- w3 Y/ }' F2 d3 p- p3 ?+ V
  83. TIM_ClearFlag(TIM2,TIM_IT_CC2);//清除标志位: V! G' f1 Z; R5 w, T- ?
  84. TIM_Cmd(TIM2,ENABLE);//使能定时器2
    % f7 h5 |7 o$ G( j, h3 n
  85. }
    ! T* Y7 n+ P  b- h
  86. 1 v0 d7 C5 Z, a9 E2 |
  87. void TIM3_Configuration(void)! ?7 O* B3 c# a2 v2 V" h4 o% x
  88. {
    ; b% g, x1 `' q& Y: z
  89. TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
    1 P' n! w/ Z7 E/ ?. M* z! Q7 F. {$ z
  90. TIM_OCInitTypeDef TIM_OCInitStructure;; W0 H2 Z: n* \
  91. TIM_TimeBaseStruct.TIM_Period=72000;//计数初值
      ~9 t7 ~* `3 R" R& O# h$ X  V) [2 ?
  92. TIM_TimeBaseStruct.TIM_Prescaler=0;//分频系数
    0 J  |4 V1 X5 p) P" l1 x9 K
  93. TIM_TimeBaseStruct.TIM_ClockDivision=0;//时钟分割
    : |; k" r5 C/ O
  94. TIM_TimeBaseStruct.TIM_CounterMode=TIM_CounterMode_Up;//向上计数模式' C0 Z% a- _3 z/ P

  95. . ]  l+ P9 }+ J$ Z7 b; _
  96. TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStruct);* v) }5 v; T$ W& t* G* Z9 P
  97. % C) V5 O1 o" }( u$ Y
  98. //TIM3_CH1作为pwm输出4 e7 s/ F" G) ^, K( j6 g' i
  99. TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;" [1 q2 X1 E- K5 c( x# k$ y  B
  100. TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;& N+ q) z1 V% D+ u/ ?
  101. TIM_OCInitStructure.TIM_Pulse=36000;
    / C; l' B. R5 `
  102. TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;& H* T6 v- v* {/ ]# N
  103. ! F& k3 p/ C" p2 f
  104. TIM_OC1Init(TIM3,&TIM_OCInitStructure);
    ! M  u4 Y# r1 d9 m) D. ?- x' s

  105. - {: h) t! E/ s: O
  106. TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Enable);
    5 J$ e  v9 \5 A9 `6 E( |
  107. TIM_ARRPreloadConfig(TIM3,ENABLE);
    5 |. Q  e6 N$ w; |  I+ g
  108. TIM_Cmd(TIM3,ENABLE);+ s. y, A+ Q$ m6 Y
  109. / \9 p' Z- y' d
  110. }: z7 R2 J8 Y: `/ a0 g$ g
  111. 8 H4 r" l, d( _7 K+ J
  112. void NVIC_Configuration(void)
    3 I) z- c/ o) T+ v! k5 Y+ d: `# ~
  113. {: y" y% Y5 Q) `0 q# f1 ^2 C. R
  114. NVIC_InitTypeDef NVIC_InitStructure;8 J( ]( c  S; t3 P. F4 `

  115. 5 \/ E7 C9 ~1 @, T/ A# ?' p
  116. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
    3 O/ w! l. |$ z1 a- g
  117. 9 b) V1 J  b& Y% ?* H: y
  118. NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;9 R8 Y8 Q- N1 K9 M7 c4 w
  119. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    ; N. s8 d) C: ^0 l+ q3 ~6 j
  120. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;5 M2 y' e# ^( i9 i
  121. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;, m7 H" l+ o! [) Y, y6 U8 d* s
  122. NVIC_Init(&NVIC_InitStructure);
    9 p4 w1 ]% B. Z  t) \

  123. / F" a5 O. J+ {" w7 r& e
  124. }
    6 i/ F7 ^! {5 b$ W7 n5 m

  125. * X# {* M0 N2 J6 r+ Y: j1 Q* S
  126. void USART_Configuration(void)
    3 N7 q; U% C! ^4 o9 A& c' o' V2 ]
  127. {
    5 L# m- J4 V0 n5 r1 n
  128. USART_InitTypeDef USART_InitStructure;
    6 I+ |7 I7 _5 D

  129. , q  u5 g+ L" }! ]! v6 j: v( ?. K. P
  130. USART_InitStructure.USART_BaudRate=115200;; _' c( w5 d- H/ v8 y
  131. USART_InitStructure.USART_WordLength=USART_WordLength_8b;+ }+ {3 Y9 {4 c9 L. p. h4 v
  132. USART_InitStructure.USART_StopBits=USART_StopBits_1;' t6 j% r" s- e0 C$ N& A% m4 z
  133. USART_InitStructure.USART_Parity=USART_Parity_No;
    ) O% G+ H" H: A
  134. USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
    / _5 k' r# j3 A/ C) X
  135. USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
    : I0 h& K+ W0 B3 l6 @; [% _

  136. 1 u2 ]: t' W1 f
  137. USART_Init(USART1,&USART_InitStructure);& [9 p2 V' ^. c  L4 }
  138. USART_Cmd(USART1,ENABLE);
    + C0 |  Q0 S: E7 b0 W+ ]
  139. USART_ClearFlag(USART1,USART_FLAG_TC);. P: x4 U! V) m4 r$ y0 P2 T
  140. }
    0 ?/ X1 b+ V$ s! `) j- k

  141.   U% R8 D% k& h$ a5 A4 X
  142. //中断程序
    2 L, q' A  e1 S1 W6 u( X3 S
  143. void TIM2_IRQHandler(void)4 w4 L5 Y+ U' L
  144. {
    $ R& k4 G$ f/ z1 ^# g, e
  145. if(TIM_GetITStatus(TIM2,TIM_IT_CC2)==Bit_SET): @* H, a9 R* c) E* T# {2 D+ _
  146. {5 r# f4 _0 D1 c# {& i  |
  147. float IC2Value=0;4 C0 X7 ?; P( r4 T' b/ ?  r4 ~- Z
  148. float DutyCycle=0;
    , ~- a6 O8 u4 ^  T7 S! V
  149. " ^' X8 ?0 W6 P) T
  150. float Frequency=0;* J0 @: D- k0 m5 d+ s  n! D; c' a. I
  151. float pulse=0;
    # j8 T9 G* A4 {3 |7 `
  152. ( Z. B( P2 i6 x* B* r: P
  153. IC2Value=TIM_GetCapture2(TIM2);//获得CCR2的值( k: [+ ^( ?& j
  154. pulse=TIM_GetCapture1(TIM2);//获得CCR1的值
    " Y7 Q$ e, p( E5 \* Q3 d+ ^/ `
  155. DutyCycle=pulse/IC2Value;4 M8 v  R  L1 u+ U( ?
  156. Frequency=72000000/IC2Value;+ {. z- T( Q) Y0 G
  157. duty=(u32)(DutyCycle*100);
    + F- H' f6 Q  R/ h0 ~7 ]
  158. freq=(Frequency/1000);9 [; S1 ~7 ~1 {! C4 S+ N' ~
  159. , |0 S) z8 \5 J5 }6 x  P
  160. flag=1;) Q( q# Y' p1 ]8 Z) V" {
  161. . x7 F4 L# B6 H9 m1 g. r
  162. TIM_ClearITPendingBit(TIM2,TIM_IT_CC2);% e- K% @1 M7 L; a' x0 ?$ t' R
  163. }
    2 }+ l- ~8 e& D& D+ c% A, S/ U. I
  164. }; }# `: {! j9 V! y$ s
  165. 9 w7 t3 D2 c8 e' a- r4 Z
  166. duty和freq是定义的全局变量
    : c5 k, X( [7 ]# X" @9 e; K
  167. extern u32 duty;
    0 R7 j! F! G, j# D
  168. extern u16 freq;: U) ]  G, O3 v! u
  169. , H7 d3 ]6 }! A5 l% M
  170. u32 duty=0;
    7 K2 o: I6 F, P7 J  S0 G: t
  171. u16 freq=0;
复制代码
经调试程序可用。频率和占空比都对。频率的设置不要太高,因为printf函数发数所需时间较多,两次捕获的时间间隔短的话可能使printf不能及时地送出数据,造成数据被刷新。更改方法,使用:USART_SendData();函数发数。8 q# ^4 c( \9 Q. K$ k! \& P

, n7 A, a/ _- \+ m

1 z2 P" ^: w  W  s6 w, Y其他应用:
. c/ h1 W) v; d. f# g+ e, k7 S3 C1.测量高电平时间:a,上文中的CCR1就是高电平时间;b,当使用一个通道CH1时,先将触发沿选为为上升沿,产生捕获中断,读取CCR1中的内容,再改变触发沿为下降沿,下降沿到来时捕获,再次读出CCR1的内容,两次相减为高电平时间。0 `: \  q) K6 n! K9 t
2.测量脉冲个数:a,开启定时器1的捕获中断,捕获信号边沿(上升沿或下降沿)进中断,count++计数,再开启定时器2的更新中断,定时一定时间进更新中断,读取count值,此为脉冲个数。b,开启外部中断,配置沿触发中断,count++计数,再开启定时器x的更新中断,定时一定时间进更新中断,读取count值,此为脉冲个数。# C7 y( H6 s1 u# R8 D' Q) ?
3.计算一路信号的频率,可以选择定时器的CH1或CH2(不可同时计算两路频率,否则计算出的频率是后初始化的那个通道代表的信号频率。当然,要同时也可以,每次得到频率后切换通道,将数据通过DMA取走即可),使用PWM输入捕获模式,使用上升沿触发。而CH3和CH4通道则不行,如图2所示,只有红线所指的4个信号连在了从模式控制器上。所以,对于3和4通道,计数器的值不可能在接受到信号上升沿时候,有复位这个动作。9 A6 q% T" o2 e' ~

6 I# h, ?; m  z1 l6 R4 X2 L6 B2 s1 h$ v, z1 l
赞 收藏 评论0 发布时间:2021-6-18 12:57

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版