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

【经验分享】STM32H7的TIM定时器基础知识和HAL库API

[复制链接]
STMCU小助手 发布时间:2021-12-21 23:00
32.1 初学者重要提示0 H7 n, B$ I) I& T
  学习定时器外设推荐从硬件框图开始了解基本的功能特性,然后逐步深入了解各种特性,这种方式方便记忆和以后查阅。) }! s) }1 ~8 D& z1 U. O* ^6 R4 e
  STM32H7的定时器输出100MHz方波是完全没问题。
* s9 M3 W: g5 ]4 X$ A; Z* A: W  STM32H7定时器进出中断的速度能跑到12.5MHz,所有程序在TCM和Flash运行没差别。
4 A1 @9 V- O' J* L$ s, Y  STM32H7的定时器输入捕获可以实现12MHz方波的双边沿捕获,单边沿可以做到24MHz。  Q. H* }" R2 r9 `2 w% M0 m. m
  特别注意STM32H7的TIM1,8,15,16,17才有RCR重复计数器,其它都没用的。
: c6 R; a2 r6 M  v+ n- S: x  STM32H7的单个定时器中不同通道可以配置不同频率PWM。! Q# c8 P% D4 V+ u3 `! T8 O9 O: ]6 ?( [
  STM32H7的TIM1-TIM17中断入口函数名使用时要注意,别搞错了:
" b$ y+ Y+ n0 H" i' u
  1. TIM1_BRK_IRQHandler            
    / |4 r$ V; q, ^0 w7 F" R0 Y* A
  2. TIM1_UP_IRQHandler              
    - \0 e; n7 T9 ^; g  Z( }. S
  3. TIM1_TRG_COM_IRQHandler        & F2 F0 I! g5 k8 I% d' M+ L
  4. TIM1_CC_IRQHandler                                                    - w, ~- L- T8 |4 I# V
  5. TIM2_IRQHandler                                           % ~4 ^  b9 m' [$ o
  6. TIM3_IRQHandler                                                 & d( x. k+ p! G3 Z  {+ \% R5 |9 N. M
  7. TIM4_IRQHandler                 
    8 E/ @* k( O8 m( W7 c) Y! t
  8. TIM5_IRQHandler            ; ~' G  }; e! G
  9. TIM6_DAC_IRQHandler           <------------------要注意            % a  g2 _" N; f$ n, R6 ^2 A$ O8 X
  10. TIM7_IRQHandler
    % W  y( T) U. j: n9 w
  11. TIM8_BRK_TIM12_IRQHandler      <------------------要注意,定时器12也是用的这个. u5 \5 u% Y- H3 V( K* E
  12. TIM8_UP_TIM13_IRQHandler       <------------------要注意,定时器13也是用的这个# d( o. l( S, F/ j
  13. TIM8_TRG_COM_TIM14_IRQHandler  <------------------要注意,定时器14也是用的这个
    5 ]0 i2 Q2 @- J6 @4 f
  14. TIM8_CC_IRQHandler          , s( t7 u7 z5 ]1 @
  15. TIM15_IRQHandler   l8 h( S" A4 ~. N; k* a
  16. TIM16_IRQHandler
    $ C* W- C. y2 A! h5 }0 q
  17. TIM17_IRQHandler
复制代码

1 {) @: N1 R5 [4 U' _- J) S* C! Y32.2 定时器基础知识
) n, \4 G5 V  e/ l注,不同定时支持的功能略有区别,基础定时器功能较少,TIM1和TIM8高级定时器功能多些。! D/ }2 c) j  M& Y, U
2 s  d8 }0 _% a
  TIM2和TIM5是32位定时器,其它定时器都是16位定时器。16位和32位的区别是CNT计数器范围不同,32位的范围是0 到2^32 – 1,而16位的是0到65535;它们支持的分频是范围是一样的,都是1到65535。
7 A! a/ f6 X6 J# w. {  计数器支持递增、递减和递增/递减二合一。
% W' h) G0 E, J( v( |8 h$ G  多个独立通道,可用于:% h6 K& F$ [; X2 G+ Y! k$ O: ]; w
– 输入捕获。
" M' U! c8 r  F  e; }1 t" W" K: x. ~6 Y/ b9 M
– 输出比较。1 w$ ?3 @+ e% Y0 m4 @
' M) O4 v3 [- U. ?) C" D+ k- P; ~
– PWM 生成(边沿和中心对齐模式)。
+ t2 V; I" s7 t0 ^& p% z
- `/ A5 g: S+ I' S5 Q2 H+ y– 单脉冲模式输出。0 S' U3 [! H: O) j
# m6 \0 M' F# v1 c* E
  带死区插入,断路功能和PWM互补输出
+ s* U- T; L* Y  发生如下事件时生成中断/DMA 请求:
1 E8 \% d. X! h– 更新:计数器上溢/下溢、计数器初始化(通过软件或内部/外部触发)5 X$ `$ R3 G. N# ~
8 p8 k) o+ t; F1 s
– 触发事件(计数器启动、停止、初始化或通过内部/外部触发计数)
; U: i: y8 w3 Q  g$ }: b+ u2 |+ O* z; M0 W
– 输入捕获$ }9 d: e4 X6 h4 y% j! p0 z

3 x2 E/ i; d, d9 s# B9 b$ Z1 A+ {– 输出比较& L4 B7 z& `# Y* q$ q
$ `  ?" I% \7 Y( M
  支持增量式编码器和霍尔传感器。
) n0 _8 @( @& u' _7 ?8 O6 S32.2.1 定时器TIM1-TIM17的区别
) s' p7 @, e/ }! l9 I8 d' k2 ISTM32H7支持的定时器有点多,要简单的区分下。STM32H7支持TIM1-TIM8,TIM12-TIM17共14个定时器,而中间的TIM9,TIM10,TIM11是不存在的,这点要注意。
: I& x  B  W) U/ p8 q
1 k! f5 _8 B. b: A3 G& P) m  W粗略的比较如下:
$ n* {: y7 e6 s, g4 v# Q) x7 P+ \0 {* B. A
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png

  Y" O- w. N/ n+ ]9 G# U: |9 \8 S4 S) P* D" S/ B) y/ S" D9 F: ~
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png

4 i  s9 |* Z; k3 e. E9 [& M- u% O0 z: c$ ?
通过上面的表格,至少要了解到以下两点:
  j: i3 \$ R& S4 {, r9 J8 x9 M( W" f) Y/ ]3 S7 y
  STM32H7的定时器主要分为高级定时器,通用定时器,基础定时器和低功耗定时器。
7 p" r" R. M3 ^' _3 o5 P( N  TIM2和TIM5是32位定时器,其它都是16位定时器。  H6 N, w0 r" o; _" A  g

0 B6 {% }! O9 \) [  l7 Q32.2.2 定时器的硬件框图# Y" [. R) U; S) ^* \
认识一个外设,最好的方式就是看他的框图,方便我们快速的了解定时器的基本功能,然后再看手册了解细节。2 i4 o. n7 z( G1 [

# T4 x2 B0 }2 o8 F$ c7 `下面我们直接看最复杂的高级定时器TIM1&TIM8框图:, n, u1 |& |# d4 E" b4 \$ f
( \( e  i! U3 U! Q, z- n5 k* a
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png
+ v: m5 D5 Y' Q9 u( o
2 Q6 _% b9 ^  [1 h3 n9 q
通过这个框图,我们可以得到如下信息:
, u# O. z- B* X5 {
% w3 N9 }$ h  n! ^. h8 R  u* S  TIMx_ETR接口
& q: \/ ^3 b. ?2 y  u- @1 X, R, o8 I* X外部触发输入接口。ETR支持多种输入源:输入引脚(默认配置)、比较器输出和模拟看门狗。
% e! {% }9 |) U+ e4 t# I! p& H5 \5 n8 C& T
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png

) L2 O8 s8 a! _0 _6 T7 W! v& j- R& J! ?% W& l9 t8 t
  截图左侧的TIMx_CH1,TIMx_CH2,TIMx_CH3和TIMx_CH4接口
* C/ Z: N) V! B0 I这四个通道主要用于输入捕获,可以计算波形频率和脉宽。                                                                                                                             ( m8 X9 P# R7 X1 {9 d: G! a# A

+ k5 ?* }, E; n& P  TIMx_BKIN和TIMx_BKIN2接口, ]- E) [" x; ?( r
断路功能,主要用于保护由 TIM1 和 TIM8 定时器产生的 PWM 信号所驱动的功率开关# [( T9 ~, d* r! y) X* Z
( Y3 S; A1 Q+ s; o2 e- l  x6 C
  TRGO内部输出通道
' A8 y4 B/ w: S3 ^) A* s0 X5 z& Y主要用于定时器级联,ADC和DAC的定时器触发。) d* Q4 E! b4 M* H) u/ n

7 G% \$ m; x) ?8 H" x7 L5 Q/ c  U  6组输出比较单元OC1到OC6
* Y# w4 T6 a; y) q4 NOC1到OC4有对应的输出引脚,而OC5和OC6没有对应的输出引脚,主要用于内部控制。
1 m2 \  {9 ]8 z9 J/ N& F- i4 H: G
; y/ f- H/ o- q& i; B  截图右侧的输出比较通道TIMx_CH1,TIMx_CH1N,TIMx_CH2,TIMx_CH2N,TIMx_CH3,TIMx_CH3N和TIMx_CH4
' u& X: H3 G) I主要用于PWM输出,注意CH1到CH3有互补输出,而CH4没有互补输出。
1 D1 P! S/ f) @$ [1 O
7 J5 T1 ]9 k+ x2 ~$ p2 Q  o5 u# e  其它框图里面未展示出来功能
, i7 |1 y  E1 m7 b. U6 B  h定时器TIM1&TIM8还支持的其它功能在用到的时候再做说明。
. f5 h/ s/ W) t8 d$ I
8 h% D) l0 _9 Z9 P2 F32.2.3 定时器的时基单元; X8 e. }  f' S2 ?$ |8 ~5 i
定时器要工作就需要一个基本时基单元,而基本的时基单元是由下面几个寄存器组成的:
8 q; F  a. X1 n8 ?: D" w
5 L! N7 P4 B8 j4 c  c& _  预分频器寄存器 (TIMx_PSC)
6 Y9 X  o# P6 S2 N1 B) S用于设置定时器的分频,比如定时器的主频是200MHz,通过此寄存器可以将其设置为100MHz,50MHz,25MHz等分频值。3 v" o; K! S( _2 q) O
+ l/ x& L4 x0 c+ J# y" ]
注:预分频器有个缓冲功能,可以让用户实时更改,新的预分频值将在下一个更新事件发生时被采用(以递增计数模式为例,就是CNT计数值达到ARR自动重装寄存器的数值时会产生更新事件)。
8 U# T6 w! t, W9 K& L8 L' p3 `# k$ b9 P) ]) @
  计数器寄存器 (TIMx_CNT)
4 S" T8 B& X& ~( u& h计数器是最基本的计数单元,计数值是建立在分频的基础上面,比如通过TIMx_PSC设置分频后的频率为100MHz,那么计数寄存器计一次数就是10ns。+ S: n/ j7 ^+ `" g. _- B  Y; Y
! N# b; ~7 Z: d! d* B# m( q
  自动重载寄存器 (TIMx_ARR)
  N# b9 n* ]4 M# w; f+ o自动重装寄存器是CNT计数寄存器能达到的最大计数值,以递增计数模式为例,就是CNT计数器达到ARR寄存器数值时,重新从0开始计数。
1 D0 |4 U: l2 L9 v' @) N! y7 i2 L3 n" p& m* C
注,自动重载寄存器是预装载的。对自动重载寄存器执行写入或读取操作时会访问预装载寄存器。预装载寄存器的内容既可以立即传送到影子寄存器(让设置立即起到效果的寄存器),也可以在每次发生更新事件时传送到影子寄存器。简单的说就是让ARR寄存器的数值立即更新还是更新事件发送的时候更新。6 c6 D9 p# y* b8 P; C
4 L  U9 a: K& I' K) {" w
  重复计数器寄存器 (TIMx_RCR)
2 q9 ]8 m5 p/ R. m/ b$ [. q$ l以递增计数模式为例,当CNT计数器数值达到ARR自动重载数值时,重复计数器的数值加1,重复次数达到TIMx_RCR+ 1后就,将生成更新事件。
8 g1 ~1 y% m, j' U$ T. A6 w: W. {2 j2 Q, Q
注,只有TIM1,TIM8,TIM15,TIM16,TIM17有此寄存器。# Z' Y9 v4 y9 z; M2 r9 N7 v
5 U2 ]% v  r/ q1 R& e' x7 d* b0 w: w
比如我们要配置定时器实现周期性的中断,主要使用这几个寄存器即可。" Q3 Q5 P/ l0 v& a, w

! S  N1 }; x: ~1 ^  r32.2.4 定时器输出比较(PWM)" [; [& l  H6 J9 d: z, a1 e; s
使用定时器时基单元的那几个寄存器仅仅能设置周期,还不能设置占空比。针对这个问题,还需要比较捕获寄存CCR的参与,这样就可以设置占空比了。1 Z9 w- G4 S$ g/ U
/ O) p+ \% v8 N( r
为了方便大家理解,以PWM 边沿对齐模式,递增计数配置为例:
" ]+ f- |: {2 w: u6 Z
9 S7 P! a0 ~" x  当计数器TIMx_CNT < 比较捕获寄存器TIMx_CCRx期间,PWM参考信号OCxREF输出高电平。
- A! c$ m1 g1 I. @  当计数器TIMx_CNT >= 比较捕获寄存器TIMx_CCRx期间, PWM参考信号OCxREF输出低电平。
% C( @7 ?8 Z  w  当比较捕获寄存器TIMx_CCRx > 自动重载寄存器TIMx_ARR,OCxREF保持为1。
, e2 B1 M! n0 T# [  当比较捕获寄存器TIMx_CCRx = 0,则OCxRef保持为0。" i! C6 f9 `4 T
下面是TIMx_ARR=8的波形效果:5 A1 |9 p1 V1 W, l3 y8 |

% T2 o/ J, C; q( W  w3 N/ v! W: H. N
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png
& ?! \% d+ }2 T4 [3 w& R
6 s1 K2 k; w4 U/ C
32.2.5 定时器输入捕获' ]) j" {% r! Q( Y% o- f: c, b
与PWM一样,使用定时器实现输入捕获,仅靠时基单元的那几个寄存器是不行的,我们需要一个寄存器来记录发生捕获时的具体时间,这个寄存器依然由比较捕获寄存器TIMx_CCRx来实现。
4 Q! a! d+ G: y0 y
: K* S) ~3 Z* x. i5 n8 N比如我们要测量一路方波的周期:
/ b) c3 G" L4 C- J5 f! i/ l9 f0 Z# R% @
  配置定时器为输入捕获模式,上升沿触发,设置分频,自动重装等寄存器,比如设置的CNT计数器计数1次是1微秒。
' T+ b9 p8 V% W# v  当有上升沿触发的时候,TIMx_CCRx寄存器就会自动记录当前的CNT数值,然后用户就可以通过CC中断,在中断复位程序里面保存当前的TIMx_CCRx寄存器数值。等下次再检测到上升沿触发,两次时间求差就可以得到方波的周期。  b  F3 b: |$ b$ {  b, Y8 C
不过这里要特别注意一点,如果CNT发生溢出(比如16位定时器,计数到65535就溢出了)就需要特别处理下,将CNT计数溢出考虑进来。
$ k! m8 `, p$ Q! k9 C( E# E# L! o2 H7 T
32.3 定时器的HAL库用法) T/ S6 t/ K* b9 w  ^
定时器的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置GPIO、时钟,并根据需要配置NVIC、中断和DMA。下面我们逐一展开为大家做个说明。7 `- l; n8 [$ P+ N

% N' Z5 U3 E( T& S* f/ e32.3.1 定时器寄存器结构体TIM_TypeDef& _) g% ]+ ~' @, Q' J4 s/ i8 o+ x3 E
定时器相关的寄存器是通过HAL库中的结构体TIM_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:# ?! K: C: ^3 I

9 S& J) s0 p8 D0 ~
  1. typedef struct
    6 i! h( z7 f' U5 s( p- \2 x3 n
  2. {. @3 J/ I5 j' o; F/ c2 V
  3.   __IO uint16_t CR1;         /*!< TIM control register 1,                   Address offset: 0x00 */
      d( A; L. T, ], Z8 |
  4.   uint16_t      RESERVED0;   /*!< Reserved, 0x02                                                 */8 ]. l% \% Y$ A% j9 T1 l
  5.   __IO uint32_t CR2;         /*!< TIM control register 2,                   Address offset: 0x04 */3 b4 i' `5 h$ O, a, f# d- V* g3 C; g
  6.   __IO uint32_t SMCR;        /*!< TIM slave mode control register,          Address offset: 0x08 */+ g% d6 i; q- y) p% r
  7.   __IO uint32_t DIER;        /*!< TIM DMA/interrupt enable register,        Address offset: 0x0C */
    5 Z& M/ ~; d3 U7 f
  8.   __IO uint32_t SR;          /*!< TIM status register,                      Address offset: 0x10 */
    3 ?8 H3 g( T9 H. R
  9.   __IO uint32_t EGR;         /*!< TIM event generation register,            Address offset: 0x14 */. p' l. P. @# r" z
  10.   __IO uint32_t CCMR1;       /*!< TIM capture/compare mode register 1,      Address offset: 0x18 */- K8 x/ w) b! g6 A3 Z0 w. k
  11.   __IO uint32_t CCMR2;       /*!< TIM capture/compare mode register 2,      Address offset: 0x1C */
    , J7 t! r8 V: ~5 b
  12.   __IO uint32_t CCER;        /*!< TIM capture/compare enable register,      Address offset: 0x20 */( Q: U; J2 y1 Z% ~: d# A9 \% @
  13.   __IO uint32_t CNT;         /*!< TIM counter register,                     Address offset: 0x24 */$ Q9 R. C% i4 s6 R; D
  14.   __IO uint16_t PSC;         /*!< TIM prescaler,                            Address offset: 0x28 */( E: K& r; A' i! l
  15.   uint16_t      RESERVED9;   /*!< Reserved, 0x2A                                                 */
    / g) N, C9 ?$ ^) n' v& H
  16.   __IO uint32_t ARR;         /*!< TIM auto-reload register,                 Address offset: 0x2C */# Z: U) e$ Y% v1 ^. g8 H% A' x
  17.   __IO uint16_t RCR;         /*!< TIM repetition counter register,          Address offset: 0x30 */
    + u& j0 ?* v* [5 l" E2 N9 N
  18.   uint16_t      RESERVED10;  /*!< Reserved, 0x32                                                 */4 z) Z* q0 r4 b7 w' ]
  19.   __IO uint32_t CCR1;        /*!< TIM capture/compare register 1,           Address offset: 0x34 */6 I" J; E1 r+ \/ H; x' z# k! i& ]
  20.   __IO uint32_t CCR2;        /*!< TIM capture/compare register 2,           Address offset: 0x38 */
    ; B# \: _+ O) o8 B5 E0 {6 a* R
  21.   __IO uint32_t CCR3;        /*!< TIM capture/compare register 3,           Address offset: 0x3C */
    $ A5 B( c! I2 @0 }. j
  22.   __IO uint32_t CCR4;        /*!< TIM capture/compare register 4,           Address offset: 0x40 *// T# e7 _+ i" O# m: e5 g$ p/ e+ t6 N
  23.   __IO uint32_t BDTR;        /*!< TIM break and dead-time register,         Address offset: 0x44 */
    5 s$ Q  |( W  n- P
  24.   __IO uint16_t DCR;         /*!< TIM DMA control register,                 Address offset: 0x48 */4 i8 B* s/ `  X% f7 O
  25.   uint16_t      RESERVED12;  /*!< Reserved, 0x4A                                                 */
    # N8 D3 h% P" v% R
  26.   __IO uint16_t DMAR;        /*!< TIM DMA address for full transfer,        Address offset: 0x4C */
    4 ~+ O! g5 Z5 N7 l& K4 W
  27.   uint16_t      RESERVED13;  /*!< Reserved, 0x4E                                                 */1 }1 C- J! m; j/ L6 p: M* u
  28.   uint16_t      RESERVED14;  /*!< Reserved, 0x50                                                 */2 K* @$ w9 _0 l" F: c
  29.   __IO uint32_t CCMR3;       /*!< TIM capture/compare mode register 3,      Address offset: 0x54 */6 V. U: |' ^/ Y+ i, y
  30.   __IO uint32_t CCR5;        /*!< TIM capture/compare register5,            Address offset: 0x58 */: \) x& O" O- i: q: I# P9 n
  31.   __IO uint32_t CCR6;        /*!< TIM capture/compare register6,            Address offset: 0x5C */
    $ l* E7 g1 `& ^; H) Q
  32.   __IO uint32_t AF1;         /*!< TIM alternate function option register 1, Address offset: 0x60 */9 d' T- n' `5 T0 R: {0 i
  33.   __IO uint32_t AF2;         /*!< TIM alternate function option register 2, Address offset: 0x64 */4 U1 I  C7 i, p- P  I( Z
  34.   __IO uint32_t TISEL;       /*!< TIM Input Selection register,             Address offset: 0x68 */; j. \9 D9 c4 ]* M7 y' W* Y
  35. } TIM_TypeDef;
复制代码
$ ]4 G* O$ S+ S+ N8 U: v+ [
这个结构体的成员名称和排列次序和CPU的定时器寄存器是一 一对应的。. ^& G+ e' y# [; t: g3 g" M! U6 J
" I5 z( H, p+ j) `7 S
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:9 s) q' A& f1 p

