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

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

[复制链接]
STMCU小助手 发布时间:2022-3-25 10:29
前言:
# R+ v1 P# x8 E, s, U- p本系列教程将外设原理,HAL库与STM32CubeMX结合在一起讲解,使您可以更快速的学会各个模块的使用) C  Z+ a8 @' K

1 I! L1 V; C3 U# i# m0 D% q$ S& |% F# n
所用工具:
' `* w7 W3 j5 G. S
( Q% t, v. O+ Z8 V) P4 k5 M1、芯片: STM32F407ZET6/STM32F103ZET6
" s/ r1 f" S- `! B$ h7 W
* L1 ?* V5 A5 E( u" u+ e6 V2、STM32CubeMx软件
7 K& l+ t$ O, W& \! n
& b9 b% k; U; L6 j, c. m$ B3、IDE: MDK-Keil软件
! v4 p& J; R4 W8 R
! N6 w, a  N1 V* Q- N2 C' V3 i4、STM32F1xx/STM32F4xxHAL库 : _4 U) ]) Z# l6 C- l

; C3 U/ _  n1 l6 w* ]: ~9 N; B+ t" @知识概括:
- S# e, V. Q& x8 t" e, A/ V: k, q+ H4 e# d) y( a. Z
通过本篇博客您将学到:3 C: H' f7 J$ s" p, Y  w
) G( z# r* A3 @! W9 `
SMT32定时器输入捕获8 w! N7 n2 G& V, \7 @' n
1 h4 Y8 A6 A, @$ J  h
测量PWM频率和占空比
* f; [* H: k8 ]2 c$ ~+ ^3 o, ?. T7 T1 ?% e) M% M5 p
9 Q9 ^% E6 a9 b, m; v# [) G
输入捕获
2 J2 v3 t% ^" h  N* D. s- Y/ t输入捕获概念
0 @( F! z; @+ ?$ C2 P; u) k( r输入捕获模式可以用来测量脉冲宽度或者测量频率。STM32的定时器,除了TIM6、TIM7,其他的定时器都有输入捕获的功能。
( A. ?* H# r7 q; V- S7 e/ ^" n/ B! K/ A! |! r% ~1 k
输入捕获的工作原理% W7 a& |8 z3 a

+ m& ?2 B* F1 E2 {7 w& d/ W 20190813094532466.png
) L" L( f: Q& p" t* A' `①先设置输入捕获为上升沿检测,: \6 n. H- F9 k6 g# c( r$ `2 N
. f4 n8 |, Y0 c# R8 _9 j. ]! _' D* y
②记录发生上升沿时TIMx_CNT(计数器)的值
' M9 b! P& o3 ]" Z' \; N0 Y8 S" ]
% C, i+ T3 }9 v+ c③配置捕获信号为下降沿捕获,当下降沿到来的时候发生捕获
2 U, |) C) B9 N+ D2 S/ a5 V2 Y& A
" Z& [( l! q+ R1 g) }④记录此时的TIMx_CN(计数器)T的值- R! S1 B, I9 b
" `4 Q( w1 o# r1 e9 Q
⑤前后两次TIMx_CNT(计数器)的值之差就是高电平的脉宽。同时根据TIM的计数频率,我们就能知道高电平脉宽的准确时间。: O9 _: a7 c2 d

