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

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

[复制链接]
STMCU-管管 发布时间:2021-6-18 12:57
STM32定时器pwm模式输入捕获##
, y- D, ~8 r0 J, I5 b' uSTM32中的定时器,除了TIM6和TIM7,其他定时器都有输入捕获功能。这种模式通常用在对输入信号频率frequency、占空比duty、高低脉宽的计算中,具有很广泛的用途。* Q' ]% V6 r- f5 Q
# P; d1 A* Z( n" o. D

7 b' K1 p/ h* o* ?3 LSTM32的输入捕获,简单的说就是通过检测TIMx_CHx上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存(TIMx_CCRx)里面,完成一次捕获。同时还可以配置捕获时是否触发中断/DMA 等。
" w9 ^3 G* B' ]
$ P, u) P2 ]0 C2 d

# c9 Q# @0 ?% D) g5 V; g0 JPWM模式捕获方法:利用TIM3_CH1作PWM输出,TIM2_CH2捕获上述PWM信号,并测出频率和占空比。设置PWM频率为1KHz,占空比50%。
( ~0 s1 V$ U+ f3 W+ _8 R具体步骤:3 ?9 N5 ^% P3 O) {, w& E

% s, c$ k$ x: b4 Z  K3 U5 d
: o% s  G. k7 \7 F" ^6 d
1、为了实现PWM输入捕获,TIM2占用了2个通道。第2通道的电平变化会被第一通道和第二通道引脚检测到,其中第一通道被设置为从机模式(如何快速判别主从机模式,规则如下:如果设置的是第二通道作为PWM输入捕获,则剩余的第一通道都为从机,反之亦然)。
4 Q% O* \$ u0 r2 r1 K1 k2、假设输入的PWM从低电平开始跳变,在第一个上升沿到来时,1,2通道同时检测到上升沿。而从机设置为复位模式,所以将TIM2的计数值复位至0,此时不会产生一个中断请求。$ ]3 O; B/ U4 A- e. ]( H  r# R
3、下一个到来的电平是下降沿,此时通道1发生捕获事件,将计数值存入通道1的CCR1里。
. y2 J3 W4 _- k  G' E4 b然后是第二个上升沿到来后,此时通道2发生捕获事件,将此时的计数值存入通道2的CCR2里。复位模式此时又将TIM2计数值复位至0,等待第二个下降沿到来。/ |- {9 S, b* p* }6 e
4、一次捕获过程完成,则PWM的频率f=72M/CCR2;占空比:duty=(CCR1/CCR2) X100%9 W. r( d' v1 R* y% H$ b* N3 _
12.png
注:; G4 o5 K% a( d4 i3 |$ ~
PWM输入模式时,用到两个通道(一般用TIMx_CH1或TIMx_CH2),只给其中一个通道分配gpio时钟即可,另一个在内部使用。给一个通道分配gpio时钟后,需要设置另一个为从机且复位模式。(例如使用ch2,ch1就得设置成从机模式)。当一个输入信号(TI1或TI2)来临时,主通道捕获上升沿,从机捕获下降沿。
! K1 ^: ^* e% F7 r在CH2通道中:
1 O5 h! G8 {: tTI2FP1和TI2FP2都来自同一信号TI2 的边沿检测,信号相同,同一个TIx输入映射了两个ICx信号。& j- ?4 u  F3 o& U
TI2FP1和TI2FP2可以分别由连接到的ICx (IC1或是IC2)相对应的控制寄存器设为上升沿或是下降沿触发,这两个ICx信号分别在相反的极性边沿有效。如果TI2FP2设置为上升沿触发,则TI2FP1设置为下降沿触发,二者极性相反。3 p4 z& ?1 R2 F1 e7 j8 d4 w
CH1,3,4相同。
* J' x6 O1 y+ V6 _% P% H* v" W# g) d, ~8 c/ w  z, }4 n
! C  d( d& ~5 O' i% ?5 Q
具体程序:" h) N0 b3 D& A
  1. include “pbdata.h”
    ' Z5 P5 Y* g" H( s" a) h
  2. $ a# Q+ m5 _+ X0 \, H
  3. void RCC_Configuration(void);7 j' h* X6 E- E5 }: z9 K, W! O  m7 }/ X
  4. void GPIO_Configuration(void);' s5 K7 B4 l4 l0 X3 l0 n& k9 z
  5. void NVIC_Configuration(void);
    ; d/ q8 J! n& X2 R
  6. void TIM2_Configuration(void);
    : ^) ?+ K; P2 s0 T
  7. void TIM3_Configuration(void);  N+ N2 i1 ~  S+ h3 S8 g  ^* ^" e+ F! E
  8. void USART_Configuration(void);
    8 Z& @" r% N% ]
  9.   W" z- ~; A3 A: |" V" D
  10. int fputc(int ch,FILE *f)" M% j; P- ?7 l; @" _
  11. {; X0 X2 X1 x7 N) N1 B
  12. USART_SendData(USART1,(u8)ch);
    ' B  N5 L( s. G. Y8 |
  13. while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);! B: y+ J1 [5 S3 ^# i" X( x
  14. return ch;
    & G9 [0 g8 J; S) C' F
  15. }
    " G8 U/ O9 U6 R+ m7 H9 L
  16. 4 f. T) i. d4 K' X
  17. int main(void)9 Y  a3 q( c  I' z. C
  18. {: o5 G% @5 ?: L6 e/ v
  19. RCC_Configuration(); //配置时钟
    4 g5 ^0 s' r. {! {: x5 y
  20. GPIO_Configuration();//IO口配置0 o8 a8 S6 \1 s+ [
  21. TIM3_Configuration();8 p" I1 z, z1 B1 ~
  22. TIM2_Configuration();  v. f8 o. y( x$ W! P% |0 K6 m, K
  23. NVIC_Configuration();
    8 ^" l* U% f8 o1 G( [! u1 ^+ @
  24. USART_Configuration();
    , X& e0 F: a$ l0 Z

  25. % |( N1 B) z2 S6 b/ }1 z7 c' M2 b
  26. while(1)
    . k: k+ }, C, f6 W8 c5 e
  27. {
    4 c( ?1 e" d9 ~$ Z: }  F
  28. if(flag==1)) M: X0 H0 _+ |$ w" t/ F- R* K
  29. {6 q& M/ z7 ?5 n. b% O1 v0 v
  30. flag=0;4 ]' \% {& u. I8 K7 d0 q$ U1 u
  31. printf(“the duty is %d/r/n”,duty);
    # i0 a! {9 o' X! `
  32. printf(“the frequency is %.2fKHz /r/n”,freq);3 t6 @3 C7 y4 x3 B% S
  33. }
    : z9 ^2 E4 P9 S' i. K& c% @
  34. }
    4 a$ O* D4 o" f/ N9 s
  35. }1 F; p0 `- i" p0 u2 ^" s$ F; ^

  36. * v1 R) y4 [) B% X/ l. a
  37. void RCC_Configuration(void); k, c! ^8 A0 Q* X) d% |
  38. {! F$ r8 u+ |9 t
  39. SystemInit();, y' n1 r5 |$ B+ J3 S# O* R( P1 z
  40. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);
    ) L1 L: i3 S) g" p2 @+ c
  41. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2|RCC_APB1Periph_TIM3,ENABLE);1 Y$ g0 }& G( T2 _7 a* I% }2 k5 ?
  42. RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
    2 {: |6 S4 B& X6 U' k
  43. }
    5 n3 H/ J" ^' O" s7 Z3 y4 Q
  44. * a$ `4 j3 L6 f# R9 o
  45. void GPIO_Configuration(void)1 a+ N' O9 N; j+ i
  46. {% b- |2 r# R% R8 a* \
  47. GPIO_InitTypeDef GPIO_InitStructure;
    ' `" `* Q9 F* L5 \9 G
  48. //LED
    7 F3 V! n+ \. w# M
  49. GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//TX. W" u% p5 ~4 N9 E1 I9 v7 Y/ Z
  50. GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    . N- j! L+ D( c" t  ~9 m
  51. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;& i" O& @3 R) R. h1 A0 g
  52. GPIO_Init(GPIOA,&GPIO_InitStructure);
    3 z4 ~7 Y) F7 s! c( z8 N3 e& P
  53. 0 W7 n4 U1 M: ?1 A
  54. GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//RX4 j* F$ j) \, J/ y
  55. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;9 M1 f7 g8 C' w) D$ P/ I
  56. GPIO_Init(GPIOA,&GPIO_InitStructure);
    1 }$ H  O( ?, a% u" P# _( P
  57. 0 h0 s% _6 G' f9 \8 V3 R
  58. GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;//PWM,TIM3_CH1  P: @5 B  b, b0 ]" i7 U& {
  59. GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    1 s# P) h" B* l0 W  C8 Z" Z
  60. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;0 A( a) k' K3 v8 t) j
  61. GPIO_Init(GPIOA,&GPIO_InitStructure);
    5 f, @& v, W  D7 K! j' E8 c( Y

  62. , T' d/ g' `' F( q; c
  63. GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;//TIM2_CH2* [3 x, q1 r+ z9 h* I3 Y+ t* ]
  64. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
    0 w: w/ D% b9 l* ?/ i: k
  65. GPIO_Init(GPIOA,&GPIO_InitStructure);) L* M8 I: |7 Q6 K) u, q
  66. }3 k8 K* F5 W. }. J/ m

  67. & G$ M1 w* Z0 v4 l8 K+ H8 I
  68. void TIM2_Configuration(void)
    * ]9 X( ?  ?9 R* G- |  @; ^9 ~/ I
  69. {
    ( s0 S% X8 t4 P$ y* u
  70. TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
    . n- L- t. }2 f
  71. TIM_ICInitTypeDef TIM_ICInitStructure;
    # _1 @: e1 e- G  L: ?

  72. ; p4 f& D2 G8 S9 m( e' p
  73. TIM_ICInitStructure.TIM_Channel=TIM_Channel_2;//选择TIM2_CH2,选择输入端 IC2映射到TI2上2 g- U, [8 @/ b( U) ]5 C& h
  74. TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//上升沿捕获' Y6 f* v* W+ ~! {3 v0 J
  75. TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//映射到TI2上' V9 h& w+ v* Z+ A- b; Q5 W, S
  76. TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;//在捕获输入上每探测到一个边沿执行一次捕获* o# r# ^% Z& ~# l# w# J0 V
  77. TIM_ICInitStructure.TIM_ICFilter=0;//滤波设置,经历几个周期跳变认定波形稳定。(采样高电平,只有连续采集到N个电平是高电平时才认为是有效的,否则低于N个时认为是无效的,N取0x0-0xF), F' x9 h8 ?0 M/ T2 [
  78. TIM_PWMIConfig(TIM2,&TIM_ICInitStructure);//以上是输入捕获配置4 u& {0 y5 A+ t
  79. TIM_SelectInputTrigger(TIM2,TIM_TS_TI2FP2);//选择滤波后的TI2FP2输入作为触发源,触发下面程序的复位% x! ~8 U5 n" y
  80. TIM_SelectSlaveMode(TIM2,TIM_SlaveMode_Reset);//从模式控制器被设置为复位模式-选中的触发信号上升沿重新初始化计数器并产生一个更新信号(上升沿一到,TIM2->CNT被清零,每次上升沿来到,CNT都会被清零)
    ! d* W5 f* h" q3 G1 Q. Q6 d
  81. TIM_SelectMasterSlaveMode(TIM2,TIM_MasterSlaveMode_Enable);//启动定时器的被动触发( z! u% B: z5 E& g
  82. TIM_ITConfig(TIM2,TIM_IT_CC2,ENABLE);//捕获中断打开9 e1 q8 O) i+ ?) `! ]6 r
  83. TIM_ClearFlag(TIM2,TIM_IT_CC2);//清除标志位
    & }) y. n3 m- d% h, B0 |
  84. TIM_Cmd(TIM2,ENABLE);//使能定时器2
      ]$ U2 q9 c2 B; g$ `
  85. }
    . f- K: A3 c# I3 ^# {7 W

  86. ' W; w* m# @* v% x/ o- {, \' e
  87. void TIM3_Configuration(void)
    7 ?- Z- [+ O9 j1 Q1 L; e
  88. {
    0 C% o! k7 [7 z. s
  89. TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;8 P8 `* E; q* j5 Z" K, P
  90. TIM_OCInitTypeDef TIM_OCInitStructure;
    2 Y2 p9 O9 i3 ~: `1 I8 C8 q, o, i
  91. TIM_TimeBaseStruct.TIM_Period=72000;//计数初值8 J" E0 i/ b- T7 A" o" a1 b0 A
  92. TIM_TimeBaseStruct.TIM_Prescaler=0;//分频系数
    : U' P5 O4 o3 P4 F$ V! i
  93. TIM_TimeBaseStruct.TIM_ClockDivision=0;//时钟分割
    , L% V4 t& m" @  K" `; P+ a1 Z+ {0 W" h
  94. TIM_TimeBaseStruct.TIM_CounterMode=TIM_CounterMode_Up;//向上计数模式
    4 f9 k$ z3 \* B$ m# i1 a4 }
  95. + z8 {9 e! ]: w; M% N
  96. TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStruct);) ?' k& r8 s1 ?- E& M9 l

  97. + K& ~+ P2 S6 j: r
  98. //TIM3_CH1作为pwm输出
    : \" e& k$ m. C) W+ X
  99. TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
    " D2 M$ H7 v, D& I0 P1 M
  100. TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;7 d; L' y! T; a1 {
  101. TIM_OCInitStructure.TIM_Pulse=36000;9 S( W9 t( c  X$ k2 a
  102. TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;& Q2 X% j9 c7 [4 j+ n  f; f
  103. 9 ^5 A. K% B3 x8 {
  104. TIM_OC1Init(TIM3,&TIM_OCInitStructure);
    + E4 I' x" `# C+ U1 Y3 `1 v
  105. 4 p9 T# E; c3 w; N, X5 V+ G
  106. TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Enable);! ~4 H2 n3 N: r8 i% ^+ \& I
  107. TIM_ARRPreloadConfig(TIM3,ENABLE);
    " ?* y& O, T! V* |: A- q7 v' _
  108. TIM_Cmd(TIM3,ENABLE);+ m( K' H; o/ u8 m
  109. & O4 Y) U6 ]8 w8 o* a% [
  110. }
    3 p/ `' C  _4 ], f
  111. 1 k* n- P! ?8 p" K1 r  O
  112. void NVIC_Configuration(void)3 r: r" Y/ d1 \& g
  113. {) Q4 `3 F: R3 G8 X3 o
  114. NVIC_InitTypeDef NVIC_InitStructure;. R# O. F- R9 g, o% p% j

  115. : P' ]$ `6 P+ D" }4 {" r8 P
  116. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);4 D% q, p% x: @: }# e

  117. : Z! P+ M1 [8 ]) r& {9 C0 [
  118. NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    5 v; F8 M. x( ?: m$ H
  119. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    ; o# I* d# o$ H7 S
  120. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    ! N' i% m% J, T, O
  121. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;+ d) E1 e$ k. V9 g/ ]) X1 I
  122. NVIC_Init(&NVIC_InitStructure);6 `. Y  }: y) i! O; j% H+ m3 ^
  123. 4 I9 h* C& p$ `# M9 b4 {$ o
  124. }
    3 r8 J( B) I/ p6 k4 a
  125. 8 w5 M3 n* K! R2 x( M# r4 y/ N1 S
  126. void USART_Configuration(void)2 Q! x" c: O4 j
  127. {- B0 z# i! z: s6 P0 }; Z* H, M
  128. USART_InitTypeDef USART_InitStructure;
    " N+ C7 r7 N. H% R; ]( [) P7 C# _
  129. / y0 k8 T! P; c# a" |  r, q
  130. USART_InitStructure.USART_BaudRate=115200;
    . [. B1 {4 m- I. T2 n2 t5 ]
  131. USART_InitStructure.USART_WordLength=USART_WordLength_8b;
    ) S: q3 ]. H. e6 i- G
  132. USART_InitStructure.USART_StopBits=USART_StopBits_1;# ]; p& V! E- K  l7 c  v% B0 d) w' W
  133. USART_InitStructure.USART_Parity=USART_Parity_No;
    6 \5 Q/ Q% P3 Q* U2 f9 m+ A
  134. USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
    . p  d4 {" ^2 d: c" P% z  ^8 x
  135. USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
    0 l5 v; r6 a7 z" Q; V
  136. ) X, y* t' H! q& B* h1 j7 \
  137. USART_Init(USART1,&USART_InitStructure);* e! B0 b, k2 [9 P- l/ C
  138. USART_Cmd(USART1,ENABLE);) ~. v. j7 }2 S* @7 d
  139. USART_ClearFlag(USART1,USART_FLAG_TC);7 K; L3 m: Q3 [- o! k
  140. }
    - [8 Q+ g" L6 q

  141. ) l' D4 M1 [& J8 ]2 w3 {! o
  142. //中断程序
    ) f6 g! Z0 ^4 @6 h* [8 K5 k6 G2 D
  143. void TIM2_IRQHandler(void)
    7 q& n: j4 J/ ?; K2 o
  144. {2 z  Y$ j7 p8 q9 i
  145. if(TIM_GetITStatus(TIM2,TIM_IT_CC2)==Bit_SET)9 D1 O* c( v0 n& \9 r
  146. {$ j7 T; t& N' Y! |
  147. float IC2Value=0;
    # V9 f( L# v& ?$ L
  148. float DutyCycle=0;( e- I8 a  g: F% X* e

  149. % g* K) g6 }& @2 ^
  150. float Frequency=0;8 q( x8 u3 k( m- J4 T8 E) g/ H# d
  151. float pulse=0;
    - z# R5 t) J4 p5 S% v

  152. ( v/ U& [3 }* n' n, d* c( q0 Z
  153. IC2Value=TIM_GetCapture2(TIM2);//获得CCR2的值1 A5 p$ F( p2 g4 i. I2 y' W8 h2 W) w
  154. pulse=TIM_GetCapture1(TIM2);//获得CCR1的值# `4 ~5 O3 {7 Z" A1 N
  155. DutyCycle=pulse/IC2Value;# x5 L  {) q  j  V& E& Q. u
  156. Frequency=72000000/IC2Value;& _% K0 l. |, V4 H
  157. duty=(u32)(DutyCycle*100);
    . w1 ^; R( i3 x, l& X$ G) T; A
  158. freq=(Frequency/1000);7 {5 a% r  n3 H3 C; O

  159. 7 W5 x, ?3 N# u
  160. flag=1;
    . A+ d2 F9 b& d( ~
  161. , r6 U+ V7 t0 W, g
  162. TIM_ClearITPendingBit(TIM2,TIM_IT_CC2);
    + N* E) O1 j  `  p7 b
  163. }1 q- M- }# `" ^3 [
  164. }# R$ c5 R$ B" v6 R

  165. + ]9 S/ l* u, c" f( }+ n1 W
  166. duty和freq是定义的全局变量, d3 p9 ?" j+ s/ y) u! R
  167. extern u32 duty;- R# j: x5 L. Y% \/ M# y
  168. extern u16 freq;3 W! S. y0 J; {, M
  169. $ }3 ]7 q7 ?# B/ C( M
  170. u32 duty=0;
    ; S3 r! N$ o8 \
  171. u16 freq=0;
复制代码
经调试程序可用。频率和占空比都对。频率的设置不要太高,因为printf函数发数所需时间较多,两次捕获的时间间隔短的话可能使printf不能及时地送出数据,造成数据被刷新。更改方法,使用:USART_SendData();函数发数。
9 E1 S8 R: M8 \
; n! G- n* C, T. P5 @+ B% l
( [2 C7 \, }% W5 B% j
其他应用:; g5 o( T7 t! b8 ?" C1 B$ p' O
1.测量高电平时间:a,上文中的CCR1就是高电平时间;b,当使用一个通道CH1时,先将触发沿选为为上升沿,产生捕获中断,读取CCR1中的内容,再改变触发沿为下降沿,下降沿到来时捕获,再次读出CCR1的内容,两次相减为高电平时间。% c2 Q& T( n9 @% N- w
2.测量脉冲个数:a,开启定时器1的捕获中断,捕获信号边沿(上升沿或下降沿)进中断,count++计数,再开启定时器2的更新中断,定时一定时间进更新中断,读取count值,此为脉冲个数。b,开启外部中断,配置沿触发中断,count++计数,再开启定时器x的更新中断,定时一定时间进更新中断,读取count值,此为脉冲个数。. ~" M9 m3 r0 c5 N$ J8 v
3.计算一路信号的频率,可以选择定时器的CH1或CH2(不可同时计算两路频率,否则计算出的频率是后初始化的那个通道代表的信号频率。当然,要同时也可以,每次得到频率后切换通道,将数据通过DMA取走即可),使用PWM输入捕获模式,使用上升沿触发。而CH3和CH4通道则不行,如图2所示,只有红线所指的4个信号连在了从模式控制器上。所以,对于3和4通道,计数器的值不可能在接受到信号上升沿时候,有复位这个动作。
( n4 p/ d2 @1 F  B; K) r
6 n: C( z9 W% b4 }( |& D, x( G# x# G; R7 E/ ?- s2 G3 o
收藏 评论0 发布时间:2021-6-18 12:57

举报

0个回答

所属标签

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