1 Q4 q: G% |! G) m: n, K7 e* z
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */6 ]7 q* C; m; b
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码
+ D! l% m7 _( }: x( y/ l5 x) \
下面我们看下定时器的定义,在stm32h743xx.h文件。
( L- I5 h1 v" M6 C. @9 h
) K$ Y; o/ t0 e
  1. #define PERIPH_BASE         ((uint32_t)0x40000000)
    ' `8 q9 c# T1 @: _
  2. #define D2_APB1PERIPH_BASE   PERIPH_BASE
    % {% b' e2 ?- k# U2 p  W/ a
  3. #define D2_APB2PERIPH_BASE   (PERIPH_BASE + 0x00010000)1 o* V% i6 h) b- i8 U& w3 F, w

  4. 5 I! V1 d2 x1 ^4 R3 g9 Y& o( c1 H
  5. /*!< D2_APB1PERIPH 外设 */
    9 }- b; b; g0 O4 N8 l: O# ^
  6. #define TIM2_BASE             (D2_APB1PERIPH_BASE + 0x0000) <----- 展开这个宏,(TIM_TypeDef *) 0x40000000
    2 p' n- a2 U$ Q( ?
  7. #define TIM3_BASE             (D2_APB1PERIPH_BASE + 0x0400)
    ( I0 B; l4 H4 e% c. q
  8. #define TIM4_BASE             (D2_APB1PERIPH_BASE + 0x0800)
    # S3 [! ~5 n. u( t
  9. #define TIM5_BASE             (D2_APB1PERIPH_BASE + 0x0C00)
      Y' x, o2 V+ |8 J# P2 o5 [
  10. #define TIM6_BASE             (D2_APB1PERIPH_BASE + 0x1000)
    , Q: q! g& k$ n4 F5 V
  11. #define TIM7_BASE             (D2_APB1PERIPH_BASE + 0x1400)) A2 @8 j. W0 L; e. V" P2 N5 A& c
  12. #define TIM12_BASE            (D2_APB1PERIPH_BASE + 0x1800)
    8 B, a) h1 \; U' b
  13. #define TIM13_BASE            (D2_APB1PERIPH_BASE + 0x1C00)6 e. K* e( v3 ]/ A% L
  14. #define TIM14_BASE            (D2_APB1PERIPH_BASE + 0x2000)- n  v' D; K7 B7 y7 Q! s' p% w
  15. ) m+ u2 D, T, D1 _' F
  16. /*!< D2_APB1PERIPH 外设 */
    & D, i) P2 U; c) G+ {
  17. #define TIM1_BASE             (D2_APB2PERIPH_BASE + 0x0000); g  P) h" B. h  I" ~
  18. #define TIM8_BASE             (D2_APB2PERIPH_BASE + 0x0400)2 P& n& H0 W4 h: C3 ]9 ^
  19. #define TIM15_BASE            (D2_APB2PERIPH_BASE + 0x4000); [% P$ _4 g/ r( b, G* R* c
  20. #define TIM16_BASE            (D2_APB2PERIPH_BASE + 0x4400)9 L' C' r- ^0 L' z, R: [# d* |4 ]" J
  21. #define TIM17_BASE            (D2_APB2PERIPH_BASE + 0x4800)2 C9 L0 T, J. I) E3 d: ^
  22. 8 @  S4 i, s' ?
  23. #define TIM1                ((TIM_TypeDef *) TIM1_BASE)0 G5 R9 R, }. w/ w
  24. #define TIM2                ((TIM_TypeDef *) TIM2_BASE)
    " _6 C8 ~9 u; ?; G: E
  25. #define TIM3                ((TIM_TypeDef *) TIM3_BASE)
    $ d) P0 u& v& Z# w' K
  26. #define TIM4                ((TIM_TypeDef *) TIM4_BASE)  N6 E* e% l0 }$ D
  27. #define TIM5                ((TIM_TypeDef *) TIM5_BASE), [6 M5 f2 u2 H- r% G6 W
  28. #define TIM6                ((TIM_TypeDef *) TIM6_BASE)
    . j  D1 K" G+ f! i: ?+ X
  29. #define TIM7                ((TIM_TypeDef *) TIM7_BASE)% \% T0 a0 z) w5 `
  30. #define TIM8                ((TIM_TypeDef *) TIM8_BASE)
    & w$ V2 c9 x/ x( M- o
  31. #define TIM12               ((TIM_TypeDef *) TIM12_BASE)/ e" G5 ^  @- T: j
  32. #define TIM13               ((TIM_TypeDef *) TIM13_BASE)
    * \' t9 y: k2 ~( T, s% ^  a2 v
  33. #define TIM14               ((TIM_TypeDef *) TIM14_BASE)2 D: r6 n4 s0 V2 [0 O7 ^) ^$ s
  34. #define TIM15               ((TIM_TypeDef *) TIM15_BASE)
    % M  `/ I6 c  o* _+ X
  35. #define TIM16               ((TIM_TypeDef *) TIM16_BASE); {' y- @! Z% U2 N0 J" U. O
  36. #define TIM17               ((TIM_TypeDef *) TIM17_BASE)
复制代码

) v3 ]% O2 X- S+ o6 ~4 V我们访问TIM2的CR1寄存器可以采用这种形式:TIM2->CR1 = 0;5 `* T9 L& a+ K

7 \: q; a% k3 E! Q32.3.2 定时器句柄结构体TIM_HandleTypeDef
% o* n" @5 k9 {# q; {HAL库在TIM_TypeDef的基础上封装了一个结构体TIM_HandleTypeDef,定义如下:
/ T& |5 ^0 J" m4 `7 X) p8 u( j( K! r- `1 @
  1. typedef struct& Z* U  z6 q; N1 c, E
  2. {
    - S9 v- S8 y) N) b$ \
  3.   TIM_TypeDef              *Instance;     /*!< Register base address             */
      `6 j" M. T5 b8 [
  4.   TIM_Base_InitTypeDef     Init;          /*!< TIM Time Base required parameters */+ U% Y# R; x; A
  5.   HAL_TIM_ActiveChannel    Channel;       /*!< Active channel                    */
    " }: n- K$ Y- z( }; P. I$ W

  6. 5 x" h( ?$ F( O. x1 M& I+ T
  7. /*!< DMA Handlers array This array is accessed by a @ref DMA_Handle_index */
    7 e& ^5 r7 n! l3 |) o, |1 m
  8.   DMA_HandleTypeDef        *hdma[7];      5 [# T$ K6 C. B6 E8 b) Y
  9.   HAL_LockTypeDef          Lock;          /*!< Locking object                    *// N' {& L& X: U
  10.   __IO HAL_TIM_StateTypeDef   State;      /*!< TIM operation state               */  - d  }5 D* S* O& ^
  11. }TIM_HandleTypeDef;
复制代码

6 v. f: R. s! p, v) W$ E这里重点介绍前四个参数,其它参数主要是HAL库内部使用的。& K" m7 l6 u1 N* A( a& M: `; q

; N" C0 T0 g2 l4 E  TIM_TypeDef  *Instance
, W+ I% l, @( o, S4 A! X6 ]- ~) A) b) Z
这个参数是寄存器的例化,方便操作寄存器,比如使能定时器的计数器。
6 a, y3 D7 s* r" Z. D
. P/ {" q+ ?7 y' c9 q6 \SET_BIT(huart->Instance->CR1,  TIM_CR1_CEN)。6 l! j$ J( P2 P4 I
& z  C, g8 }* i! ^- V
  TIM_Base_InitTypeDef  Init
/ S( h/ ^( }4 s
" E! h3 D) S3 h4 I这个参数是用户接触最多的,用于配置定时器的基本参数。
' [- Q/ B( ~, c# }
6 i) R- u7 i. gTIM_Base_InitTypeDef结构体的定义如下:
8 K6 K5 B2 N" B. n+ w7 M
- `# o; r( n7 \- F. L
  1. typedef struct
    2 w: ^9 u; v, X- {& w. S
  2. {5 {2 B( ?  ?& y% R6 j
  3.   uint32_t Prescaler;      
    & ]' C& r  k4 f, q' C9 f2 M
  4.   uint32_t CounterMode;    $ C  ^& }, ~' n; K- C) z  g
  5.   uint32_t Period;         ) b- D* h5 u0 n
  6.   uint32_t ClockDivision;   
    % [5 x9 ^4 Z: n" J9 n8 g! L
  7.   uint32_t RepetitionCounter; + Z: F' C  X3 T+ B
  8.   uint32_t AutoReloadPreload;  ; V& {* }6 u6 }9 v- F. N, X% h
  9. } TIM_Base_InitTypeDef;
复制代码

, p* V+ Q1 r+ I/ O! W% u  成员Prescaler
- a& b; [9 G; n* l" w5 c. M用于设置定时器分频,对于32位的TIM2和TIM5范围是0到0xFFFFFFFF,其它定时器是0到0xFFFF。
) X# x: W" Y3 P$ `  U7 E1 I0 e# ~+ W; x5 [
  成员CounterMode1 y6 A2 @/ O# u
用于设置计数模式,向上计数模式、向下计数模式和中心对齐模式。9 {8 M! I2 C5 N

" a* k1 |6 ^& a
  1. #define TIM_COUNTERMODE_UP                ((uint32_t)0x0000U)   /*!< Up counting mode */5 ]9 O2 w$ h3 c
  2. #define TIM_COUNTERMODE_DOWN               TIM_CR1_DIR          /*!< Down counting mode */2 _! x- ~. [. f2 K! s
  3. #define TIM_COUNTERMODE_CENTERALIGNED1     TIM_CR1_CMS_0        /*!< Center-aligned counting mode 1 */! D7 Q2 s5 B6 }8 w: B. z
  4. #define TIM_COUNTERMODE_CENTERALIGNED2     TIM_CR1_CMS_1        /*!< Center-aligned counting mode 2 */* L- `( p# N( v
  5. #define TIM_COUNTERMODE_CENTERALIGNED3     TIM_CR1_CMS          /*!< Center-aligned counting mode 3 */
复制代码

/ F! y5 ^5 j( }7 `  成员Period
* g- r4 ]8 O3 C6 R, X  Q用于设置定时器周期,对于32位的TIM2和TIM5范围是0到0xFFFFFFFF,其它定时器是0到0xFFFF。; m) y2 ^) h! W9 S
3 c2 M7 R$ `/ P: `  N' O
  成员ClockDivision/ [  M; ~0 c5 i0 O+ ?
用于指示定时器时钟 (CK_INT) 频率与死区发生器以及数字滤波器(ETR、TIx)所使用的死区及采样时钟 (tDTS) 之间的分频比。6 ~; m* |4 N3 w
: Y1 |, {  o3 e- z4 z; n; F
  1. #define TIM_CLOCKDIVISION_DIV1       ((uint32_t)0x0000U)        /*!< Clock Division DIV1 */
    ) p0 k! I4 s# Y' l& n
  2. #define TIM_CLOCKDIVISION_DIV2       (TIM_CR1_CKD_0)            /*!< Clock Division DIV2 */& M8 w6 \; Y+ T1 ?1 L0 d1 P
  3. #define TIM_CLOCKDIVISION_DIV4       (TIM_CR1_CKD_1)             /*!< Clock Division DIV4 */
复制代码

2 t3 _" R; [1 y# w  成员RepetitionCounter
- z0 c4 _6 w) q# A用于设置重复计数器,仅TIM1和TIM8有,其它定时器没有。作用是每当计数器上溢/下溢时,重复计数器减1,当减到零时,才会生成更新事件,这个在生成PWM时比较有用。
* B- U5 |% \3 V" `! t9 _4 U2 B% e
' j: w% U% c, d' H2 e" B  成员AutoReloadPreload. t2 Y# M) m8 N5 c9 P5 }
用于设置定时器的ARR自动重装寄存器是更新事件产生时写入有效还是立即写入有效。如果使能了表示更新事件产生时写入有效,否则反之。, |! Y/ M7 s, T; W+ a* X9 E
/ [% O* C# f% ~  B0 S8 P; W4 K
  1. #define TIM_AUTORELOAD_PRELOAD_DISABLE   ((uint32_t)0x0000U)   /*!< TIMx_ARR register is not buffered */
    " H5 V; }6 ?5 t5 b
  2. #define TIM_AUTORELOAD_PRELOAD_ENABLE    (TIM_CR1_ARPE)        /*!< TIMx_ARR register is buffered */
复制代码
# J6 b2 c7 P# a6 A: \; |0 t
  HAL_TIM_ActiveChannel    Channel;
0 y+ s% }& ~+ A. u( @3 G* w  S! U
% z3 }. T  p) `" H用于设置定时器通道,比如TIM1和TIM8都是6个通道。! Z4 T( }/ R8 y1 I  g
7 ], y- b2 j8 r
  1. typedef enum
    4 F5 N4 }( [0 f4 N9 O0 j
  2. {
      C4 `/ g- `4 ~: u- E2 h7 N+ v( h
  3.   HAL_TIM_ACTIVE_CHANNEL_1        = 0x01U,    /*!< The active channel is 1     */
    8 Z+ d& O$ v: V% U% ^) J/ H
  4.   HAL_TIM_ACTIVE_CHANNEL_2        = 0x02U,    /*!< The active channel is 2     */; `5 e, P' V1 b4 i
  5.   HAL_TIM_ACTIVE_CHANNEL_3        = 0x04U,    /*!< The active channel is 3     */   9 X; ?" u$ i- G3 z9 P' A
  6.   HAL_TIM_ACTIVE_CHANNEL_4        = 0x08U,    /*!< The active channel is 4     */. O2 A  K9 P& [- c" ^! R
  7.   HAL_TIM_ACTIVE_CHANNEL_5        = 0x10U,    /*!< The active channel is 5     */
    9 t0 o% ^" j: m
  8.   HAL_TIM_ACTIVE_CHANNEL_6        = 0x20U,    /*!< The active channel is 6     */
    ) E' i, X" S" W8 O) ?5 j
  9.   HAL_TIM_ACTIVE_CHANNEL_CLEARED  = 0x00U     /*!< All active channels cleared */   
    7 r5 H" O* R3 ~
  10. }HAL_TIM_ActiveChannel;# S4 s$ H9 a" G
  11.   DMA_HandleTypeDef        *hdma[7];
复制代码
. P( X, H& Z  g+ N4 M) b
用于关联DMA。
  i4 a5 \4 q$ q0 F/ V
5 @3 r; |+ U$ G4 H! @& O: p; d配置定时器参数,其实就是配置结构体TIM_HandleTypeDef的成员。
# R4 O" `9 u4 @
: e- E+ A6 {. v+ b) m
  1. TIM_HandleTypeDef   TimHandle = {0};) b  `' g; t  ^0 b2 i

  2. ( [) y; a# S, e
  3. /* / w+ J1 C0 F% W* J
  4.     定时器中断更新周期 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)
    . I- v9 h5 I5 F: W" R
  5. */
    & H3 \9 G9 c/ N: `. n' ?# j
  6. TimHandle.Instance = TIMx;
    # F7 f! _- F6 D* N6 k* C# f5 Q
  7. TimHandle.Init.Prescaler         = usPrescaler;: M! w& b5 k5 Z6 A& X0 J
  8. TimHandle.Init.Period            = usPeriod;        7 O! N# v8 R% Y  n5 O2 N
  9. TimHandle.Init.ClockDivision     = 0;
    3 a2 H4 }7 W+ g  a/ G+ j+ v
  10. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;" D% I; @7 Z; J& Q; {; w+ p
  11. TimHandle.Init.RepetitionCounter = 0;
    # a9 I: z6 M& ~7 i4 l1 b" ?
  12. TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
    6 p5 ?0 c8 W5 B' z
  13. if (HAL_TIM_Base_Init(&TimHandle) != HAL_OK)  |! s1 j5 w+ ~0 A2 u+ R6 X! A0 J+ r
  14. {
    3 i% L3 C! b0 T
  15.         Error_Handler(__FILE__, __LINE__);
    % E9 d' k* d+ G/ X; _9 {
  16. }