; U! K% I+ O( Y' j
( U  _  h! K% Z简单说:
# U3 H* `+ j, b; Y1 F' M) F; A5 ?  C, _4 u) n
当你设置的捕获开始的时候,cpu会将计数寄存器的值复制到捕获比较寄存器中并开始计数,当再次捕捉到电平变化时,这是计数寄存器中的值减去刚才复制的值就是这段电平的持续时间,你可以设置上升沿捕获、下降沿捕获、或者上升沿下降沿都捕获,
/ |7 K7 ^, r- E( W& l7 W
1 L% }, W) o; A6 I2 s7 a) `) y( i+ H
# d- {. u/ `) {( O( [$ D: n7 Y输入捕获的工作流程(对应CubeMx的四个选项)
( d! e6 O8 m/ K; C5 ?. j
: z6 D; S+ }/ T; Y 20180419215648175.png
# P; t) V. r$ ]' a
4 ]5 v$ W! D8 @( g- i1 ?0 n1 o设置输入捕获滤波器
9 B% Y! T* w( o0 z- q
STM32在很多功能中都提供了滤波器,滤波器的功能简单来说就是多次检测视为一次有效,达到滤波效果,
. ]7 m1 ^* V% K$ q
7 l1 [8 A4 C% a. @% B数字滤波器由一个事件计数器组成,假设我们是检测高电平,滤波N次,那么记录到N个事件后计数器会产生一个输出的跳变。也就是说连续N次采样检测,如果都是高电平,则说明这是一个有效的电平信号,这样便可以过滤掉那些因为某些而干扰产生的一些信号        
: H1 }2 T% I8 u) G; ]9 ^1 M# G* b* V- b* X) C
输入捕获滤波器IC1F[3:0],这个用于设置采样频率和数字滤波器长度。其中:fCK_INT是定时器的输入频率,fDTS是根据TIMx_CR1的CKD[1:0]的设置来确定的。
1 m+ F# \7 d: G4 V
9 G  |: X4 y/ q# S% X9 z设置输入捕获极性, |7 i" S- F& o* b* W2 q
" r5 u! o/ u! X" t$ w" Z# d
设置具体为那种
捕获事件
# m. I0 F" D4 i6 C; m6 j
# ~# H" ?6 `' s) q可以设置上升沿捕获、下降沿捕获、或者上升沿下降沿都捕获
# r) x+ n! Z! L9 x  _6 A* N
: D/ ]* c8 `) b0 I设置输入捕获映射关系
# D$ S8 \+ e  Z8 c9 V3 pSTM32为了更好的优化使用,TIMx_CH1通道1捕捉到的信号可以传输到IC1,TIMx_CH1捕捉到的信号也可以连接到IC2,TIMx_CH2捕捉到的信号也可以连接到IC2,也可以连接到IC2
+ C8 M5 C% l, `/ x( d: L. y9 r) D6 k
20190813111456218.png ; s8 c+ y5 o2 k9 O
/ \1 A" n- e( a: G" v
; P* |9 |& n. c! l
设置输入捕获分频器6 w) k. n( Q1 N$ c; v; \
设置每N个事件触发一次捕获,可以设置为1/2/4/8次检测到电平变化才触发捕获
  X, w7 V6 Y" X/ b. }! ~& B, c( ^
0 t+ b, N/ v/ n) v: g3 r- ]溢出时间计算:0 V* p! W% X) z/ w
aHR0cHM6Ly9pbWFnZXMyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTIwNzU3Ni8yMDE4MDUvMTIwNzU3Ni0y.png
% u6 L$ P, r3 z0 J  x, @3 {; [6 j
! |' `/ m* [, Z; y7 J- Zt1时刻检测到高电平,发生中断,在中断里将计数值置0,开始记溢出次数N,* k! N* }  E- d1 m8 r* \8 z' r
8 @, M$ E( {' C  q  E' w
其中每计数0xFFFF次溢出一次,直到t2时刻跳变回低电平,  S7 ~  v1 ~: l' d; U

; C0 B7 w2 B7 ^$ u/ h2 U" T获取最后一次溢出时到t2时刻的计数值TIM5CH1_CAPTURE_VAL" K% ]0 ?7 |1 j
" }1 B4 a' i2 M; v/ A
则  高电平时间 = 溢出次数*65535+TIM5CH1_CAPTURE_VAL     us ;根据定时器初始化时的频率即可计算出溢出总次数所占用的时间,即为高电平时间。
6 H5 G7 Z) j# q: S8 b6 N/ N! I& B1 R! f; s7 {' s3 ?
如果计数器值为 32 bit   那么最大为0xFFFFFFFF      
5 d: [/ @1 N8 s6 \& ?) P, m9 p  e* T& B' u$ G) r
高电平时间:
( b) p& u2 Q0 k, m; \' ]! I3 T; w5 ~$ n* p& C6 W
20190813172958716.png 4 e3 y. \# ^8 ?1 Z
0 ?" @& _4 B# j6 W- c; k

9 a: y( l9 K- q输入捕获的工作框图
( P$ ~: b/ ]" c7 B" x/ \6 {8 Y, c: v/ M- D7 F! }
20180419213733338.png
' k8 N) }& \: K. ?. V9 W0 e8 J8 k. I
( z* w! D7 M) o1 J, ^: P
9 s* g6 q. T4 i# u0 B$ W工程创建
& H7 E+ P  i6 k* t设置RCC

/ C/ h! g$ l/ d$ g8 K' p- y7 H  H
设置高速外部时钟HSE 选择外部时钟源* }; p8 }& S1 J. l, K
1 M7 h. u) z. C4 z; B2 V& Y
20190810145615696.png * H- m, j2 V) T, I( f% `

6 k6 x' T/ ?4 M4 T. J3 Q3 D2设置时钟
8 j  i9 x% ^# W1 h$ d1 p/ |/ ]# i7 ?* X0 f- n
2019081117400555.png 6 o( @$ i7 D. _( _+ S/ |

/ |" b) A- U, b6 X6 Z+ A4 ^+ D+ R我的是  外部晶振为8MHz
1 f6 |, d* q' C+ @, h) `1选择外部时钟HSE 8MHz   
$ K- v2 K1 w! }! ~, R2PLL锁相环倍频72倍
! v: I9 W/ r) P/ N3系统时钟来源选择为PLL
7 ^) _0 X8 C1 \+ C( b4设置APB1分频器为 /2; o1 ], y7 s, i- |) ~2 c
5 这时候定时器的时钟频率为72Mhz" F3 P0 S# n8 K) H+ _( q
9 J+ q8 O0 a: x# J% n
3定时器配置
2 K; V) @1 E* @) g% ^) @
6 F. o& s; p' s) g! C3 W- \( u 20190813120324793.png $ ]) ~7 x7 |# c. E7 B, J& F. c

