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

【经验分享】HAL库 STM32CubeMX教程八---定时器输入捕获

[复制链接]
STMCU小助手 发布时间:2022-3-25 10:29
前言:9 N3 _2 {2 X2 h8 r! ^
本系列教程将外设原理,HAL库与STM32CubeMX结合在一起讲解,使您可以更快速的学会各个模块的使用6 ~- o( L1 v9 d  M4 S! B) x+ B9 Z

, j6 O7 f- S0 C
( t# v3 U& u+ h  `所用工具:: P+ n3 m  }/ p3 D) [
; o0 s) o! V" x- h) T- F
1、芯片: STM32F407ZET6/STM32F103ZET69 g# m" s* T! z) V5 y4 e+ R

( s0 x# u  _. _. c7 ]2、STM32CubeMx软件
. A: @7 F- W3 N+ O+ y, c( c& j$ q1 X4 r1 H8 u
3、IDE: MDK-Keil软件8 k4 y0 x& E8 ~7 }5 ]. |* w

. z) u; J4 k" j% Q5 z! y$ |4、STM32F1xx/STM32F4xxHAL库 3 \3 B. ^5 u& X4 s/ K

6 g/ V* |# u, O; G# |+ j0 b" h知识概括:5 m0 F# H3 x7 x1 G; h, r6 L
, b1 N9 _  U! ^" i: J
通过本篇博客您将学到:( w6 J  a0 i2 Z  o8 [

0 L' L9 T$ v8 ]) NSMT32定时器输入捕获0 [5 H( @( E" k, p7 L( M! W
5 Y/ `4 p: r/ B* n5 F
测量PWM频率和占空比
5 k. }/ q) I, A- P9 N+ P8 T
3 ]5 R6 D( R4 s8 w$ `8 f
9 n1 h1 [! [4 O( t输入捕获
" y' V8 [$ @$ i# y9 H, z' c* S输入捕获概念! ]1 U- @- W( B( f. r, {" z6 a
输入捕获模式可以用来测量脉冲宽度或者测量频率。STM32的定时器,除了TIM6、TIM7,其他的定时器都有输入捕获的功能。2 [+ t3 M% i" o' M5 a7 h

' q' A- U# d) L% V/ ~  T输入捕获的工作原理
; r! f/ r$ B8 I' m' |& U  j  [; y( c; Y
20190813094532466.png
* b2 X, \' W! E! x' @①先设置输入捕获为上升沿检测,
. h) U  P7 @. d+ o$ }! u( v/ D* \7 x8 r; \; h; ]0 ~7 a1 }
②记录发生上升沿时TIMx_CNT(计数器)的值3 A) t. }: C4 k. Q  r

; e1 n1 [1 V* X3 F/ C③配置捕获信号为下降沿捕获,当下降沿到来的时候发生捕获* X% ~0 V8 M! F
# o8 n# I% {: u( U2 _  u
④记录此时的TIMx_CN(计数器)T的值
% n# G3 }: J) c" m5 G2 K' Y, a) u) [! \$ E: q* |' D$ C
⑤前后两次TIMx_CNT(计数器)的值之差就是高电平的脉宽。同时根据TIM的计数频率,我们就能知道高电平脉宽的准确时间。
- M2 A5 d5 g) j0 o& e& N, Q
) e+ E, U' ?& S& _- N7 i
3 k  p$ {( c" H3 ~简单说:
; M, c$ e. I, F: n* \7 q; s6 {2 s9 q- A! i! q/ W4 w! a- n
当你设置的捕获开始的时候,cpu会将计数寄存器的值复制到捕获比较寄存器中并开始计数,当再次捕捉到电平变化时,这是计数寄存器中的值减去刚才复制的值就是这段电平的持续时间,你可以设置上升沿捕获、下降沿捕获、或者上升沿下降沿都捕获,' x5 W9 E3 F0 P3 Q4 _8 R

9 O" a8 M& |( d4 N( n5 [) G$ |" z% A
输入捕获的工作流程(对应CubeMx的四个选项)
( ~" t. |5 Z% f( Y$ H5 |/ b
5 B7 r: f9 r" D& F. y 20180419215648175.png ! n' u$ P: J* S+ B* A" Y

2 P0 E! }; w4 K2 W( t+ O+ r1 G& C设置输入捕获滤波器
. m: F6 m: Y' }
STM32在很多功能中都提供了滤波器,滤波器的功能简单来说就是多次检测视为一次有效,达到滤波效果,
; \3 Y6 B" `! |$ S
4 Z4 x+ A+ f( g8 d0 j% z" _数字滤波器由一个事件计数器组成,假设我们是检测高电平,滤波N次,那么记录到N个事件后计数器会产生一个输出的跳变。也就是说连续N次采样检测,如果都是高电平,则说明这是一个有效的电平信号,这样便可以过滤掉那些因为某些而干扰产生的一些信号        
( G- C9 [/ A$ k1 s* h% D1 v; l' n% B. z
输入捕获滤波器IC1F[3:0],这个用于设置采样频率和数字滤波器长度。其中:fCK_INT是定时器的输入频率,fDTS是根据TIMx_CR1的CKD[1:0]的设置来确定的。9 [$ q" s9 N4 I2 Q8 G! R
$ j( S$ r. @6 |
设置输入捕获极性
' m# a) n- g( N$ p& O, A" i
) J2 }( n" T2 l$ |' q设置具体为那种
捕获事件
: J) S6 }- Y4 D  V: |
0 |: R2 O( e0 L' Q3 r可以设置上升沿捕获、下降沿捕获、或者上升沿下降沿都捕获
8 j) G8 }" p1 i( [* W
4 q* b5 c. D& s7 B0 r设置输入捕获映射关系8 ]  {, z3 z9 `+ S  O3 J* _
STM32为了更好的优化使用,TIMx_CH1通道1捕捉到的信号可以传输到IC1,TIMx_CH1捕捉到的信号也可以连接到IC2,TIMx_CH2捕捉到的信号也可以连接到IC2,也可以连接到IC26 s, Z* x1 I2 T, V* R- W
# f' [! n, B1 {6 M5 ^/ g
20190813111456218.png
' z: ^* a  X1 l3 A
4 G( ?& Y& l5 ~8 R% C' ?2 O4 c2 ?. h. K) U- h& `* h, m& {
设置输入捕获分频器
: A9 }- l; `# Z) U) k8 f设置每N个事件触发一次捕获,可以设置为1/2/4/8次检测到电平变化才触发捕获; T* n& ]) `  V

1 `  E  e  \/ u1 R  n0 Y) f/ |溢出时间计算:7 H' V( S, N% k! ~- A/ |9 H* I
aHR0cHM6Ly9pbWFnZXMyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTIwNzU3Ni8yMDE4MDUvMTIwNzU3Ni0y.png 9 u. B/ ?+ O4 C5 i7 x

- u, w/ |4 p) I. z+ u2 ot1时刻检测到高电平,发生中断,在中断里将计数值置0,开始记溢出次数N,
* o% J7 ~' h$ r6 W& O
, t# X3 O  }. l* E) N  \其中每计数0xFFFF次溢出一次,直到t2时刻跳变回低电平,
- l& ~- ?- c2 e% G
2 c  v2 T4 I5 v# S9 n" m! p获取最后一次溢出时到t2时刻的计数值TIM5CH1_CAPTURE_VAL+ b& I* \" a1 u8 Q$ R

+ f3 ]  G. `! d! ]- J$ y( F5 L1 L则  高电平时间 = 溢出次数*65535+TIM5CH1_CAPTURE_VAL     us ;根据定时器初始化时的频率即可计算出溢出总次数所占用的时间,即为高电平时间。
" c) d; x8 q6 F! X* q; W2 L0 ?
  C$ g# {6 J% Y9 w如果计数器值为 32 bit   那么最大为0xFFFFFFFF      
6 t3 x$ M( ^# r$ S2 o
. q# f  }! p5 ~: \高电平时间:, {! W+ f7 v# |/ |; W
* V# g: X( N% @9 s5 T) c1 U
20190813172958716.png
( ?$ z5 B7 [7 A5 P0 d! c. I0 t' R* [1 Y( m3 X

, T; ], d0 c7 [8 I$ }: o* D2 d输入捕获的工作框图
7 j! O9 j3 O3 A8 Z0 g4 p. Q1 K6 s, Z  ^( d* M3 C+ R
20180419213733338.png 0 ~2 I- o$ i( z3 j' J
+ Y. y1 |% W! `# o% Y

- J5 `- ?% i' M/ v工程创建! Q/ a: `: T4 B
设置RCC
1 i/ ~/ G" m" p! z6 e
, i) O3 o4 J, g: d# W) F
设置高速外部时钟HSE 选择外部时钟源
  [' F1 Y1 i' N5 A8 p4 p/ @7 G, X9 @- B5 S$ s
20190810145615696.png 3 x4 M) F9 q3 d1 E
% Y6 Z) o% U1 Z4 g+ A
2设置时钟
% J3 Y  A: D6 b- v5 b+ F) X
* b; @8 o* ^% I6 Q! ^' p 2019081117400555.png
$ M, j! v7 a% I5 @, l6 N: q
! }  w2 `: G- |9 k我的是  外部晶振为8MHz ! q: \6 s/ F# P3 x# u6 X
1选择外部时钟HSE 8MHz   - e! O( T. [% N% m* E7 v
2PLL锁相环倍频72倍! N; Q! M  D  L- O
3系统时钟来源选择为PLL
' `1 m. P, T  l, d" M8 D4设置APB1分频器为 /2$ g: V9 K" |  v$ b8 C/ x" U
5 这时候定时器的时钟频率为72Mhz
5 D% w, Q* `0 t% G: r) V4 g* F
  z$ \, h1 G3 ^+ V3定时器配置# b0 N" e1 u8 @% [& h  e# l
& f5 f5 y/ ~. t: g6 e
20190813120324793.png
5 m- v0 C9 B% o) |' i$ w
% H- V- ~$ e3 c: x* C; M7 X这里我们选择TIM5的通道1
1 M; T* e+ G  b& A3 f. ^+ C% V8 w1 F1 S4 X$ n# W
预分频系数为71   计数时钟频率就是 72MHz/(71+1) = 1MHz        此时1us计数一次7 Q# v6 G$ v2 [6 G
自动加载值设置为32bit最大值  0xFFFFFFFF          + x. j( s% t/ t  ?5 B
上升沿捕获
/ X* u- Z6 T2 S# U4 h0 Y不分频
# M0 T8 i8 {1 ~1 e% O3 `& }滤波值为8
1 m& a* Q% r( X" k( w, N
/ S- ^+ N7 {. X3 C$ r0 x同时在NVIC一栏使能TIM5的中断2 @+ ~" d1 b: g5 ^6 `
9 c2 s1 B0 D* P6 e' k0 L
对应引脚设置下拉电阻,保证没有信号输入的时候电平稳定: o7 ?" |$ f2 G( L( f
; t- |+ u/ h6 B$ ?, L) v; d
20190813152340197.png ! A- J) f4 z7 w; w

* u6 R8 F2 l: a# f* k9 Y4项目文件设置
2 z4 _0 L, ^; ~" O& l4 M, }) v- k1 R% `9 R5 n$ t8 q" d4 o
20190811193124463.png
# o2 S) {5 G) G: s  b
3 u) B. ?7 h2 Z9 B% b1 设置项目名称
- O1 D+ q9 _  Z1 @; j, k' h9 F2 设置存储路径6 W1 V: X  f  W0 w7 Q- q
3 选择所用IDE
& q9 S2 Q, W  q( M5 `( D) d/ B& E( M3 U8 z2 @
2019080921100765.png / b! N( T, b+ o0 {) a4 f
. E' A, \$ e, A' F
5创建工程文件: O2 H! H; |7 {" m- c/ u

$ x0 Z$ C. h, k然后点击GENERATE CODE  创建工程" L* v# e( l/ V# \) h

8 v9 e1 ~2 _0 r& q' d4 G配置下载工具
% y/ ~4 v' ~- o) a1 ]) \8 w! x3 C& z新建的工程所有配置都是默认的  我们需要自行选择下载模式,勾选上下载后复位运行
: R! f3 e3 L( q) q3 b" [, Q9 Q3 w/ c5 Y) {& S8 g3 J
20190809172359875.png
: O7 S$ ~; {& G) j: ~7 c; _, I6 \
例程实现:  S, S2 A. k! v4 f: c: ~
定义变量:
  1. /* USER CODE BEGIN 0 */
    2 C2 `9 X* a" a$ Z
  2.     uint32_t capture_Buf[3] = {0};   //存放计数值
    3 q8 J" y9 D4 e
  3.     uint8_t capture_Cnt = 0;    //状态标志位" j  i9 x0 b9 K7 E& H+ Y" ]  e
  4.     uint32_t high_time;   //高电平时间
    ; N$ Y% p' d# I5 r9 q3 ?  L
  5. /* USER CODE END 0 */
复制代码
& X7 d- j6 H) w  m9 P. H; Q& D
在 while(1)中的用户代码区 3,写入TIM2 CH1通道的输入捕获控制和数据处理6 V) [1 t, l4 F5 p: S0 }# ]

. f* M/ N$ L% g  F
  1. while (1)( ~0 Z* E, i; d) h% X" A
  2. {
    ' b2 q9 ~- o1 f
  3.     /* USER CODE END WHILE */
    1 e, \8 e6 F! J. r. S
  4. 7 z& k2 H7 k/ r: H/ B, I
  5.     /* USER CODE BEGIN 3 */
    - v4 m1 u  I  p; e! K9 }
  6.   switch (capture_Cnt){4 [) k9 w0 j& z9 s& Q
  7.         case 0:5 y( p: u. u5 f3 r
  8.                 capture_Cnt++;
    4 J0 n" I$ k5 H4 l  Z- C
  9.                 __HAL_TIM_SET_CAPTUREPOLARITY(&htim5, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING);
    1 j) I2 `4 b! X6 f  ~' U
  10.                 HAL_TIM_IC_Start_IT(&htim5, TIM_CHANNEL_1);        //启动输入捕获       或者: __HAL_TIM_ENABLE(&htim5);+ ~# K: ]- B& t' \- A' l
  11.                 break;
    0 n0 G& J- N  ~! J. \9 \! q  N
  12.         case 3:
    9 g; Y% V& l( C8 U6 O
  13.                 high_time = capture_Buf[1]- capture_Buf[0];    //高电平时间7 l& n$ _1 p9 k. L7 v- |
  14.                 HAL_UART_Transmit(&huart1, (uint8_t *)high_time, 1, 0xffff);   //发送高电平时间2 x' X. Z9 R1 V; X7 w+ b7 w
  15.                                 : F/ s  L! Y4 @" ]! ?! `/ o1 |
  16.                                 
    : S* j, u2 u9 V* D. }/ A. z# N! Z- r
  17.                 HAL_Delay(1000);   //延时1S1 ~' E* M7 h5 A3 D$ e) ~
  18.                 capture_Cnt = 0;  //清空标志位
    & U; t- g4 c2 @( g$ P  k/ U9 b
  19.                 break;
    - R1 ?9 M/ d8 m$ N+ a6 i0 U
  20.                                 ' w3 S% ]  i2 P( |- x/ ?! l
  21.         }
    . h2 b  p9 {/ T6 ]" h' S
  22. }
    7 d/ u0 u9 j$ C+ t4 Q
  23. /* USER CODE END 3 */
复制代码
% O  f" L0 Q; @
在main函数下方添加中断回调函数:
; X/ v+ @8 `5 N2 _- v1 T4 J) K# h" I, n! t6 e& z' {5 D" }
  1. /* USER CODE BEGIN 4 */
    6 s* q2 ]/ e" Q- [' b& e6 J
  2. void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)0 G# ~# r/ C8 P& h. }1 F! b
  3. {) j3 s! R  l  E5 v" X* K! n' u
  4.         
    0 t/ i' o8 k, k
  5.         if(TIM5 == htim->Instance)$ E6 X1 F7 ~, x* m9 D
  6.         {
    ( H' Y. b; `/ D" k4 I' B0 D
  7.                 switch(capture_Cnt){) i- p) c- @* q  g8 I
  8.                         case 1:
    5 u0 G1 |  @, N' C% a7 T; ^
  9.                                 capture_Buf[0] = HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_1);//获取当前的捕获值.
    ) z: q9 C2 E, V; N
  10.                                 __HAL_TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING);  //设置为下降沿捕获
    ( _' o+ k6 L* v% y7 V
  11.                                 capture_Cnt++;: N" \' N+ f) j
  12.                                 break;) Z0 y# B2 [  l
  13.                         case 2:
    ! o9 Z/ A. W3 B# o
  14.                                 capture_Buf[1] = HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_1);//获取当前的捕获值.$ q& E* U) l! K' Z9 ^7 M
  15.                                 HAL_TIM_IC_Stop_IT(&htim5,TIM_CHANNEL_1); //停止捕获   或者: __HAL_TIM_DISABLE(&htim5);! X1 D- ?# Y9 K. c# i
  16.                                 capture_Cnt++;    ! B3 x3 M* o( C/ c+ V5 f6 h
  17.                 }- s3 X  n$ |3 G. ]( I
  18.         
    % g. ^' w: Z. p* D4 K& P+ C
  19.         }% r* ~; D) W8 y" I1 S
  20.         , J& `( R8 E' e- X
  21. }
    8 g/ I/ K9 H6 r8 z2 ]& N  X3 k
  22. /* USER CODE END 4 */% q, a( I& G1 A
复制代码
/ F7 C) K/ P  X9 }( f: z; Z! A9 B
具体流程:  ]* u  [/ J# z7 U
$ \* a4 _1 l( B) ~
1.设置TIM5 CH1为输入捕获功能;  * |9 W7 d& l+ Z: C) \+ C
4 m4 c" [: j; Z1 X9 ~
2.设置上升沿捕获; ( f+ J8 \( @6 j, A

, p* _& H4 X/ z5 f$ z3.使能TIM2 CH1捕获功能;  
( J$ u1 G0 H, ^- f2 h- Q5 ~, ]- c4 [' B, U# U6 b
4.捕获到上升沿后,定时器当前计数值存入capture_buf[0],改为捕获下降沿;     v- i# L. P% W0 m$ Z2 ]
$ P. L1 S0 j# X+ `) U' N8 O
5.捕获到下降沿后,定时器当前计数值存入存入capture_buf[1],关闭TIM2 CH1捕获功能;  capture_Cnt=3;4 a$ q5 h. I3 j! u: ?' Z  t  G4 C0 Q

  u9 N+ b( X9 a, P! P; U' x6.  高电平时间: capture_buf[1] - capture_buf[0]        发送到上位机  重新启动输入捕获5 V' d- V2 @1 }% ~! U