复制代码
3 ]. g- n5 d5 X/ O* w6 [
32.3.3 定时器输出比较结构体TIM_OC_InitTypeDef
1 b! ], g$ g8 q1 D9 G9 Y' P7 U9 H0 g
此结构体主要用于定时器的输出比较,定义如下:
/ E1 ?  }2 }; J6 M$ x$ |' n# w$ y# ~2 Y8 n* g2 o, n
  1. typedef struct2 Y+ N3 x+ F$ M% k6 ~/ Q
  2. {                                   D; N, n* Y( v5 T: C7 f9 g
  3.   uint32_t OCMode;      
    2 B4 _% b& I9 F" k7 T# {: X$ b
  4.   uint32_t Pulse;         j5 i6 E# T1 [5 I, R
  5.   uint32_t OCPolarity;    5 x3 [+ W6 _, d9 X
  6.   uint32_t OCNPolarity;   
    , n* _; W8 e. A; {
  7.   uint32_t OCFastMode;  
    5 O/ E; e. j% x$ g) q
  8.   uint32_t OCIdleState;   
    6 g2 K8 i' s3 T
  9.   uint32_t OCNIdleState;  
    ! s5 U+ f3 H7 M) b5 Q+ m
  10. } TIM_OC_InitTypeDef;  
复制代码

9 O2 V4 G5 T" V% c下面将这几个参数一 一做个说明。
; P2 A: Q# ]2 z" m' s7 @) G
( j4 @* v' M) V7 M$ }& L  OCMode
  }. ~+ |! G. Z7 u8 F6 \( L# O用于配置输出比较模式,支持的模式较多:& `  |4 `7 a9 J
7 ?& ~  T8 l6 m9 S; ]
  1. /*!< TIM Output timing mode */
    # ^0 H! _% V5 ]# q8 _+ Y
  2. #define TIM_OCMODE_TIMING                ((uint32_t)0x0000U)      
    ! G( j6 T8 l' s/ r, |. W
  3. 1 F$ m4 q. l+ o7 j* W
  4. /*!< TIM Output Active mode */                          + b8 p: _9 U, R( B9 R* p; O
  5. #define TIM_OCMODE_ACTIVE                ((uint32_t)TIM_CCMR1_OC1M_0)
    3 r/ y- K5 R$ E" g7 C
  6. 8 G' R0 U2 F& F6 a+ N: P, U; N
  7. /*!< TIM Output Inactive mode */                       8 d& z3 K6 Z9 E' V& |
  8. #define TIM_OCMODE_INACTIVE              ((uint32_t)TIM_CCMR1_OC1M_1)           3 r/ N& _( o) s: H; \( i0 o/ P

  9. ; {$ m  |$ v# h3 i: F
  10. /*!< TIM Output Toggle mode */               9 i0 p# X# |1 T8 V* n$ y( i
  11. #define TIM_OCMODE_TOGGLE                 ((uint32_t)TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_0)         
      c0 \( D5 L  C/ u
  12. 8 f, |& ]2 C. \: I
  13. /*!< TIM PWM mode 1 */
    % p/ S% _9 t5 O/ {
  14. #define TIM_OCMODE_PWM1                   ((uint32_t)TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1)
    ' L% }% _) H1 o

  15. 1 |% ?5 q* m9 @
  16. /*!< TIM PWM mode 2 */                    0 l# H  ?: a7 q2 _  x, o
  17. #define TIM_OCMODE_PWM2                    ((uint32_t)TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_0)   & P" _. f" k& F+ c# ]6 U% \! e7 u: Z

  18. % B. H# j; _5 j- ?, u
  19. /*!< TIM Forced Active mode */   
    7 @2 \- Z$ Y* g! D. y6 b' M
  20. #define TIM_OCMODE_FORCED_ACTIVE           ((uint32_t)TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_0)         
    , ]" Y2 z* Z- u$ k2 S6 u. U
  21. - G0 ]3 q) I2 m8 N2 E( K- c" ^5 U
  22. /*!< TIM Forced Inactive mode */            
    0 M0 [( y* @  i% Z9 s- N' h
  23. #define TIM_OCMODE_FORCED_INACTIVE         ((uint32_t)TIM_CCMR1_OC1M_2)                                        ) Q# \% R! u, ?# ]1 ]4 _
  24. 1 E6 N# g& J5 g
  25. /*!< TIM Rettrigerrable OPM mode 1 */  
    6 d0 @5 E0 M2 \' c; [
  26. #define TIM_OCMODE_RETRIGERRABLE_OPM1      ((uint32_t)TIM_CCMR1_OC1M_3)   
    9 D: G5 l' ]4 n3 u! l; ^* I) V
  27.   ~9 g+ q% c1 u" K4 I1 r
  28. /*!< TIM Rettrigerrable OPM mode 2 */                                        ! M6 u( Z4 G$ ~, {6 ?; t
  29. #define TIM_OCMODE_RETRIGERRABLE_OPM2      ((uint32_t)TIM_CCMR1_OC1M_3 | TIM_CCMR1_OC1M_0)   
    ' l2 s7 S% g; w

  30. 4 F' A3 D2 z* i3 [: x+ k
  31. /*!< TIM Combined PWM mode 1 */                     / g2 @, H3 E9 k( R3 ]9 U& H! M$ M
  32. #define TIM_OCMODE_COMBINED_PWM1           ((uint32_t)TIM_CCMR1_OC1M_3 | TIM_CCMR1_OC1M_2)     
    1 c6 k# t" h# G0 s0 ]

  33. ! A+ N+ u! x' Z) ]0 e
  34. /*!< TIM Combined PWM mode 2 */                  5 J- Q9 g" l) J- O$ d$ `' @
  35. #define TIM_OCMODE_COMBINED_PWM2           ((uint32_t)TIM_CCMR1_OC1M_3 | TIM_CCMR1_OC1M_0 | TIM_CCMR1_OC1M_2)   " p/ I  G3 c, w1 p

  36. % v' E$ E  e& x# m5 j" R
  37. /*!< TIM Asymetruc PWM mode 1 */  % Y4 C' @7 z* E
  38. #define TIM_OCMODE_ASSYMETRIC_PWM1         ((uint32_t)TIM_CCMR1_OC1M_3 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2)  
    % `3 x' W- m4 r% @

  39. 2 G1 i! S1 ]2 l6 m5 l7 }& Q( o
  40. /*!< TIM Asymetruc PWM mode 2 */    1 Q3 z1 o' @' {( t5 Z; \' L
  41. #define TIM_OCMODE_ASSYMETRIC_PWM2         ((uint32_t)TIM_CCMR1_OC1M_3 | TIM_CCMR1_OC1M)  
复制代码

, ?3 o; y7 l' U% w- }& u  5 w3 j" M6 e  U
  Pulse2 l0 G1 ~; v4 f9 q+ j& n
可用于设置占空比,对应定时器的CCR寄存器,32位的TIM2和TIM5范围是0到0xFFFFFFFF。. q. q0 `$ Z; A( `4 ]
* h& |* V7 I& K+ z0 K5 G  s0 h
  OCPolarity
2 l( w9 z* S4 {4 q* e设置输出极性,可选高电平或低电平有效。
$ Y" [( h  ~/ q* O, z0 i9 I; _4 K5 {5 g1 ]0 ]
  1. #define TIM_OCPOLARITY_HIGH                ((uint32_t)0x0000U)
    - j% I' ^6 o% `( p2 a7 h, F
  2. #define TIM_OCPOLARITY_LOW                 (TIM_CCER_CC1P)
复制代码
$ k, V1 E8 a6 f7 z! v& y
  OCNPolarity
  }! |2 `" \0 h( o" c1 N$ |3 S互补输出极性设置,可选高电平或者低电平有效。
4 _9 x* }& Y/ W
0 s2 }  u$ K4 e! d! J& |
  1. #define TIM_OCNPOLARITY_HIGH               ((uint32_t)0x0000U)
    5 X- K* o& `& s. T% I4 E3 P# e
  2. #define TIM_OCNPOLARITY_LOW                (TIM_CCER_CC1NP)
复制代码
0 g( a- j+ s/ N! \5 e) A8 m
  OCFastMode, l6 G, R- d6 B8 m, H8 {. g
快速输出模式使能,仅OCMode配置为PWM1或者PWM2模式时才有意义。
0 H$ ?- z( g5 o8 @2 X( {$ r- E7 N/ ?; W- F
  1. #define TIM_OCFAST_DISABLE                ((uint32_t)0x0000U)
    3 l7 L6 j$ D) p; `- h4 J
  2. #define TIM_OCFAST_ENABLE                 (TIM_CCMR1_OC1FE)
复制代码
! W. P0 V5 o5 W/ Y
  OCIdleState
0 p* Z& c0 ]/ o" K9 I空闲状态时,设置输出比较引脚的电平状态。& N# [; P% w- l: M6 p  t+ f

5 q# a3 Y7 M5 u3 f
  1. #define TIM_OCIDLESTATE_SET                (TIM_CR2_OIS1)' Q# |3 ~" H6 V! Q+ n# K$ E
  2. #define TIM_OCIDLESTATE_RESET              ((uint32_t)0x0000U)
复制代码
4 {) q5 s) N$ ?7 l; D
  OCNIdleState+ X. j% J4 ~6 M5 p2 P& ~" [6 L1 P8 ^
空闲状态时,设置互补输出引脚的电平状态。
) J7 `8 G' x# n1 c
4 k- Q: X3 z: Y
  1. #define TIM_OCNIDLESTATE_SET               (TIM_CR2_OIS1N)
    ) L3 l) h+ [' M1 s) \. G, v
  2. #define TIM_OCNIDLESTATE_RESET             ((uint32_t)0x0000U)
复制代码

5 ]7 @: R8 n4 E" g8 f32.3.4 定时器输入捕获结构体TIM_IC_InitTypeDef/ q0 l% g$ P' [1 Q$ C
此结构体主要用于定时器的输入捕获,定义如下:
9 I7 R9 t" M* w9 }; G/ Y  G; y( j
/ r( _  S; k( F! a
  1. typedef struct
    6 }% ]/ I3 z; @! x! q7 ]
  2. {                                 
    ! N, l8 ~6 q. i; O2 k# J
  3.   uint32_t ICPolarity;   
    6 s# l1 ~" y" P' a* E* I
  4.   uint32_t ICSelection; . w, m9 Z5 E' |
  5.   uint32_t ICPrescaler; ! {/ H# m+ z& H+ v8 e- F
  6.   uint32_t ICFilter;    ) U  d  M+ J0 L- ]
  7. } TIM_IC_InitTypeDef;
复制代码

1 c* U' U& E" F) n2 N下面将这几个参数一 一做个说明。! f% c/ w8 ^: P4 ?" I5 }2 b
& V0 x9 G+ M7 W: |- e/ `6 b
  ICPolarity
+ `# K  W% d, l3 j. }: W4 R' O/ _输入触发极性,可以选择上升沿,下降沿或者双沿触发。
4 N2 C/ }- F/ w+ F) r. c2 g& D' X: u% i/ v9 n6 g4 X- J( \
  1. #define  TIM_ICPOLARITY_RISING             TIM_INPUTCHANNELPOLARITY_RISING$ A9 }. I6 d! H( F! y2 A
  2. #define  TIM_ICPOLARITY_FALLING            TIM_INPUTCHANNELPOLARITY_FALLING/ @& [9 h/ b) Z3 Z
  3. #define  TIM_ICPOLARITY_BOTHEDGE           TIM_INPUTCHANNELPOLARITY_BOTHEDGE
复制代码

4 P% k, L9 H9 N9 e) |7 [2 X  ICSelection3 j% T- ~! {9 U% o/ P
输入捕获通道选择,可以选择直接输入(即CC1选择TI1,CC2选择TI2等),间接输入(CC1选择TI2,CC3选择TI4等)或者TRC。
' ^6 X1 S6 C2 q0 ]% e- E: e% `/ ?: E2 t7 h0 j7 R
  1. #define TIM_ICSELECTION_DIRECTTI       (TIM_CCMR1_CC1S_0)   
    3 }* G- h! v) b; _+ V
  2. #define TIM_ICSELECTION_INDIRECTTI     (TIM_CCMR1_CC1S_1)  $ z1 g8 k& m  T. ^; E1 E
  3. #define TIM_ICSELECTION_TRC            (TIM_CCMR1_CC1S)   
复制代码

8 s7 K( s1 B, c- ?4 n; h  ICPrescaler. J: v+ w' l: c$ s6 [  B
输入捕获分频,表示每捕获1,2,4或8个事件后表示一次捕获。
: ?% G9 o6 @! }/ e0 }( g& O
0 D: K" `  W; o3 u; k
  1. #define TIM_ICPSC_DIV1       ((uint32_t)0x0000U)                 
    ! j( b- {: f- N. H( G  J$ j- y
  2. #define TIM_ICPSC_DIV2       (TIM_CCMR1_IC1PSC_0)   
    7 G% N0 p& h' l. i
  3. #define TIM_ICPSC_DIV4       (TIM_CCMR1_IC1PSC_1)   
    $ i, T6 [/ B  E
  4. #define TIM_ICPSC_DIV8       (TIM_CCMR1_IC1PSC)
复制代码

0 R' e* x' y/ w2 S  ICFilter  `/ {6 x$ h" L$ h" B& o8 R
输入捕获滤波器,可以定义采样频率和多少个连续事件才视为有效的触发,参数范围0到15。具体定义如下,其中fCK_INT表示定时器时钟,fDTS表示死区时间采样率,N表示这么多个事件代表一次有效边沿。! q" z) f! x3 S% V" X
* ]6 @, Y: A# `
  1. 0000:无滤波器,按 fDTS 频率进行采样! w) W4 {- b8 g
  2. 0001: fSAMPLING=fCK_INT, N=2& P# W2 `# j' Z2 q8 k5 y( q4 `6 h2 H
  3. 0010: fSAMPLING=fCK_INT, N=4, x' d5 f2 A" M8 S. X  S% Y
  4. 0011: fSAMPLING=fCK_INT, N=8
    2 u& t, k9 p0 x4 M) K0 g
  5. 0100: fSAMPLING=fDTS/2, N=6
    ) ~) ]5 m8 o, d# ~  m
  6. 0101: fSAMPLING=fDTS/2, N=8( i. u6 a3 b7 ^
  7. 0110: fSAMPLING=fDTS/4, N=6
    " `$ J& `" U$ f
  8. 0111: fSAMPLING=fDTS/4, N=8
    * }$ \1 D" r5 `% T# p
  9. 1000: fSAMPLING=fDTS/8, N=66 v6 i4 b3 q* f7 D
  10. 1001: fSAMPLING=fDTS/8, N=8, I% }. I* e+ ^) K: L2 V
  11. 1010: fSAMPLING=fDTS/16, N=5
    ) ~! {' G9 R# b6 P
  12. 1011: fSAMPLING=fDTS/16, N=6, i2 w6 Q% m  a8 u7 l1 p5 u0 n
  13. 1100: fSAMPLING=fDTS/16, N=8
    6 M. t$ }% Q+ Q) g/ M
  14. 1101: fSAMPLING=fDTS/32, N=5
    2 Y( Y, H% K. H4 W8 M9 Z
  15. 1110: fSAMPLING=fDTS/32, N=6
复制代码
0 ~: |! |- K. W+ K9 V( K
32.3.5 定时器的底层配置(GPIO,时钟,中断等), X6 u0 p5 `' N
HAL库有个自己的底层初始化回调函数,比如调用函数HAL_TIM_Base_Init就会调用HAL_TIM_Base_MspInit,此函数是弱定义的。
5 w4 p( ]6 n8 V4 O: _  b  P5 F: ^* x+ q- G
  1. __weak void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim). M. m9 ~7 `+ _( ?% O# E5 v
  2. {; M% p$ @3 b- p2 }+ ^* _4 g6 M( Z" A
  3.   /* Prevent unused argument(s) compilation warning */
    % R% U) t4 U# W! n6 \
  4.   UNUSED(htim);
    1 G( q* U0 q4 r8 d8 _( y; t, p
  5.   /* NOTE : This function Should not be modified, when the callback is needed,
    " {0 ^, _" O. N2 C; z$ M* B3 w" ]
  6.             the HAL_TIM_Base_MspDeInit could be implemented in the user file
    5 U/ G" y0 I/ I3 M5 c& w4 H
  7.    */, v; |- Y- l* M
  8. }
复制代码
0 a) [0 c. C1 s7 o. V( y
用户可以在其它的C文件重定向,并将相对的底层初始化在里面实现。对应的底层复位函数HAL_TIM_Base_DeInit是在函数HAL_TIM_Base_MspDeInit里面被调用的,也是弱定义的。
4 G6 ^' `# {/ `0 f2 I: |  [3 f9 u. h
当然,用户也可以自己初始化,不限制必须在两个函数里面实现。" m- J* y8 P# |* p

4 j' l3 O( C! N% [9 ?定时器外设的基本参数配置完毕后还不能使用,还需要配置GPIO、时钟、中断等参数,比如下面配置TIM1使用PA8做PWM输出。
5 \" z, d5 \$ ~* G+ u6 Q' ]/ A" b
- ~. s4 Z) O8 A  I0 f
  1. void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)6 G8 N' f& ~" ~: t1 D3 K
  2. {
      n  c5 O+ P$ @5 e# X& i
  3.   GPIO_InitTypeDef   GPIO_InitStruct;
    1 g" [- P6 P* T1 i) y- }8 }
  4. 5 i7 t' r6 D: r/ |* t
  5.   /* 使能TIM1时钟 */
    6 o. H( L# i" ]; U! q
  6.   __HAL_RCC_TIM1_CLK_ENABLE ();2 b% a7 l# o: l( R3 x0 o
  7. , o+ m) f. t% E
  8.   /* 使能GPIOA时钟 */
    $ l8 k# Z" k$ N( D0 f% e7 \) ?
  9.   __HAL_RCC_GPIOA_CLK_ENABLE ();  }) s/ ?4 x* Z, ]
  10.   U' d( _, _! z) ~: V
  11.   /* 设置TIM1使用PA8做PWM输出引脚,将其配置为输出,推挽,复用模式 */
    - E" P: V- h" V
  12.   GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;' a5 O, Q2 I3 j; w  P. I3 a
  13.   GPIO_InitStruct.Pull = GPIO_PULLUP;
    ' a* ~+ K3 Q4 I+ q
  14.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;, b. d$ _/ v  V9 P: g5 \
  15. , P% m" U: W4 F2 X0 t
  16.   GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;$ [. J' T- _: r$ b( m
  17.   GPIO_InitStruct.Pin = GPIO_PIN_8;, X9 ]  G) B& Z9 Z# J( I
  18.   HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    * _+ w# }( X; B5 f

  19. 5 ]" H7 @9 \/ u
  20. }