/ x% Q/ g6 a8 ?6 ?4 u1 p这里我们选择TIM5的通道1
" [9 |7 r0 H, C/ M" \. H7 Q9 {# K7 {  S
预分频系数为71   计数时钟频率就是 72MHz/(71+1) = 1MHz        此时1us计数一次. q5 m) M4 x6 M9 d: f# C  Z
自动加载值设置为32bit最大值  0xFFFFFFFF         
5 S* l* m7 O; y) O上升沿捕获0 ]+ ?6 A7 m! i# C+ g% r; m
不分频
# h/ ]: O5 D7 s9 u  N6 S+ [( y- e滤波值为86 U) |0 |! U) O  ?. L
8 L- ^4 O" y- L5 T1 d; L
同时在NVIC一栏使能TIM5的中断
1 k/ m- a) Y% Z4 Q" K- Z9 c2 R: Y  ^8 c0 R9 Y/ {
对应引脚设置下拉电阻,保证没有信号输入的时候电平稳定  d6 C& m% b$ \% H  z

4 \0 ]( E6 G) u" Q- X  l! Q9 h 20190813152340197.png
! g+ M9 a! I, ]/ i; d" N; h, D8 M
4项目文件设置
" ]' E; g5 L4 B" p! n* |
; ^: x# U2 k8 C1 f5 Y  p4 Z: V 20190811193124463.png & d; |5 y# W9 y  C, v

3 n% u% H6 ]: J) s1 设置项目名称3 k. B; b2 K2 y+ k
2 设置存储路径
: S& ^+ P+ E( H3 选择所用IDE2 W$ z: J, b. {6 _0 U& _! T' M
  x( x* B* Q8 a, N1 f
2019080921100765.png
& C% S& m' N0 Z  x, ?# a/ r# c& R0 v5 @' e) {
5创建工程文件6 ]3 v9 J  f: t4 x2 J

# M( s  v* h- W5 m然后点击GENERATE CODE  创建工程
, f0 `5 l  d8 u! F$ t+ J. Z; Z! a
. f) n- ?6 m9 b# Q6 Z配置下载工具
0 z; v: T& @* F) z, i* t% w7 K. g新建的工程所有配置都是默认的  我们需要自行选择下载模式,勾选上下载后复位运行
' q- ?% W6 H$ J6 g% p3 t3 ?: G- T% ^( g
20190809172359875.png 7 j: ^# B) t$ F, s5 \* O
, x# ~* W* R1 e# G
例程实现:- y  g' G" L9 |  L
定义变量:
  1. /* USER CODE BEGIN 0 */
    + Y; P" `4 A3 |3 x+ _+ M5 \
  2.     uint32_t capture_Buf[3] = {0};   //存放计数值8 ?- s) C3 P9 e1 c9 d* R& C
  3.     uint8_t capture_Cnt = 0;    //状态标志位
    , }: ^3 K3 D/ J- t5 r
  4.     uint32_t high_time;   //高电平时间
    ! c8 w+ |' J( a- j
  5. /* USER CODE END 0 */
复制代码
- ^0 Z/ X2 A2 g$ e) f
在 while(1)中的用户代码区 3,写入TIM2 CH1通道的输入捕获控制和数据处理; O$ O0 |# R" D! W, j8 \