7 A0 V" |/ b# P3 n% I% o
! a8 c5 E$ d& N9 P& d) ?% p
__HAL_TIM_SET_COUNTER(&TIM5_Handler,0);   //设置计数寄存器的值变为07 I$ k! \) {# l# ]& t7 M; @# k

  c6 q8 `% v8 [# Q7 q# |HAL_TIM_PWM_Start()              函数用于使能定时器某一通道的PWM输出。) w; u6 n1 b; s8 ]
0 g3 m1 i$ U8 {# C2 B
HAL_TIM_IC_Start_IT()                  函数用于使能定时器某一通道的输入捕获功能,并使能相应的中断  S) ^9 z. Z& f8 r7 O0 l' ~
' }! a9 e# ?0 Y2 ^0 t5 c
HAL_TIM_IC_Stop_IT()                 函数和开启功能相反,是关闭定时器某一通道的输入捕获功能和相应中断
( q: R/ Y- h6 ?' C
& s) L+ o  `' p) K) x: r) h& T" R! v__HAL_TIM_SET_CAPTUREPOLARITY
不是函数,而是底层操作的一个宏定义
. u# t+ i' L- |3 W# j. W  G: s: W, t/ n# C  v
在stm32f4xx_hal_tim.h文件中可以找到。其作用是修改定时器某一通道的输入捕获极性4 I5 K/ t' O7 p/ @6 u
" e% Q7 G7 L: r& V% A) j
20190813171232499.png
. O' V, t, K4 Q2 r* r8 t
* x9 ?: l8 H# f- i" H) r% Y2 b其中有两个函数,第一个为清除清除原来的捕获极性,第二个为设置通道捕捉极性8 t/ j2 F  t" _9 h1 }0 p
; ?" p/ W6 L/ E
等价于:. [7 x* q; R. E* C2 K/ S
6 c. N$ q$ U. r% m; `: b; W$ x
  1. TIM_RESET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1);   //一定要先清除原来的捕获极性!!
    ' A! M. b! M: G& Q* l: r; [
  2. TIM_SET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING);//定时器5通道1设置为下降沿捕获(重设捕获极性)
复制代码

& W' X* k+ v- N在修改定时器某一通道的输入捕获极性时,一定要先清除该通道之前捕获极性/ l- f- B" L  P6 c6 c, t- ^

& \' V/ g) H) S. t6 y__HAL_TIM_GET_COMPARE也是一个宏定义。 ( k$ l- T/ O: N
在stm32f4xx_hal_tim.h文件中可以找到。其作用是获取定时器某一通道的捕获/比较寄存器值+ u  v$ r0 B7 s" X9 K, e

6 x, n6 R0 g2 ^* v3 `' { 20190813171323391.png
, x# |/ x( ~3 J
( }* K8 l, [# K; n0 d等价于 :  HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_1);
0 Q  q, y. \: A3 `; F/ X" _! s! d- V' V( y  d' r2 `; I  P
  两者都是直接读取对应CCRx寄存器的值
2 J( L( f: k4 v& e8 ^5 w: Z) j. [+ c1 B: `) \1 e  F0 A  ^7 Y4 H
% |- ]" K5 n2 ~: f7 ~+ q' S
# C# e+ w- X: z8 a$ m8 K; F: h
收藏 评论0 发布时间:2022-3-25 10:29

举报

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