复制代码
8 y; t9 p: x! u4 @5 G
总结下来就是以下几点:- W! s* }3 j. g' |2 I0 O. O" K$ e

0 J; @- S+ f  C9 X  配置TIM时钟。3 |$ L4 j0 u" Y8 H5 X2 `4 g
  配置TIM所用到引脚和对应的GPIO时钟。
9 v3 D& @# X/ e* i6 `' w  如果用到定时器中断,还需要通过NVIC配置中断。
& A8 ]0 T( a$ h% m) ~8 U# x  如果用到DMA,还要配置DMA。
( n' k! h& O; O# \; u关于这个底层配置有以下几点要着重说明下:
$ M4 ?5 g3 d" ?/ [
  o; Z. ]0 {, n2 |- f+ p  L  定时器所使用引脚的复用模式选择已经被HAL库定义好,放在了stm32h7xx_hal_gpio_ex.h文件里面。比如TIM1有一个复用,
* h" {0 r  {+ }; F. R3 t
  1. #define GPIO_AF1_TIM1      ((uint8_t)0x01)  /* TIM1 Alternate Function mapping */
复制代码
9 n5 W6 F7 e, e1 [  g* v
但是却有4个输出通道,每个通道都有几个支持的输出引脚:5 `! H8 {7 L9 w
1 t6 G) }/ _* n& Z
  1. TIM1_CH1,  PA8   PE9    PK1" r  z, i& ?. z  ?. N. A2 E1 S
  2. TIM1_CH2,  PA9   PE11- g/ }2 I3 u2 e& P: f
  3. TIM1_CH3,  PA10  PE13   PJ9
    1 O  K$ D' b, I% n' U
  4. TIM1_CH4,  PA11  PE14   PJ11
复制代码
& n6 I0 K  m6 ^. z9 L" h! h! g
具体使用哪个,配置对应引脚的复用即可:% p) ?( Z2 R" R  g3 {3 {. g

* t  R1 [; `5 X8 v4 j  o
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png
* L/ V( P; Y$ x9 x/ p

5 }8 s0 h: w% x* R32.3.6 定时器的状态标志清除问题9 j( ^* Q! }1 D2 _% _
下面我们介绍__HAL_TIM_GET_FLAG函数。这个函数用来检查定时器标志位是否被设置。# k  \+ U3 D, u
  1. & f. }5 ?, J$ b. L; r; A
  2. /** @brief  Check whether the specified TIM interrupt flag is set or not.) Q$ O2 Y: G& J4 s' e2 }; E' E/ \( n
  3.   * @param  __HANDLE__: specifies the TIM Handle.
    0 k! }+ Q+ x# P
  4.   * @param  __FLAG__: specifies the TIM interrupt flag to check.+ i0 D3 M3 l5 W  t# R- m- R5 R
  5.   *        This parameter can be one of the following values:0 s  h7 n5 s$ h
  6.   *            @arg TIM_FLAG_UPDATE: Update interrupt flag5 j3 `$ e: d( b2 }" s3 t
  7.   *            @arg TIM_FLAG_CC1: Capture/Compare 1 interrupt flag& c6 m# z  s1 D0 X' N& c
  8.   *            @arg TIM_FLAG_CC2: Capture/Compare 2 interrupt flag
    , s. [9 C7 B/ H( I. [( z9 S
  9.   *            @arg TIM_FLAG_CC3: Capture/Compare 3 interrupt flag
    0 e- |6 ^8 l& A! \
  10.   *            @arg TIM_FLAG_CC4: Capture/Compare 4 interrupt flag3 e9 |. k+ a8 W" n8 e1 D. j3 u. f
  11.   *            @arg TIM_FLAG_CC5: Compare 5 interrupt flag
    5 Q" v# q1 [: _9 Y; h* L% u8 s
  12.   *            @arg TIM_FLAG_CC6: Compare 6 interrupt flag
    & ?# [$ I/ `0 O6 y2 B4 V% W9 E" `6 }. d
  13.   *            @arg TIM_FLAG_COM:  Commutation interrupt flag4 u, f0 t( r" ^
  14.   *            @arg TIM_FLAG_TRIGGER: Trigger interrupt flag
    8 f- T8 O0 j) N0 f  J( a3 r5 [
  15.   *            @arg TIM_FLAG_BREAK: Break interrupt flag   
    ! a6 m; n2 }5 W8 A- v- T( }
  16.   *            @arg TIM_FLAG_BREAK2: Break 2 interrupt flag                     
    / y" p1 V1 _) J1 y/ G" H9 ?
  17.   *            @arg TIM_FLAG_SYSTEM_BREAK: System Break interrupt flag
    7 c0 s0 ?; F0 d+ |
  18.   *            @arg TIM_FLAG_CC1OF: Capture/Compare 1 overcapture flag
    # X5 Q2 e) G3 T* A
  19.   *            @arg TIM_FLAG_CC2OF: Capture/Compare 2 overcapture flag
    0 X3 K) E+ }) c+ k8 I' w- x
  20.   *            @arg TIM_FLAG_CC3OF: Capture/Compare 3 overcapture flag
    & F* Q& b: X% I2 e4 m0 l9 J
  21.   *            @arg TIM_FLAG_CC4OF: Capture/Compare 4 overcapture flag
    3 i* i/ |+ C8 j$ n4 K8 ^% q
  22.   * @retval The new state of __FLAG__ (TRUE or FALSE).
    7 K) t4 X% \8 r; K$ v
  23.   */
    4 f+ K, M# g! |
  24. #define __HAL_TIM_GET_FLAG(__HANDLE__, __FLAG__)   (((__HANDLE__)->Instance->SR &(__FLAG__)) == (__FLAG__))
复制代码

; W  t9 K+ Y# K  Y* g& ~前5个是比较常用的中断标志。
' a4 c# C( {, W5 L1 F& e- V( `) b( C: P* O  {8 D' [, p
  TIM_FLAG_UPDATE+ Q' q6 E- ?2 q* z& z2 Y$ m( B
定时器更新标准,配置一个周期性的定时器中断要用到。
* x1 @$ F2 _. ?6 o- A* g8 i- e) Z* N. Y) T' _+ n; |
     TIM_FLAG_CC1$ w+ V/ F0 r3 F/ B