( ?& m0 }" c6 D3 ~) k  f& O4 w
  1. while (1)
      d7 \( D( u& _$ F" ]5 ~' I
  2. {
    ! Q" m4 J; v9 T  t7 u
  3.     /* USER CODE END WHILE */4 F2 u$ g- I2 i% w4 ^% B* X# q1 q

  4. : O1 }1 O4 i6 v2 T
  5.     /* USER CODE BEGIN 3 *// y' _9 i9 s+ |( u
  6.   switch (capture_Cnt){1 t# i- c3 Z" w. u7 x9 o
  7.         case 0:$ K% x; ~, ?/ F0 T
  8.                 capture_Cnt++;! `4 i; E$ |# s; I# H, ^
  9.                 __HAL_TIM_SET_CAPTUREPOLARITY(&htim5, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING);
    / Y. i6 q6 i) H+ B; d
  10.                 HAL_TIM_IC_Start_IT(&htim5, TIM_CHANNEL_1);        //启动输入捕获       或者: __HAL_TIM_ENABLE(&htim5);! U3 Y) b: `+ T9 C
  11.                 break;
    # h# |/ e. Y0 Y2 P
  12.         case 3:
    2 U% ]! }4 k( d- D0 H: a  a8 i
  13.                 high_time = capture_Buf[1]- capture_Buf[0];    //高电平时间
    0 v* U: a. r9 b, ^
  14.                 HAL_UART_Transmit(&huart1, (uint8_t *)high_time, 1, 0xffff);   //发送高电平时间
    / h1 U8 @" Y) y' p. T$ r
  15.                                 
    8 c, k. B8 @/ q  A
  16.                                 
    4 G  Z: `( o2 S5 Y
  17.                 HAL_Delay(1000);   //延时1S  `& d. a8 S6 ~$ _3 I2 M  t
  18.                 capture_Cnt = 0;  //清空标志位
    8 O' w2 n: |" L: t# R
  19.                 break;
    ' b- Q& v+ Y' N' x5 [! m% G, E
  20.                                 
    : m" t/ v* `$ n8 |" ?; h5 W
  21.         }5 G# a  B4 Z5 q8 k  n1 z
  22. }
    + w( H9 R' k! n) v1 w: g
  23. /* USER CODE END 3 */
复制代码

: m0 i3 g4 _6 p: _在main函数下方添加中断回调函数:& t1 a2 R% Y% J+ t/ l8 \& w
7 n) Q: x. P8 B% k( N
  1. /* USER CODE BEGIN 4 */& r7 k; ?/ }0 u
  2. void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
    ; c4 R1 g7 X0 J- ?5 t- v
  3. {6 x' \- n3 W4 I$ Y* `' G
  4.         + e/ s, c6 c( w  ~
  5.         if(TIM5 == htim->Instance)6 e# j8 h) L3 j0 z' b$ ~
  6.         {
    2 z( l1 g6 h" i; O
  7.                 switch(capture_Cnt){$ L% U% A$ O3 u- ]; G8 B. @' }
  8.                         case 1:0 `: k5 X: C- Q" G9 C2 n
  9.                                 capture_Buf[0] = HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_1);//获取当前的捕获值.* O" a6 D7 Y" i* n5 T
  10.                                 __HAL_TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING);  //设置为下降沿捕获! V+ E$ V* F) L
  11.                                 capture_Cnt++;
    4 ^" ]0 F1 s0 K* f8 s: j' t/ I
  12.                                 break;+ X# v  S4 t3 M) E, `
  13.                         case 2:/ Q  O& ?0 w  h, \
  14.                                 capture_Buf[1] = HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_1);//获取当前的捕获值.
    # q8 |- w3 t6 l) f; A
  15.                                 HAL_TIM_IC_Stop_IT(&htim5,TIM_CHANNEL_1); //停止捕获   或者: __HAL_TIM_DISABLE(&htim5);
    0 V8 \1 _" |% m; A) z
  16.                                 capture_Cnt++;    . V! J8 _2 m& O) X; P, z; `
  17.                 }: b! T8 P+ y  V% ]! E
  18.         
    . ~& A" [( `$ p
  19.         }" K) ]( t5 Y6 T
  20.         
    7 b5 D6 ^0 _7 J* N5 K% F
  21. }
    + D2 h, C) Q/ O2 Q0 d. a
  22. /* USER CODE END 4 */$ v# {" Z* M' z# V( C) }
复制代码