TIM_FLAG_CC2
8 Q4 b  U5 V# h6 H: v2 m. B& c) C) G+ b( C3 j! P
TIM_FLAG_CC3; f' f# Q7 p6 i1 c; P6 n9 U2 v9 H
* I8 G: \3 a( g$ v6 {/ S- w# c
TIM_FLAG_CC43 [- q1 \; Q* O( O

" F+ T, [% P" v& A( n( k; L# {/ k' E捕获/比较标志,配置了捕获/比较中断要用到。
* L/ Z  a+ u7 a: g0 w5 |
1 D3 e3 V3 F" h! I# Q7 v与标志获取函数__HAL_TIM_GET_FLAG对应的清除函数是__HAL_TIM_CLEAR_FLAG:
( I2 l* [1 V9 }6 S; q+ T
" N. m/ U/ D7 K" D) Z
  1. /** @brief  Clear the specified TIM interrupt flag." ]# R; q5 J9 ]- t0 w+ d" G5 N) P+ v
  2.   * @param  __HANDLE__: specifies the TIM Handle.; T( ?  o3 \7 V4 E% I
  3.   * @param  __FLAG__: specifies the TIM interrupt flag to clear.( l# H9 q+ G9 r( v  _* x+ C6 `
  4.   *        This parameter can be one of the following values:2 ]0 I* w( M* ^' m1 ~
  5.   *            @arg TIM_FLAG_UPDATE: Update interrupt flag
    % ]/ e; `+ _, J% ]: s
  6.   *            @arg TIM_FLAG_CC1: Capture/Compare 1 interrupt flag
    3 b* ^$ O- T  J' }& y8 F
  7.   *            @arg TIM_FLAG_CC2: Capture/Compare 2 interrupt flag3 Z5 ^/ Y# G# S, R. ]
  8.   *            @arg TIM_FLAG_CC3: Capture/Compare 3 interrupt flag
    : r' h/ i& l" L4 d7 t
  9.   *            @arg TIM_FLAG_CC4: Capture/Compare 4 interrupt flag# ?2 ~) y$ Z: t& n9 O/ r
  10.   *            @arg TIM_FLAG_CC5: Compare 5 interrupt flag  X/ p% d$ L0 Y2 K9 M) w
  11.   *            @arg TIM_FLAG_CC6: Compare 6 interrupt flag1 ]9 q3 `0 T* a( L) G4 c  `* Q
  12.   *            @arg TIM_FLAG_COM:  Commutation interrupt flag
    " o' H/ i/ |/ \4 H& l; z
  13.   *            @arg TIM_FLAG_TRIGGER: Trigger interrupt flag( R& c  ?' b/ t7 w7 g1 T
  14.   *            @arg TIM_FLAG_BREAK: Break interrupt flag   
    ! p9 N) U3 n' Q* n
  15.   *            @arg TIM_FLAG_BREAK2: Break 2 interrupt flag                     
    ! l, Z) O( F) c2 u/ z: L
  16.   *            @arg TIM_FLAG_SYSTEM_BREAK: System Break interrupt flag; R7 y: A& O6 l( d. h# l
  17.   *            @arg TIM_FLAG_CC1OF: Capture/Compare 1 overcapture flag5 I1 d. K( d+ O7 W
  18.   *            @arg TIM_FLAG_CC2OF: Capture/Compare 2 overcapture flag; S8 }3 K& c; W
  19.   *            @arg TIM_FLAG_CC3OF: Capture/Compare 3 overcapture flag& H- u' i0 H; q2 d
  20.   *            @arg TIM_FLAG_CC4OF: Capture/Compare 4 overcapture flag
    2 C3 |* z; H0 v9 z
  21.   * @retval The new state of __FLAG__ (TRUE or FALSE).
    & s" X& Y$ V$ G& k+ ]. ]3 ^
  22.   */3 E, l( I3 N( h  d% t
  23. #define __HAL_TIM_CLEAR_FLAG(__HANDLE__, __FLAG__)       ((__HANDLE__)->Instance->SR = ~(__FLAG__))
复制代码

/ X! N* p6 j7 P3 x' i" A清除标志函数所支持的参数跟获取函数是一 一对应的。除了这两个函数,还是定时器的中断开启和中断关闭函数用的也比较多。
6 d1 q  _& j/ P& z0 G  L. f: k8 K  \- [+ {/ M2 ^
  1. /** @brief  Enable the specified TIM interrupt.
    , D" Q7 C; `0 l8 Z; _
  2. * @param  __HANDLE__: specifies the TIM Handle.
    # Y, v9 r& a2 _' Z, G! ?
  3. * @param  __INTERRUPT__: specifies the TIM interrupt source to enable.
    ( z6 ]9 [5 {& i( Q- s3 l
  4. *          This parameter can be one of the following values:3 Y+ U2 W" u7 h: r& K# Z. D
  5. *            @arg TIM_IT_UPDATE: Update interrupt
    , z, @0 U5 ^/ A
  6. *            @arg TIM_IT_CC1:   Capture/Compare 1 interrupt3 M4 v/ \; c* P0 P) `5 t+ d& q
  7. *            @arg TIM_IT_CC2:  Capture/Compare 2 interrupt
    " `# T+ A9 Z) t$ b
  8. *            @arg TIM_IT_CC3:  Capture/Compare 3 interrupt2 _9 o! R( L8 Y: _
  9. *            @arg TIM_IT_CC4:  Capture/Compare 4 interrupt7 k/ {! @& G2 `; t; ~
  10. *            @arg TIM_IT_COM:   Commutation interrupt
    ) [4 A2 W" A8 x# S
  11. *            @arg TIM_IT_TRIGGER: Trigger interrupt" B/ `7 B5 K" _) i
  12. *            @arg TIM_IT_BREAK: Break interrupt
    ' y# s  Q% C0 a  j: Z1 ?
  13. * @retval None- g3 L, N! v" d$ Y
  14. */
    6 e- M1 Z8 H! b4 z+ S$ B* y. A
  15. #define __HAL_TIM_ENABLE_IT(__HANDLE__, __INTERRUPT__)  ((__HANDLE__)->Instance->DIER |= (__INTERRUPT__))
    $ n% V: o9 Z, B2 x) ~% m
  16. + j' B; L4 n( t+ ~) o7 g) k
  17.   /** @brief  Disable the specified TIM interrupt.9 ?5 F. u% v: i9 `% D8 t# v9 ~
  18.   * @param  __HANDLE__: specifies the TIM Handle.
    " L6 ?# ?3 Z2 [
  19.   * @param  __INTERRUPT__: specifies the TIM interrupt source to disable., f: r/ |( O& _/ D" {0 K- [
  20.   *          This parameter can be one of the following values:
    0 i6 \' o$ k: M$ f, [" X
  21.   *            @arg TIM_IT_UPDATE: Update interrupt) R& @: }7 y5 ~% `
  22.   *            @arg TIM_IT_CC1:   Capture/Compare 1 interrupt
    , g/ T0 M# a) Y( @! [
  23.   *            @arg TIM_IT_CC2:  Capture/Compare 2 interrupt
    4 i3 X( `& P+ j' b5 `
  24.   *            @arg TIM_IT_CC3:  Capture/Compare 3 interrupt
    ( J: \* `- [/ s- E
  25.   *            @arg TIM_IT_CC4:  Capture/Compare 4 interrupt# ]) T. k2 _8 ^, m. G: ]
  26.   *            @arg TIM_IT_COM:   Commutation interrupt; E% j0 S" @# u- O7 w$ d' g
  27.   *            @arg TIM_IT_TRIGGER: Trigger interrupt
    6 h9 M/ D% A' o) B/ N- [  R9 c0 U* P
  28.   *            @arg TIM_IT_BREAK: Break interrupt
    : G- j# Z- w. Y( t
  29.   * @retval None0 A# y$ L: h9 Y
  30.   */+ W! l4 g6 x4 b7 y1 P. s
  31. #define __HAL_TIM_DISABLE_IT(__HANDLE__, __INTERRUPT__)   ((__HANDLE__)->Instance->DIER &= ~(__INTERRUPT__))
复制代码

' `2 z+ y* z& G常用的也是前五个参数,1个定时器更新中断以及4个CC中断 。
1 |( b- K$ {, O* E( S# \9 T7 `
+ K& _% l; z" U2 G$ {6 p注意:操作定时器的寄存器不限制必须要用HAL库提供的API,比如要操作寄存器CR1,直接调用TIM1->CR1操作即可。' C6 l6 v8 s+ P
1 m3 W  F, j7 b' H$ r7 r
32.3.7 定时器初始化流程总结
( W. L% `, C/ i' l* Y( l$ ^  p% t$ N使用方法由HAL库提供:. e8 J/ W+ f0 R, n9 r" c. B
' g  @9 ^2 v( k* d
  第1步:通过下面几个函数配置定时器工作在相应的模式
* v8 X- w- J' ~3 Y4 Y3 ]' a' ^7 ^" K  S: B# {' d
  HAL_TIM_Base_Init
& O! j; E& K6 v7 W, I简单的定时器时基础功能
* `; a% p- j+ h! M6 u) J: ]0 S  u# O
  HAL_TIM_OC_Init 和 HAL_TIM_OC_ConfigChannel1 n: g" J% M: R7 f2 N) s. V, s
配置定时器产生输出比较信号
4 ?; F5 W% R' H, q4 u( o  Z  y$ z2 U3 j# n
  HAL_TIM_PWM_Init 和 HAL_TIM_PWM_ConfigChannel
) _2 j( J: E( k+ M. h+ M' {配置定时器产生PWM信号
4 c% K  s& y- g! Y! \+ W: v; l' M! i. \% b# L' u( L4 I
  HAL_TIM_IC_Init 和 HAL_TIM_IC_ConfigChannel
) x( c4 \( N: S2 R; L3 X0 c配置定时器测量外部信号$ J2 b1 ?+ ^# G. S
8 O3 [2 E6 E. G
  HAL_TIM_OnePulse_Init 和 HAL_TIM_OnePulse_ConfigChannel$ B& ~: [  Q3 n* S1 ]
配置定时器工作在单脉冲模式* s1 R; ^' d$ v$ k8 o
* w1 V; q& E! L
  HAL_TIM_Encoder_Init( T. \6 s0 ^2 ~; p
配置定时器使用编码器接口
; y2 _) b& `' G1 W) K/ V; N2 f  K4 P2 k1 R6 N9 W
  第2步:定时器几个常用功能的底层初始化API,这个里面需要用户自己填6 h: J+ r; w; C% t  ~
1 F3 J' G% f; y6 r% S  k8 @
第1步里面的几个函数会调用下面的API。' N3 w/ v" J1 d8 E2 T7 ~8 m
. N! z! ^2 _6 m7 Z0 p
  定时器基本功能 : HAL_TIM_Base_MspInit()
" k2 C$ U: Q& t2 m# B; q  输入捕获 : HAL_TIM_IC_MspInit()' H' v$ L8 Z! r! `; L
  输出比较 : HAL_TIM_OC_MspInit()# `0 z' m' l9 J. [4 j$ x3 s* g
  PWM输出 : HAL_TIM_PWM_MspInit()
+ ]* E% x; ]9 e- ]4 v# P* A  单脉冲输出模式: HAL_TIM_OnePulse_MspInit()" k( p* l* B5 q9 v# D
  编码器模式 : HAL_TIM_Encoder_MspInit()7 h8 Z& A: e4 V
  第3步:底层初始化具体实现
* _! P4 Q- X2 ^3 W9 h- B8 \( t3 [# u1 @; Q$ W/ W7 @1 t
第2步中函数的具体实现。# t  h, M. H. o3 _" q

* n$ q6 p( S( D" \3 F+ F% S  使用函数__HAL_RCC_TIMx_CLK_ENABLE()使能定时器时钟。& f8 x9 y9 c$ U
  使用函数__HAL_RCC_GPIOx_CLK_ENABLE()使能定时器使用到的引脚时钟。
. s" w' T& d0 _: a  R" Y  使用函数HAL_GPIO_Init()配置GPIO的复用功能。$ e; y0 m( j2 Q* g4 w- L5 z! R
  如果使能了定时器中断,调用函数HAL_NVIC_SetPriority和HAL_NVIC_EnableIRQ配置。) Y" i/ e! P8 s. y& e0 o
  如果使能了DMA,还需要做DMA的配置。, L4 o* [% B4 @! ^' U$ H7 ]
  定时器默认使用APB时钟,如果使用外部时钟,调用函数HAL_TIM_ConfigClockSource可以配置。! I; E$ @; ?& G/ d
  第4步:启动定时器外设
* I# U8 }, t3 i7 a9 i' T/ I
( H) |! u9 o- h4 F  定时器基础功能:& Y* {0 q" b5 p# n, _% x$ S
HAL_TIM_Base_Start()
& D: m- c1 X  b
; P% ~/ [/ }) }HAL_TIM_Base_Start_DMA()8 J* w5 g4 C* @2 Z6 Y

' P- F9 B" F" l( h1 \4 @  w( hHAL_TIM_Base_Start_IT()
+ B. `3 p# m* v& }  Q  Y; L# b4 S8 C3 J" \2 ?
  输入捕获 :
7 R8 ?( ]. X$ {2 v  Y& n- t; SHAL_TIM_IC_Start()0 I6 p0 U& v7 S- Y: h

, J  h6 x9 O- u7 |# ~HAL_TIM_IC_Start_DMA()( C  W6 S0 A2 j' z2 R* k; k9 e
  C' e* W& M- i8 M# f
HAL_TIM_IC_Start_IT()( P, Z+ {7 u% V3 }+ M, N8 Z) q

; N9 r! q6 u& L" b/ a% R  输出比较 :. M9 E: \" R/ |/ e9 R! ?" q
HAL_TIM_OC_Start()
6 C6 E* X# X" E& v# V( b* g+ F( @: j* Y* P- {  k
HAL_TIM_OC_Start_DMA()7 `$ k; O) b8 ?5 a# k" i8 V

- J( `- [4 D5 aHAL_TIM_OC_Start_IT()
# \( |+ C1 q, k( L3 V5 ]  {: w9 Y! p* m: g$ O4 m
  PWM输出:7 J# V& K5 @, T8 W6 M
HAL_TIM_PWM_Start()
& x( Z. X: e& @( g7 t
0 j2 i% G# O) ]+ B+ }" K  b. AHAL_TIM_PWM_Start_DMA()6 P4 Z  B) a; e& b# O$ x# g' H

  U( Y: s  @2 iHAL_TIM_PWM_Start_IT()( d  n2 q: x; }0 Z  i
5 K1 [/ `# A- {5 [
  单脉冲模式:
2 n! ?! W2 [4 X6 X$ w  EHAL_TIM_OnePulse_Start()
1 o5 ?2 c2 c1 e8 L" X3 L/ C0 u+ k( o' g) `) Y& a  c" E
HAL_TIM_OnePulse_Start_IT().7 k! R% |3 C% _+ {1 C* e

/ R: u9 t% j+ A# g+ Y; {! \  编码器模式:
5 l3 J! V" L' }, qHAL_TIM_Encoder_Start()
0 ?5 [% Q/ g, a8 E3 `5 \& l- r. e6 {# y' w9 T$ A* P2 v9 ^
HAL_TIM_Encoder_Start_DMA()
  d4 K$ n4 S2 s$ W4 m  |
- ^7 T7 ^- ~* e+ Z4 l3 g" `HAL_TIM_Encoder_Start_IT().
5 O; i$ S6 A0 }4 L5 e8 `% W) C* F' s+ z9 I8 s
  第5步:定时器的DMA突发使用下面两个函数; b  w) j6 M4 ~& {% _% J

/ S, e3 l2 o# |! A  HAL_TIM_DMABurst_WriteStart()% N9 T! p3 m2 r8 k! u) Q4 I0 I; N
  HAL_TIM_DMABurst_ReadStart(); s; m3 r5 Z  X
定时器常用的功能,通过上面这几步即可实现。
% N& C' f8 i8 F$ @0 s% L! n( h9 Y6 ?- v
32.4 源文件stm32h7xx_hal_tim.c7 |  Y4 f5 o" H
此文件涉及到的函数非常多,这里把几个常用的函数做个说明:
9 x% f! {9 i$ O9 Q- B5 J5 E
8 x2 X5 \) k( E3 q& m/ v* I, ?# @  HAL_TIM_Base_Init
& _: P  u/ F. ]$ Z5 `  HAL_TIM_Base_Start
5 q6 M2 Q% ?& E, a$ g  HAL_TIM_PWM_Init
+ N7 L7 k' K, b  N# O. }  HAL_TIM_PWM_ConfigChannel
$ ?- e  m/ H. {  i6 s  HAL_TIM_PWM_Start
  [; T& {0 B9 m" x  HAL_TIM_IC_Init
  a! g' j% T$ u4 Z& N) H9 ^. m  HAL_TIM_IC_ConfigChannel
' ^! p! q' m3 ^4 x/ F- k0 j0 b  HAL_TIM_IC_Start_IT
4 f/ F% x  S, t0 t3 I9 k  HAL_TIM_OC_Init
, D  O, G5 X( T  HAL_TIM_OC_ConfigChannel
9 i  V$ J* o: ^+ L  HAL_TIM_OC_Start
8 m/ O. [0 y* @2 J$ j32.4.1 函数HAL_TIM_Base_Init" D! ~- S4 a; q2 t$ ?
函数原型:' x4 w8 c( d( Z6 C& p
8 I) W: c- p: _/ K7 e
  1. HAL_StatusTypeDef HAL_TIM_Base_Init(TIM_HandleTypeDef *htim)& v7 R: l- [7 L/ `; W& A& N
  2. {
    - E) c2 ~& w0 @! Z
  3.   /* 检测是否是有效句柄 */
    9 J- G: f* z) \% ?
  4.   if(htim == NULL)
    0 t+ x7 Q2 B; u4 o
  5.   {
    $ z& v% M" E) X9 f! [; h7 e
  6.     return HAL_ERROR;
    7 Z% W- k, P8 {+ N
  7.   }
    $ k$ A( t' a  o/ b

  8. . Y. t; n/ y+ w: h6 I' B
  9.   /* 检测参数 */( U3 j9 W- J8 X6 a2 {
  10.   assert_param(IS_TIM_INSTANCE(htim->Instance));
    ) N/ N, v7 Q4 P4 K, Z* p
  11.   assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode));
    # {, m* U; Y2 t# m: n  C: b
  12.   assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision));
    : @+ w$ N1 j6 P' i% [
  13. % x% m; P( w4 b
  14.   if(htim->State == HAL_TIM_STATE_RESET)' c$ [2 a& |2 O1 B! s! P/ x/ p( l' \
  15.   { % N/ L3 q9 h4 K. {6 w7 y: `/ V
  16.     /* 默认取消锁 */% j8 @; o: F+ \/ y/ ]$ P" q
  17.     htim->Lock = HAL_UNLOCKED;+ b9 b- G3 b8 K
  18.     /* 初始化底层硬件 : GPIO, CLOCK, NVIC */$ u" {; k6 p5 b! S
  19.     HAL_TIM_Base_MspInit(htim);+ s. Q" r1 D( O
  20.   }6 I; r0 V; b& J* D/ q# {; A) d
  21. 3 u6 s5 V; \1 P! m1 G) ^! K
  22.   /* 设置TIM状态 */
    * e8 Q' r4 T" ~  u
  23.   htim->State= HAL_TIM_STATE_BUSY;
    % s/ o0 x& M9 h
  24. 0 P( p  ~$ @0 s/ _; w3 {. }) Q
  25.   /* 基本参数配置 */
    : Y% P- ?9 ]" f/ n5 N# p* a# `3 N# n
  26.   TIM_Base_SetConfig(htim->Instance, &htim->Init); & E- R% G/ W* c2 n! @) e6 }
  27. . Q5 e, x- i$ u& J3 Z
  28.   /* 设置TIM就绪 */9 ?- a/ p8 z* D% z7 m
  29.   htim->State= HAL_TIM_STATE_READY;' I& \& D5 o- B' `
  30. 8 d$ J+ K) f( o0 d$ `5 X8 I
  31.   return HAL_OK;
    1 y: x' k1 {- z) t' ~
  32. }
复制代码
$ L6 W7 a# x1 b5 z! z
函数描述:' j' c- G, k* y; l5 a, T

5 E$ H+ ^* t, T  [# m: P  P此函数用于初始化定时器用于PWM。
6 Q9 h( {% h* t+ l9 f# \3 ], h. q( K) l. c) p2 t  |/ j7 _: |
函数参数:# V7 f5 D% i& r% f* X
: k5 X! P9 P3 c6 n
  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。
* Q6 I9 A4 K8 N8 a  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
& Z: i' T- F, ]* X2 K注意事项:
  c: M# `  ?0 S/ P9 X3 @8 i; I/ w6 I) B/ M" o
函数HAL_TIM_Base_MspInit用于初始化定时器的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能,由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。  M6 O2 ?7 h+ A8 i2 j( }. A" F
如果形参htim的结构体成员gState没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量TIM_HandleTypeDef TimHandle。
5 s  ]8 t! k' U7 }1 ~对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_TIM_STATE_RESET  = 0x00U。9 h! v; `! L3 r  W- h
/ R+ f4 w6 P: Z( O5 W9 _9 n: |
解决办法有三:
7 S+ m! J2 G- [3 o. ~4 z  j+ x6 |  d/ r& v( s9 j) J- l
方法1:用户自己初始定时器和涉及到的GPIO等。
0 }0 H) P8 |. b- W! |8 N1 p3 W7 j. f
方法2:定义TIM_HandleTypeDef TimHandle为全局变量。
$ V" A7 n8 n: p; \9 V
# T" h( a8 Q3 Z' O( B% @6 I方法3:下面的方法' p" y9 n& t8 M* b5 i9 l

2 i1 I, @6 W- N; |
  1. if(HAL_TIM_Base_DeInit(&TimHandle) != HAL_OK)
    ) M2 V7 D2 u+ R# |. c( F! W
  2. {/ N! V: R7 b" Y  V
  3.     Error_Handler();) D/ e: L. C$ `4 H: q" b* X
  4. }  
    1 B/ @+ G7 u5 S/ [
  5. if(HAL_TIM_Base_Init(&TimHandle) != HAL_OK)
    $ s  v1 _6 B  `; b
  6. {
    7 z0 R- \' u% ]& p
  7.     Error_Handler();
    $ ^  S, ^$ y9 [0 @+ [0 d+ l
  8. }
复制代码
- C7 }1 D7 ]7 C4 M* e3 c$ y& E
使用举例:
1 O3 r& q1 S! |" K
6 [* Z8 l) @$ z. U8 {- K6 H
  1. TIM_HandleTypeDef   TimHandle = {0};) \' [* E8 M; v" F, a) E3 y6 q/ x
  2. 5 g/ E/ ^( L' A" o3 j
  3. /* $ `7 X2 Q1 a, x* h0 O7 o
  4.     定时器中断更新周期 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)
    9 a7 ~% K, h4 C* N
  5. */0 j7 s3 W$ p0 c
  6. TimHandle.Instance = TIMx;) y0 e  f! M( |  |2 L
  7. TimHandle.Init.Prescaler         = usPrescaler;3 ~, O" G0 E3 G
  8. TimHandle.Init.Period            = usPeriod;        
    - H& d" ~0 W8 V3 {0 Y5 A- R
  9. TimHandle.Init.ClockDivision     = 0;0 q, B* s# G+ I. S" j1 ^2 j$ @
  10. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;$ q6 I: I+ S1 F3 l  `" {
  11. TimHandle.Init.RepetitionCounter = 0;
    * `+ M; v" X; C4 J- P- `7 y; S2 i
  12. TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;# i3 ^& `, d' `% ?: [4 H' Y% K( B
  13. if (HAL_TIM_Base_Init(&TimHandle) != HAL_OK)
    $ N' k( b7 P4 c" [+ [& _4 T- ]
  14. {$ _* z) L* X! m0 t4 d
  15.         Error_Handler(__FILE__, __LINE__);
      T, T; U- F5 U; H" l) l8 e
  16. }
复制代码

- g' l, @  W, L& A* b32.4.2 函数HAL_TIM_Base_Start
; J6 h* D4 N+ ?( P; ~- b+ t函数原型:% b0 }4 x% b9 g/ ~4 q

8 Q0 v- O) s' j0 k
  1. HAL_StatusTypeDef HAL_TIM_Base_Start(TIM_HandleTypeDef *htim)/ y4 k8 C" D( B
  2. {
    ( g6 e# \& `# t4 ]
  3.   /* 检测参数状态 *// x! \+ p& U# H- U: S
  4.   assert_param(IS_TIM_INSTANCE(htim->Instance));6 w, V2 f+ F* U" L
  5. / h: ]5 C; C6 r1 \: K$ O+ o
  6.   /* 设置定时器状态 */) r! P4 G  j5 |4 k
  7.   htim->State= HAL_TIM_STATE_BUSY;
    9 Y* [' k" l0 H6 W7 [! u% e
  8. + H# a$ x, ?/ s1 B; @
  9.   /* 使能定时器 */" t7 `0 @& R$ M; H: y8 N' t' \
  10.   __HAL_TIM_ENABLE(htim);
    , G5 z9 v) q. w+ x2 p. |

  11. , o5 m; r. t1 H6 |  M. \
  12.   /* 设置定时器状态 */
    7 g7 w( e/ N/ u9 P  a
  13.   htim->State= HAL_TIM_STATE_READY;+ z: P" H/ q6 s& I7 a
  14. ) \( e" K/ a4 F# |1 p  E1 F- E
  15.   /* 返回HAL_OK */  }0 K7 M  V) [+ Z  S# V- H
  16.   return HAL_OK;6 J7 i  Q6 F) Z+ ]
  17. }
复制代码

2 V8 o& Q( A# j2 e. ?6 `2 ]' f函数描述:
, B2 o- R9 J* y" U/ d3 b9 M) Q" t" i5 T
此函数比较简单,调用函数HAL_TIM_Base_Init配置了基础功能后,启动定时器。+ n2 J6 ]; ~+ s1 h/ |3 \1 k

. M/ v6 U3 t1 f5 w: [" }, D函数参数:$ ^! t1 h: G) F% n6 }* E2 D- j

/ W$ s3 Q4 l7 E6 m  K( C; ^  第1个参数是TIM_HandleTypeDef类型结构体指针变量。: \& j. U+ z) z4 x
  返回值,固定返回HAL_OK,表示初始化成功。( c; v0 H6 u, m+ r0 m
使用举例:0 K" l( T0 `. q# W  K% J
# L7 A  A/ ~/ P! j* ^9 K2 J# `! B# l# {
  1. TIM_HandleTypeDef   TimHandle = {0};. r/ R! q4 ^# A
  2. 2 P2 J# B; v) P% G& K- O* @$ q
  3. /*
    5 z' `3 X* d. E9 `; }
  4.     定时器中断更新周期 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)8 r+ }1 l9 T8 C9 ]
  5. */6 C% U* R. X( \, U0 ^0 ?# a
  6. TimHandle.Instance = TIMx;
    8 B& `, |& O  K8 \5 W
  7. TimHandle.Init.Prescaler         = usPrescaler;0 s0 z6 s! ^8 c8 O; u% e
  8. TimHandle.Init.Period            = usPeriod;        
    8 }. u* t" _9 \3 Q6 l8 v
  9. TimHandle.Init.ClockDivision     = 0;' g% X9 j5 A& I+ m( V6 F
  10. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;
    / D0 @4 p6 t2 R' r
  11. TimHandle.Init.RepetitionCounter = 0;
      b7 f  n' Z& D8 }5 y
  12. TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
    & g) F7 [( H- i6 `: N3 t
  13. if (HAL_TIM_Base_Init(&TimHandle) != HAL_OK)3 p- k, S8 Q0 p0 N4 i$ P) v
  14. {
    ; [8 B/ F$ ~# {! N2 r; S
  15.         Error_Handler(__FILE__, __LINE__);( B3 n( p0 j+ Z1 y& ?3 N: ~
  16. }
    ' y( V6 E& f$ K# X, s' v8 J5 F

  17. ' K0 }& k- o8 f
  18. /* 启动定时器 */
    ( R1 J5 H6 `6 m- r& c
  19. if (HAL_TIM_Base_Start(&TimHandle) != HAL_OK)- Q8 o9 [4 g7 t; s6 V
  20. {5 e, T2 V3 r- f- O- O$ e
  21. Error_Handler(__FILE__, __LINE__);
    & K3 ^: k, G; s& S
  22. }
复制代码
7 _. {" _' w: e/ n1 b6 g) O1 K
32.4.3 函数HAL_TIM_PWM_Init8 d1 ^$ M+ E. a  C0 a9 e
函数原型:
' [7 n2 I! I% [$ i, d5 P
/ ~( _( x) G/ }$ M! l4 w0 P$ m
  1. HAL_StatusTypeDef HAL_TIM_PWM_Init(TIM_HandleTypeDef *htim)
    2 C( a# h$ e9 ^$ k
  2. {5 D# m7 j+ ~9 H/ A0 V8 g2 {1 @
  3.   /* 检查句柄是否有效 */8 Y' Z" U( m5 O3 [% i) R* q3 b
  4.   if(htim == NULL)4 o# J) x0 L, ~) D
  5.   {
    $ _% L5 Q7 ]/ b( }* O# o7 t: c, I
  6.     return HAL_ERROR;/ Y! d: z6 t$ t& f  g
  7.   }; C1 t7 ]' y) |5 N' s. f, i2 T
  8. $ z9 I1 Z! [/ P* y5 s7 t; D
  9.   /* 检测参数 */
    . ^3 X8 l) o- e+ D. s) N. a
  10.   assert_param(IS_TIM_INSTANCE(htim->Instance));
    . b+ l! @4 {8 b' t; V
  11.   assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode));. H& @- B# R& h( v) d; ^
  12.   assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision));: D5 g1 g. x( E# w$ `
  13. $ N* V3 q" @( S- R0 J
  14.   if(htim->State == HAL_TIM_STATE_RESET)" u: ?5 p" D6 k. v; I
  15.   {
    ) H$ V8 i3 {- b3 s4 y
  16.     /* 默认取消锁 */
    - b+ w! @2 I( ~0 w% ?
  17.     htim->Lock = HAL_UNLOCKED;
    # x) o; K3 Q: ^) I- X
  18. 4 ?  `4 R: ~4 h
  19.     /* 初始底层 : GPIO, CLOCK, NVIC 和 DMA */- e! F9 J% _; |' m3 t4 T# A
  20.     HAL_TIM_PWM_MspInit(htim);) [+ A* {3 e5 Q( R
  21.   }5 d( l/ n' O" t) W& a7 j* \

  22. & R+ o/ \; I" F" h, C
  23.   /* 设置定时状态 */3 i2 f+ p' X8 b" }3 L
  24.   htim->State= HAL_TIM_STATE_BUSY;7 S0 n: ^9 ~0 Y# r$ h/ c& w

  25. ! I: ?1 w4 ^  L% m
  26.   /* 配置定时器用于PWM */  " C2 _' ^  r$ b
  27.   TIM_Base_SetConfig(htim->Instance, &htim->Init); 2 y& F  ?5 a- s$ q
  28. : v& v7 q1 X# S4 H- G& \$ r* z
  29.   /* 设置定时器状态 */7 }2 Q+ U& t& m0 R, T9 @# Y2 g; o7 B) S
  30.   htim->State= HAL_TIM_STATE_READY;
    : d. x/ e0 f! @5 {
  31. 7 O" S! m. v/ G: d( B
  32.   return HAL_OK;. ^# [# X6 Y$ }1 w% Y
  33. }
复制代码
6 k7 T; Z" z9 i) e4 l) G
函数描述:
" k$ X: W8 i. g% q) Y
: U2 z+ {" ?  ]) ]+ l5 ^此函数用于初始化定时为PWM方式。
2 }4 f4 A4 `. U5 Z0 q  P+ I
( e! W# n( c, P函数参数:
% Y" d9 b% k6 [! w# w" T& [3 s1 N) o# C
  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。
1 l7 z) D( [, Y  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
5 s$ ?. _7 T% _9 @( S/ Z5 e7 W7 ~注意事项:
, Y0 Z2 S  W4 G* `+ m1 b
0 u$ v' O) V& u) d! q1 _6 b函数HAL_TIM_PWM_MspInit用于初始化定时器的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能,由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。/ {' [, ]) j7 y( ^
如果形参htim的结构体成员gState没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量TIM_HandleTypeDef TimHandle。, {' a) A0 H6 a6 d+ R+ ~) v
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_TIM_STATE_RESET  = 0x00U。
  ~$ `1 Q- V7 v* o
1 R( |* V1 Z* w# L$ R0 x解决办法有三:. O# h$ L4 O/ L6 J: M# H
7 @  r) J& r, A* R6 Z
方法1:用户自己初始定时器和涉及到的GPIO等。) x( f/ u, E4 e# e2 t$ ~

; @- }' }0 m+ f方法2:定义TIM_HandleTypeDef TimHandle为全局变量。
" Y9 i( C$ Q( ?1 F6 W. g2 N# K: F5 L
; Q8 q5 ~. p2 `& L方法3:下面的方法  I# y7 H* W4 n3 q2 }- I
. V& y& f& x* p' I
  1. if(HAL_TIM_PWM_DeInit(&TimHandle) != HAL_OK)3 y5 r8 e) L/ u9 I3 h& u' \& j  c
  2. {6 M9 c# I. r( s: I
  3.     Error_Handler();2 \4 F" F% @0 L2 \
  4. }  . c4 L1 k3 g; K1 Y  f
  5. if(HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)
    5 i, W0 z% Q6 n3 C9 A% A9 ]+ ^8 H
  6. {
    ) i1 {( i. l4 `1 N, ~' B% l" k, Q& N
  7.     Error_Handler();
    % T7 H$ a$ X/ q' [" B3 z% i9 X
  8. }
复制代码
- i( U! O6 m0 P, i0 ^( S3 D
使用举例:. f( e) R0 I* ?" T2 G4 v
* t6 Z6 I+ a$ I- B9 D# r7 Q$ a
  1. TIM_HandleTypeDef  TimHandle = {0};
    9 {, f' y6 H# ~' x
  2. 4 ~% W9 L) k, `: ~
  3. /*  PWM频率 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)*/! c$ A. c( w6 Y" i
  4. TimHandle.Instance = TIM1;
    4 Y5 j4 l) Z& e/ l/ ]* F
  5. TimHandle.Init.Prescaler         = usPrescaler;
    ( ]; |6 N* U9 t$ N
  6. TimHandle.Init.Period            = usPeriod;
    # Q) q% Q) n; _' I2 W7 m) w
  7. TimHandle.Init.ClockDivision     = 0;
    5 e# r4 k0 O5 t8 q* E2 S+ B
  8. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;
    8 d  u" o. z7 O# Q; J7 O
  9. TimHandle.Init.RepetitionCounter = 0;
    7 x; i& ^& N2 d
  10. TimHandle.Init.AutoReloadPreload = 0;
    : k. z6 ]1 X" v( z# Y
  11. if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)$ Q1 L3 A7 ~0 |
  12. {% r. |3 X' z8 S8 U/ n: _9 w1 a
  13.     Error_Handler(__FILE__, __LINE__);7 Z/ V( x1 n4 k6 x/ V) J* |" v
  14. }
复制代码
1 z  L: ~9 k) j+ M! u" |
32.4.4 函数HAL_TIM_PWM_ConfigChannel
0 Z, _# i! u8 w2 T- \$ g函数原型:/ A; B5 u9 {& b% G0 d

: }) r! B# g& n* B- Z) C
  1. HAL_StatusTypeDef HAL_TIM_PWM_ConfigChannel(TIM_HandleTypeDef *htim,3 p1 m! k, |" r  ~1 c  J6 P
  2.                                             TIM_OC_InitTypeDef* sConfig,6 E/ m5 f7 V+ j  N! g9 r7 U& e, j
  3.                                             uint32_t Channel)
    9 f) D- _7 H+ z9 g: _
  4. {3 `& D+ j$ f% K" H: V( l& K
  5.    /* 省略 */$ L. ?/ A. V0 p& X/ z

  6. $ s" x) q) B% ~& L# r' B
  7.   /* 开锁 */
    * ~+ b2 F& ?5 k7 z5 X: M: n1 n
  8.   __HAL_LOCK(htim);9 v, E, E3 `- v. P# U( L

  9. 0 n, w; s% y& }2 V% b. z8 e: z
  10.   htim->State = HAL_TIM_STATE_BUSY;
    - N: B5 {4 U! a
  11.   d; X+ w2 ]! t
  12.   switch (Channel)
    8 N5 _, u( {, c
  13.   {+ Z+ ^: ]! t# \  ~
  14.     case TIM_CHANNEL_1:; Z1 _% q! u' A
  15.     {
    ! Y- q5 t. e* G0 q" B( v8 i5 s! b  a
  16.       /* 检查参数 */% L- w: y1 R8 h% g2 W8 q
  17.       assert_param(IS_TIM_CC1_INSTANCE(htim->Instance));
    ( L( y) F' {& o) A
  18. 0 }6 R' X2 B- E% @/ ?# d
  19.       /* 配置通道1的PWM模式 */
    , V0 j0 B% }  d# _9 ]7 |
  20.       TIM_OC1_SetConfig(htim->Instance, sConfig);3 q1 x( J' n  }; P; ~; V

  21. 2 ^( o0 a: }# ~1 l! ?! o; j
  22.       /*预装载使能,更新事件产生时写入有效 */# g& R2 T- x" L/ ~- L
  23.       htim->Instance->CCMR1 |= TIM_CCMR1_OC1PE;
    2 v7 |% |0 y5 }8 G6 g0 T# T

  24. % y+ ?# F: {: e- g
  25.       /* 配置是快速输出模式 */! @6 W: {% s: ]4 r3 x' L+ p! r
  26.       htim->Instance->CCMR1 &= ~TIM_CCMR1_OC1FE;
    2 k+ e5 P3 s! L; C3 S: O6 |4 T3 K
  27.       htim->Instance->CCMR1 |= sConfig->OCFastMode;) z9 h0 t) ]" E* e+ F* _
  28.     }- Q# n5 e- f; [8 C2 `( w1 Z7 O
  29.     break;( ?" m# b; \0 T+ L6 F/ Z
  30. " ?1 `$ I0 {! L: ?- J7 t
  31.     case TIM_CHANNEL_2:
      u- `1 }" G5 k
  32.     {
    / _. W, Z5 V5 U5 Z/ z4 q# H
  33.        /* 省略 */
    , h# b  e+ p. @) }+ a# n
  34.     }. v# ?" k, [' u' A, n' J( w. v7 O' O
  35.     break;! J8 f# |( h( ~! Q) B1 p  U7 N

  36. + R' N& d$ ~  U8 P  A9 r" X
  37.     case TIM_CHANNEL_3:, e+ K. T, |) E/ z0 H2 P
  38.     {: n: W/ b8 R  B: u; r9 q# |4 H
  39.        /* 省略 */
    . V9 _# A# R& }, s
  40.     }
    6 q& u- p) E+ h9 D3 m) s
  41.     break;
    4 ]3 U0 F* n9 n$ ?9 q  {2 X

  42. ( ^0 w2 m' |* K% r% w
  43.     case TIM_CHANNEL_4:
    7 e" |7 z% n' z$ `5 [* d9 V/ m0 s
  44.     {# t8 F) C' H5 t/ r- U
  45.       /* 省略 */# J' O6 A! r6 u; o0 l
  46.     }
    4 l& ?  e) m- H  _* |
  47.     break;8 O4 t2 w9 P  C" n! o& b: R

  48. + e' i% S! s9 R; V9 e' M8 G
  49.     case TIM_CHANNEL_5:' f! O+ r- `( v5 S# O
  50.     {
    9 Z0 v" @0 A/ l1 c6 W4 d
  51.        /* 省略 */# V  k4 K: ], O$ N, J! G/ Z- t0 x
  52.     }
    ! B! Z9 A& |5 ?% R( z
  53.     break;" v/ M2 j; G6 s

  54.   H9 M9 }5 X& Q1 J
  55.     case TIM_CHANNEL_6:
    7 f( _7 ^: r, \  v+ U$ P# E
  56.     {
    4 D: P5 q1 r2 `
  57.         /* 省略 */
    + X4 ^1 e3 U- n! A
  58.     }
    $ Z. U, A4 M" [" u/ h' I( U
  59.     break;& [9 Z- g1 ~& z) `# b* B: m# n
  60. 8 ~3 s2 ^& M( q$ [/ m
  61.     default:
    " s" @; @8 |% ~0 k! N& t
  62.     break;: u, u' J* O$ x
  63.   }
    0 T2 L/ i0 g) F

  64. ' e1 E; `8 v' d  I( ^7 A# K7 ~# u
  65.   htim->State = HAL_TIM_STATE_READY;1 p+ I! e- B# ~2 f8 o8 F4 L7 i
  66. . V. ?! z, A* g% Z0 |' R
  67.   /* 关锁 */4 C# j) t9 n, M* r+ l1 j6 W
  68.   __HAL_UNLOCK(htim);
    ) S5 s6 Z! b3 t' B7 \  @$ r) t/ ?

  69. * U4 I" r) Q+ s% l1 n& h
  70.   return HAL_OK;
    $ q. n/ u; `! ]# ~0 r
  71. }
复制代码
' q* s7 h2 e8 u, l! e, B# I
函数描述:
) C7 I9 r; O: E; T" {' s. `  \4 J* t2 L
此函数用于配置定时器的PWM通道。+ [* J  O" I' P. i. b

/ B" @% E8 y; h! l! [0 z) U函数参数:: u6 }) V' S2 d1 |8 T! H0 S0 Z) [

- A5 [6 N7 ?" b5 B* s7 [4 v( b/ i  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于定时器基本参数配置。
3 {* F7 j0 A. [& T& p/ L, z  第2个参数是TIM_OC_InitTypeDef类型结构体指定变量,用于定时器输出比较参数配置。$ G9 Z9 J/ [% t
  第3个参数是通道设置,支持以下参数:& c: \5 ^% N  _4 L7 e0 P
TIM_CHANNEL_1
3 p! ~* x. Z) c" j4 X; M1 @: @6 v% R3 m) ~9 ?
TIM_CHANNEL_2
& l1 O* h8 v5 `, H8 O
  P8 q" |% {' h3 cTIM_CHANNEL_3; G% W* X$ [$ ]
7 B. G1 d" ^$ E3 ]$ p
TIM_CHANNEL_4; b9 @, y3 f0 D  u5 _, o( }- Q
/ C$ u0 m+ ?* b, n7 u8 ]$ }
TIM_CHANNEL_5) S* X# U) C# K% @4 e
2 J  f6 x: `! ^
TIM_CHANNEL_6
* D% F3 h0 o8 u; W; M. R9 L4 ?* @( ?
3 [. D" U6 l! N6 O" x  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。. p4 f$ C8 Z1 @- v) E" U1 v
使用举例:1 v2 O8 E6 g; @8 w) ^' j
$ [9 l" H1 J4 j
  1. TIM_HandleTypeDef  TimHandle = {0};" O: G' K3 F- c

  2. 7 O0 v, p& O5 y6 @' z: m
  3. /*  PWM频率 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)*/
    9 m5 H% {" r0 b' K% v/ I2 k9 W/ e9 B
  4. TimHandle.Instance = TIM1;; J3 A8 F7 W0 D
  5. TimHandle.Init.Prescaler         = usPrescaler;
    $ |7 G- u- W0 `
  6. TimHandle.Init.Period            = usPeriod;$ \! T5 D  o* M# n
  7. TimHandle.Init.ClockDivision     = 0;0 G0 r- [* p  [  i5 Q- E4 p" a4 N
  8. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;
    9 n9 q5 h/ I1 }4 H  f7 d
  9. TimHandle.Init.RepetitionCounter = 0;) M6 o  S( U6 b! D; ^7 [0 @
  10. TimHandle.Init.AutoReloadPreload = 0;7 L; e; ~! J% f
  11. if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)3 d; G$ N+ \8 l& _+ @; C  @
  12. {4 G1 u% m! |* Z
  13.     Error_Handler(__FILE__, __LINE__);
    6 [& u4 W( e# c5 h/ p0 J, [
  14. }% X' d4 t2 S7 m! r. ^+ Z

  15.   q, l: d) b- p- v
  16. /* 配置定时器PWM输出通道 */5 q3 y# J3 P, M1 k4 i' }3 w
  17. sConfig.OCMode       = TIM_OCMODE_PWM1;6 d$ A) P( j  z' ?1 o, `
  18. sConfig.OCPolarity   = TIM_OCPOLARITY_HIGH;
    6 h# W: x9 j6 H
  19. sConfig.OCFastMode   = TIM_OCFAST_DISABLE;
    2 k9 ^: o/ l" a# F
  20. sConfig.OCNPolarity  = TIM_OCNPOLARITY_HIGH;* l% c5 ]+ S) g) f' X$ ?& M0 R# S7 y
  21. sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;
    , R) V4 t6 ^- f
  22. sConfig.OCIdleState  = TIM_OCIDLESTATE_RESET;
    $ [. d5 U4 n2 v0 E7 k
  23. / s$ n9 q6 g0 B
  24. /* 占空比 */' b& `1 d9 Z$ S0 B) `
  25. sConfig.Pulse = pulse;/ u- N; |. t, g; B7 P/ w7 S# U
  26. if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &sConfig, TimChannel[_ucChannel]) != HAL_OK)
    ) `' I* e, C( g. U4 S6 s& Y
  27. {
    , s! N9 y! s. @3 S
  28.     Error_Handler(__FILE__, __LINE__);  I8 g$ H( t6 C8 A
  29. }
复制代码

5 e0 ^! Y0 C* u, H32.4.5 函数HAL_TIM_PWM_Start
! E2 z2 r9 A* y# [/ k) F函数原型:/ w7 h1 ^/ w% K7 ]
( s6 ~+ V. f( E# _3 P
  1. HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel)$ j2 J* s( f; {" B
  2. {1 r" f! F* K8 P9 W. ^
  3.   /* 检测参数 */6 F; x+ Z; S9 p: z0 U! l
  4.   assert_param(IS_TIM_CCX_INSTANCE(htim->Instance, Channel));* b7 h* b& }1 ]6 n( R6 }1 y% r
  5. ; P( F. o" p; i8 e* m
  6.   /* 使能捕获比较通道 *// y* j" G: }' w" @6 T
  7.   TIM_CCxChannelCmd(htim->Instance, Channel, TIM_CCx_ENABLE);
    ! {7 M/ |8 i% m( K
  8. : {5 q$ e, h" M. O/ M: I( X) `0 }
  9.   if(IS_TIM_BREAK_INSTANCE(htim->Instance) != RESET)  * Z+ ^- x: y/ A- y! D
  10.   {2 L' f; v/ F0 u' f
  11.     /* 使能主输出 */
    - S7 S& c; Y' @5 f# M# P) _
  12.     __HAL_TIM_MOE_ENABLE(htim);
    - L9 ^  ^% A. w3 {
  13.   }3 i" I+ Z8 n! Z; M1 q
  14. 2 `6 N0 f; |) V
  15.   /* 使能定时器 */
    ' T& @; M$ u. k2 R8 ~
  16.   __HAL_TIM_ENABLE(htim);
    8 N. J) U, g" `

  17. - `! j& }5 d# q" w
  18.   /* 返回状态*/
    ! @9 f3 C9 ~) W, X) b; c
  19.   return HAL_OK;
    7 U2 x/ k- @$ y) }# L' x* F
  20. }
复制代码

# u) o- ^' f# z3 m+ Z. d" X/ {. K函数描述:
) ^+ H$ k8 O' \! J
9 l% c  s# v4 G- j/ R) H4 \此函数用于启动PWM。
+ H9 s0 r' v% S4 d3 I* |6 f7 x: U8 M. L& E! L9 K+ k
函数参数:! z, E/ t7 z+ N: H$ i

! U! u- y- ]$ r% Y/ F  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。
' H$ q" V- G/ {3 X0 N' F( C  第2个参数是通道设置,支持以下参数:
, @2 L0 p! X9 \! r/ iTIM_CHANNEL_1
" [) T0 y% K- B) K6 z7 S0 M4 F
2 j3 N& X/ a- ~* l! J5 R7 fTIM_CHANNEL_2
2 f3 e2 S% V6 z7 h2 ]4 m5 U$ @) W- B+ K! H
TIM_CHANNEL_3( @' K2 ^: B- I1 y5 u) v6 d" Y

  c$ [- }) c- i: j+ \TIM_CHANNEL_4; F; r& V" T$ }+ i' \2 Y

' B6 {( N8 v! }. N  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
8 h3 N9 j  X) f+ D3 H( W3 E4 I8 }使用举例:
* M/ F( z2 M( N# l6 {% d4 c5 l% S) M' L$ w
  1. TIM_HandleTypeDef  TimHandle = {0};4 l% S# f/ M  v' m
  2. - n  R9 Y( c7 e
  3. /*  PWM频率 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)*/, J" t" ]) d! [! G3 Q4 r* L4 I
  4. TimHandle.Instance = TIM1;  ]4 h% `+ I( k  b- U+ {2 f* @* y+ m8 y& t
  5. TimHandle.Init.Prescaler         = usPrescaler;) g: H7 F9 E  u. X
  6. TimHandle.Init.Period            = usPeriod;
    & b& {7 C* t4 Y( i  w
  7. TimHandle.Init.ClockDivision     = 0;1 T4 H, E) n6 i( e) ]. o" h
  8. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;
    / I. K8 g4 G9 Y" j
  9. TimHandle.Init.RepetitionCounter = 0;& |2 d5 y2 |; f. z3 N$ {' D; S
  10. TimHandle.Init.AutoReloadPreload = 0;  m3 j$ }: Q' H/ h1 A) V
  11. if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)1 z5 f: t$ U/ Q( ]+ |" B
  12. {
    1 e( s$ V- N/ r9 G" D, m4 @7 \9 |
  13.     Error_Handler(__FILE__, __LINE__);
    + P9 w4 [& ~4 c/ J. @& Z
  14. }$ O/ z8 v# r" m

  15. 2 u/ ?5 U' k1 `9 G, O# T
  16. /* 配置定时器PWM输出通道 */" X- q; z5 ^' E3 y+ j! }; {
  17. sConfig.OCMode       = TIM_OCMODE_PWM1;. D" c* W# y" s; B6 c
  18. sConfig.OCPolarity   = TIM_OCPOLARITY_HIGH;
    ! w- Y  V6 k$ e3 |
  19. sConfig.OCFastMode   = TIM_OCFAST_DISABLE;
    8 C# [. X, b1 z+ D; R
  20. sConfig.OCNPolarity  = TIM_OCNPOLARITY_HIGH;' a8 ^* x8 Z5 S* Q5 k
  21. sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;
    4 F+ N4 j: y# y, p. I; O
  22. sConfig.OCIdleState  = TIM_OCIDLESTATE_RESET;
    - P/ d9 D: k) \9 z# F7 N2 [
  23. 6 t3 w) U% j2 u
  24. /* 占空比 */
    ! e6 O, _: V% ]' ?) E
  25. sConfig.Pulse = pulse;
    9 d/ h  k! d/ V! R! Q3 H( @7 n. c( b
  26. if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &sConfig, TimChannel[_ucChannel]) != HAL_OK)
    8 K" H# y* t0 x" e6 x- b& B+ F
  27. {" x1 A6 J5 ~, E# m
  28.     Error_Handler(__FILE__, __LINE__);* J2 ~3 Y( H; j- X
  29. }1 I9 b8 d. t( l% d* N5 n3 i
  30. 8 b: f0 R' \& ?; K
  31. /* 启动PWM输出 */
    1 o7 B4 r% T9 C3 a# c
  32. if (HAL_TIM_PWM_Start(&TimHandle, TimChannel[_ucChannel]) != HAL_OK)
    * K# _  @; p0 t: T& ]* \1 B
  33. {
    , W& b. F( Y9 H8 ~
  34.         Error_Handler(__FILE__, __LINE__);% G! T4 J+ V3 ~+ w
  35. }
复制代码
+ n' _3 [  ?+ D9 i
32.4.6 函数HAL_TIM_IC_Init
8 F/ P9 n" E$ B& z函数原型:
" k7 w5 |) B* X% A
' t  n0 u. `3 A
  1. HAL_StatusTypeDef HAL_TIM_IC_Init(TIM_HandleTypeDef *htim)5 e9 v# I  X. @) ^9 l, w
  2. {" l' Q8 d6 B# u/ b. C# X4 J! }4 u( i
  3.   /* 检测形参是否有效 */
      {9 ?! C, M6 w& l& ~4 K" R+ P$ `
  4.   if(htim == NULL)
    2 g# i5 s3 G% A, W; V! o
  5.   {
    ) d6 Z: x- J4 G* A  P
  6.     return HAL_ERROR;
    + q" x6 [6 V) _% ]. k: \
  7.   }/ y7 i5 X4 P4 U) |+ g5 i
  8. * b# L* s8 @$ Q: k* Y' o
  9.   /* 检测参数 */
    8 B$ ?6 I# Q. a
  10.   assert_param(IS_TIM_INSTANCE(htim->Instance));: N, C0 u* z- u
  11.   assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode));
    . s3 h' V3 @/ E
  12.   assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision));
    2 K9 P7 k1 R6 V, _
  13. ( Y3 @* c5 P4 h) ^3 `
  14.   if(htim->State == HAL_TIM_STATE_RESET)
    / B" I. n9 o3 U- r/ |
  15.   {
    3 H' T4 t1 p2 n/ z7 i! L' {4 W
  16. /* 默认取消锁 */
    : L% K6 N& n) J
  17.     htim->Lock = HAL_UNLOCKED;
    4 _% ~- y- m' x5 |. ^* z2 W) X

  18. : E3 Y$ Y& G0 M" Y+ v' _2 q' J) M. q
  19.      /* 初始底层 : GPIO, CLOCK, NVIC 和 DMA */: b( Y. Y3 a- E! k
  20.     HAL_TIM_IC_MspInit(htim);6 O+ U: n6 `8 Z" I# t
  21.   }
    9 V, w2 t. d! x9 J2 D

  22. 8 }. r" E2 G6 M" D$ [# A( _
  23.   /* 设置定时器状态 */1 i0 H7 t  q2 N6 ~1 b5 k& R' Z
  24.   htim->State= HAL_TIM_STATE_BUSY;
    0 E5 K4 _9 c# b+ _
  25. 7 _0 ]' D+ Z8 Y8 L# _
  26.   /* 配置定时器为输入捕获模式 */  
    4 u( M4 w9 Z! a& G% |6 J
  27.   TIM_Base_SetConfig(htim->Instance, &htim->Init);
    ( t! E  K9 Z" M
  28. ' M4 Q1 A- n/ L: e1 n6 N/ j: D3 i
  29.   /* 设置定时器状态 */, R! I9 W# w: e* r
  30.   htim->State= HAL_TIM_STATE_READY;! a; c! g1 S: e' L: u0 _( Z. K" w
  31. % j$ B  t6 b8 p: k* y
  32.   return HAL_OK;
    7 M* s, R1 I9 E2 f2 }6 x
  33. }
复制代码

* s, }+ N# V$ D7 r0 V; M函数描述:
3 @& ]0 q+ |' D% _! {  L! I
5 R; y! r' \; a* S5 G" U+ q( u此函数用于定时器输入捕获初始化。$ S8 G8 ?7 N3 G  O2 z: V+ ^; Z; w3 \

0 l+ i3 R: I2 O  d( G* F7 F6 M: l函数参数:
4 s+ d! u) F- i, r% `2 E4 |/ l9 W. C
  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。( {6 ~* @( P5 w/ Q) J' [1 ^
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
1 J, @& p& G  ~# q注意事项:5 d& P) K5 r+ K# d# C- w
7 D, D# X! i. N+ {3 r2 x, R: Q
函数HAL_TIM_IC_MspInit用于初始化定时器的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能,由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
7 l* \9 Z1 ~+ |& q+ w# G如果形参htim的结构体成员gState没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量TIM_HandleTypeDef TimHandle。" `  G7 D. d6 M- m
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个HAL_TIM_STATE_RESET  = 0x00U。
: e2 Y7 W5 ^, f% X
; ~0 m* E3 f+ P解决办法有三:% j: l( X7 c4 M$ a) X! X2 O% Q

+ n3 `( q9 m8 `3 Z( ]# ?+ ~" L1 ?方法1:用户自己初始定时器和涉及到的GPIO等。
/ l1 F+ k& T/ H: l  W- ~) A9 \6 s2 v2 B% j/ `/ W/ p
方法2:定义TIM_HandleTypeDef TimHandle为全局变量。
5 j7 q) k8 o# x2 D, _. d9 T
: f$ l7 f* {: A7 B- D5 ]& {方法3;下面的方法  I4 `5 r! b  Z! ^! W
. Q& I. K# t& }2 H4 `% o+ O
  1. if(HAL_TIM_IC_DeInit(&UartHandle) != HAL_OK)3 X, c! H$ U: R  L9 {, |
  2. {
    ' m% U% T# l. m- p3 W% L' k# |
  3.     Error_Handler();
    $ E4 B& a; D3 X. E) y) `
  4. }  ( r  y" \0 x+ n) k( r6 m
  5. if(HAL_TIM_IC_Init(&UartHandle) != HAL_OK)7 T( \' T5 c, [  z9 L3 C' E
  6. {0 z+ |' k( a" O( T
  7.     Error_Handler();7 E, N3 h# F* ?& A
  8. }
复制代码
) ~: b2 R( v! [. P) D) ^6 G: X
32.4.7 函数HAL_TIM_IC_ConfigChannel8 m1 g* H% e' W, A$ ~9 y
函数原型:
5 F4 x0 @2 L' B/ {
# \8 h% j3 l. M
  1. HAL_StatusTypeDef HAL_TIM_IC_ConfigChannel(TIM_HandleTypeDef *htim, TIM_IC_InitTypeDef* sConfig, uint32_t Channel)
    , h& z5 E& U8 V% F# m+ ]/ B
  2. {
    - p0 R% I+ X3 Z- r2 N) K
  3.   /* 检查参数 */
    2 y# s% T/ X, Z( G: F
  4.   assert_param(IS_TIM_CC1_INSTANCE(htim->Instance));  V% @2 u8 f+ }5 u# u$ f4 }
  5.   assert_param(IS_TIM_IC_POLARITY(sConfig->ICPolarity));) {, R4 K" S$ ^# {
  6.   assert_param(IS_TIM_IC_SELECTION(sConfig->ICSelection));
    ( ]3 l% A4 {4 J' O* @, ~
  7.   assert_param(IS_TIM_IC_PRESCALER(sConfig->ICPrescaler));* F  M! x, H; j1 O1 ~
  8.   assert_param(IS_TIM_IC_FILTER(sConfig->ICFilter));
    $ X) w8 f. r0 I
  9. ) J7 m' u! R, [# q8 ~, ]' P
  10.   /* 开锁 */  
    9 e. a9 P6 S" z) v$ L3 j
  11.   __HAL_LOCK(htim);
    0 ?9 \. t1 Z% K; T& G# r6 I

  12. ( c/ {, r& W- o  O8 H
  13.   htim->State = HAL_TIM_STATE_BUSY;
    0 x2 B1 Y! b% q9 h# {: _

  14. 4 \1 t& K$ b, }- B! ^/ F
  15.   if (Channel == TIM_CHANNEL_1)+ D1 {7 q2 K7 F+ M! K* f8 H1 i+ P
  16.   {; \' F- W! m, V% Z$ F; K: S
  17.     /* 配置输入通道1 */$ Z8 x) C. v5 I5 ]( L6 H3 ?( r
  18.     TIM_TI1_SetConfig(htim->Instance,
    . N( ?+ X2 w. S
  19.                sConfig->ICPolarity,, W4 V2 Y. `, u  a" A% U) M
  20.                sConfig->ICSelection,1 ^. u  ~* X2 A' b( z
  21.                sConfig->ICFilter);# X- m7 C: D- _$ L- P
  22. ! \3 m* \: Q6 K- f
  23.     /* 清零IC1PSC位 */- v; Z) w+ O8 ^2 O% k
  24.     htim->Instance->CCMR1 &= ~TIM_CCMR1_IC1PSC;
    ( g' k* U& r: u+ `* J

  25. 2 m+ |/ j2 X) M
  26.     /* 根据用户配置,设置分频 *// {& {8 X2 s/ c2 T0 z
  27.     htim->Instance->CCMR1 |= sConfig->ICPrescaler;
    : y7 y% w! P$ q" ?
  28.   }
    : _% w9 y2 b* q5 e+ \, p' V
  29.   else if (Channel == TIM_CHANNEL_2)
    " W" O1 u7 ^. t2 d+ K4 Z
  30.   {
    , @+ l' {2 ^: `9 Y3 s$ e! R1 o
  31. /* 省略 */
    " N- ], `! @) x7 U1 \
  32.   }
      k; c( o, R5 F  P. \% {
  33.   else if (Channel == TIM_CHANNEL_3)' q& c' L0 x" R& U
  34.   {
    ' q; }% z( N. b
  35.      /* 省略 */
    * C0 ^9 c$ W" J  w: t, b$ X, d% C; {+ n
  36.   }
    $ Q2 J3 m" Z' x" j* J  R
  37.   else
    5 i- x, x- w4 O. c, e
  38.   {! g" m  }6 ?) N. t
  39.      /* 省略 */; v# A' s* V2 h
  40.   }
      {8 a1 @( u: g2 N: Y
  41. - f$ O/ r$ _3 o- B# x: b
  42.   htim->State = HAL_TIM_STATE_READY;
    ; y  F7 Y- \* h" D4 j) Y

  43. / _! J6 W! q: v3 v8 k  U% Z
  44.   __HAL_UNLOCK(htim);1 Q! l/ z" z; M

  45. ( X6 ^7 S. w% t2 e1 n7 l
  46.   return HAL_OK; ! U+ O9 E( p3 ]1 v4 |$ D+ ?6 b
  47. }
复制代码
5 E" ~/ e& X! D! \: M
函数描述:" c4 V; _2 U: X' ~6 E! T' O8 P5 o: t
- \! f! u( N$ x* h) D
此函数用于配置定时器的输入捕获通道。
% p' [4 ?' D7 [9 K: {5 b2 |6 t0 q/ _" z9 ^/ P' c( M3 w' c2 w
函数参数:
: b1 J. _& ^3 d- w, |7 \
6 f- C% Q$ k# v# M! C, g' p& B' k  T8 E  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于定时器基本参数配置
0 W, P9 `( \% Z/ \- E; Z# @  第2个参数是TIM_IC_InitTypeDef类型结构体指定变量,用于定时器输出比较参数配置。
- o$ ^6 T. k1 d3 t8 ]  第3个参数是通道设置,支持以下参数:
9 o$ Q# ]( j8 _3 ?+ Z0 a+ d( y# j3 \8 wTIM_CHANNEL_13 V' I9 T& e5 x  d; T
% I( x  y- P: K: Y. [9 F
TIM_CHANNEL_2) S: A+ D, f) K# j# s, y  [

. e3 q& W6 H! U7 P* RTIM_CHANNEL_3, B+ W3 M, r% Y) P  [: J, B5 U' k
: ]" f7 N" T' r% z! {1 j
TIM_CHANNEL_45 a& J9 L2 U! Q" b: S, \3 t

. I  O1 @& M: |  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。; W# \6 }  |. N6 O$ R" ]3 g9 U6 f
5 Y+ T; z2 ]  B+ V! o6 J
32.4.8 函数HAL_TIM_IC_Start_IT# ]: u2 a: s% ]! n* i, }
函数原型:6 o# E4 t; W5 K7 ^. P3 |7 w( q( a/ q3 T

0 I# I5 {* q# k1 j
  1. HAL_StatusTypeDef HAL_TIM_IC_Start_IT (TIM_HandleTypeDef *htim, uint32_t Channel)
    + @: z3 I- o" v* u
  2. {
    ) z  r4 ^$ g. j; P, n- C) X7 V
  3.   /* 检查参数 */
    ; X& Z" T' q2 s
  4.   assert_param(IS_TIM_CCX_INSTANCE(htim->Instance, Channel));
    % u0 ~2 ~. n- Y
  5. ( H4 A' K5 E! J* w4 H) ^
  6.   switch (Channel)( j6 U6 r, N0 P
  7.   {1 Z$ I/ H* e8 l; O. R6 s* i
  8.     case TIM_CHANNEL_1:
    - o8 b  {$ H1 ^7 G2 N7 m
  9.     {       1 ?: k2 x! k! Y! L3 B- q0 t
  10.       /* 使能CC1(Capture/Compare 1)中断 */, h* h# r: S+ P# @$ v
  11.       __HAL_TIM_ENABLE_IT(htim, TIM_IT_CC1);
    . |# E$ T0 g' \$ X4 O8 w/ p
  12.     }! i- e6 q7 e5 |9 D
  13.     break;
    3 u, e& L( U6 ]) l
  14. : u( z2 c3 z; u& `& \6 B# t! b
  15.     case TIM_CHANNEL_2:
    % d# A$ Q, k! c' `  M# Q
  16.     {) p! K5 t: ]  G9 g5 a6 W% Y1 N
  17.    /* 省略 */
    ; N3 z2 C8 H7 |0 e9 j2 H5 f
  18.     }
    . H8 ]% h' F0 v  }8 L
  19.     break;' N5 [$ w& W6 l$ W) k

  20. ( M2 M, }4 G7 l  X  D
  21.     case TIM_CHANNEL_3:2 W3 k  D7 A# N2 z( q
  22.     {/ m& s0 X/ M+ k# j) B+ X9 r
  23.   /* 省略 */0 p, D: J1 E7 o  K" `' K- M+ J8 k
  24.     }
    8 a  t. {, a2 a, c& D5 g; J) I
  25.     break;# }# v. v% C' M
  26. . N- b; ]/ {# X; r2 A+ T2 X
  27.     case TIM_CHANNEL_4:  ~9 k' w" N3 i& ^
  28.     {
    ) P/ _  O1 W4 Z" j8 I8 {
  29.   /* 省略 */
    6 _$ @/ x" W9 B2 m  {8 l2 K3 l
  30.     }
    1 \3 F+ }- k  r5 E  t
  31.     break;) z. t* s2 M# }  B

  32. - v5 E# S1 B$ p2 e# [3 ^
  33.     default:0 d* Y. X$ e2 I0 Y6 g
  34.     break;, U1 T  I0 ^5 j5 o
  35.   }  
    ( x" K9 {; J7 Z7 M4 {0 Q& w! J! m
  36.   /* 使能输入捕获通道 */# y" x+ h7 U: F0 E3 M* ]
  37.   TIM_CCxChannelCmd(htim->Instance, Channel, TIM_CCx_ENABLE);4 T" G$ R! a. E/ |+ C: U* `

  38.   N" o$ B& [2 A8 l: w: i3 I) t
  39.   /* 使能定时器 */4 _# g/ J& K5 F3 i) v& z
  40.   __HAL_TIM_ENABLE(htim);  
    6 \. D4 S! W5 Q: K
  41.   v) O9 B! N3 |
  42.   /* 返回状态 */+ c5 N- Y  q+ F. Y1 ~$ t) u6 B. ]/ f
  43.   return HAL_OK;  3 }! Z5 M0 A5 L( l' `2 g
  44. }
复制代码
( V! v; [$ L' |
函数描述:$ |" y7 ?( ~1 F! Z8 d$ j; F

6 x% w2 T% P' x4 h! F. W此函数用于启动定时器输入捕获模式,采用定时器方式。7 p9 }# p% t3 T( b- l9 b

, ]6 S, V2 e) K& Q8 R, i函数参数:
+ O% U, p! D6 t" {" ?: `4 r; Y' m1 u. ]  @0 K
  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。% L/ y7 V2 h% R* B4 I- z
  第2个参数是通道设置,支持以下参数:
( P+ ]7 S0 Z7 G5 O) h: f* B7 bTIM_CHANNEL_1
6 g. t& c% G' K8 F8 }: j. {7 \
2 g. T  T$ S6 T* H0 }8 c) v- KTIM_CHANNEL_2
3 Q8 ^7 o5 |# E" Z/ l, j  L
: m( T  |, q& p4 ETIM_CHANNEL_3/ {! q$ l, T# {! M0 q8 z
  M  f1 M% j  @% S3 n! z9 o6 J
TIM_CHANNEL_43 v; T; a5 ^$ N# p. e
3 f: h: ?' J8 o2 }( @) L
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
7 H0 L  J( N3 C, \% I0 n* g$ q( w0 X2 U$ Z$ |  r
32.4.9 函数HAL_TIM_OC_Init
0 N2 r& S* {! k0 I" X- Q  a/ ~函数原型:+ l, ^1 j( ?- ]
- M# w* c' D0 \% b& G5 L2 `: F& n
  1. HAL_StatusTypeDef HAL_TIM_OC_Init(TIM_HandleTypeDef* htim)% C) U: ?3 n) k/ Q: U4 B$ T4 l4 O
  2. {
    % y, P# Z: P$ H; _/ M
  3.   /* 检测形参是否有效 Check */
    ' {" c: N# O) t4 m# l2 N
  4.   if(htim == NULL)
    % {( {: Y) q5 d0 V0 f: u5 @
  5.   {
    ( i1 C% J) }  F
  6.     return HAL_ERROR;( Y& n! s, ?. A' s
  7.   }
    3 m8 e( s( H) s1 c# z/ ?

  8. 3 S) b8 q. \7 D+ d
  9.   /* 检查参数 */+ Z- C0 B7 B7 `5 j" T6 X$ a) t
  10.   assert_param(IS_TIM_INSTANCE(htim->Instance));
      s: {  D$ j: M1 f
  11.   assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode));
    - Q, \- c  y; r+ N, P' V9 K/ v
  12.   assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision));
    $ Y& }( Y  p0 a) {

  13. ; l2 ?& c  O5 \% t
  14.   if(htim->State == HAL_TIM_STATE_RESET)
    6 D5 M* U4 v9 ^
  15.   {
    5 \' v" I+ o' l1 J; d
  16. /* 默认取消锁 */
    0 Y+ O3 {6 g4 ?( {! Z8 c
  17.     htim->Lock = HAL_UNLOCKED;
    9 [/ w0 b2 w6 [7 j* k4 g, b
  18. 1 {$ F" }9 p4 S' \: F+ i
  19. /* 初始底层 : GPIO, CLOCK, NVIC 和 DMA */
    : ^$ I/ s0 i7 l2 M
  20.     HAL_TIM_OC_MspInit(htim);3 O; }" C6 F$ B6 `
  21.   }
    7 `. ~7 y/ j" J/ z9 D: I4 a' z
  22. # ]" m4 i5 G" d9 `6 K5 Z0 a
  23.   /* 设置定时器状态Set the TIM state */
    4 n7 F0 J3 B/ i  G! ]
  24.   htim->State= HAL_TIM_STATE_BUSY;( j/ s. Y- @- `( M- C+ `

  25. % {( L" W' P! h& v
  26.   /* 配置定时器为输出比较模式Init the base time for the Output Compare */  ; h+ `- @: t2 c
  27.   TIM_Base_SetConfig(htim->Instance,  &htim->Init); , w6 ?$ I! r! Z
  28. 6 `( \+ X" |3 a9 C
  29.   /* 设置定时器状态 */. C! F; V) {8 d% L/ u3 ~$ g
  30.   htim->State= HAL_TIM_STATE_READY;
    $ c$ o! l# W4 @

  31. + s* Q7 L. p8 g3 {  Y5 u0 z  g
  32.   return HAL_OK;
    7 a; N$ f& _8 o# A8 U  k& t
  33. }
复制代码
  X3 T8 Q) ~2 Z7 K
函数描述:% v4 b5 }' l4 |/ t  }7 ?8 \) ?1 z3 B$ C

1 F- V  ^% U  o2 X' w9 Q5 q此函数用于定时器输出比较初始化。
1 ~1 F# O1 x% {8 I
# P' q3 T6 Z. ]; I% Y  ]函数参数:
  f& H! X( R. ?2 Y3 f3 N, p# |9 ~3 {" L* ]7 H' x7 s9 U
  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。' p, \3 p; y* Y2 c7 b# i; J) p
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。: z) j& l9 ^" z! ~1 l- |: l; o
注意事项:
8 A; B( r$ d% q/ U6 a: X' l5 ]0 d9 |# J, D( _8 }
函数HAL_TIM_OC_MspInit用于初始化定时器的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能,由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。3 q9 @$ t0 A! |5 _+ s7 T
如果形参htim的结构体成员gState没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量TIM_HandleTypeDef TimHandle。
/ l3 B9 n; Q' q2 A% T4 Q/ x5 ^对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个HAL_TIM_STATE_RESET  = 0x00U。
- G/ E- x; A- [& }2 F) U. I* u8 f3 J8 B
解决办法有三:
  v/ M7 d: x7 a6 x: I( a8 t* B* H0 v$ M! T$ Q7 h
方法1:用户自己初始定时器和涉及到的GPIO等。
/ I, P" c6 W5 ~6 B
7 {& Q1 M3 \( d3 _方法2:定义TIM_HandleTypeDef TimHandle为全局变量。: S# i& ]" z( I4 g
8 C" P: k- ^! H9 D# q
方法3;下面的方法# G+ ]0 k9 q5 N. J" p/ ?
0 _7 ?* I" p) l* h2 q5 z2 k  v0 L3 Y
  1. if(HAL_TIM_OC_DeInit(&UartHandle) != HAL_OK); `+ i" _7 u$ y2 u# q7 q2 B
  2. {- {4 n5 |% f4 t( }# O) z2 ?
  3.     Error_Handler();) a6 d/ ~5 r, f  J  w1 l8 B0 e
  4. }  + M( [% d! M9 O6 F7 T
  5. if(HAL_TIM_OC_Init(&UartHandle) != HAL_OK)! j' A, V6 U& S7 [
  6. {6 s  b6 ^- H& _- K. s0 W
  7.     Error_Handler();
    + {2 w* A3 k. ~; g. ]" M: B  P$ f
  8. }
复制代码
& G! Q1 h  U. r; @: ]# d
32.4.10   函数HAL_TIM_OC_ConfigChannel
% U6 ~1 _/ l4 _2 A- O函数原型:
; M2 B  e! u( t
% a7 |- B, s+ E5 j
  1. HAL_StatusTypeDef HAL_TIM_OC_ConfigChannel(TIM_HandleTypeDef *htim,
    6 z. F6 _; @$ O
  2.                                            TIM_OC_InitTypeDef* sConfig,
    / G9 @0 H1 @) a* Q4 f0 W
  3.                                            uint32_t Channel)
      k  `9 Y# v, ~3 B
  4. {  
    $ t# d1 p2 N) c, j+ P+ i2 K
  5.   /* Check the parameters */
    7 i. d% o2 R  n" X! S
  6.   assert_param(IS_TIM_CHANNELS(Channel));
    5 f8 K$ Z( I0 F; F- J+ ], f2 A& W
  7.   assert_param(IS_TIM_OC_MODE(sConfig->OCMode));
    $ }7 G( @+ w) M* r3 p! q3 g; V+ _
  8.   assert_param(IS_TIM_OC_POLARITY(sConfig->OCPolarity));
      ]  t* G+ I( f! z

  9. 2 L! W7 Y7 `( |. N- X( f. g" @
  10.   /* Process Locked */
    4 r& Q% ]' d, k3 y
  11.   __HAL_LOCK(htim); + O) e6 w1 B( a4 B0 \4 q5 [. ~

  12. 5 n$ i! j6 V4 V& P
  13.   htim->State = HAL_TIM_STATE_BUSY;+ F2 L4 E- A2 i0 B/ p
  14. $ y3 y+ V# v; |+ ^8 c6 [
  15.   switch (Channel), v3 [4 A  `, @4 p8 Q# v
  16.   {5 ~& _* O" v3 ?2 ^9 g( z
  17.     case TIM_CHANNEL_1:
    * \, T& W. _, z' D5 q
  18.     {8 F: M* F" J3 ^: p* x
  19.       /* 检测参数Check the parameters */3 O+ S% p4 @' ]9 S! }7 L# D, ^9 g
  20.       assert_param(IS_TIM_CC1_INSTANCE(htim->Instance));   `. `) K9 |8 ~/ l& [
  21. ! D5 T3 V* n0 r" Z; c1 z; x
  22.      /* 配置定时器输出比较通道1 */
    4 ~. Q: d, U! h- Z$ c3 m
  23.       TIM_OC1_SetConfig(htim->Instance, sConfig);
    ' t, R) t+ L9 U1 U; L% l
  24.     }- f( s: {: Q4 P' b
  25.     break;
    * A8 W" F9 b. x5 S' @

  26. : [( ~) ^6 a" G1 _, V; O* k1 |
  27.     case TIM_CHANNEL_2:0 p, D5 u; u" ]2 W* @
  28.     {6 @, Q; V; d8 k! m- ~- i$ l4 T
  29.       /* 省略 */
    - j6 \, Q5 K8 t6 f$ l3 k$ b
  30.     }
      F( {, [, A. r  W5 R
  31.     break;# s( h* F0 X0 C2 L

  32. ) O3 k& v7 c! x. {. f2 A# X) Q
  33.     case TIM_CHANNEL_3:
    6 x& `9 S' W# E8 ~
  34.     {
    5 K& f& _4 ]! z$ Z  T/ h
  35.       /* 省略 */
    8 S# K( G0 K8 k; F) W4 E
  36.     }
    " i5 o$ `: A5 L: o6 }
  37.     break;
    - V5 s9 f0 M- N- I# f" M, Q
  38. 9 @! @+ a- y* G" A1 w! d  }
  39.     case TIM_CHANNEL_4:
    + I: S& P, ^! h. U' }, M
  40.     {
    ' W2 D) ~9 R9 f! l2 n
  41.       /* 省略 */" o" j- }* W3 f! E% q4 u
  42.     }  p* H& E* K0 p2 T
  43.     break;
    - A0 G* s) \) `( r  O9 s

  44. ' O( W: @4 p7 S9 g, [" ]
  45.     case TIM_CHANNEL_5:
    ; b  d9 G; k$ |9 z1 [' {3 h! W! i
  46.     {. q$ S& ?2 s* O* [! i, D- w4 }
  47.       /* 省略 */
    " ]7 N- s+ C0 o9 q: N- \
  48.     }
    0 {( q9 Q* |& W( g- Z2 R+ }6 v. X
  49.     break;
    " Q- J: J& i; `  g

  50. ! w& o1 U3 b) K; w8 _
  51.     case TIM_CHANNEL_6:
    ! y  o9 J% R4 S5 g& C+ e' x
  52.     {+ I  a0 S8 e" s( L5 c8 |
  53.       /* 省略 */
    0 H/ T1 w" ^7 Q
  54.     }* y) X& J0 u, ~2 ]
  55.     break;4 a; j% C# a6 d& U/ m  d
  56. 2 k* N: O/ W; U4 R1 t  c) ~) n
  57.     default:2 R3 ]# H4 H, O0 g) i
  58.     break;    9 F! R7 W6 u& C: ~3 y
  59.   }
    3 N+ i8 ^* b# z  e- h! J

  60. $ }" X3 }+ @1 _- x
  61.   htim->State = HAL_TIM_STATE_READY;% t1 @) [+ A+ P9 t2 C
  62. . o, k, k- K6 }* Q1 ?0 d/ E( ?3 k
  63.   __HAL_UNLOCK(htim);
    9 x2 x1 ~" }# U% G- y

  64. 6 [, T# A0 q  Y
  65.   return HAL_OK;
    9 @. v2 o; N' O; Q4 P! }+ A; q
  66. }
复制代码

& Q9 ~0 U3 \5 j/ m3 n6 n& i* _; j& y函数描述:. T' z* V9 {! C; O7 q
* k8 T# i/ \& {
此函数用于初始化串口的基础特性和高级特性。
4 K5 |4 R' l6 y# Q# e  [9 `& m6 b5 |  t! `' C
函数参数:
4 K: Z1 S) W9 ^; g
, }5 r0 t' S3 c% P( M$ o. s  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于定时器基本参数配置。/ H* q* K. y. |6 _  W
  第2个参数是TIM_OC_InitTypeDef类型结构体指定变量,用于定时器输出比较参数配置。' t& j3 o1 W8 J" o2 l6 J
  第3个参数是通道设置,支持以下参数:8 G! Q5 l. \0 x* p
TIM_CHANNEL_1
* g1 U5 z" Q# m
4 g; R% w0 S+ K  b/ ^$ l& A& vTIM_CHANNEL_2  |! ~% `5 i5 c

- G- h' t6 W" j1 s7 r9 `TIM_CHANNEL_3
8 p6 z8 D' B3 n$ z, a) Q; Y0 v( n& J. ?7 v' O0 s) k- A
TIM_CHANNEL_47 n6 E" [/ L  j1 v3 {

1 [! N; ?# p( r6 f- ]9 KTIM_CHANNEL_55 Z% I% r' [- |! l# u% `) Y. Z

4 G/ {" ?1 `, tTIM_CHANNEL_68 v! R, Z4 n4 a" c$ z' }
4 S1 J4 z$ q8 B0 ^7 \- T$ K
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。2 x3 j' }1 u$ a; o& _. _, K
" f" T0 D4 @( U& u9 M: T
32.4.11   函数HAL_TIM_OC_Start
  X! z- A. s8 g) B# x% I) w函数原型:* _+ @4 f! W: q8 }! Z

& P8 U$ O$ f: v: s  w/ a" Z7 a' h: u
  1. HAL_StatusTypeDef HAL_TIM_OC_Start(TIM_HandleTypeDef *htim, uint32_t Channel)
    8 A* n. i1 ^+ M! Z* }
  2. {
    5 x4 S' h9 N2 J! ^& U7 v' }
  3.   /* 检查参数 */
    & `& ?$ _. @* F# N
  4.   assert_param(IS_TIM_CCX_INSTANCE(htim->Instance, Channel));
    . Y* R' P; x9 ^
  5. $ E* s" O1 \; b0 T
  6.   /* 使能输出比较通道 */
    7 H- n" v3 t, M: a& Q6 r+ c
  7.   TIM_CCxChannelCmd(htim->Instance, Channel, TIM_CCx_ENABLE);
    8 N2 G4 n! c* x, T& V) ^

  8. / c! W/ \) \, p. R
  9.   if(IS_TIM_BREAK_INSTANCE(htim->Instance) != RESET)  
    " y: g- e$ s: w7 t( V3 [" T
  10.   {
    & L7 R& D% Z  H+ ~! c9 }/ u( h
  11.     /* 使能主输出 */9 E6 k+ F/ V; ?# u' ^0 a- |! f
  12.     __HAL_TIM_MOE_ENABLE(htim);: _6 D! R, _1 C+ i9 R2 B
  13.   }
    9 k! {; |7 U; r: D
  14. . ]! V0 H5 f( H( ^
  15.   /* 使能定时器 */
    . b. o, |' P: g2 ]. z2 `
  16.   __HAL_TIM_ENABLE(htim);   v8 m3 C7 d8 Q; U

  17. 7 a2 y% M( K' x* g. ^1 m1 A7 [
  18.   /* 返回状态 */
    ( j9 @$ I2 z5 }. d/ q
  19.   return HAL_OK;& ^* L2 ^' b3 D2 }5 q( M- w( d
  20. }
复制代码
  D5 B( r: _+ D) }$ U4 Q8 S/ W' W; ^
函数描述:
4 O' Y& |! G" h7 k- x. x  l7 G$ p0 V& D" D8 u/ r1 ~% k
此函数用于启动定时器输出比较模式。
" v2 E1 a, K6 m  z
: B+ S  S; J" C! s函数参数:
/ n) o6 C4 G/ |$ i; \4 o5 s
: V/ ?2 a! `; J! X% C9 }  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。
+ d' Z, p: d1 n! t! ?  第2个参数是通道设置,支持以下参数:0 ?7 S9 {: l/ I5 G- I. `/ W
TIM_CHANNEL_12 b' C5 l( O- I8 |) X

1 q) L, I/ ^8 v2 B* P1 h5 gTIM_CHANNEL_2  b4 o+ e  U9 T4 Z- I7 {
9 O% _; H* @; |9 j& W
TIM_CHANNEL_3$ l' ?! y# D) p5 \; p" o" n

% U+ O- f# _  @4 {8 lTIM_CHANNEL_4
* F+ z2 t( O" T& Z4 a/ a0 ~2 p9 Z5 M$ ~6 Z4 p7 e
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
! t' t4 f3 Y+ H2 O+ l5 E4 c# r( |; Q3 X. o; p$ I) }1 v1 ?* m( R
32.5 总结
! M- `  B9 v3 ]5 d# Q/ l本章节就为大家讲解这么多,建议大家将GPIO的驱动源码结合参考手册中的寄存器通读一遍,对于我们后面章节的学习大有裨益。# Q# O) m# x$ x4 Y4 g9 @9 b6 ?
2 H6 ^1 f. n7 f" V$ `5 `
( F/ r1 H2 @# X
! Z5 h" M. W2 A2 X5 _3 S) J: w4 O
收藏 评论0 发布时间:2021-12-21 23:00

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版