: z4 Z; W6 @) w$ ]& U! d具体流程:
5 J6 S4 _" s# R( V. m% [+ r. N: ~2 z" X+ }. C: f% S; Z
1.设置TIM5 CH1为输入捕获功能;  + v& W2 o' S1 {
6 Q+ w4 y2 ?% H* F* m7 V
2.设置上升沿捕获;
7 @/ _5 n8 Y5 G' d" `4 ]/ }# f( L- M' @
3.使能TIM2 CH1捕获功能;  0 F$ k4 p! r. `6 d& ]( ^. u
8 h, v" w3 [% r, O' T% w
4.捕获到上升沿后,定时器当前计数值存入capture_buf[0],改为捕获下降沿;   7 z/ ~/ ?( [! z' t! u
9 g+ s7 L) u0 ?
5.捕获到下降沿后,定时器当前计数值存入存入capture_buf[1],关闭TIM2 CH1捕获功能;  capture_Cnt=3;
# l! H1 J  [( Q- ]& y
4 `- `+ d8 z6 X/ b% `6.  高电平时间: capture_buf[1] - capture_buf[0]        发送到上位机  重新启动输入捕获
/ A6 L" b- e1 k; c% R& H5 h& H2 I7 _* m: S7 v+ J

/ q6 o% V% l; I2 I+ P__HAL_TIM_SET_COUNTER(&TIM5_Handler,0);   //设置计数寄存器的值变为0
, u1 m7 F" L$ Z5 g( G) W* k; g
& T% ~' |- ]$ a! ]" tHAL_TIM_PWM_Start()              函数用于使能定时器某一通道的PWM输出。& x( i- V2 m0 G& h  O' {+ C

1 j+ v! ]  r+ c/ `3 B  `% `2 ZHAL_TIM_IC_Start_IT()                  函数用于使能定时器某一通道的输入捕获功能,并使能相应的中断2 k% L3 s* \- I8 i9 X! S

2 p& |' R7 \& l, E# _& Q) OHAL_TIM_IC_Stop_IT()                 函数和开启功能相反,是关闭定时器某一通道的输入捕获功能和相应中断
6 n0 P6 C0 V+ m6 ?1 R/ R7 C, F" r# M, M4 j$ D
__HAL_TIM_SET_CAPTUREPOLARITY
不是函数,而是底层操作的一个宏定义7 G' P9 y) Q; i

6 j2 w0 }& ]7 b3 U+ K( r在stm32f4xx_hal_tim.h文件中可以找到。其作用是修改定时器某一通道的输入捕获极性! H! a; B/ G$ h

6 z7 M$ W3 q. X) O 20190813171232499.png
) Q  E. L$ k) I  S
2 V, t3 n, u1 @9 z) X其中有两个函数,第一个为清除清除原来的捕获极性,第二个为设置通道捕捉极性: a8 [9 h' d% O9 [$ s

( T0 `6 p8 F1 ^7 W( d等价于:
1 M" z9 h  d1 M! b( m4 j9 \1 |6 G' x+ f& J! P) `, \
  1. TIM_RESET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1);   //一定要先清除原来的捕获极性!!
    1 {9 r0 n, l1 w
  2. TIM_SET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING);//定时器5通道1设置为下降沿捕获(重设捕获极性)
复制代码
3 G5 E1 G) e) W
在修改定时器某一通道的输入捕获极性时,一定要先清除该通道之前捕获极性: ^7 U+ O! Z* A% H9 H3 W
9 ^# L* S! }; y, o' i& n/ x
__HAL_TIM_GET_COMPARE也是一个宏定义。 
" G$ _9 S. h9 d' U7 a( r在stm32f4xx_hal_tim.h文件中可以找到。其作用是获取定时器某一通道的捕获/比较寄存器值5 V$ K. J% R! \9 n0 U

2 T: b! X4 d" x- k1 X: X 20190813171323391.png 5 |2 ^4 g1 P4 I, T9 @* X& N$ }% `

6 O# [. w4 b* K& T  n5 L9 P) P; q等价于 :  HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_1);
; V9 Q9 A+ w0 }9 d" a: f' ~9 i2 g$ N3 r# k. f+ m7 A8 P/ Y' }  U
  两者都是直接读取对应CCRx寄存器的值1 m* x/ @5 e5 a; ^6 v9 M/ b

4 I7 F& `6 f/ Z6 V% b2 }+ n
: C0 c4 G3 C; ]( ?4 t& i
- y2 W/ a! N* {' \, }( Q) g
收藏 评论0 发布时间:2022-3-25 10:29

举报

0个回答

所属标签

相似技术帖

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