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

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

[复制链接]
STMCU小助手 发布时间:2021-12-21 23:00
32.1 初学者重要提示( ]5 p5 b' B2 F9 D. O4 x0 u1 {
  学习定时器外设推荐从硬件框图开始了解基本的功能特性,然后逐步深入了解各种特性,这种方式方便记忆和以后查阅。, p- N* P3 P- |3 O( }% _1 `7 T' Z
  STM32H7的定时器输出100MHz方波是完全没问题。
4 M1 n/ F6 y1 O' C  STM32H7定时器进出中断的速度能跑到12.5MHz,所有程序在TCM和Flash运行没差别。; Y+ ]5 a" W  y/ C: w* I, c" I. _
  STM32H7的定时器输入捕获可以实现12MHz方波的双边沿捕获,单边沿可以做到24MHz。
! ?* L4 y+ P9 m" Y  特别注意STM32H7的TIM1,8,15,16,17才有RCR重复计数器,其它都没用的。
  {4 @1 C; A6 }* s& L  STM32H7的单个定时器中不同通道可以配置不同频率PWM。
- v- D! y$ `+ f" u8 V" F: H1 D: `  STM32H7的TIM1-TIM17中断入口函数名使用时要注意,别搞错了:, S/ ]$ ]. B4 l* ]9 p$ U3 |) K
  1. TIM1_BRK_IRQHandler            
    6 y- k' n* z2 v* q6 P
  2. TIM1_UP_IRQHandler              
    0 v2 ?0 P* U5 ~: o
  3. TIM1_TRG_COM_IRQHandler        6 h3 M* s; g0 O4 ]6 l: g) p
  4. TIM1_CC_IRQHandler                                                    # S2 I1 O( u5 Q* {
  5. TIM2_IRQHandler                                          
    & P4 D  r3 w, z. D- t& l1 _
  6. TIM3_IRQHandler                                                
    ; U+ e! f! E3 U
  7. TIM4_IRQHandler                 
    ' _+ E2 m5 M9 x% A5 C1 J# {
  8. TIM5_IRQHandler            
    9 C1 [4 s6 }$ }; c8 A* b8 U" U
  9. TIM6_DAC_IRQHandler           <------------------要注意            
    $ X! d% \* ^. q8 ~. o0 G
  10. TIM7_IRQHandler # w! y8 N) I* t7 ^9 C& L
  11. TIM8_BRK_TIM12_IRQHandler      <------------------要注意,定时器12也是用的这个, F; ?: K# Z& v
  12. TIM8_UP_TIM13_IRQHandler       <------------------要注意,定时器13也是用的这个. n# z: {. j0 y7 e
  13. TIM8_TRG_COM_TIM14_IRQHandler  <------------------要注意,定时器14也是用的这个
    9 W6 N6 f5 Y* u7 O- B  @
  14. TIM8_CC_IRQHandler         
    3 q* M6 ~- ^3 o, O2 m
  15. TIM15_IRQHandler * ]8 P  O3 O8 J: n9 R! W
  16. TIM16_IRQHandler
    2 Z8 c: i. v  S! S! _
  17. TIM17_IRQHandler
复制代码
7 c& [  d$ Q2 w. o
32.2 定时器基础知识- x$ H: o8 @& m  ^/ p' V( u
注,不同定时支持的功能略有区别,基础定时器功能较少,TIM1和TIM8高级定时器功能多些。( Z1 S' G  J" K$ s
, i0 O; D/ w" l1 t9 p) q
  TIM2和TIM5是32位定时器,其它定时器都是16位定时器。16位和32位的区别是CNT计数器范围不同,32位的范围是0 到2^32 – 1,而16位的是0到65535;它们支持的分频是范围是一样的,都是1到65535。& ]0 b& }& V* K  ]0 O$ l  A$ N6 y
  计数器支持递增、递减和递增/递减二合一。
$ i( G9 x8 G( ^+ S0 g7 d  多个独立通道,可用于:7 v8 d# y4 C' J) a% }4 d( {
– 输入捕获。
$ P* X) s2 B- Y4 \" U* R* i5 t  r3 t& J$ l) I8 }
– 输出比较。/ {9 F$ ?) a! Y6 D
; {/ E1 ~( v7 e9 _# r  D
– PWM 生成(边沿和中心对齐模式)。$ H( I0 w; K& l' H2 }- P: _3 Z
2 [  u6 r1 g- j, V: J6 B
– 单脉冲模式输出。' v6 ^2 @# \2 W! D% y& X% _
, p, m( Q/ s9 M
  带死区插入,断路功能和PWM互补输出
& U! j/ U: O, w7 H8 B  发生如下事件时生成中断/DMA 请求:
+ k+ d' H6 r1 g- o* I– 更新:计数器上溢/下溢、计数器初始化(通过软件或内部/外部触发)
" m& t# e9 @) a7 w
- H0 |6 O3 U7 p1 f– 触发事件(计数器启动、停止、初始化或通过内部/外部触发计数)
2 n7 c: t( P6 k
# J2 I3 ?8 k% q/ F- |. E+ E, C– 输入捕获- O. i6 c5 u$ _4 C$ I0 p, g% d

. {+ [. q% l" w– 输出比较: s! `5 H9 |* Q  ~8 U

- o7 w& @: O, U2 d- S# I  支持增量式编码器和霍尔传感器。9 {0 |! K6 \+ x
32.2.1 定时器TIM1-TIM17的区别
0 j3 Z  W' v% ~  Z3 pSTM32H7支持的定时器有点多,要简单的区分下。STM32H7支持TIM1-TIM8,TIM12-TIM17共14个定时器,而中间的TIM9,TIM10,TIM11是不存在的,这点要注意。
( O. ?4 q" d8 e2 l3 `
- i9 o$ V$ }2 I4 f粗略的比较如下:
2 K2 u8 f' S2 i% H0 m
( e/ }. I4 X: f; |5 b2 ^1 q: a4 |5 j
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png
0 C& ^! f( Z6 L7 M, x0 A

' C' ?+ G* l) g: a
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png

. j- V2 D, `: Y  V" X
1 z& D4 ]: d$ t+ d' I$ w+ W通过上面的表格,至少要了解到以下两点:1 I; a9 S1 r" Z) \  j1 |0 _
" S% p$ D5 H0 P2 ]
  STM32H7的定时器主要分为高级定时器,通用定时器,基础定时器和低功耗定时器。
- u2 t, ^! T0 ^6 s1 E  TIM2和TIM5是32位定时器,其它都是16位定时器。
5 O3 z) [$ x' j% Z* Y
# P7 r# d2 P/ g0 n( R( W) |1 R32.2.2 定时器的硬件框图
0 e) f$ x! }% w' C$ p; r% E认识一个外设,最好的方式就是看他的框图,方便我们快速的了解定时器的基本功能,然后再看手册了解细节。
% r) X) T/ k5 {$ ?: K4 f+ j
" r7 G5 s9 F4 r$ ]下面我们直接看最复杂的高级定时器TIM1&TIM8框图:
- F3 A) W% E& m6 ]" U% h
, H( \  H$ W! p
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png
# g- |& W% G3 @8 t/ [& @

! s2 I& ~" i4 g通过这个框图,我们可以得到如下信息:
4 o- K% p; A" I+ l5 v4 T; W+ z3 H) t9 G, _) p4 `5 H- d
  TIMx_ETR接口4 m: U6 R" h: f: Q* `! h
外部触发输入接口。ETR支持多种输入源:输入引脚(默认配置)、比较器输出和模拟看门狗。
' P3 P* F8 M. g% T2 f) W9 f5 |; Z& l: B. s. ^
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png

" t) j$ X. Q& p$ x: C
1 d$ x  F1 X/ h4 \5 n9 I- E8 [  截图左侧的TIMx_CH1,TIMx_CH2,TIMx_CH3和TIMx_CH4接口$ X% j9 f% R: h6 U% l  d' j/ u
这四个通道主要用于输入捕获,可以计算波形频率和脉宽。                                                                                                                             4 d8 q6 S5 H% Y% z8 q" X

8 N6 s, `' A5 w( Z2 ~* L1 _  TIMx_BKIN和TIMx_BKIN2接口  U/ c* W: z' ]" a) G3 e
断路功能,主要用于保护由 TIM1 和 TIM8 定时器产生的 PWM 信号所驱动的功率开关
1 o* x* a& o5 z8 X) v7 S* z3 A
5 @  U3 F, }9 R3 b1 K! }6 _  TRGO内部输出通道' H- U% s) j# s
主要用于定时器级联,ADC和DAC的定时器触发。1 o% G$ z: k; B7 M" s

( q4 ?( M* O( u5 R0 I2 x  6组输出比较单元OC1到OC6
8 u: T" a& K+ D4 ?% K* L" a! pOC1到OC4有对应的输出引脚,而OC5和OC6没有对应的输出引脚,主要用于内部控制。4 k# X7 m9 X; J, R' [

0 q4 h  Z7 M% _  截图右侧的输出比较通道TIMx_CH1,TIMx_CH1N,TIMx_CH2,TIMx_CH2N,TIMx_CH3,TIMx_CH3N和TIMx_CH49 R, Y0 H2 ~3 a! J* _( O
主要用于PWM输出,注意CH1到CH3有互补输出,而CH4没有互补输出。# r  N  Z6 o8 z+ l4 v; L& M
& R) m: K3 X& o$ e4 n) q% i: G
  其它框图里面未展示出来功能+ |  H5 m9 B7 |; {6 i. Y. E+ S
定时器TIM1&TIM8还支持的其它功能在用到的时候再做说明。
6 }4 \* i+ c. i4 J$ T. S: f5 _; l4 l8 }( f5 _' e3 [' S/ V* \* c# F
32.2.3 定时器的时基单元
5 _, x  w8 z* N$ n" C定时器要工作就需要一个基本时基单元,而基本的时基单元是由下面几个寄存器组成的:
5 r$ `  T. g' ]% \2 W$ U# J' C, g% I- a$ d$ v( U5 d
  预分频器寄存器 (TIMx_PSC)8 d5 L  x. J' ^  a: d7 {
用于设置定时器的分频,比如定时器的主频是200MHz,通过此寄存器可以将其设置为100MHz,50MHz,25MHz等分频值。
6 m; k4 l) i9 u6 p  n+ x7 c; p/ _- V8 u0 _9 |2 O
注:预分频器有个缓冲功能,可以让用户实时更改,新的预分频值将在下一个更新事件发生时被采用(以递增计数模式为例,就是CNT计数值达到ARR自动重装寄存器的数值时会产生更新事件)。
. X% ^' l8 D  Y2 G3 O2 s
# q/ j& l5 x; \: o% X) ?  计数器寄存器 (TIMx_CNT)' f9 {/ o0 N4 h" T
计数器是最基本的计数单元,计数值是建立在分频的基础上面,比如通过TIMx_PSC设置分频后的频率为100MHz,那么计数寄存器计一次数就是10ns。( r/ T1 U4 l$ |9 t# r" \  e

0 L" |$ H7 I6 o( |  自动重载寄存器 (TIMx_ARR)
3 e* `2 W9 c) b' A7 E' o: w- ]$ ~自动重装寄存器是CNT计数寄存器能达到的最大计数值,以递增计数模式为例,就是CNT计数器达到ARR寄存器数值时,重新从0开始计数。
, g0 h9 O4 Y" \. h) C/ G& W
$ S) d/ L6 D7 [* ~5 ~注,自动重载寄存器是预装载的。对自动重载寄存器执行写入或读取操作时会访问预装载寄存器。预装载寄存器的内容既可以立即传送到影子寄存器(让设置立即起到效果的寄存器),也可以在每次发生更新事件时传送到影子寄存器。简单的说就是让ARR寄存器的数值立即更新还是更新事件发送的时候更新。$ t8 C/ c1 _+ D4 f( o; h
0 p, D  S& s' u# _! T+ B
  重复计数器寄存器 (TIMx_RCR)
: t+ P5 c0 V1 ^) y! y: L/ ~4 ?) H以递增计数模式为例,当CNT计数器数值达到ARR自动重载数值时,重复计数器的数值加1,重复次数达到TIMx_RCR+ 1后就,将生成更新事件。) A" a/ d2 z5 L# V
" R/ O& [% f4 C9 c$ s. s
注,只有TIM1,TIM8,TIM15,TIM16,TIM17有此寄存器。
$ d! R4 _6 X2 B# w, t# M! s  X
. G3 ^* h- B* g) M$ w6 j& ~比如我们要配置定时器实现周期性的中断,主要使用这几个寄存器即可。8 ]2 ?$ s- l" [$ A+ u# q
" z9 }! I! c8 ]4 ~7 @
32.2.4 定时器输出比较(PWM)8 X4 Q4 K9 d5 E
使用定时器时基单元的那几个寄存器仅仅能设置周期,还不能设置占空比。针对这个问题,还需要比较捕获寄存CCR的参与,这样就可以设置占空比了。
0 e8 X6 @( }. z; s- W* f1 L% B5 G, T: Z5 ^  K# |4 k# I, j
为了方便大家理解,以PWM 边沿对齐模式,递增计数配置为例:5 `1 W/ {) `; ^1 P) x
' s' A. Y* B3 `0 v0 m, \$ k
  当计数器TIMx_CNT < 比较捕获寄存器TIMx_CCRx期间,PWM参考信号OCxREF输出高电平。9 @$ Y/ Y& }# }
  当计数器TIMx_CNT >= 比较捕获寄存器TIMx_CCRx期间, PWM参考信号OCxREF输出低电平。, ]1 J" e" i. h3 ?
  当比较捕获寄存器TIMx_CCRx > 自动重载寄存器TIMx_ARR,OCxREF保持为1。
5 G+ ]' ?) M% ^  当比较捕获寄存器TIMx_CCRx = 0,则OCxRef保持为0。4 K' }" W; z, n- W
下面是TIMx_ARR=8的波形效果:7 g5 A5 J$ }9 m
2 R$ a( p7 D9 `# s. _2 q
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png
7 d/ |" [# c& u; a0 [

9 [1 I& R/ M3 {32.2.5 定时器输入捕获
* m8 U/ t" P& j; `8 h与PWM一样,使用定时器实现输入捕获,仅靠时基单元的那几个寄存器是不行的,我们需要一个寄存器来记录发生捕获时的具体时间,这个寄存器依然由比较捕获寄存器TIMx_CCRx来实现。
+ {6 B( e: `! h8 j# q/ ?0 \7 X: Q* ^  T. ~' o' }
比如我们要测量一路方波的周期:' j; B; l+ o' W, q1 l. b

7 Y3 g' g5 n, W* X7 F( G% o  配置定时器为输入捕获模式,上升沿触发,设置分频,自动重装等寄存器,比如设置的CNT计数器计数1次是1微秒。  {0 S& h- O) h9 I+ C
  当有上升沿触发的时候,TIMx_CCRx寄存器就会自动记录当前的CNT数值,然后用户就可以通过CC中断,在中断复位程序里面保存当前的TIMx_CCRx寄存器数值。等下次再检测到上升沿触发,两次时间求差就可以得到方波的周期。+ i; r5 U$ N3 n4 v' m
不过这里要特别注意一点,如果CNT发生溢出(比如16位定时器,计数到65535就溢出了)就需要特别处理下,将CNT计数溢出考虑进来。
4 k0 D* S# S& n" l9 e; G& ]# ^5 N& ]& N- G* d+ I, R8 N3 N/ H( v
32.3 定时器的HAL库用法
4 {: V/ N: T. O定时器的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置GPIO、时钟,并根据需要配置NVIC、中断和DMA。下面我们逐一展开为大家做个说明。5 T9 [  a9 x" z$ t. L
7 X. d) {3 n2 h. l- ~
32.3.1 定时器寄存器结构体TIM_TypeDef" c' `- g  x, ]" e3 R
定时器相关的寄存器是通过HAL库中的结构体TIM_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:
& A" A% A3 `8 _) H; }! ]5 J- J- Y
4 }4 p% p5 r& g7 Z+ Y' I. z
  1. typedef struct
    " J1 I) x1 D. ?2 B* s. [& ]
  2. {
    ) p+ k. `9 W% b, h
  3.   __IO uint16_t CR1;         /*!< TIM control register 1,                   Address offset: 0x00 */, g6 S. j" ]1 U7 ]% ^, z; F; h& j
  4.   uint16_t      RESERVED0;   /*!< Reserved, 0x02                                                 */
    ) ?7 k& J) a) h7 i" }/ q/ X9 X
  5.   __IO uint32_t CR2;         /*!< TIM control register 2,                   Address offset: 0x04 */% T/ G- G2 [9 A6 x& E+ z
  6.   __IO uint32_t SMCR;        /*!< TIM slave mode control register,          Address offset: 0x08 *// b( n. p6 ^) t2 r$ b7 R
  7.   __IO uint32_t DIER;        /*!< TIM DMA/interrupt enable register,        Address offset: 0x0C */7 M. ]4 A3 ~2 J( @
  8.   __IO uint32_t SR;          /*!< TIM status register,                      Address offset: 0x10 */
    9 ~% K2 p6 a* B/ T5 U" c. }
  9.   __IO uint32_t EGR;         /*!< TIM event generation register,            Address offset: 0x14 */! m" p0 o1 s% L; Y* F& E5 k2 d; n
  10.   __IO uint32_t CCMR1;       /*!< TIM capture/compare mode register 1,      Address offset: 0x18 */
    ) t' p# b$ g+ s) ?0 j; Z
  11.   __IO uint32_t CCMR2;       /*!< TIM capture/compare mode register 2,      Address offset: 0x1C */
    # }9 S$ x5 _- ]7 ?
  12.   __IO uint32_t CCER;        /*!< TIM capture/compare enable register,      Address offset: 0x20 */
    - d' ]. g7 y; T# g, p6 z
  13.   __IO uint32_t CNT;         /*!< TIM counter register,                     Address offset: 0x24 */* ]9 I; Z5 V" V- w$ |- D2 u
  14.   __IO uint16_t PSC;         /*!< TIM prescaler,                            Address offset: 0x28 */. _" F1 H5 }- k: ^& u8 w
  15.   uint16_t      RESERVED9;   /*!< Reserved, 0x2A                                                 */
    5 s4 P, j: Y" Y! e- ]
  16.   __IO uint32_t ARR;         /*!< TIM auto-reload register,                 Address offset: 0x2C */- ~1 x$ I7 s1 Q0 N: s. X9 f
  17.   __IO uint16_t RCR;         /*!< TIM repetition counter register,          Address offset: 0x30 */
    $ F0 z& P' v- ], ]& M4 A
  18.   uint16_t      RESERVED10;  /*!< Reserved, 0x32                                                 */
    2 R6 Q7 e, L" w" }" W' H
  19.   __IO uint32_t CCR1;        /*!< TIM capture/compare register 1,           Address offset: 0x34 */
    6 D+ L: L" u/ r. ?, v
  20.   __IO uint32_t CCR2;        /*!< TIM capture/compare register 2,           Address offset: 0x38 */2 @* j- x2 Q1 a: A
  21.   __IO uint32_t CCR3;        /*!< TIM capture/compare register 3,           Address offset: 0x3C */. k; C' S1 A" E5 ?! J( q7 e( \
  22.   __IO uint32_t CCR4;        /*!< TIM capture/compare register 4,           Address offset: 0x40 */
    ; u# S6 L$ Q4 i
  23.   __IO uint32_t BDTR;        /*!< TIM break and dead-time register,         Address offset: 0x44 */, K  ~2 Q. i7 ^; t. w! t
  24.   __IO uint16_t DCR;         /*!< TIM DMA control register,                 Address offset: 0x48 *// V9 ~. }2 y* _5 T) c- h) b
  25.   uint16_t      RESERVED12;  /*!< Reserved, 0x4A                                                 */
    3 x% U) I* Q# ?% e; J/ }
  26.   __IO uint16_t DMAR;        /*!< TIM DMA address for full transfer,        Address offset: 0x4C */
    5 a. a8 d6 f/ ~/ C6 j
  27.   uint16_t      RESERVED13;  /*!< Reserved, 0x4E                                                 */
    8 V3 j2 M& Z) r/ R* a
  28.   uint16_t      RESERVED14;  /*!< Reserved, 0x50                                                 */
    * G0 p! D" B" W! {" k0 U
  29.   __IO uint32_t CCMR3;       /*!< TIM capture/compare mode register 3,      Address offset: 0x54 */
    % g0 f5 s. f. m+ V6 V. M
  30.   __IO uint32_t CCR5;        /*!< TIM capture/compare register5,            Address offset: 0x58 */
    ) v8 v! e* ~! Z. _: ~% M/ W
  31.   __IO uint32_t CCR6;        /*!< TIM capture/compare register6,            Address offset: 0x5C */
    / A* D6 z: D8 y: b. [
  32.   __IO uint32_t AF1;         /*!< TIM alternate function option register 1, Address offset: 0x60 */5 [# k. _# Q( U. X7 d9 u
  33.   __IO uint32_t AF2;         /*!< TIM alternate function option register 2, Address offset: 0x64 */# `8 L- `, R$ j4 U: G2 f
  34.   __IO uint32_t TISEL;       /*!< TIM Input Selection register,             Address offset: 0x68 */
    - D' U# N1 L2 ]! _! O" ~
  35. } TIM_TypeDef;
复制代码
, ^" r3 v4 w' s* t8 O
这个结构体的成员名称和排列次序和CPU的定时器寄存器是一 一对应的。9 K* `2 w! y) v2 n0 l0 c2 w+ h1 X

# v* Z- a7 U- L5 C__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:* ^3 X7 B% B& s; d1 k

' k/ f1 o. Y5 Q, b) l
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */! W9 {& c- L* i: R( r! [
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码

& T; V7 F) R$ w- _8 @; }% v下面我们看下定时器的定义,在stm32h743xx.h文件。- J# }) D4 ?, Q3 r& b

& H" E+ V1 Z# k# U0 k( e- @
  1. #define PERIPH_BASE         ((uint32_t)0x40000000)
    ( C$ i  f  p5 S% j
  2. #define D2_APB1PERIPH_BASE   PERIPH_BASE7 R% O3 g6 |% Y! k9 J* e
  3. #define D2_APB2PERIPH_BASE   (PERIPH_BASE + 0x00010000)
    ) R% z! V' n( W7 R1 a0 Z& m7 g% M
  4. : d+ h2 U% X7 V" Y: ]& @( x0 h2 z
  5. /*!< D2_APB1PERIPH 外设 */  G, K0 d3 g! e7 p4 f2 C
  6. #define TIM2_BASE             (D2_APB1PERIPH_BASE + 0x0000) <----- 展开这个宏,(TIM_TypeDef *) 0x40000000
    , A4 c) }9 s4 b
  7. #define TIM3_BASE             (D2_APB1PERIPH_BASE + 0x0400)
    3 d: h9 I9 B- v* ]$ Z
  8. #define TIM4_BASE             (D2_APB1PERIPH_BASE + 0x0800)
    ) ?1 v# N$ m# n7 Z5 Y: R
  9. #define TIM5_BASE             (D2_APB1PERIPH_BASE + 0x0C00)
    5 u# H8 Y  N, F) y  Q2 {/ `
  10. #define TIM6_BASE             (D2_APB1PERIPH_BASE + 0x1000)5 Y2 x! b. {5 e& k8 r$ o( J- p7 h# ^
  11. #define TIM7_BASE             (D2_APB1PERIPH_BASE + 0x1400)
    ! W$ A& t6 k1 j4 N
  12. #define TIM12_BASE            (D2_APB1PERIPH_BASE + 0x1800): X( |( H( m: c8 ~
  13. #define TIM13_BASE            (D2_APB1PERIPH_BASE + 0x1C00)
    0 }, K$ [. X8 [' S
  14. #define TIM14_BASE            (D2_APB1PERIPH_BASE + 0x2000)2 i# @( v  ^: S3 q3 Z
  15. # e) K( U0 C) K1 x1 Q
  16. /*!< D2_APB1PERIPH 外设 */
    / l- w& w5 V! U% k  C) a
  17. #define TIM1_BASE             (D2_APB2PERIPH_BASE + 0x0000)4 N5 S7 N( ?4 A' G$ T9 g# E4 U
  18. #define TIM8_BASE             (D2_APB2PERIPH_BASE + 0x0400)- m4 t! W$ k6 ^+ {2 ^
  19. #define TIM15_BASE            (D2_APB2PERIPH_BASE + 0x4000)2 z9 ]& d9 @" j! f7 ?$ ]' X
  20. #define TIM16_BASE            (D2_APB2PERIPH_BASE + 0x4400)
    " J4 U5 z( l' n0 _( M+ F, ]
  21. #define TIM17_BASE            (D2_APB2PERIPH_BASE + 0x4800)9 t, V7 N8 n1 p  C8 \: X

  22. * ~, S- `$ d4 j! U/ ~4 y: d
  23. #define TIM1                ((TIM_TypeDef *) TIM1_BASE)8 ~$ M3 O8 E" f  T
  24. #define TIM2                ((TIM_TypeDef *) TIM2_BASE)9 H; g2 N/ k7 x" A6 x) R$ O
  25. #define TIM3                ((TIM_TypeDef *) TIM3_BASE)7 F) g3 I1 j! ]4 P# f
  26. #define TIM4                ((TIM_TypeDef *) TIM4_BASE)
    8 l8 v  w& S5 c
  27. #define TIM5                ((TIM_TypeDef *) TIM5_BASE)
    ( O* ~7 e, q8 \) M. ^4 g/ f+ J
  28. #define TIM6                ((TIM_TypeDef *) TIM6_BASE)
    1 `' E4 I: y" O8 c  _/ V( R  J! x
  29. #define TIM7                ((TIM_TypeDef *) TIM7_BASE)
    2 W5 R# V" N3 [8 M
  30. #define TIM8                ((TIM_TypeDef *) TIM8_BASE)
    3 \6 q0 b, Y3 Z8 r' V; a: w& b
  31. #define TIM12               ((TIM_TypeDef *) TIM12_BASE)  @2 a+ E' T" T& Y
  32. #define TIM13               ((TIM_TypeDef *) TIM13_BASE)
    % [5 D6 G; j6 q9 b/ }3 }
  33. #define TIM14               ((TIM_TypeDef *) TIM14_BASE)
    ; {; L1 a  u, V% D. E7 D
  34. #define TIM15               ((TIM_TypeDef *) TIM15_BASE)
    5 L* r4 J, V8 T- @1 j
  35. #define TIM16               ((TIM_TypeDef *) TIM16_BASE)
    # N8 S6 q  S$ G3 J! F: V
  36. #define TIM17               ((TIM_TypeDef *) TIM17_BASE)
复制代码

8 S* l& C) @+ C, N我们访问TIM2的CR1寄存器可以采用这种形式:TIM2->CR1 = 0;7 I8 H, N3 A- L$ O  T% M

0 B* L0 Q" f  B7 o$ W32.3.2 定时器句柄结构体TIM_HandleTypeDef
# x. a7 y* f0 I! \3 r& p, q% vHAL库在TIM_TypeDef的基础上封装了一个结构体TIM_HandleTypeDef,定义如下:
% d% X8 Q5 s/ R6 _7 |1 u/ j% E0 f6 J  G/ j
  1. typedef struct/ z& Y4 C% R6 E) T
  2. {
    * X9 M8 ^& k5 K# y* ^
  3.   TIM_TypeDef              *Instance;     /*!< Register base address             */
    8 e7 `7 ]! B; F+ x8 I9 M/ r
  4.   TIM_Base_InitTypeDef     Init;          /*!< TIM Time Base required parameters */
    ' q; |, e9 d8 |! n" }! B" H2 ]
  5.   HAL_TIM_ActiveChannel    Channel;       /*!< Active channel                    */
    7 X& [0 K% I& W) [" g

  6. ' u+ t& R* B) C% S+ U4 R
  7. /*!< DMA Handlers array This array is accessed by a @ref DMA_Handle_index */) b9 j2 \& u4 b, ^" L
  8.   DMA_HandleTypeDef        *hdma[7];      . z- O: f9 o  C0 g8 g3 x
  9.   HAL_LockTypeDef          Lock;          /*!< Locking object                    */' T; h) e$ O1 k; S
  10.   __IO HAL_TIM_StateTypeDef   State;      /*!< TIM operation state               */  # M3 V9 X1 t1 Y4 t8 D  O: U5 A; C2 ]
  11. }TIM_HandleTypeDef;
复制代码
5 l: G0 P# F% ^2 t* M
这里重点介绍前四个参数,其它参数主要是HAL库内部使用的。
. r8 r9 Q( |7 Y& Q6 C( j! m9 A8 A8 h
  TIM_TypeDef  *Instance  q/ m" Y0 W- [  p" K! t! j' V
, u" V6 {6 S1 [& K9 @. V1 v" t
这个参数是寄存器的例化,方便操作寄存器,比如使能定时器的计数器。% }: J! H6 x; z$ P7 `
" i) \7 a0 B' S' _7 h% V& U
SET_BIT(huart->Instance->CR1,  TIM_CR1_CEN)。
4 g1 m8 d7 h: B' l5 F' k# _1 f' K7 D. L4 j  j- Q2 q7 D& X
  TIM_Base_InitTypeDef  Init% i' o! o2 c+ o; k

0 V6 j$ Y$ @6 V4 f7 [这个参数是用户接触最多的,用于配置定时器的基本参数。. {) O) P% O' |: z5 y2 r; f

8 [0 E5 ~9 a8 E5 G& e$ R: KTIM_Base_InitTypeDef结构体的定义如下:) U" T/ _) l- @! X

, l& Q  j# b; u9 {" {
  1. typedef struct
    " W2 x$ {4 s$ V1 }/ V5 p8 Y3 X2 [
  2. {
    ( I  v, {9 v8 E* B: P! p
  3.   uint32_t Prescaler;      
    , C& p- B+ ?( L' o9 y$ s3 I
  4.   uint32_t CounterMode;    % \1 L! f" |1 t9 v8 Y, o. D5 h/ [
  5.   uint32_t Period;         
    % V8 r  M" h& K* U
  6.   uint32_t ClockDivision;   
    7 x" y( i' `; X+ ~# t
  7.   uint32_t RepetitionCounter;
    4 G6 v8 y' z$ Z+ X; ]* ~
  8.   uint32_t AutoReloadPreload;  
    / P- q: ]6 v, ~( A+ |) v
  9. } TIM_Base_InitTypeDef;
复制代码

1 F  L* K+ ~0 [6 s1 o( |  成员Prescaler6 {& s! x. T4 Z  E) [* S
用于设置定时器分频,对于32位的TIM2和TIM5范围是0到0xFFFFFFFF,其它定时器是0到0xFFFF。7 P. e; a- |7 c/ a

8 Z9 {% \9 y; O$ G! n: q  成员CounterMode
2 N5 j$ o4 Y! k, |) C用于设置计数模式,向上计数模式、向下计数模式和中心对齐模式。, I. ~$ q& H1 Z( k4 w
& n1 g& M) K+ I$ X9 L% _
  1. #define TIM_COUNTERMODE_UP                ((uint32_t)0x0000U)   /*!< Up counting mode */
    : ]; I; C7 q2 U2 \! u8 x/ \( Y
  2. #define TIM_COUNTERMODE_DOWN               TIM_CR1_DIR          /*!< Down counting mode */
    8 w0 U) d4 P& l7 g; u
  3. #define TIM_COUNTERMODE_CENTERALIGNED1     TIM_CR1_CMS_0        /*!< Center-aligned counting mode 1 */2 J% @) I" E* G2 b) i; s
  4. #define TIM_COUNTERMODE_CENTERALIGNED2     TIM_CR1_CMS_1        /*!< Center-aligned counting mode 2 */' w7 a2 z- N4 m
  5. #define TIM_COUNTERMODE_CENTERALIGNED3     TIM_CR1_CMS          /*!< Center-aligned counting mode 3 */
复制代码

" x; {) r  M* ~' J2 l1 v$ c  成员Period
. Z% z4 X: k) i  j7 N用于设置定时器周期,对于32位的TIM2和TIM5范围是0到0xFFFFFFFF,其它定时器是0到0xFFFF。
  q% ?# M1 e( `- w" X0 ~/ W- E' s4 q- r8 z% a# r: I
  成员ClockDivision
4 B1 N6 f* _; C用于指示定时器时钟 (CK_INT) 频率与死区发生器以及数字滤波器(ETR、TIx)所使用的死区及采样时钟 (tDTS) 之间的分频比。+ A' b" J' ]$ b% q7 H( w' f' m) k5 f
, Y! @+ ], ~' b% X/ U
  1. #define TIM_CLOCKDIVISION_DIV1       ((uint32_t)0x0000U)        /*!< Clock Division DIV1 */
    & H2 p4 h0 t& T  J
  2. #define TIM_CLOCKDIVISION_DIV2       (TIM_CR1_CKD_0)            /*!< Clock Division DIV2 */
    , @) @  F! K$ ~; l. ]& V# Z9 ^8 `
  3. #define TIM_CLOCKDIVISION_DIV4       (TIM_CR1_CKD_1)             /*!< Clock Division DIV4 */
复制代码
+ {' b8 Z- m( v0 R: e4 c6 E
  成员RepetitionCounter
- g$ [; r; D$ B. C用于设置重复计数器,仅TIM1和TIM8有,其它定时器没有。作用是每当计数器上溢/下溢时,重复计数器减1,当减到零时,才会生成更新事件,这个在生成PWM时比较有用。
& S# ?4 F! ^  ^: C# o4 |
1 w* J3 M& {6 }- ~& p5 R  ?: ^  成员AutoReloadPreload/ o- g$ P. j. v6 j2 I
用于设置定时器的ARR自动重装寄存器是更新事件产生时写入有效还是立即写入有效。如果使能了表示更新事件产生时写入有效,否则反之。; z0 H  w# m% V

9 @# ~0 |- I4 b& F
  1. #define TIM_AUTORELOAD_PRELOAD_DISABLE   ((uint32_t)0x0000U)   /*!< TIMx_ARR register is not buffered */
    . n5 z6 P7 K7 H- H, |7 m0 p
  2. #define TIM_AUTORELOAD_PRELOAD_ENABLE    (TIM_CR1_ARPE)        /*!< TIMx_ARR register is buffered */
复制代码
: [0 |' }, d+ @* i
  HAL_TIM_ActiveChannel    Channel;
7 m  q2 T: _7 y8 u8 }- U
6 Q$ [. g5 _: ~' C# {用于设置定时器通道,比如TIM1和TIM8都是6个通道。  ]3 l) h' \7 }: I; G& Y

! S5 l) e: `$ a/ S- Z; L0 n$ _2 \
  1. typedef enum
    7 m# c& {; ]3 T3 V
  2. {
    9 M- _0 k; `2 s( a0 ~
  3.   HAL_TIM_ACTIVE_CHANNEL_1        = 0x01U,    /*!< The active channel is 1     */7 Q2 f2 Y2 z' a5 z8 t, m
  4.   HAL_TIM_ACTIVE_CHANNEL_2        = 0x02U,    /*!< The active channel is 2     */6 s( a0 z2 n' C* Z
  5.   HAL_TIM_ACTIVE_CHANNEL_3        = 0x04U,    /*!< The active channel is 3     */   7 h/ b" k9 B6 u. s  S1 i
  6.   HAL_TIM_ACTIVE_CHANNEL_4        = 0x08U,    /*!< The active channel is 4     */3 N+ e( e( y* e# u4 F4 l
  7.   HAL_TIM_ACTIVE_CHANNEL_5        = 0x10U,    /*!< The active channel is 5     */
    % v# M, r8 h- X% |4 {. \0 q* C3 Q5 s
  8.   HAL_TIM_ACTIVE_CHANNEL_6        = 0x20U,    /*!< The active channel is 6     */6 l* C1 i( v5 ^
  9.   HAL_TIM_ACTIVE_CHANNEL_CLEARED  = 0x00U     /*!< All active channels cleared */    4 G6 k; p) r, k/ b4 w: k" y
  10. }HAL_TIM_ActiveChannel;1 L* v$ K' O% ?$ h$ }- h% j
  11.   DMA_HandleTypeDef        *hdma[7];
复制代码
. U! R: }! c, ~" K0 w
用于关联DMA。
0 Y! f' ~, R. b
# A  y2 y, ]* Q" h0 L配置定时器参数,其实就是配置结构体TIM_HandleTypeDef的成员。, D0 Q7 K6 R% _4 t' K! I& H% a1 n
/ w% E: Q4 A0 M/ e! J( R
  1. TIM_HandleTypeDef   TimHandle = {0};/ ~! Z! A) ~0 q0 x: s

  2. 1 {" Q1 z+ V( k2 z
  3. /* ; ]) r  X$ l' K( x& y
  4.     定时器中断更新周期 = TIMxCLK / usPrescaler + 1)/usPeriod + 1). \+ C6 g# ~" l- r+ ?4 j$ B* R
  5. */
      k3 |! n' E" m( u: |5 l* O
  6. TimHandle.Instance = TIMx;
    4 z3 p+ [6 f: _+ l: E1 Z% n, N
  7. TimHandle.Init.Prescaler         = usPrescaler;: M, h/ Y0 g& ]; y; o( Z
  8. TimHandle.Init.Period            = usPeriod;        , N7 b  G- Y; O
  9. TimHandle.Init.ClockDivision     = 0;
    2 o0 U0 q% k# V# r0 I* O
  10. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;1 N' L0 f! B4 U- t. d
  11. TimHandle.Init.RepetitionCounter = 0;
    0 q: N8 m- c0 V, ^* [
  12. TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
    . m4 r* W1 T$ I1 X" a: v
  13. if (HAL_TIM_Base_Init(&TimHandle) != HAL_OK)$ c: Z  I6 q6 m& _. z+ G8 H9 K  e
  14. {
    & s, g& `  j! j; `7 n# B
  15.         Error_Handler(__FILE__, __LINE__);
    . O' m) z9 ^0 P. H% o
  16. }
复制代码

5 S2 K& C+ U1 r! c1 x# z9 W) a9 m32.3.3 定时器输出比较结构体TIM_OC_InitTypeDef
9 S" n7 Z1 a7 W+ |8 ?# T$ }+ M
此结构体主要用于定时器的输出比较,定义如下:
2 H# P, U" N! }, D" x3 n4 n. K- {6 a$ v+ s/ Z+ r& N4 J
  1. typedef struct
    1 {, L) I( Y( c9 o- _
  2. {                                 ) d: r% Y. t; k; s2 |2 j2 I
  3.   uint32_t OCMode;       . s1 h0 I9 f. \5 A9 j
  4.   uint32_t Pulse;      
    9 [# I$ ]* |+ X% C) E& c! N7 m" |! f8 W
  5.   uint32_t OCPolarity;   
    ! C5 W+ ]0 ], V7 Y$ L7 M
  6.   uint32_t OCNPolarity;   0 k8 X4 o0 p, _, k
  7.   uint32_t OCFastMode;  
    : g  M0 O' ?- }( x1 _) M
  8.   uint32_t OCIdleState;   
    9 ^) n" F" u1 [
  9.   uint32_t OCNIdleState;  . e' N' _+ Y  Z7 ~8 p" g) J
  10. } TIM_OC_InitTypeDef;  
复制代码
6 n$ I2 ]& X; p5 X" r7 Z
下面将这几个参数一 一做个说明。
8 e( @' ~' j8 C6 A1 |  e5 a1 D8 ?1 ]' z1 T* B. p$ v
  OCMode
1 {; [, @# f7 f2 z用于配置输出比较模式,支持的模式较多:
- \2 U% i" x3 {5 I/ Y8 A5 N: G7 H. p" }) A% k
  1. /*!< TIM Output timing mode */
    # d* M( d! f3 E1 ^. S' n. _- y
  2. #define TIM_OCMODE_TIMING                ((uint32_t)0x0000U)       $ L0 g% ^3 y8 Q) N

  3. ' B+ ^' r9 {% q5 L
  4. /*!< TIM Output Active mode */                          : f0 V& U/ ^; S
  5. #define TIM_OCMODE_ACTIVE                ((uint32_t)TIM_CCMR1_OC1M_0) + N5 @+ ?- ^- A1 Y

  6. 3 ^- h" h7 {0 c% o, C/ a
  7. /*!< TIM Output Inactive mode */                       
    ; U( O" \7 k; J2 K
  8. #define TIM_OCMODE_INACTIVE              ((uint32_t)TIM_CCMR1_OC1M_1)             z! |( m- q% Q( f0 Q+ l/ n
  9. " q5 X) s" D1 l
  10. /*!< TIM Output Toggle mode */               
    # ~# A& a9 i/ E
  11. #define TIM_OCMODE_TOGGLE                 ((uint32_t)TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_0)         9 O$ a; g. {! K  u) {& y& _
  12. * M: z4 S- m2 D6 r
  13. /*!< TIM PWM mode 1 */
    & K" w7 y1 s8 m2 Z8 L  i( X
  14. #define TIM_OCMODE_PWM1                   ((uint32_t)TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1)
    2 B2 I5 q4 h. ~# f# _$ P2 k; x0 ]
  15. ' K- {8 r2 W- a+ @6 _7 A
  16. /*!< TIM PWM mode 2 */                    
    : C5 Q9 x& [. S  }2 `7 t
  17. #define TIM_OCMODE_PWM2                    ((uint32_t)TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_0)   
    1 P2 Y$ X, w6 N% c$ G! W
  18. 9 F9 m4 J9 o5 s; Q+ l" E
  19. /*!< TIM Forced Active mode */   # t4 ]" M- \5 N- a  c* s
  20. #define TIM_OCMODE_FORCED_ACTIVE           ((uint32_t)TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_0)         ! w  {5 E' u9 ^/ _) H

  21. : U$ J. t6 W5 n+ j+ g5 g
  22. /*!< TIM Forced Inactive mode */             - a$ x% {  U7 r
  23. #define TIM_OCMODE_FORCED_INACTIVE         ((uint32_t)TIM_CCMR1_OC1M_2)                                       
    - r" e; P. c, ?
  24.   A% t! i0 _7 B& \/ ^0 R
  25. /*!< TIM Rettrigerrable OPM mode 1 */  9 O8 Q/ S( H! i* S
  26. #define TIM_OCMODE_RETRIGERRABLE_OPM1      ((uint32_t)TIM_CCMR1_OC1M_3)   , |; L! h" n# O, V
  27. " @: w4 `' _- @% C  i" j/ n
  28. /*!< TIM Rettrigerrable OPM mode 2 */                                        * G! G0 C0 Q  T
  29. #define TIM_OCMODE_RETRIGERRABLE_OPM2      ((uint32_t)TIM_CCMR1_OC1M_3 | TIM_CCMR1_OC1M_0)    7 y1 ]& ?, A5 J

  30. 9 H5 r  E* M# x1 c
  31. /*!< TIM Combined PWM mode 1 */                     * `( `  s3 w: }1 l- F: I1 o
  32. #define TIM_OCMODE_COMBINED_PWM1           ((uint32_t)TIM_CCMR1_OC1M_3 | TIM_CCMR1_OC1M_2)     5 n! J% G$ D0 k+ {2 J

  33. / e) f" o) |% i6 f: r( `' K
  34. /*!< TIM Combined PWM mode 2 */                    \& D' _2 j$ I, ^" F' G
  35. #define TIM_OCMODE_COMBINED_PWM2           ((uint32_t)TIM_CCMR1_OC1M_3 | TIM_CCMR1_OC1M_0 | TIM_CCMR1_OC1M_2)   
    - b$ v  B8 a( [" c
  36.   L' h& C9 w$ j
  37. /*!< TIM Asymetruc PWM mode 1 */  
    7 Z* b) `# S  z% C# M/ K+ O2 J
  38. #define TIM_OCMODE_ASSYMETRIC_PWM1         ((uint32_t)TIM_CCMR1_OC1M_3 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2)  
    ' f  f1 s# K( W3 }# F1 y- \
  39. 1 W. f6 I, M6 }% x. f
  40. /*!< TIM Asymetruc PWM mode 2 */   
    ' x- [, B4 c6 N/ R6 J
  41. #define TIM_OCMODE_ASSYMETRIC_PWM2         ((uint32_t)TIM_CCMR1_OC1M_3 | TIM_CCMR1_OC1M)  
复制代码

. J, i. f4 a/ o' Q3 N. ~( k! x  - R! K# ?- F2 |8 q' @
  Pulse3 n# c/ Q: u7 g
可用于设置占空比,对应定时器的CCR寄存器,32位的TIM2和TIM5范围是0到0xFFFFFFFF。+ |# P( D! N. h& h/ A

, w7 i7 k/ ?7 Z+ R  OCPolarity
" U; Q# i5 l0 \! c2 ~% F" m% N; v设置输出极性,可选高电平或低电平有效。1 \# |) p; @/ G9 j2 g$ |- g. K
, x5 h8 n" A! v$ P% b
  1. #define TIM_OCPOLARITY_HIGH                ((uint32_t)0x0000U)
    : k) u, g2 [. D3 F5 Y: i
  2. #define TIM_OCPOLARITY_LOW                 (TIM_CCER_CC1P)
复制代码

4 v- T8 T" e% b  OCNPolarity
( k1 e+ a. T% g  c5 |; y+ @互补输出极性设置,可选高电平或者低电平有效。
* e3 }6 ^! q0 _) e1 ^7 x5 c. j% {$ r- E$ w( I
  1. #define TIM_OCNPOLARITY_HIGH               ((uint32_t)0x0000U)/ R% k7 T0 ~( B3 Z) I. C
  2. #define TIM_OCNPOLARITY_LOW                (TIM_CCER_CC1NP)
复制代码

7 J' R6 ]+ e% D/ k  OCFastMode& I, F& J/ j' }9 f
快速输出模式使能,仅OCMode配置为PWM1或者PWM2模式时才有意义。$ |# a4 S* f7 G1 y
# e: g$ U5 C) x7 f
  1. #define TIM_OCFAST_DISABLE                ((uint32_t)0x0000U)
    1 U. M; `6 g& e, ~: Z& `1 }
  2. #define TIM_OCFAST_ENABLE                 (TIM_CCMR1_OC1FE)
复制代码
* P3 n% @8 m) @
  OCIdleState8 a0 S0 c5 ]3 j! T( ?; j) ]
空闲状态时,设置输出比较引脚的电平状态。
8 O8 N# b, z0 u, d9 o6 k6 f" o9 W% {; r3 B: J0 ?
  1. #define TIM_OCIDLESTATE_SET                (TIM_CR2_OIS1)
      G7 f  ^( U" |7 M5 b5 j6 t
  2. #define TIM_OCIDLESTATE_RESET              ((uint32_t)0x0000U)
复制代码

0 \( u& A0 e) O' M  OCNIdleState6 R7 O8 ?. q& H9 @3 z$ v
空闲状态时,设置互补输出引脚的电平状态。
! ^1 K! E9 Y, j; _2 b. W* P2 j! M1 ^& U3 Y. U" ?+ y5 _
  1. #define TIM_OCNIDLESTATE_SET               (TIM_CR2_OIS1N)( d" n/ [- W! G
  2. #define TIM_OCNIDLESTATE_RESET             ((uint32_t)0x0000U)
复制代码

& ^! _9 E" `. H$ T; M" J0 v32.3.4 定时器输入捕获结构体TIM_IC_InitTypeDef. c6 p3 |+ n2 P* ]
此结构体主要用于定时器的输入捕获,定义如下:6 X: O! ]* n4 K/ v  I
8 R5 \, l" G3 I
  1. typedef struct% f  Z0 ~  C' J+ T& }/ v/ Q
  2. {                                  / e$ k% k; d6 N; t: g4 w
  3.   uint32_t ICPolarity;   , W5 ]& ]6 e/ `3 r: R4 ]
  4.   uint32_t ICSelection; : S) m& E: x1 S: V
  5.   uint32_t ICPrescaler;
    + P3 W( \; V5 j4 L' O+ X: L
  6.   uint32_t ICFilter;    # ^" {7 Z" w. C! [5 ^/ R% C4 Y) e
  7. } TIM_IC_InitTypeDef;
复制代码

/ J+ j  y1 W  s6 t' K; V下面将这几个参数一 一做个说明。. X+ v: R9 G7 u$ {
2 q2 B- I% e7 G0 k
  ICPolarity+ F/ t8 R& K$ k* I* S' ^3 r
输入触发极性,可以选择上升沿,下降沿或者双沿触发。
6 I8 Q5 M$ x* ]8 V3 d3 {: ]1 _, N: b6 \. J9 a
  1. #define  TIM_ICPOLARITY_RISING             TIM_INPUTCHANNELPOLARITY_RISING
    2 B! m, P* ]7 o* V9 }  P. I+ U
  2. #define  TIM_ICPOLARITY_FALLING            TIM_INPUTCHANNELPOLARITY_FALLING" Z& z0 ^( Q  H6 y, X8 d2 H: ^
  3. #define  TIM_ICPOLARITY_BOTHEDGE           TIM_INPUTCHANNELPOLARITY_BOTHEDGE
复制代码
- z1 v, I0 S+ T) L2 k& ~) X
  ICSelection
; v8 i4 z  K" C输入捕获通道选择,可以选择直接输入(即CC1选择TI1,CC2选择TI2等),间接输入(CC1选择TI2,CC3选择TI4等)或者TRC。
6 _! Z: E. i8 Q7 F6 B* A& R3 N  v6 G3 j& w
  1. #define TIM_ICSELECTION_DIRECTTI       (TIM_CCMR1_CC1S_0)   
    ! j& G1 Q8 w3 A# Y% m8 P0 E
  2. #define TIM_ICSELECTION_INDIRECTTI     (TIM_CCMR1_CC1S_1)  # B+ G$ V6 f9 E
  3. #define TIM_ICSELECTION_TRC            (TIM_CCMR1_CC1S)   
复制代码

2 ^& F- l  X$ X7 s  ICPrescaler
7 n4 C4 S  f' ?! w输入捕获分频,表示每捕获1,2,4或8个事件后表示一次捕获。5 T( j( ^; e* x; L3 C" F1 A7 S+ c

; _8 l: W; ~* q; a  |0 _
  1. #define TIM_ICPSC_DIV1       ((uint32_t)0x0000U)                 & J4 P+ B' A0 _- p5 q/ ]/ ]
  2. #define TIM_ICPSC_DIV2       (TIM_CCMR1_IC1PSC_0)   
    : b4 Z5 G1 Q" K1 K
  3. #define TIM_ICPSC_DIV4       (TIM_CCMR1_IC1PSC_1)    3 @  m* m# B* ]7 I* a4 ~: T
  4. #define TIM_ICPSC_DIV8       (TIM_CCMR1_IC1PSC)
复制代码

: x3 P5 u9 k" `$ ]  ICFilter' l8 U6 [* k, e1 s& |
输入捕获滤波器,可以定义采样频率和多少个连续事件才视为有效的触发,参数范围0到15。具体定义如下,其中fCK_INT表示定时器时钟,fDTS表示死区时间采样率,N表示这么多个事件代表一次有效边沿。  L+ c& e# ?, v* G
" @, @; b/ q- n, u
  1. 0000:无滤波器,按 fDTS 频率进行采样
      ]% E7 o0 u  A5 H( J" d! K
  2. 0001: fSAMPLING=fCK_INT, N=26 m- R9 Q- y) y1 s
  3. 0010: fSAMPLING=fCK_INT, N=4+ u( E* {$ O  K6 O! f3 D) Q  |
  4. 0011: fSAMPLING=fCK_INT, N=8
    / z! Y0 w  q/ p9 f9 {2 L
  5. 0100: fSAMPLING=fDTS/2, N=6
    ) T) w" C& C6 V- K
  6. 0101: fSAMPLING=fDTS/2, N=8
    5 ]: L" o; Q/ X- U6 I9 Z
  7. 0110: fSAMPLING=fDTS/4, N=6% t- R# n" [7 H  w0 ]
  8. 0111: fSAMPLING=fDTS/4, N=81 a& y4 G0 Y2 i) U5 g
  9. 1000: fSAMPLING=fDTS/8, N=6/ x7 ~% i4 k/ T& I. |( J' x5 B$ V& P8 g
  10. 1001: fSAMPLING=fDTS/8, N=8
    3 P0 x( G' h. q& Q. X
  11. 1010: fSAMPLING=fDTS/16, N=5
    0 b" g0 b% _, E& O, q3 T# I
  12. 1011: fSAMPLING=fDTS/16, N=6
    $ q- u5 m/ T/ ?# `0 K8 O
  13. 1100: fSAMPLING=fDTS/16, N=8
    ) e4 _% h' d! m; }2 P% X
  14. 1101: fSAMPLING=fDTS/32, N=50 F4 r7 ~/ c! g: a
  15. 1110: fSAMPLING=fDTS/32, N=6
复制代码
4 H7 P- e  N( B
32.3.5 定时器的底层配置(GPIO,时钟,中断等)
7 }# q8 s& M* E% ]% _HAL库有个自己的底层初始化回调函数,比如调用函数HAL_TIM_Base_Init就会调用HAL_TIM_Base_MspInit,此函数是弱定义的。+ H) `/ M$ L) c
- `; W% e0 S& O- i6 n
  1. __weak void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)) ]2 _/ k- p6 a
  2. {/ c" {5 K5 D" Z" O/ w
  3.   /* Prevent unused argument(s) compilation warning */
    " G9 z% @( C: ~3 d8 X! s! d
  4.   UNUSED(htim);7 H/ D% D2 H0 |& ?
  5.   /* NOTE : This function Should not be modified, when the callback is needed,
    6 ~+ Q+ T. x  D/ W; S& `" I- V
  6.             the HAL_TIM_Base_MspDeInit could be implemented in the user file) w1 _1 ?1 P$ x& P& X
  7.    */6 h$ H8 A6 z: @# h: Q9 @
  8. }
复制代码
; j$ k$ c& e' n/ A6 t& R
用户可以在其它的C文件重定向,并将相对的底层初始化在里面实现。对应的底层复位函数HAL_TIM_Base_DeInit是在函数HAL_TIM_Base_MspDeInit里面被调用的,也是弱定义的。
" s; j$ r4 Z2 T8 P; v. k" z2 E( {$ E
$ q) V& I7 ^1 B8 z: [当然,用户也可以自己初始化,不限制必须在两个函数里面实现。
3 v4 q4 E& l: F" {5 k  H, T; n* @* F6 d# T& m9 }( g7 F
定时器外设的基本参数配置完毕后还不能使用,还需要配置GPIO、时钟、中断等参数,比如下面配置TIM1使用PA8做PWM输出。
5 X* M4 b3 u$ g7 r1 H. `- Q2 }# p  I# s/ F9 a
  1. void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
    ! Z6 S# a5 U& J6 X) ?7 l/ f- D
  2. {: I9 V- u0 }' e  \1 _* X3 b. B& K: B
  3.   GPIO_InitTypeDef   GPIO_InitStruct;
    : |: g4 d5 w( R4 D2 X! c- g2 h/ B0 M
  4. ! k9 o) _9 J  O) N+ l) ?4 }3 T; f
  5.   /* 使能TIM1时钟 */
    - N3 N5 O4 {4 y: N3 H
  6.   __HAL_RCC_TIM1_CLK_ENABLE ();6 [' c/ {. q5 [2 R7 B
  7. * q+ G# y2 w2 e  J  w
  8.   /* 使能GPIOA时钟 *// a! }: q& F: z
  9.   __HAL_RCC_GPIOA_CLK_ENABLE ();
    / ~& P1 B- H6 g0 w' D4 y* S
  10. , y7 n* [1 [5 n& n
  11.   /* 设置TIM1使用PA8做PWM输出引脚,将其配置为输出,推挽,复用模式 */* `- X0 ~' ~( x4 z2 o
  12.   GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;* z1 U2 r0 w, K
  13.   GPIO_InitStruct.Pull = GPIO_PULLUP;' `. O! m4 |% O' N6 j6 z
  14.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    . F  }6 N3 x. u- I

  15. ( r. |3 j0 t* F! x' D
  16.   GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;6 h+ K) n6 W# Q+ G0 J6 s
  17.   GPIO_InitStruct.Pin = GPIO_PIN_8;" W/ w) d  f4 O  q
  18.   HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);. u! N' J% v. V6 P" \
  19. 2 C6 n6 l) g% x3 I6 w% u8 g. Y
  20. }
复制代码
9 k' ?; d) P' j  t# i: ]
总结下来就是以下几点:
& b, N2 f0 B" B$ @; i; Z; Z& ]& `0 v, U
  配置TIM时钟。
- E2 X! Y" G( Y0 A( n% a- Z  配置TIM所用到引脚和对应的GPIO时钟。( g; d( {+ @) G% O9 j
  如果用到定时器中断,还需要通过NVIC配置中断。0 L1 n) D8 z* w- E9 M6 I
  如果用到DMA,还要配置DMA。
: X+ G+ v8 H3 D关于这个底层配置有以下几点要着重说明下:
0 b0 F' \3 e2 M6 R8 J: p& b
7 F/ @. h: N( r* C  D  定时器所使用引脚的复用模式选择已经被HAL库定义好,放在了stm32h7xx_hal_gpio_ex.h文件里面。比如TIM1有一个复用,; E! F: Y0 u  k
  1. #define GPIO_AF1_TIM1      ((uint8_t)0x01)  /* TIM1 Alternate Function mapping */
复制代码

( R4 t5 Z, W) H9 v6 @但是却有4个输出通道,每个通道都有几个支持的输出引脚:
4 h* r1 d% ?! X/ V# g  T9 _( {/ {7 M7 m# I9 D  z" N& c" Q% _6 C
  1. TIM1_CH1,  PA8   PE9    PK1! O" H9 S; j# W5 k0 m- U
  2. TIM1_CH2,  PA9   PE11
    6 V- X9 X+ _- A6 A, b. ^7 z
  3. TIM1_CH3,  PA10  PE13   PJ9# y1 ]  ?4 z8 S9 c! w+ D
  4. TIM1_CH4,  PA11  PE14   PJ11
复制代码

6 V3 M' e' Y- H  H8 {1 t具体使用哪个,配置对应引脚的复用即可:# H: v( Z% ]! N- c; L% B- q; i
* G/ |7 I; M0 n  n: }. f# l6 J
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png

, ?) n& \4 F' M! k8 c2 h6 V' F2 }
3 Y& l# \" l8 N" ^3 ~4 b32.3.6 定时器的状态标志清除问题0 B3 v& D- p. ^' ^+ K
下面我们介绍__HAL_TIM_GET_FLAG函数。这个函数用来检查定时器标志位是否被设置。# a8 y+ B" a' K* ^
  1. : z/ Z4 ^% c$ _  M# U
  2. /** @brief  Check whether the specified TIM interrupt flag is set or not.
    0 c. D* o6 z+ l% \: v  i" ~( s# Q
  3.   * @param  __HANDLE__: specifies the TIM Handle.7 c  J* k# F) J3 _; |9 M
  4.   * @param  __FLAG__: specifies the TIM interrupt flag to check.
    ' M1 V' i  ]: p  R; i; G
  5.   *        This parameter can be one of the following values:- [% D+ K5 D4 t! c/ [" p) U: v
  6.   *            @arg TIM_FLAG_UPDATE: Update interrupt flag
    & b$ \4 |+ Y, N, W7 ~$ V- f4 \9 u+ z' l
  7.   *            @arg TIM_FLAG_CC1: Capture/Compare 1 interrupt flag
    0 T' d# M& ^6 V" B+ |- {& m& _
  8.   *            @arg TIM_FLAG_CC2: Capture/Compare 2 interrupt flag7 l& u2 L9 V# F# d
  9.   *            @arg TIM_FLAG_CC3: Capture/Compare 3 interrupt flag
    8 T$ m7 |6 D4 w7 b
  10.   *            @arg TIM_FLAG_CC4: Capture/Compare 4 interrupt flag; u  N( N, O' J% M  `
  11.   *            @arg TIM_FLAG_CC5: Compare 5 interrupt flag
    . O% B. @: v  T$ K+ l1 x! p/ T
  12.   *            @arg TIM_FLAG_CC6: Compare 6 interrupt flag
    ! {) a: a0 Y' H' g" F' i" G
  13.   *            @arg TIM_FLAG_COM:  Commutation interrupt flag) Z8 M7 K2 s" e* T
  14.   *            @arg TIM_FLAG_TRIGGER: Trigger interrupt flag
    ) F4 X1 g# Z; j4 ?/ V( C
  15.   *            @arg TIM_FLAG_BREAK: Break interrupt flag   
    9 E' H' b" }% Q3 _0 f9 x
  16.   *            @arg TIM_FLAG_BREAK2: Break 2 interrupt flag                     4 a  G% h! b1 }2 ]4 Z, t
  17.   *            @arg TIM_FLAG_SYSTEM_BREAK: System Break interrupt flag4 Q5 n& R- ~. M2 W
  18.   *            @arg TIM_FLAG_CC1OF: Capture/Compare 1 overcapture flag: J1 C  _$ r. y/ P& i6 F
  19.   *            @arg TIM_FLAG_CC2OF: Capture/Compare 2 overcapture flag
    2 [% o/ k. {, z( n# T
  20.   *            @arg TIM_FLAG_CC3OF: Capture/Compare 3 overcapture flag, |( `6 F4 V" @& R
  21.   *            @arg TIM_FLAG_CC4OF: Capture/Compare 4 overcapture flag6 x* A0 _- R1 d3 ^) G: M
  22.   * @retval The new state of __FLAG__ (TRUE or FALSE).3 ]9 B. Q9 r( q( w6 d3 K
  23.   */
    ) a* v- t: M9 w
  24. #define __HAL_TIM_GET_FLAG(__HANDLE__, __FLAG__)   (((__HANDLE__)->Instance->SR &(__FLAG__)) == (__FLAG__))
复制代码

( r0 r' t- c6 D. b% T前5个是比较常用的中断标志。
: d' x3 r$ d: R" l# K$ o3 M4 c4 O. ]. f( p
  TIM_FLAG_UPDATE
$ W% }0 r- p1 H定时器更新标准,配置一个周期性的定时器中断要用到。
* `' [8 K+ g' @" r+ A7 e1 K# F9 W& l
     TIM_FLAG_CC1" {" n6 H( w6 F0 f( s* F
TIM_FLAG_CC2
5 C7 H0 u% D! e2 a- n9 R  ~
& O! _# f) y4 i- l% @TIM_FLAG_CC3: N  x' c$ ^- Q

6 k: g+ |  d3 p' PTIM_FLAG_CC49 ]! ]( _9 A+ ^& Z% I9 M
& h1 w, p4 t# [
捕获/比较标志,配置了捕获/比较中断要用到。  }, |- m; Y4 h0 R4 q: {, E

' s. `2 E: X% G( b+ m与标志获取函数__HAL_TIM_GET_FLAG对应的清除函数是__HAL_TIM_CLEAR_FLAG:, I6 r. y% p# r6 h

! U+ {3 v9 P3 i3 H0 M0 F: {1 G
  1. /** @brief  Clear the specified TIM interrupt flag.- |9 H0 n: i$ B$ C
  2.   * @param  __HANDLE__: specifies the TIM Handle.
    . D0 o3 D* P' |6 r; f
  3.   * @param  __FLAG__: specifies the TIM interrupt flag to clear.# w+ T( R& U0 C5 E0 {
  4.   *        This parameter can be one of the following values:3 y) n% |2 u4 F; z# g; b
  5.   *            @arg TIM_FLAG_UPDATE: Update interrupt flag. i4 N) O! S5 n" _6 @: ?( Y0 j
  6.   *            @arg TIM_FLAG_CC1: Capture/Compare 1 interrupt flag
    . u' c- e& E8 F" Z
  7.   *            @arg TIM_FLAG_CC2: Capture/Compare 2 interrupt flag
    % _: K' N; K+ i2 t, [
  8.   *            @arg TIM_FLAG_CC3: Capture/Compare 3 interrupt flag
    3 A+ S2 X5 }8 I0 R- T! {) f0 f
  9.   *            @arg TIM_FLAG_CC4: Capture/Compare 4 interrupt flag, u8 c) _& O6 k( j" M3 ^
  10.   *            @arg TIM_FLAG_CC5: Compare 5 interrupt flag
    ) P( H. }6 y7 G: x
  11.   *            @arg TIM_FLAG_CC6: Compare 6 interrupt flag* Q# F+ L! A# d- D6 Q% w
  12.   *            @arg TIM_FLAG_COM:  Commutation interrupt flag
    ) ~+ N8 U. U/ c. ]2 [" e* y
  13.   *            @arg TIM_FLAG_TRIGGER: Trigger interrupt flag
    4 a$ h4 B- z0 S+ `+ `# v
  14.   *            @arg TIM_FLAG_BREAK: Break interrupt flag   
    " c0 S; J& ~1 b+ y; c+ I
  15.   *            @arg TIM_FLAG_BREAK2: Break 2 interrupt flag                     
    7 t: l; Z% G- }$ @0 V
  16.   *            @arg TIM_FLAG_SYSTEM_BREAK: System Break interrupt flag
    $ \4 b; G- l! ?' D) h( H( l6 [
  17.   *            @arg TIM_FLAG_CC1OF: Capture/Compare 1 overcapture flag
    ' O8 b9 X0 G& ~2 x  s
  18.   *            @arg TIM_FLAG_CC2OF: Capture/Compare 2 overcapture flag
    7 G$ H! o7 T3 o5 D
  19.   *            @arg TIM_FLAG_CC3OF: Capture/Compare 3 overcapture flag8 ^5 Y6 }' s0 H+ u' ~: \  m; Z. q$ V
  20.   *            @arg TIM_FLAG_CC4OF: Capture/Compare 4 overcapture flag
    4 K3 d7 f0 W: a, Z; A1 a
  21.   * @retval The new state of __FLAG__ (TRUE or FALSE)." h$ z; M, [, g, O9 ~, n5 m
  22.   */
    - y( P6 x7 ^" T) v0 f% d
  23. #define __HAL_TIM_CLEAR_FLAG(__HANDLE__, __FLAG__)       ((__HANDLE__)->Instance->SR = ~(__FLAG__))
复制代码

6 x3 Y7 Z+ s- ^" A, q" }* |清除标志函数所支持的参数跟获取函数是一 一对应的。除了这两个函数,还是定时器的中断开启和中断关闭函数用的也比较多。
! L' c' i; {2 N9 E
3 F& ^' g' [) B, C7 z" f. X6 [
  1. /** @brief  Enable the specified TIM interrupt.
    ) u9 a& w8 z4 J. C8 T
  2. * @param  __HANDLE__: specifies the TIM Handle.9 L" x8 \. |8 {1 ^* N" y8 {
  3. * @param  __INTERRUPT__: specifies the TIM interrupt source to enable.* X5 |, N* b' J; f) F: `
  4. *          This parameter can be one of the following values:/ A( B6 G0 P4 U1 W3 w% b9 z. s, c
  5. *            @arg TIM_IT_UPDATE: Update interrupt
    : Q8 _! f  d# D
  6. *            @arg TIM_IT_CC1:   Capture/Compare 1 interrupt% b5 B: P7 v3 C$ g+ L+ P
  7. *            @arg TIM_IT_CC2:  Capture/Compare 2 interrupt
    0 }* r' E! Z) {- o- y8 t4 j+ q
  8. *            @arg TIM_IT_CC3:  Capture/Compare 3 interrupt$ z9 {# D3 _; W. Y: O
  9. *            @arg TIM_IT_CC4:  Capture/Compare 4 interrupt2 |7 E- `, J! Q5 }
  10. *            @arg TIM_IT_COM:   Commutation interrupt' O' d; ^! h: [4 D
  11. *            @arg TIM_IT_TRIGGER: Trigger interrupt
    , v# V( [# U- m
  12. *            @arg TIM_IT_BREAK: Break interrupt
    * y) ~9 M# n9 d3 s
  13. * @retval None  Y  R# `4 x4 ~* s* P+ P
  14. */0 ~, `! Q0 N% p8 a
  15. #define __HAL_TIM_ENABLE_IT(__HANDLE__, __INTERRUPT__)  ((__HANDLE__)->Instance->DIER |= (__INTERRUPT__))
    : w7 V, J8 E# X2 A& |6 O

  16. 4 B- z6 ^0 T- K; G
  17.   /** @brief  Disable the specified TIM interrupt.
    5 J/ I- D( d9 y* f5 C- b9 h
  18.   * @param  __HANDLE__: specifies the TIM Handle.
    6 y2 u: {7 X, b- s8 t1 ^+ }
  19.   * @param  __INTERRUPT__: specifies the TIM interrupt source to disable.
    - j7 t" a' ]/ l0 G
  20.   *          This parameter can be one of the following values:
    # `2 W$ J% G; ^# O
  21.   *            @arg TIM_IT_UPDATE: Update interrupt% _- x: k5 Q) U) w
  22.   *            @arg TIM_IT_CC1:   Capture/Compare 1 interrupt$ `, W6 z- s$ p1 G5 |. v
  23.   *            @arg TIM_IT_CC2:  Capture/Compare 2 interrupt
    2 Q' l+ x4 n  P, a4 V* d
  24.   *            @arg TIM_IT_CC3:  Capture/Compare 3 interrupt$ F9 B! L1 D" P4 O. B) @+ Q
  25.   *            @arg TIM_IT_CC4:  Capture/Compare 4 interrupt
    " C) ~( u1 J1 f! p+ C9 o& A
  26.   *            @arg TIM_IT_COM:   Commutation interrupt
    + `- k; m" k* ~& m8 o3 R5 G7 m
  27.   *            @arg TIM_IT_TRIGGER: Trigger interrupt% G  J- L0 G6 \" h3 n; p# E  \9 N5 C
  28.   *            @arg TIM_IT_BREAK: Break interrupt4 u& ?0 v; T. {2 p0 x; g6 r
  29.   * @retval None7 w& ~# _- t$ \; u: f
  30.   */
    ; F& F/ w5 B1 |1 |& t
  31. #define __HAL_TIM_DISABLE_IT(__HANDLE__, __INTERRUPT__)   ((__HANDLE__)->Instance->DIER &= ~(__INTERRUPT__))
复制代码
; w8 ^7 Q4 H. H' o" ^8 U
常用的也是前五个参数,1个定时器更新中断以及4个CC中断 。7 s$ Z2 ?* w! c  ?8 R+ b

( a8 {' r6 }! |7 ]3 d* _注意:操作定时器的寄存器不限制必须要用HAL库提供的API,比如要操作寄存器CR1,直接调用TIM1->CR1操作即可。$ n/ X) Y/ f) E
2 q" Z# ]6 L: k
32.3.7 定时器初始化流程总结
6 N: E% i# l  d, k使用方法由HAL库提供:9 v7 M2 `( [6 G; c" F

$ E1 k, _4 j- S$ x6 R  第1步:通过下面几个函数配置定时器工作在相应的模式2 O! n) I' f: S: G+ S1 J$ \

/ v' r! l+ l' t, z' t! v  HAL_TIM_Base_Init
6 ~' l9 x4 L7 T4 `2 t简单的定时器时基础功能; R; W7 r  z5 p, M" S

( v* A( p0 s& e4 P% v0 C  HAL_TIM_OC_Init 和 HAL_TIM_OC_ConfigChannel
+ @1 s1 E! Z  R7 a6 J) Q- F配置定时器产生输出比较信号  s1 Y( W" @) f. M4 N" O

$ P$ c5 P" h# h/ V$ Q6 _  HAL_TIM_PWM_Init 和 HAL_TIM_PWM_ConfigChannel( f! \8 j* d. ^# `9 b" P8 M9 y
配置定时器产生PWM信号
8 Q5 s& {" e) w. X* t" i: u# R4 }% w
  HAL_TIM_IC_Init 和 HAL_TIM_IC_ConfigChannel! m$ n1 ^4 j$ m: w: C4 q
配置定时器测量外部信号
' B8 W* L5 _( X* p' r- Z9 g$ t0 ^4 |  z; j5 L
  HAL_TIM_OnePulse_Init 和 HAL_TIM_OnePulse_ConfigChannel' q' n/ d* H# [! i& Q
配置定时器工作在单脉冲模式; {. w5 ]* {1 L7 a! O

) B8 N/ U3 l% s; z3 R  HAL_TIM_Encoder_Init
6 p4 ~2 n" `) D% c1 p$ W配置定时器使用编码器接口
" L1 p, s7 g2 I! I
* z4 a4 c! G% U  第2步:定时器几个常用功能的底层初始化API,这个里面需要用户自己填
3 u# S. f0 v0 i0 G; l! K" F( a1 F
- }/ H  w7 c2 H$ h2 \第1步里面的几个函数会调用下面的API。
$ w  b; i" m0 l5 e. P7 @' _
, a1 V$ E2 Y# t8 U7 i  定时器基本功能 : HAL_TIM_Base_MspInit()8 @/ N3 p% S1 }2 Q  K  t# ~
  输入捕获 : HAL_TIM_IC_MspInit()
5 |6 t2 a: Y# v* P: I+ p% W  输出比较 : HAL_TIM_OC_MspInit()
: z4 _" ~/ u  R- R: h  PWM输出 : HAL_TIM_PWM_MspInit()/ n* @! W4 g6 R
  单脉冲输出模式: HAL_TIM_OnePulse_MspInit(); e, K& }1 _! k# W$ Q; G! U
  编码器模式 : HAL_TIM_Encoder_MspInit()
2 _3 U7 Q* p, N9 n: ]  第3步:底层初始化具体实现4 {6 G# r8 C; ?$ \7 V

+ v2 N+ P7 y( M6 w5 H第2步中函数的具体实现。
' w& |; X3 w8 x$ s: Q
% e0 c" o: Y. Z$ a1 U& U  使用函数__HAL_RCC_TIMx_CLK_ENABLE()使能定时器时钟。
) s' [8 f4 o) s( y: Q# i  使用函数__HAL_RCC_GPIOx_CLK_ENABLE()使能定时器使用到的引脚时钟。
: V8 G1 k" ]  v/ n& T) y  使用函数HAL_GPIO_Init()配置GPIO的复用功能。2 T" K! T3 I  o7 ?
  如果使能了定时器中断,调用函数HAL_NVIC_SetPriority和HAL_NVIC_EnableIRQ配置。( t- d1 d# e" p7 H" |! A
  如果使能了DMA,还需要做DMA的配置。
5 L3 E$ L* Y2 X# V6 e7 L  定时器默认使用APB时钟,如果使用外部时钟,调用函数HAL_TIM_ConfigClockSource可以配置。
$ X6 K. a' e0 b( F' g  第4步:启动定时器外设& b- x) A+ [; J- M
- R& p/ n* ]( P. S7 N. H: _) v
  定时器基础功能:" r3 [+ h3 S% g  `  ^* l
HAL_TIM_Base_Start()
6 [# l0 ^" v, r& }/ k8 `, ]+ r* y" Z; z* H( ^6 y* e; M2 _. t
HAL_TIM_Base_Start_DMA()
4 L! d& P! ]$ r* l! |4 o* |: ?8 W6 `( j
" X: D( H' ^( t* K% SHAL_TIM_Base_Start_IT()
7 m/ g. ^2 t1 p4 g7 U& L( D4 @$ L1 {! v# s% b7 p; J1 [% G
  输入捕获 :
: y5 w" t9 Z- h5 o$ z4 m; E4 \HAL_TIM_IC_Start(). o  G5 I8 |) [& w2 A
5 B0 B- I1 u4 s) N4 s
HAL_TIM_IC_Start_DMA()# H/ h- P* ~( u; ~; |. o& X1 w0 a- b

9 v# Q5 n* H* i3 @: A! }& FHAL_TIM_IC_Start_IT()0 M$ Y( G3 }! A7 v

; Y0 C2 J# f/ v  输出比较 :
( Q; ^1 q: T/ s7 K6 s+ vHAL_TIM_OC_Start()
& @( s0 L1 ]/ v* A8 N( `; M. F! |, D* T) Q* ]8 |8 D9 d
HAL_TIM_OC_Start_DMA()# t' e9 i) Z5 i7 P, O6 k* Z5 U* ?
  E. w7 Z" K+ t! G. C
HAL_TIM_OC_Start_IT()0 M" |- `$ L3 `
. Y' V4 K5 w1 d
  PWM输出:2 e3 g% v' f2 @" y/ s# f# @0 U' i
HAL_TIM_PWM_Start(), m3 T- b3 b( C

- W/ n* \" W; ~0 n7 _: g4 dHAL_TIM_PWM_Start_DMA()  f) T1 f5 Q# R9 w
3 B  j* J# Q) s
HAL_TIM_PWM_Start_IT(), M0 F8 e/ f" W

$ A* r4 h2 v- s  单脉冲模式:6 V7 ]2 F1 \6 F
HAL_TIM_OnePulse_Start()4 Q6 E1 w2 }& f# Z1 K. ~' ^( J
; r9 [& o) x- [8 i0 o, R
HAL_TIM_OnePulse_Start_IT().6 R& v! Z4 g; S2 G' J+ E

, A5 `9 D- L+ o& j. F  编码器模式:
; E% a: g1 S, p, r7 zHAL_TIM_Encoder_Start()
1 A$ B+ P8 p* d% U7 m6 F$ h  y- t4 e7 P9 \' B
HAL_TIM_Encoder_Start_DMA()
8 f/ ?. n, r) [0 U3 u  ?3 r1 R$ o$ I- G0 {
HAL_TIM_Encoder_Start_IT().7 H8 U" `/ a" F6 v1 b

' {- L; z( c6 B7 T( c. }* b: P' Y  第5步:定时器的DMA突发使用下面两个函数
' }7 e& D% o( B, w5 H$ ^/ g
- I- U0 o/ L* l7 z* ^! k  HAL_TIM_DMABurst_WriteStart()
  R8 o( H' g/ [9 I4 M& z+ V  HAL_TIM_DMABurst_ReadStart()
$ ?3 z! W  {7 p; u定时器常用的功能,通过上面这几步即可实现。
$ R! _! q% ^! z* {# ^# j3 n/ t& y
4 B; e5 u6 R2 q9 |# F32.4 源文件stm32h7xx_hal_tim.c
: H1 ?& c  ^( @+ p! V) v此文件涉及到的函数非常多,这里把几个常用的函数做个说明:
5 w7 P) r0 N5 A  {6 }% Q4 D5 k/ F1 ?6 |9 y7 H- C9 O% j
  HAL_TIM_Base_Init
7 w2 Q( ~% t" o7 V  HAL_TIM_Base_Start
2 `1 `* @1 J( c. ?: E' I  HAL_TIM_PWM_Init+ o3 V5 w& q) I/ w& o
  HAL_TIM_PWM_ConfigChannel: j" W6 e- \" x8 o( `: r2 c1 M0 L' [
  HAL_TIM_PWM_Start; ~+ n) ]( C  i
  HAL_TIM_IC_Init
! a0 j2 \" q4 X- S3 ^  HAL_TIM_IC_ConfigChannel( N4 G5 S/ J" r0 F
  HAL_TIM_IC_Start_IT
- Z  c$ o1 j2 R7 ?- X2 {# t  HAL_TIM_OC_Init
; `% R" A6 P9 K/ J9 K  L! E. J  HAL_TIM_OC_ConfigChannel
) h7 U) p- G. b) P. T" x6 G' _  HAL_TIM_OC_Start! N) P4 b% F* }7 g! R1 ?7 E
32.4.1 函数HAL_TIM_Base_Init3 o+ S0 w, v6 e! M3 E1 x& a
函数原型:
; n3 I% e) {( P' |% r& o. j+ o8 A3 z& E5 M0 \
  1. HAL_StatusTypeDef HAL_TIM_Base_Init(TIM_HandleTypeDef *htim): N# k2 q: J5 k% Y2 H/ \
  2. {
    ( B4 |- X- W( \; h( J6 g1 G, U
  3.   /* 检测是否是有效句柄 */0 g) W' R  r$ p- _7 F
  4.   if(htim == NULL)
    ( j9 M0 _/ l1 i$ b, t
  5.   {
    ) q7 R( c( M* E) e
  6.     return HAL_ERROR;- v+ O/ p% t4 n; l7 A3 i3 r) d
  7.   }
    1 G4 \9 j$ {- K4 j

  8. + C  n! w8 Q  E# [6 T* i
  9.   /* 检测参数 */. u7 ~4 V, J' I2 y
  10.   assert_param(IS_TIM_INSTANCE(htim->Instance));
    . L! C1 Z5 Z: }% v4 p
  11.   assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode));8 ?# @: ^5 ?: [+ n* |
  12.   assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision));* G" n( o5 i' {  Y# L

  13. $ j- ]+ N' _- F) \. u. V
  14.   if(htim->State == HAL_TIM_STATE_RESET)
      A# A" t3 d6 {) F7 q! s2 F0 b
  15.   { 7 N6 ?' \) g$ y9 W6 o4 L, L" }
  16.     /* 默认取消锁 */
    9 B& a' z4 |; V- k  V- x
  17.     htim->Lock = HAL_UNLOCKED;( T5 c+ |8 c  k- k
  18.     /* 初始化底层硬件 : GPIO, CLOCK, NVIC */6 m4 W) b  S5 @8 a6 X
  19.     HAL_TIM_Base_MspInit(htim);; Q0 z0 _2 u5 @! _( q. `* _
  20.   }) T$ [; E( ]/ d2 ~  o
  21. 1 Y2 M) V$ g4 \+ T
  22.   /* 设置TIM状态 */3 c6 p" U/ ?; y3 f9 i" p6 Y# o1 l
  23.   htim->State= HAL_TIM_STATE_BUSY;- }3 l8 B& Q. q- }( }0 g5 v* ]5 O

  24. 1 A$ q5 g/ p* p. M4 q) b( {) P  U3 T! ?
  25.   /* 基本参数配置 */
    + m# m9 A0 p# Y
  26.   TIM_Base_SetConfig(htim->Instance, &htim->Init);
    1 l' \, U8 o' y' A2 ]1 @5 ?

  27. # M+ S# G/ {4 }. f
  28.   /* 设置TIM就绪 */! d# I2 [: N0 s8 U
  29.   htim->State= HAL_TIM_STATE_READY;' w2 H& O8 W# e# R

  30. " Q& }0 {6 {7 B% t
  31.   return HAL_OK;
    ; O6 i$ o* u% `( ]0 l
  32. }
复制代码
8 u9 i0 D1 P% }, z" ^# z; T3 d# o
函数描述:" M. V8 H( ?9 h

) H- T, x3 y$ H; @9 o& I此函数用于初始化定时器用于PWM。
7 a1 s" i/ B5 b1 Q3 F7 ~" X* }1 X" F2 \9 S
函数参数:- |% V, Q+ J" W7 Z
& o; a  |6 c9 d
  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。4 {  n, p2 [6 F" `" o/ C$ D* u/ _" b
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
$ h$ m5 P, F; B+ O1 C& o- H7 M4 c6 ~注意事项:* f. |/ i$ r1 x% ]' O
7 H7 C  q( h, R  M5 z  z  y
函数HAL_TIM_Base_MspInit用于初始化定时器的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能,由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。; S, Y% C: ^  y
如果形参htim的结构体成员gState没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量TIM_HandleTypeDef TimHandle。
7 E. ]7 C* Q# E7 a4 b对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_TIM_STATE_RESET  = 0x00U。0 {& H2 R6 n) k

0 V  O% A- Q/ p) s解决办法有三:
* W$ Z. x% Y# M" b
# P* U- X" ~2 {方法1:用户自己初始定时器和涉及到的GPIO等。
% v5 G# E5 ?* s5 T! g" p. r9 C9 A1 Z1 R% R  K$ h
方法2:定义TIM_HandleTypeDef TimHandle为全局变量。$ L. O- W( R6 v$ P

! D& {8 j0 B+ m方法3:下面的方法. L4 U# Q; _0 g
, ?5 E# U* g2 `8 M5 N
  1. if(HAL_TIM_Base_DeInit(&TimHandle) != HAL_OK)4 M6 R& S' ]! r0 l* H6 f
  2. {
    $ {; M2 f3 V4 w$ c/ O
  3.     Error_Handler();: u2 t- z$ i2 E4 _2 t& l
  4. }  
    9 Z: A) C& X& j& n
  5. if(HAL_TIM_Base_Init(&TimHandle) != HAL_OK)  P! m- @: G9 h, r
  6. {$ ]* l. i  T* d- V+ @) a
  7.     Error_Handler();
    + {% u7 b) Z" O* e6 P
  8. }
复制代码
; U  l* o1 ^( |+ A/ @5 {: L
使用举例:1 [3 k+ ~% x; i* a( i) N* g8 ?

" ~4 ~' }. J9 G
  1. TIM_HandleTypeDef   TimHandle = {0};
    ) v% Z6 e7 G- h4 O) x

  2. 9 A! i; m! l2 v9 K
  3. /* , D) b6 O% [0 t+ Z, ]6 h4 h
  4.     定时器中断更新周期 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)
    1 L' [5 a9 {( O3 c# j5 i
  5. */7 Q3 S8 l9 f# v% u8 I, V
  6. TimHandle.Instance = TIMx;
    5 q" b) R0 j8 W% i; }' F8 j
  7. TimHandle.Init.Prescaler         = usPrescaler;+ k! q2 m5 m  ]" ^; D/ a' }
  8. TimHandle.Init.Period            = usPeriod;        
    9 H  o# _. W! c8 T* Q* h& j: K& {
  9. TimHandle.Init.ClockDivision     = 0;3 N2 o$ D% A. }: O# D4 h  U
  10. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;7 @3 i8 ]  r7 V# Y7 c4 R
  11. TimHandle.Init.RepetitionCounter = 0;1 ?* e& |  v- v8 M& Y7 L
  12. TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
    + ~% }% F. q0 e" m, M6 u
  13. if (HAL_TIM_Base_Init(&TimHandle) != HAL_OK). n6 n' y1 O  ~/ u  \0 K5 Q2 ^
  14. {# ?3 M4 o+ i. \3 Q6 o% T6 o
  15.         Error_Handler(__FILE__, __LINE__);9 G8 k! r7 ^% b$ G
  16. }
复制代码

% }8 }/ N  |/ o4 e7 b, C  _7 g32.4.2 函数HAL_TIM_Base_Start6 p! @0 n0 i) M
函数原型:9 W6 \% h$ t, ~2 ~! S/ J& v. b0 h
; o* }9 f$ a& |. O) d
  1. HAL_StatusTypeDef HAL_TIM_Base_Start(TIM_HandleTypeDef *htim)6 t- x/ P6 w' b$ k  y6 A
  2. {
    ) R- [- ^6 f3 n* X
  3.   /* 检测参数状态 */
    + f  Y" Q/ y: K
  4.   assert_param(IS_TIM_INSTANCE(htim->Instance));
    . \. B$ k0 B3 y0 c) O, ^3 P/ s
  5. ( S# ~, X; i6 Z; n1 I! j, T
  6.   /* 设置定时器状态 */% j1 @$ S+ `" T, X
  7.   htim->State= HAL_TIM_STATE_BUSY;# Y/ `8 |! M+ ?, W6 j( f1 ?6 t

  8. / U  C! b  W# p( ~
  9.   /* 使能定时器 */
    ) D) @: z. V! h$ T: d% L
  10.   __HAL_TIM_ENABLE(htim);8 ~1 \% o% U9 `+ X$ d' h3 f- {/ M

  11. 5 u/ {) e9 V1 D2 [
  12.   /* 设置定时器状态 */
    ! A2 \" u- p8 B" d5 Z) B* M( G
  13.   htim->State= HAL_TIM_STATE_READY;
    ; P- x: G4 p2 P1 k4 p
  14. 2 |1 Q/ [+ F) `) q
  15.   /* 返回HAL_OK */
    # i  {0 v- Y4 u' B2 w. K
  16.   return HAL_OK;- e. d8 F. V4 w# h" O
  17. }
复制代码
( ?/ Z4 `. b+ t/ f
函数描述:% g( {, g$ c- [1 e: v

0 l$ i* q$ s/ L7 @: m4 a7 T" z此函数比较简单,调用函数HAL_TIM_Base_Init配置了基础功能后,启动定时器。
; e8 g  f/ M9 C) J
$ b( ]& ]; \: T函数参数:3 V1 W  u  l/ {- h

; h+ O$ k' g4 p# z% Q4 J5 B  第1个参数是TIM_HandleTypeDef类型结构体指针变量。
, v/ s4 \% T# \1 y) B9 K  返回值,固定返回HAL_OK,表示初始化成功。
8 V3 F/ H4 v2 G2 H& d0 F使用举例:
: A# Z0 v" V- U$ K0 i: h
7 s1 j. S$ D7 t$ n5 `) }
  1. TIM_HandleTypeDef   TimHandle = {0};
    ( @% E! L8 v/ Z6 t2 q8 X

  2. 5 f. W# A# @5 F5 G1 f! I
  3. /* ' [4 @  n6 u/ b0 g
  4.     定时器中断更新周期 = TIMxCLK / usPrescaler + 1)/usPeriod + 1): m' ~- L9 j! v- u* z' t4 {' f
  5. */
    - j6 ~) E/ o9 e( w/ ]4 @
  6. TimHandle.Instance = TIMx;8 X0 ?* t3 M, k2 D
  7. TimHandle.Init.Prescaler         = usPrescaler;
    8 b: f/ s* U! f
  8. TimHandle.Init.Period            = usPeriod;        
    ( B8 K% V: c. F5 ]4 A
  9. TimHandle.Init.ClockDivision     = 0;
    ( @% R4 g% _  D! n- z
  10. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;
    ' H9 D! {3 H$ ^/ n# F+ Q) S
  11. TimHandle.Init.RepetitionCounter = 0;( i3 g& T4 w0 S2 D/ P9 ?
  12. TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
    * z' s2 w0 `: o4 b8 E
  13. if (HAL_TIM_Base_Init(&TimHandle) != HAL_OK)+ i, a# V; V* N, K0 p
  14. {+ E! W+ W9 x& J" y
  15.         Error_Handler(__FILE__, __LINE__);
    4 P# b. V1 X: O1 t) i4 `$ m4 Y
  16. }
    ' h% x% _. F+ L2 [: c

  17. ' e5 g; f' [3 ?9 q
  18. /* 启动定时器 */! \' S- o5 t2 a, s6 R
  19. if (HAL_TIM_Base_Start(&TimHandle) != HAL_OK)5 |) \' a2 C' W  V- R4 ?3 g! _' s
  20. {6 g4 N. S! R% j3 p  e
  21. Error_Handler(__FILE__, __LINE__);- F, f8 L+ u* a1 b) L& s* t* V9 X
  22. }
复制代码
  Q# f5 m( `2 s* D
32.4.3 函数HAL_TIM_PWM_Init
4 V# C- [5 `( v函数原型:
' Z& _9 t2 O9 w- ]6 j
! q9 X! A1 l9 B. U: }' y
  1. HAL_StatusTypeDef HAL_TIM_PWM_Init(TIM_HandleTypeDef *htim)
    / t4 e+ M! H+ d) E( u7 M
  2. {6 P; ~$ S7 U5 h/ a4 w9 m
  3.   /* 检查句柄是否有效 */
    ; e. G" g% d1 c' E1 Z9 o
  4.   if(htim == NULL)0 [- S9 L4 X( M- |" ~) f* W
  5.   {
    0 z$ F! y# B' @& Z: q
  6.     return HAL_ERROR;
    ) f$ v8 ~( u3 v- s7 b# L
  7.   }# w, I! m6 g; B, S
  8. " O" V8 @, P4 |. r
  9.   /* 检测参数 */
    . T3 `7 r. B: U$ P# e) f
  10.   assert_param(IS_TIM_INSTANCE(htim->Instance));7 Z( `( H5 c7 t1 C/ R' z# [0 M
  11.   assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode));+ K( o8 o, \% M3 M; C( A+ `& j( O/ J
  12.   assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision));3 |# _9 B0 w7 i4 V: g

  13. / u9 @+ h3 g+ M- P+ x: ?8 ~
  14.   if(htim->State == HAL_TIM_STATE_RESET)/ h  ]) X9 Y- I' s4 l+ P
  15.   {
    / P- V" }( E& l! v# C- w6 K
  16.     /* 默认取消锁 */8 C& F' C. Z6 P& q2 H9 x3 U
  17.     htim->Lock = HAL_UNLOCKED;
    7 B' b! c' M- U7 ]. Q

  18. * Y6 q$ h$ M& `  s$ I( e/ e
  19.     /* 初始底层 : GPIO, CLOCK, NVIC 和 DMA */
    6 F! `) m$ q5 m5 n: n5 K1 v
  20.     HAL_TIM_PWM_MspInit(htim);
    ( b, Y) }) g, S1 K2 M
  21.   }: U! P# o/ t+ t5 X/ T: M0 V' ^

  22. 1 ]" Y7 n) d  C, M
  23.   /* 设置定时状态 */- B+ F- v! S8 e, |9 ^$ A) b
  24.   htim->State= HAL_TIM_STATE_BUSY;
    : ~2 e  g. d5 k& k

  25. & S" X1 O) D  C% A+ v+ M% i$ V
  26.   /* 配置定时器用于PWM */  ) K+ R: X; V2 B
  27.   TIM_Base_SetConfig(htim->Instance, &htim->Init); ( B+ i. h% k. T) R7 O% D+ H$ \% y
  28. $ D) J5 [& k5 [9 B- s8 Z
  29.   /* 设置定时器状态 */5 F! @5 y4 G* E% B- x) j
  30.   htim->State= HAL_TIM_STATE_READY;! t( R6 ~: V  i# {

  31. ; b( N' {8 T, q
  32.   return HAL_OK;( U$ K5 P, E" Z3 O( P7 {+ e
  33. }
复制代码

0 [' B, ^! G* H函数描述:, G3 m5 @7 U8 S. g$ r2 i# B9 {

5 P5 F1 Z# B: c( V: }此函数用于初始化定时为PWM方式。* e9 N! m/ [# ~7 A% V; N7 \
3 v* s! F- r, s% b1 g% N: A
函数参数:! E. g3 H) T" O& a
1 R$ M/ [' d: S- c! J
  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。
9 p  ?4 v/ q# l  H8 d9 u: d  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
' D  x5 x" h: E( S# m$ q8 g2 K7 [注意事项:
7 y9 L! d3 D7 v& K% F! o9 {5 m! S9 n4 z) O
函数HAL_TIM_PWM_MspInit用于初始化定时器的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能,由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
, O7 K8 F9 x, l: {3 Q. K如果形参htim的结构体成员gState没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量TIM_HandleTypeDef TimHandle。
/ b, Y7 b/ a+ j# S" }4 M! j对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_TIM_STATE_RESET  = 0x00U。& ~) v5 M% k( U+ b/ t
  c& \0 t) _5 h; a. `7 @3 _) v/ W' b
解决办法有三:2 Q% E% b! O5 E8 W3 o

# }0 R2 X, W! {" N+ s* {方法1:用户自己初始定时器和涉及到的GPIO等。
6 i8 r) C8 i! n) Y8 @* B. g1 D) r, j2 k( i
方法2:定义TIM_HandleTypeDef TimHandle为全局变量。
* V+ S# ^8 a/ s8 O* q9 l" c/ k2 M- R
方法3:下面的方法% g+ F5 K' i& s' _" U; |
( e) |2 L4 U/ Y: d4 Q# `, @
  1. if(HAL_TIM_PWM_DeInit(&TimHandle) != HAL_OK)
    6 D  N! o8 g/ Z3 R+ M
  2. {
    ! e8 }0 _+ Y% m1 _
  3.     Error_Handler();
    7 \- g+ G' n6 W' J: \. V
  4. }  
    , p4 o1 e6 U. P! p& f" u& {8 F. {& b% _
  5. if(HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)
    % X% T: G! v. j& ^' e& d
  6. {; G9 `. t+ s; V. S; [" t
  7.     Error_Handler();
    9 j! P2 y" j. T6 i, R& B$ g0 u  `
  8. }
复制代码
/ p' O" Q+ G+ B& N- e* C/ B2 B
使用举例:+ i0 T" D6 V4 T

8 r/ o, z, h7 F4 X! |
  1. TIM_HandleTypeDef  TimHandle = {0};
    $ L1 q% G9 o; v! z8 w3 @# H

  2. 3 a9 q9 k' o& L4 T' t" t) I( t
  3. /*  PWM频率 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)*/* W' F3 T; j( i7 u! c1 ^
  4. TimHandle.Instance = TIM1;3 e5 v8 Q# f: i" b/ ?2 ^  |
  5. TimHandle.Init.Prescaler         = usPrescaler;
    * G4 H3 I; e! M2 j# \7 G/ |
  6. TimHandle.Init.Period            = usPeriod;
    8 u* b# I3 m  d9 i6 o% l
  7. TimHandle.Init.ClockDivision     = 0;
    + i2 `* d+ b" m$ j. A5 j8 c
  8. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;( k0 K8 }! r4 s  c. E& B* u, O
  9. TimHandle.Init.RepetitionCounter = 0;6 s; e) `& b+ S: q
  10. TimHandle.Init.AutoReloadPreload = 0;
    / Z4 t4 [& X; x1 J3 c! z+ g) l
  11. if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)
    ! l# H7 K/ B' ^$ [- G
  12. {
    : ]' \& D( `5 w
  13.     Error_Handler(__FILE__, __LINE__);8 Z$ m+ V+ _: {. r
  14. }
复制代码

" [5 ?+ j1 E3 W- f3 t32.4.4 函数HAL_TIM_PWM_ConfigChannel( }" _0 R2 t+ D& ~
函数原型:3 }. f$ ^4 _7 [2 |' d

6 A& i$ _7 y) R/ ^$ |3 u
  1. HAL_StatusTypeDef HAL_TIM_PWM_ConfigChannel(TIM_HandleTypeDef *htim,* n( X& k" W3 ?
  2.                                             TIM_OC_InitTypeDef* sConfig,) w& E8 c8 L1 `
  3.                                             uint32_t Channel)
    8 A- G6 y+ p' ^1 |0 U; I, u8 b
  4. {$ U! O5 ^6 l- b
  5.    /* 省略 */4 M- a3 x+ C( |. Y' |0 u0 |
  6. % |2 \: \/ a; @  D- P
  7.   /* 开锁 */( _- |2 i+ n( }: d% o
  8.   __HAL_LOCK(htim);6 s% ^; ~; ~; u2 u8 _
  9. 6 F9 ^! C% Y5 U  f' V) k
  10.   htim->State = HAL_TIM_STATE_BUSY;
    ; L6 O1 p8 |. U5 _( \% n
  11. 2 b& B9 a+ p; h' q! E/ X/ R
  12.   switch (Channel)
    4 o# N% G5 B/ l2 B) z
  13.   {
    : A- Z9 {" P) J4 x6 b; n6 x9 f
  14.     case TIM_CHANNEL_1:
    4 y) T+ a4 Q9 E% F, p9 T
  15.     {
    9 u7 i3 U: P, G' L9 v
  16.       /* 检查参数 */- p' Q  p  C) o
  17.       assert_param(IS_TIM_CC1_INSTANCE(htim->Instance));- m3 `: N; l" o  H

  18.   c3 S8 ^- [# k/ W/ ~4 C
  19.       /* 配置通道1的PWM模式 */
      r! ]5 P7 ]- V/ \% r) x: x1 f
  20.       TIM_OC1_SetConfig(htim->Instance, sConfig);; S! ]) K/ `* t- o. s9 C7 f

  21. ; K  }1 _/ ^; m* v, v3 o0 @# y4 J4 T
  22.       /*预装载使能,更新事件产生时写入有效 */4 W% q  `* {: [3 @7 i
  23.       htim->Instance->CCMR1 |= TIM_CCMR1_OC1PE;: b5 e% _4 a7 `" s7 g4 N1 i1 [
  24. : V2 T  b  r3 S# j6 f) n3 T. j* i* }
  25.       /* 配置是快速输出模式 */
    1 \, W( {# N2 V6 f- @% ?5 l# U4 A
  26.       htim->Instance->CCMR1 &= ~TIM_CCMR1_OC1FE;
    & ]4 E; ^- q% j7 z: Y; Z8 U% J: S
  27.       htim->Instance->CCMR1 |= sConfig->OCFastMode;5 a  ~- J# B9 ^- \' W- o1 M; J
  28.     }
    , I7 w2 U7 P# O4 O
  29.     break;' I, F7 W5 `# Q/ k# x9 w' ?
  30. 5 J% W) V1 x  P# t- ~- n- ]; c( M
  31.     case TIM_CHANNEL_2:2 R+ `: [3 [8 t) X! B
  32.     {7 b' V2 T- K. K' `$ m) W* ^
  33.        /* 省略 */
    $ e9 |3 b. n3 U1 T- e4 b, A
  34.     }
    " s/ u  I" W' E; X8 `/ P, C9 N
  35.     break;% b$ k, r( R/ }1 m7 V# x6 R

  36. ) m- h5 K" S9 T/ W
  37.     case TIM_CHANNEL_3:
    5 \* S2 y5 _3 c1 z6 T, _& S0 `3 J" z: b
  38.     {) ?8 y- V0 v/ E5 j& `+ M
  39.        /* 省略 */
    5 p( t  d. p3 x' [/ D" h( ?
  40.     }
    7 i& l7 h4 E, ?) P$ [
  41.     break;
    " l6 Y4 F, S6 Q/ x' S$ n

  42. ; f* p9 k! Z5 P8 Z  V
  43.     case TIM_CHANNEL_4:4 X; v9 @5 H$ e0 S% d! d
  44.     {3 e% y2 Y& d$ ~& W1 W9 @8 \/ {
  45.       /* 省略 */
    ( D$ m3 G* i) d/ o  X; }6 m
  46.     }' L7 P0 ^. E" `" K+ X
  47.     break;
    $ R2 w+ U/ f$ q& M, d
  48. ( n9 p: d" p5 [0 x/ w5 G6 I
  49.     case TIM_CHANNEL_5:+ O* e, N8 `* [3 W! [. y
  50.     {( e4 q0 G# _$ W9 i' _
  51.        /* 省略 */
    9 `( z+ d: \$ N
  52.     }
    $ Y  ]$ I3 r, |# E# a1 A8 Q2 P. u
  53.     break;
    # l( S+ H& }1 R5 v! u/ k9 y

  54. ; q$ w/ P! O8 ]" M5 p9 L& |' E
  55.     case TIM_CHANNEL_6:1 H% z2 B1 K2 s
  56.     {4 k) ^* ]' j; S+ u7 B
  57.         /* 省略 */
    ! K- q2 U' d; ?. b7 q( B
  58.     }
    7 f0 T  h, C' Y3 G
  59.     break;
    8 u4 n0 u4 R3 W' O$ E

  60. " b" A  p/ @0 }* w3 h) G
  61.     default:& u) W7 ~9 m' Y# `$ W& K; ]* h2 S
  62.     break;* X/ R6 y) H3 R$ {8 F
  63.   }
    2 T; U, R8 ~  j# u+ ^  ^- X/ U
  64. - N5 Y# t3 `2 J# m- a8 C- B' ]
  65.   htim->State = HAL_TIM_STATE_READY;- O/ m& d3 _/ v+ x% i$ A" U2 d

  66. 8 H6 E% j, D& t" A7 t
  67.   /* 关锁 */
    4 I0 v+ K7 ^8 [( k9 X
  68.   __HAL_UNLOCK(htim);
    5 X6 ?; ^! L! R0 n
  69. - Z" D  P! S0 n, ~3 y* ?
  70.   return HAL_OK;" P. e+ n0 R( j  F! x+ r7 m
  71. }
复制代码
& a5 M  B- h. ?" L$ H# k* ~
函数描述:
/ e+ Z5 K+ P. r5 c& h& F" r( S2 P& `% M; I/ U% f
此函数用于配置定时器的PWM通道。0 ~+ I$ T) e2 p% `6 L
  Z0 c3 j% R8 \9 V6 l: R1 j  b
函数参数:* g5 `5 Q5 p6 m1 u3 w; F8 s
9 l: E4 w" B! p4 m
  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于定时器基本参数配置。
* k0 c- X& k- ?5 E1 `. R* }9 }  第2个参数是TIM_OC_InitTypeDef类型结构体指定变量,用于定时器输出比较参数配置。- b6 K3 |* B4 v8 ?! h0 v8 j
  第3个参数是通道设置,支持以下参数:4 _- N7 Q9 d+ A7 K3 f3 P1 {
TIM_CHANNEL_1
. Z9 g2 ^, x8 @4 h: d  M& F: D# S$ P( T- ?
TIM_CHANNEL_2& n) ?, e3 y% H, H7 l

6 }% G, @7 j! E4 LTIM_CHANNEL_3
  F$ @7 N0 C* d2 U! b2 {
7 |, b5 t/ @7 |+ p' MTIM_CHANNEL_4
, Y, l6 a) ^2 e' n7 D8 d/ v2 Q9 J3 I) }7 J! \
TIM_CHANNEL_5
+ a+ T% ~/ `; }$ S
) X- Q. C) [5 l: x# f% `7 Q9 ?TIM_CHANNEL_6
8 s4 r! W: L' Q0 `$ ~+ R2 F/ a2 h/ U
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
: o& l, E1 a2 c3 @使用举例:- K- [- \: J% J1 ?) M  c

8 [* o( ~3 U2 J+ o' h4 Z, P9 m
  1. TIM_HandleTypeDef  TimHandle = {0};
    + ?/ C4 h2 l' {8 l' ?0 n5 N
  2. 0 }6 {. L7 m# _* M0 N0 M) y
  3. /*  PWM频率 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)*/
    . e; M& f  K: |( A6 b% z
  4. TimHandle.Instance = TIM1;1 Y$ I( N& h: J* f: o
  5. TimHandle.Init.Prescaler         = usPrescaler;
    # {) G+ @+ y% C1 k4 K4 V+ }
  6. TimHandle.Init.Period            = usPeriod;* H  \) d4 F  c! l# {4 l' g
  7. TimHandle.Init.ClockDivision     = 0;0 ?7 F" V1 ?: `; W( H- F
  8. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;
    8 r) O$ y$ Q0 R- N& s* U
  9. TimHandle.Init.RepetitionCounter = 0;* h# `8 Q6 G0 m) R8 i( h& S
  10. TimHandle.Init.AutoReloadPreload = 0;4 m0 T/ x, z+ R* _5 T- I; ~# Z
  11. if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)
    ! ]4 G- V' W6 V5 n: H" v9 `& R1 A
  12. {
    ( H, O' R/ c0 W2 L6 l
  13.     Error_Handler(__FILE__, __LINE__);
    , Q$ o: C: w  s7 }, ?
  14. }1 c$ Y& V2 g7 F' ~
  15. 3 ~+ X: S; ]1 A( l8 U3 E
  16. /* 配置定时器PWM输出通道 */3 h+ X) @2 n$ g& G- z* g
  17. sConfig.OCMode       = TIM_OCMODE_PWM1;; c7 |' Y) g& ]# o+ H& x9 y# ?- s
  18. sConfig.OCPolarity   = TIM_OCPOLARITY_HIGH;
    0 _/ X0 _( K: @$ Z& u' `
  19. sConfig.OCFastMode   = TIM_OCFAST_DISABLE;3 n+ \, J) a0 I9 G  U; J
  20. sConfig.OCNPolarity  = TIM_OCNPOLARITY_HIGH;
    : e& ^, {, s3 {/ h& ^
  21. sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;3 d6 H- Y0 E  R6 t. s6 C
  22. sConfig.OCIdleState  = TIM_OCIDLESTATE_RESET;
    " l+ h7 D* v9 F' ?* n

  23. " L2 A, f- J4 ^
  24. /* 占空比 */
    / K- ]; @: z9 I, H$ d4 n6 N
  25. sConfig.Pulse = pulse;: j7 u1 Q0 ~: U* }$ e: n; f" r4 u( @
  26. if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &sConfig, TimChannel[_ucChannel]) != HAL_OK)
    * V' Q  R& R, X) G) l' K( w7 @
  27. {
    6 e( H% i' g# H7 ^9 `" N4 t8 }
  28.     Error_Handler(__FILE__, __LINE__);
    7 {! Q8 q) U, r; x3 N6 u+ d
  29. }
复制代码
$ ]: L# t: g6 p. w$ m
32.4.5 函数HAL_TIM_PWM_Start# `" B2 a) E6 E  b: k
函数原型:6 n$ |  ?% S& g: R' R
5 D9 J( L$ q0 U+ ~2 H- ^
  1. HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel)) U& P, h" w7 ?$ ~
  2. {
    ) j4 |  S: Y# q$ w4 t4 S* F& l+ L
  3.   /* 检测参数 */
    6 `) P+ @# [5 d+ k5 p
  4.   assert_param(IS_TIM_CCX_INSTANCE(htim->Instance, Channel));4 D% a0 S% V7 L. s6 j

  5. ! Z8 X- E1 b1 v( ^& r+ E0 m
  6.   /* 使能捕获比较通道 */
    . S+ A" b1 D  T4 E% H. H: A
  7.   TIM_CCxChannelCmd(htim->Instance, Channel, TIM_CCx_ENABLE);- j! h0 t0 k3 D$ I2 l; F+ x; L
  8. 4 c6 X9 s2 O/ w9 k/ F4 P
  9.   if(IS_TIM_BREAK_INSTANCE(htim->Instance) != RESET)  
    5 h7 j( h2 v) d% r7 M$ U
  10.   {/ u3 f5 v# M! D
  11.     /* 使能主输出 */& T. e) `% c7 ], h- M
  12.     __HAL_TIM_MOE_ENABLE(htim);4 G7 m7 i: {5 s# G( k- w0 p/ x
  13.   }
    8 L6 W2 T) s  `1 b

  14. 2 G+ h& j/ V4 w: \/ Z
  15.   /* 使能定时器 */
    ' K. n* Q8 Z# `( E) }
  16.   __HAL_TIM_ENABLE(htim);7 U* b; I% h) i& P5 T7 n

  17. ' p8 \% q1 F. E8 V
  18.   /* 返回状态*/
    * S9 }) F7 n7 y7 p9 Y
  19.   return HAL_OK;
    2 B) l# F, _, S( c9 o8 X5 u8 L1 [
  20. }
复制代码
& `+ H% G$ ?, Y6 X( q" s9 x
函数描述:5 G4 h2 m) `/ Q. Y' l6 u

0 w9 u& D- U! N# D2 f此函数用于启动PWM。
' V/ A. u  y6 \# R
( b- k) b: ^/ v, x# |0 E函数参数:3 T$ R" |$ n1 B+ o

+ l$ ^; |# c4 S  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。
% x) F( [6 p9 o3 d2 C3 o3 @+ S  第2个参数是通道设置,支持以下参数:% U* w, s( C  V, P
TIM_CHANNEL_1# Q& v. M/ |( W

2 [. i; J6 B- b& T2 LTIM_CHANNEL_2) @% ~- g- c/ h( Y' f: U
6 s6 r! S5 f2 _% K' w( Y; `0 h
TIM_CHANNEL_3, u# S; {8 X5 W) U/ k' x# k- [

( f' ?: h8 K7 VTIM_CHANNEL_4' u  D- q- \6 U) c
/ ]/ C! P% J$ S2 E
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。% k' @1 I8 a- V) x
使用举例:1 b$ o3 \1 G$ T+ N# y

+ q9 I2 P; r0 f$ M: [3 P6 f5 T
  1. TIM_HandleTypeDef  TimHandle = {0};8 L! G7 s1 c" X1 o6 C- E$ H5 Y8 z
  2. $ h9 h3 N0 }9 \' l) ?
  3. /*  PWM频率 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)*/6 o. B$ D) T, \, x- o+ k* p+ Y4 W: m9 F
  4. TimHandle.Instance = TIM1;/ Z; v8 V7 N0 W8 f2 G9 @
  5. TimHandle.Init.Prescaler         = usPrescaler;4 d& n# `; g/ y$ A& o: l' b2 f
  6. TimHandle.Init.Period            = usPeriod;( |  t5 F6 t! }5 u8 q1 A
  7. TimHandle.Init.ClockDivision     = 0;
    0 f. r/ v: r  x& b; ?; H$ Y) s, \
  8. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;) {; _1 _5 G4 E# y$ u' P7 B0 z; T
  9. TimHandle.Init.RepetitionCounter = 0;& D9 ^1 j' U. P9 j; _* U" ~
  10. TimHandle.Init.AutoReloadPreload = 0;( F2 @5 d& U; Q, B
  11. if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)& ]2 o& c1 S8 ^6 l% p1 r& k
  12. {; g* v) }, i! r5 C3 A( k8 M$ P
  13.     Error_Handler(__FILE__, __LINE__);
    3 r% V/ b3 k! N9 j1 M* \
  14. }
    $ w8 R; v( \, U7 e) I- J4 l2 h: G
  15. " L4 m% h% p" B* g
  16. /* 配置定时器PWM输出通道 */) u# p0 L& H  L. b! |4 ?+ c+ q
  17. sConfig.OCMode       = TIM_OCMODE_PWM1;+ y8 ]  m+ A; G3 s: M
  18. sConfig.OCPolarity   = TIM_OCPOLARITY_HIGH;0 U+ R, m2 K6 P: [
  19. sConfig.OCFastMode   = TIM_OCFAST_DISABLE;
    & S8 U5 h8 M; ~* Q
  20. sConfig.OCNPolarity  = TIM_OCNPOLARITY_HIGH;
    3 |& v- a# q" s# w" u) L0 h/ Z
  21. sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;
    3 g+ n3 T0 I4 X
  22. sConfig.OCIdleState  = TIM_OCIDLESTATE_RESET;
    4 N) l0 \  q7 K
  23. / y1 Q" p3 D: k" @
  24. /* 占空比 */) u# _' X( ]# r, M
  25. sConfig.Pulse = pulse;
    $ v, E& U  \. h% m. d3 S/ ?
  26. if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &sConfig, TimChannel[_ucChannel]) != HAL_OK)
    - K: e, M3 Z5 E3 d% o2 s, C
  27. {
    & N1 q2 J  ~$ v$ J1 U
  28.     Error_Handler(__FILE__, __LINE__);
    4 y  ^3 P" q5 t& U
  29. }' Y6 i* v% M; [

  30. 7 R* P3 \6 N( x( g8 ^
  31. /* 启动PWM输出 */
    6 X! r! i/ ~1 z* B4 m5 U8 D
  32. if (HAL_TIM_PWM_Start(&TimHandle, TimChannel[_ucChannel]) != HAL_OK)
    + ~) O6 m4 f5 W; s: @8 r+ N% h
  33. {, @- ^+ t; u+ Y& ~0 c; ?. t! O
  34.         Error_Handler(__FILE__, __LINE__);; B2 Q. @9 s. S% z
  35. }
复制代码
) o3 s2 W1 z( [0 q
32.4.6 函数HAL_TIM_IC_Init
. _7 T8 }' T" C( w函数原型:
$ q. w4 e% E" w
# L9 h- }6 t6 r. C) M0 E) o" I4 h
  1. HAL_StatusTypeDef HAL_TIM_IC_Init(TIM_HandleTypeDef *htim)) z/ H# _9 o* w' x! ]
  2. {: l0 w; @) L0 r
  3.   /* 检测形参是否有效 */
    7 p- k& @: s8 x! j
  4.   if(htim == NULL)
    ' ~' m" p8 n4 T/ [& O! N. Y# w: B
  5.   {0 t( D1 q( @  A1 a' i# [- p- E
  6.     return HAL_ERROR;6 J& ^! E  @- q7 C: Y
  7.   }4 N) d* Z( b; S$ w: y7 @
  8. 5 q3 m/ l/ o1 ~1 y0 O
  9.   /* 检测参数 */
    1 S/ s! s; J: s& K5 e
  10.   assert_param(IS_TIM_INSTANCE(htim->Instance));) h/ A9 g  K0 \9 G
  11.   assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode));
    , O" V) j' d5 R7 j9 R, m/ m
  12.   assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision));
    0 r- t. }" l" F  q' |! Q

  13. 0 ]; B0 J4 e- B
  14.   if(htim->State == HAL_TIM_STATE_RESET)0 n2 Z9 Z) Q6 }8 g8 {/ b
  15.   {
    " w9 e* f3 ?) h1 I
  16. /* 默认取消锁 */
    , m, o5 K% i+ t" Q5 r  O
  17.     htim->Lock = HAL_UNLOCKED;7 G" T- X3 [7 E; ~; C
  18.   L& V2 l( W  r; N% C
  19.      /* 初始底层 : GPIO, CLOCK, NVIC 和 DMA */
    ; [9 \, \" w! ]  j
  20.     HAL_TIM_IC_MspInit(htim);$ j! m; J  A/ I5 g
  21.   }7 ^0 b8 u; g2 w$ E+ ^7 e/ v& L

  22. 3 N% H, j3 y  G! o' M
  23.   /* 设置定时器状态 */
    % a6 a- M- G& B& w3 S- I
  24.   htim->State= HAL_TIM_STATE_BUSY;
      y( y$ V3 A3 E& A/ ^

  25. ' {- M; v* g4 Y% |0 C: z% a7 x: @* T
  26.   /* 配置定时器为输入捕获模式 */  . e& k* c# w5 A& S. b
  27.   TIM_Base_SetConfig(htim->Instance, &htim->Init); " u8 N1 C# Y! Q$ A* x
  28. . v/ ^0 y  z2 Y1 M( C7 i) V( q
  29.   /* 设置定时器状态 */5 {2 G) n6 C8 m5 t) X$ I
  30.   htim->State= HAL_TIM_STATE_READY;; G& E+ J, ^' Q6 Q/ c
  31. 4 G& R0 N% ~( n+ X4 |8 \
  32.   return HAL_OK;
    - u( I* X$ V4 _  z" u5 x6 x6 X
  33. }
复制代码
8 @8 ^5 D3 Z3 A4 E- w1 m
函数描述:9 X  G! y8 o. P  P. y; X" u' B

4 l1 y# X) @1 k8 F2 B1 G此函数用于定时器输入捕获初始化。
- n/ g$ J5 V) X; C; u! h3 ^- b& `' H
$ w, m+ S' A1 t8 ^! l7 l函数参数:+ y, g. E- k2 f, Y; x& x
; X+ W6 C: j0 E: }* ]# |6 A' P
  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。
! {7 L( U& E+ V  T% N* T  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
, N1 o# D$ Z9 e/ o; z* ^注意事项:
4 v, F+ V; h$ u& R
/ R" h; @) l8 X函数HAL_TIM_IC_MspInit用于初始化定时器的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能,由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。' c3 O& e# d9 G  S$ R! l
如果形参htim的结构体成员gState没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量TIM_HandleTypeDef TimHandle。( e7 a+ J8 R5 Q& J4 q/ t# m3 _
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个HAL_TIM_STATE_RESET  = 0x00U。: x2 M% P4 D) D* C- E- ^
. x& g# q. t0 N( l9 y
解决办法有三:
+ _, p9 f9 i- G2 a: u8 D, |9 |* r
& ?% P/ W+ P: b方法1:用户自己初始定时器和涉及到的GPIO等。
' F# v6 }4 q  w# O! o# c
& B& ]6 r+ o. \% K8 h方法2:定义TIM_HandleTypeDef TimHandle为全局变量。
/ W. k+ [8 ^8 G) ~9 q4 T7 }
' D, ?( Y# m4 j$ d方法3;下面的方法
" T7 w2 l& C* L3 g) S" T' q$ t* x( i4 m
  1. if(HAL_TIM_IC_DeInit(&UartHandle) != HAL_OK)
    ! o3 O/ F6 Y7 Y# G% M: L$ g5 P
  2. {
    6 l- C# d3 A: @, ?6 w
  3.     Error_Handler();; B) `+ R! V# v( [) L
  4. }  - H3 l4 e5 h2 N4 i0 V5 F8 z8 Y" q- p
  5. if(HAL_TIM_IC_Init(&UartHandle) != HAL_OK)! Q. v! R- }: S
  6. {( o! ?1 r% B, v: @, A+ T  Z
  7.     Error_Handler();/ N& Q5 i3 V; P- u: v9 M
  8. }
复制代码
7 p6 ?" w0 X! ~% ?* f5 R0 I
32.4.7 函数HAL_TIM_IC_ConfigChannel
" d1 o! Q: e, }# h6 V  h7 K/ a函数原型:
4 z$ ?2 z8 F+ e  Q2 z; c- C) J  q, j! ?/ O0 G( m1 P* S
  1. HAL_StatusTypeDef HAL_TIM_IC_ConfigChannel(TIM_HandleTypeDef *htim, TIM_IC_InitTypeDef* sConfig, uint32_t Channel)
    7 d/ T3 v, K9 L' U7 i& F
  2. {
    ; _) M' G# q" y0 x+ K4 r
  3.   /* 检查参数 */* f+ {, e4 W# i4 ]2 i  ~1 q! Q# W5 V& w! s
  4.   assert_param(IS_TIM_CC1_INSTANCE(htim->Instance));
    ' y7 l. a; j" o) t* H: e6 h
  5.   assert_param(IS_TIM_IC_POLARITY(sConfig->ICPolarity));7 [: v& K$ Z$ E2 B; i
  6.   assert_param(IS_TIM_IC_SELECTION(sConfig->ICSelection));; W3 i3 A8 Q6 `! n& ~
  7.   assert_param(IS_TIM_IC_PRESCALER(sConfig->ICPrescaler));# }* }; I/ q, n% b8 Y
  8.   assert_param(IS_TIM_IC_FILTER(sConfig->ICFilter));
    2 c1 X2 Q! I% o# S6 {2 c3 o1 B

  9. . `+ x; S0 j9 ^& N( N
  10.   /* 开锁 */  7 {# M1 [9 h" _1 R
  11.   __HAL_LOCK(htim);
    - i6 m4 E! G" }
  12. + `$ o  O) p( `+ d/ B
  13.   htim->State = HAL_TIM_STATE_BUSY;
    # |5 D5 K1 |, b8 r) A% K) t
  14. / m& H1 r6 B/ Q4 d! L& i
  15.   if (Channel == TIM_CHANNEL_1), A3 h( U3 V6 L9 R8 Q
  16.   {. q  e, j/ ^) B( ^. o, S" q1 ]
  17.     /* 配置输入通道1 */% ?) K0 v- P% ]
  18.     TIM_TI1_SetConfig(htim->Instance,; A/ w' |5 }' J) t$ p
  19.                sConfig->ICPolarity,
    9 l: l: T! O  ^% R  W
  20.                sConfig->ICSelection,
    : N+ l; X5 [/ H! N2 q
  21.                sConfig->ICFilter);& {! r) p8 K" c  u+ d; @3 Z7 ?
  22. , @( Z( g% j& l: L
  23.     /* 清零IC1PSC位 */
      I# m. z! a9 {% e" f
  24.     htim->Instance->CCMR1 &= ~TIM_CCMR1_IC1PSC;
    ; ?1 d6 o9 U) c" i4 }. |4 L1 K0 m8 W

  25. 8 E9 k+ N  s  f1 p7 |% ^) ~, v
  26.     /* 根据用户配置,设置分频 */
    $ p/ P! |" ~. R- _- q+ J
  27.     htim->Instance->CCMR1 |= sConfig->ICPrescaler;
    0 ^$ ?! o( D  y# y# @
  28.   }) J3 f& J) s7 e; J. }
  29.   else if (Channel == TIM_CHANNEL_2)5 _2 l% ]- \+ X
  30.   {
    3 Z+ @( p. A4 y. h! i
  31. /* 省略 */1 G: N2 F$ J$ D1 |
  32.   }3 A: D# C# ~$ Q+ R
  33.   else if (Channel == TIM_CHANNEL_3)
    ( l8 H9 F# m2 s% p
  34.   {4 s0 g, x" y9 w+ q0 }
  35.      /* 省略 */  |# F# P6 x* M  g4 A
  36.   }! ]: {* k+ f1 d7 J+ R0 X! I3 ?
  37.   else& F% [& ^5 f) h
  38.   {& P1 g2 p2 i( B3 R- o( G. _8 T
  39.      /* 省略 */
    , S. m7 M% F" E' k% ^
  40.   }
    # g* x; E- C, e0 T/ F2 |3 r( K
  41. . a; @; }3 b$ m) P
  42.   htim->State = HAL_TIM_STATE_READY;
    . L/ R& m+ I6 P7 t
  43. : A) U# k% \* V( M2 b! C
  44.   __HAL_UNLOCK(htim);! }! C# p3 I" i! `0 I: e# M
  45. . T: p4 z' h& N, C6 Z" s' k
  46.   return HAL_OK;
    : k% }+ H7 S9 \0 P2 b2 f
  47. }
复制代码
3 G3 D6 d8 v; i6 [
函数描述:
! T% U" U1 l) H% F' W* l
# H1 U: p9 D; x. K% o- \7 ^( R此函数用于配置定时器的输入捕获通道。
* O# H1 i' e/ w8 s3 Z. ^2 I6 r3 D  A- s/ P; a! m/ [& \" q$ V7 b8 o3 C( L; s
函数参数:) p# ~" o5 c* s7 `  |
1 ], a' |# ]* ]- w3 t
  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于定时器基本参数配置
* c( k! k: O. C- v  第2个参数是TIM_IC_InitTypeDef类型结构体指定变量,用于定时器输出比较参数配置。% h& k8 }$ |. p+ l
  第3个参数是通道设置,支持以下参数:. P/ s) v6 i  a
TIM_CHANNEL_1
4 g3 v7 z: }" A$ C( n' d1 \; b& }* ], n4 K& a7 r
TIM_CHANNEL_2
  N0 f. z& ^- M3 z
% y/ K# I/ {# E2 A' HTIM_CHANNEL_3
% @( |$ w3 k0 O! Q* ^+ U# J& J3 ~) P; M1 i$ f3 Y8 g
TIM_CHANNEL_4
' V+ ]: c) I, u( C* T9 S
, b4 v' `+ S0 q0 i1 a  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
5 ^3 W1 n8 \- M# |8 u) \, q. C2 e  {
32.4.8 函数HAL_TIM_IC_Start_IT
7 n9 i3 S/ e. n9 j; a函数原型:4 @2 j# K" I- j: w8 a

, q& o$ ]- @$ R$ H. d% \7 }
  1. HAL_StatusTypeDef HAL_TIM_IC_Start_IT (TIM_HandleTypeDef *htim, uint32_t Channel)
    * U8 D, Q/ @& J# Y5 `
  2. {3 p% k4 o7 m' H
  3.   /* 检查参数 */. x* U: Q9 C9 c% A
  4.   assert_param(IS_TIM_CCX_INSTANCE(htim->Instance, Channel));
    * l* ?. q* a4 B8 Q5 a1 D' K

  5. / h. `9 R( o/ g0 U3 r" W' d. @- ^
  6.   switch (Channel)
    ! I8 w  }0 ]" q2 t& Q( N
  7.   {6 k- C4 K5 t4 f3 v' N3 v  e1 _
  8.     case TIM_CHANNEL_1:
    ) }% R, g7 j  s& `7 C# T1 ^% r3 j
  9.     {      
    + @  N4 M9 }( T4 r) Q* z
  10.       /* 使能CC1(Capture/Compare 1)中断 */% }. I6 T* y. g" P* w: }3 X9 m
  11.       __HAL_TIM_ENABLE_IT(htim, TIM_IT_CC1);
    7 z' b- g! \; d. r7 {9 o* e
  12.     }+ X0 f8 H7 {0 e* l
  13.     break;! F( t7 g, P0 _4 b7 A5 u
  14. + U+ O3 x$ i) ]; n2 i5 w
  15.     case TIM_CHANNEL_2:
    2 I+ P" g& e+ Y$ Z8 T4 I0 U* T: Y
  16.     {! Q- g4 X% U; V
  17.    /* 省略 */8 ~# n( V! M0 K; u& _- m* |# l
  18.     }+ v; s2 g# l' |0 k: D* m6 x
  19.     break;
    $ v+ U' k9 _# E! V5 v4 ^7 D
  20. , G8 d4 h. E7 j6 R
  21.     case TIM_CHANNEL_3:0 s8 p5 ^+ r1 h& S  K+ I3 X
  22.     {
    ( X9 ]: h8 X. G; k/ G6 n, i% v
  23.   /* 省略 */6 E, R, C# R* T$ s$ ^
  24.     }
    6 i- D4 ]# \1 B9 J& c5 X- V
  25.     break;3 k3 \0 y% ?1 N  H- V* Q2 T! X
  26. . l( e$ h9 Z8 ]3 E  z) h% v5 P! X
  27.     case TIM_CHANNEL_4:$ p+ x& S) Z! n0 [$ s
  28.     {5 y6 _6 z! G( X; h* e) _
  29.   /* 省略 */
    ; v0 o( q. Y7 \# h, u- _$ C
  30.     }
    & g! c  p# E  t' I0 L
  31.     break;$ S1 A, o& z8 d
  32. ) M. ~, ^2 Y/ w  V& ?( z$ F$ P
  33.     default:8 a* q/ w; j; D8 d# k) l2 w7 \9 P8 H
  34.     break;
    & m# t) ]6 @6 ~5 s; f7 j3 h
  35.   }  2 `' G4 k, D) _* m! x: s
  36.   /* 使能输入捕获通道 */% ^# I( {  l, N; N
  37.   TIM_CCxChannelCmd(htim->Instance, Channel, TIM_CCx_ENABLE);
    ; q  P, X: w/ C/ k

  38. ( I9 E& Z2 v4 ?& z- f
  39.   /* 使能定时器 */' M& q( Y( A. p, {* Q/ b6 o
  40.   __HAL_TIM_ENABLE(htim);  
    4 k3 W7 V  h" O$ r
  41. 5 W) g4 I6 [  j% B& ~! w5 ]. ]
  42.   /* 返回状态 */
    1 ?. _1 |7 ?; W  s
  43.   return HAL_OK;  3 F* j- l9 |$ U: k, Y6 R( ]1 Q5 a% x
  44. }
复制代码
1 l4 o  O& x0 t% a, t, Q% R' q3 }
函数描述:
: v- K" D# p5 w8 `# H. x/ v
5 x3 C, ]# k: S5 m此函数用于启动定时器输入捕获模式,采用定时器方式。
9 ^% v3 u& W) L$ ~  ~6 m8 R# w6 s! y+ v* x( A! q/ V
函数参数:9 Q& ]& Z2 g3 }. z" k; p. f

, D( m7 Z+ k9 w9 T  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。
, F  x. n- r; y$ ~2 b+ w  第2个参数是通道设置,支持以下参数:
8 {4 \* e: u6 p3 W9 a" OTIM_CHANNEL_1
( g) t- }7 ]. j: }) U  z  i
9 P* G9 Q3 [2 t7 n) F0 e6 N7 mTIM_CHANNEL_2" O# M9 v8 s* P; F
8 x, l5 e1 X- p
TIM_CHANNEL_3
+ m  S) P/ Q7 S2 [& Y3 g  {$ x0 b
TIM_CHANNEL_4
6 A* u+ `! h. O4 P. ^+ z( w) w# z2 a
7 m: e! M0 V  G% _( I/ k  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。9 z2 v4 A$ \3 q! [# f
9 r2 z8 r7 ~/ ]
32.4.9 函数HAL_TIM_OC_Init; A8 y. {! Y% }$ R2 r
函数原型:* f  z1 g7 l# q* s  [+ {3 h

! @5 Q2 A4 I( p3 @
  1. HAL_StatusTypeDef HAL_TIM_OC_Init(TIM_HandleTypeDef* htim)! X( I, E. F: @7 F
  2. {
    7 @1 s- Y: D- E
  3.   /* 检测形参是否有效 Check */7 o2 W& m5 d/ N& C
  4.   if(htim == NULL)7 D  P6 U8 N) X* l" S
  5.   {0 g. \; [* e9 S  P" V6 [
  6.     return HAL_ERROR;
    + f; W/ j& w$ A; ^, S. P9 t9 i  x
  7.   }4 p, I. h, H) A3 _1 v2 J
  8. ! x1 j0 P5 ^4 v1 ?* x
  9.   /* 检查参数 */, Z# i, l% i& q  `( |: e% ~
  10.   assert_param(IS_TIM_INSTANCE(htim->Instance));8 G  {% J9 F; R  m* _
  11.   assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode));
    ) ^5 I" w2 j/ L$ D
  12.   assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision));
    ' o# X# Z/ @" V6 H6 x
  13. / Q  H4 l( Z3 ~& S# q1 C, M, c
  14.   if(htim->State == HAL_TIM_STATE_RESET)6 q: C1 |% T% h6 }5 \3 H; C
  15.   {
    ' g! O$ Y1 {4 K' l8 D6 w$ \) w
  16. /* 默认取消锁 */7 W0 K! p* `0 u' V6 x
  17.     htim->Lock = HAL_UNLOCKED;
    / |. w5 b" U2 s3 A( Y  K/ d: U! u

  18. ; T' _- Z" }. w' W- {" k
  19. /* 初始底层 : GPIO, CLOCK, NVIC 和 DMA */$ J* ~0 e( @. B# y
  20.     HAL_TIM_OC_MspInit(htim);
    ! n. M" F* P6 v* r+ n
  21.   }
      m$ V7 P0 Q; B- J% w

  22. * c! \& o# B- D% O9 J( r
  23.   /* 设置定时器状态Set the TIM state */6 W: l- w( D3 D3 r) T% n  t
  24.   htim->State= HAL_TIM_STATE_BUSY;
    & H9 D: [% Y; ]8 F
  25. 2 L& r- o# B4 Q* Z. @" U% Q
  26.   /* 配置定时器为输出比较模式Init the base time for the Output Compare */  
    3 n. |9 b0 J% h7 q
  27.   TIM_Base_SetConfig(htim->Instance,  &htim->Init);
    + }/ _/ N: j7 w3 S5 ]

  28. " i* }# r4 @* V* f) G7 F6 H
  29.   /* 设置定时器状态 */
    7 |# P) ^, C- g; t  y) H& B
  30.   htim->State= HAL_TIM_STATE_READY;
    5 v: \6 P8 E, s0 {' t6 x

  31. % p- X& e( A# B1 ]1 W+ K9 ^7 c2 G- W
  32.   return HAL_OK;
    4 B4 d3 z$ m4 U% X! f& m- @
  33. }
复制代码

5 P+ _1 |$ I$ C$ P0 H$ w3 u" b# u函数描述:& w  ?, c  P, O5 `! Y6 N; L  K

6 I; C1 h1 q$ i5 }0 ~! g6 u此函数用于定时器输出比较初始化。
; l) n; m  J" B/ ]$ M  `) i1 Z
% W0 D- Y- F8 g  k- A函数参数:
' \& v9 b  S/ C! d' E# E% Q
4 G! D) ?: i$ u/ p% r$ S  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。4 o6 @( D3 b" |! X) c4 A; x
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
% H6 `. @0 m  g) _( n. Z注意事项:, x4 W& V3 c( c# x6 J! M. f7 R

/ A  G7 [6 R! z' V) d: {函数HAL_TIM_OC_MspInit用于初始化定时器的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能,由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。* }5 N# w/ V5 V9 X+ g' q
如果形参htim的结构体成员gState没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量TIM_HandleTypeDef TimHandle。
! j. k. F) Y# X: \/ T! \对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个HAL_TIM_STATE_RESET  = 0x00U。
; Q6 Q+ s; w4 _5 {/ Y
6 d- ^+ R$ \. D) R8 g解决办法有三:) D2 ~5 v0 ?$ |
" R( n- @) i* Y  P
方法1:用户自己初始定时器和涉及到的GPIO等。1 i- m6 n9 N. ?- S( [9 R; z6 ]$ ?

7 k% A) h8 q+ w# w. j方法2:定义TIM_HandleTypeDef TimHandle为全局变量。2 t; m+ V7 r* M

+ F3 k1 Y5 A1 t5 w" N$ O方法3;下面的方法
: G5 D( r# a0 G4 x, v# _( O& o
! e2 ]7 [: Z4 k' o0 U
  1. if(HAL_TIM_OC_DeInit(&UartHandle) != HAL_OK)- r8 l: ^! R" [" l' f& D7 f- I, X
  2. {1 c$ c4 n  b( \9 F% L: B9 A
  3.     Error_Handler();) Y$ I9 ?5 ^+ {4 S1 p
  4. }  
    ( z! x& p  s( W) r* S( E& q( Z8 w
  5. if(HAL_TIM_OC_Init(&UartHandle) != HAL_OK)
    9 U2 d, t0 b' I# M
  6. {
    1 z% a" g! F$ v6 r  D" M
  7.     Error_Handler();# }3 ^; [& i1 c' x: k: l
  8. }
复制代码

8 K4 B* L, t+ }: @7 }: m8 F" I32.4.10   函数HAL_TIM_OC_ConfigChannel
9 y; }2 w( l. V2 N) W函数原型:- Z' I% B" s5 F* H; E
9 J; U: z3 A; W0 }" M* R
  1. HAL_StatusTypeDef HAL_TIM_OC_ConfigChannel(TIM_HandleTypeDef *htim,; v( ]# P1 h: a& Y9 \0 w1 Q
  2.                                            TIM_OC_InitTypeDef* sConfig,; M3 U! m0 S2 m4 S1 Y' N
  3.                                            uint32_t Channel)
    % }# P7 ^. q' ~
  4. {  
    ; m: p# w: ?4 V1 P
  5.   /* Check the parameters */
    , h. n( Y& x  n3 X% B# x/ P, @
  6.   assert_param(IS_TIM_CHANNELS(Channel));
    7 g1 B& A$ B: K! A0 `
  7.   assert_param(IS_TIM_OC_MODE(sConfig->OCMode));
    8 M- L. Q7 ]/ w7 G% E, n0 d% x
  8.   assert_param(IS_TIM_OC_POLARITY(sConfig->OCPolarity));. M. Z' F# X: [
  9. + r3 Z# a# p, l- r' Z
  10.   /* Process Locked */: o( S" {$ G9 }( O
  11.   __HAL_LOCK(htim); * y8 D+ M/ T* b. T" k8 l1 R4 F9 _; J8 A

  12. % F" H. w# d& m0 z* b) _
  13.   htim->State = HAL_TIM_STATE_BUSY;
    4 M/ o3 T. ]( d! F

  14. . J, q( b; i: L9 f! h) X- p
  15.   switch (Channel)! I/ [, j. q4 ]* {4 h9 ~; H) O% q
  16.   {& A0 d: K1 n. H9 R# }! ], x& E! g" O
  17.     case TIM_CHANNEL_1:. b. l( T; S$ _4 }% t  I
  18.     {
    # e; E+ G1 G* ^  g( m/ Z
  19.       /* 检测参数Check the parameters */& E2 ?/ [4 ]2 ^; b( ~
  20.       assert_param(IS_TIM_CC1_INSTANCE(htim->Instance)); : {4 y8 U/ k' T* \" P

  21. * Z& P0 P( `- \
  22.      /* 配置定时器输出比较通道1 */
    , r6 z2 j* Y* m! G; T& P7 f1 a
  23.       TIM_OC1_SetConfig(htim->Instance, sConfig);/ G- J4 s# ~. b. x0 i8 L
  24.     }
    6 B! h" t3 b4 [; Q) b, [1 c
  25.     break;
    + ]7 k! ~6 ~6 ^

  26. . S4 f0 a# R# F4 r1 O( I
  27.     case TIM_CHANNEL_2:
    ( g: L# n$ h6 m( A: ^/ H- ]4 j
  28.     {2 O+ s8 G& ]+ p' y- n8 R
  29.       /* 省略 */3 s+ j* H9 r) _* M, h' c
  30.     }
    % r/ l( G+ X4 ?
  31.     break;6 F8 S" |4 C, w' i( Q) X$ t
  32. - L& K; h% e. m
  33.     case TIM_CHANNEL_3:
    - D1 [9 `& h9 y3 S% q- N
  34.     {
    4 o7 ~( R0 K+ Q. F7 p% Q0 Z
  35.       /* 省略 */5 Q) b9 s. ~4 M: V9 K' D+ X
  36.     }$ j" u% }3 Q6 W. _2 r
  37.     break;
    # ?+ H  K+ R; f0 F3 a

  38. ; w, ~( J$ y+ ?4 e) c; ?6 a
  39.     case TIM_CHANNEL_4:6 @# G) m# |8 o5 ]/ C3 `* P" x
  40.     {
    : h. I1 |$ t7 D
  41.       /* 省略 *// A- i7 L" \# i( G) y6 [( m3 F
  42.     }
    7 H# ^: j3 Z! q6 r
  43.     break;
    1 w& W6 R- K6 {3 i

  44. / N, u8 q5 }0 D* Y( N+ F
  45.     case TIM_CHANNEL_5:
    7 q; V8 V6 w, `
  46.     {
    6 M- C0 r9 ]; g* ]8 |+ c
  47.       /* 省略 */
    % B- O1 {3 l8 g" b; L  y7 l* ]9 S& i
  48.     }4 M  \: U( Q3 l' m
  49.     break;
    9 k/ B6 p' ^0 F4 c6 S+ h" ]" y; t

  50. ( b# |5 o; w* a6 E' j
  51.     case TIM_CHANNEL_6:
    & g3 h# i3 S4 m  U4 ~
  52.     {6 B8 a2 y' t9 p9 G7 H) C
  53.       /* 省略 */
    ) G/ }: h0 M+ F% m
  54.     }
    / P" v& n& U3 U
  55.     break;
    $ R/ k2 G6 v1 e+ S
  56. . `7 }$ G$ }( a8 p) G
  57.     default:5 h: I4 t; }/ n, P/ }! t( H
  58.     break;   
    ( u, q9 J: T9 H7 ^: b
  59.   }
    6 g3 D6 \. e% G3 a7 }
  60. 5 c$ ?* _$ ~  r
  61.   htim->State = HAL_TIM_STATE_READY;! J$ R6 `* @0 d5 y! O

  62. , l  c8 s) \( f
  63.   __HAL_UNLOCK(htim); 7 R4 Z+ D" g- `" T1 D
  64. & s3 Q: ~/ h0 l% ~8 Z' e: @, y
  65.   return HAL_OK;! ~5 D. g$ f" A0 m, D
  66. }
复制代码
& g" l% n: g( P2 Q
函数描述:- W8 G' ^! Q7 e& m8 l  Z
0 g! h3 i  I& x: |( I$ D$ o3 ~
此函数用于初始化串口的基础特性和高级特性。
+ j) Q6 p& R: y
$ H7 W4 c" x# |函数参数:' v& K* M' q6 U8 ^
3 n. Q9 @1 ]% ~! b% I7 ^+ t5 y
  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于定时器基本参数配置。
6 q8 a% x& {5 a  第2个参数是TIM_OC_InitTypeDef类型结构体指定变量,用于定时器输出比较参数配置。
1 w% z$ y" P4 r3 y8 L5 p  第3个参数是通道设置,支持以下参数:
. _1 J7 R' n5 K$ B) e9 B8 G8 y* gTIM_CHANNEL_1) U1 N! P* n/ c; f9 m- g3 T7 I

% P1 d/ I" c2 F! y7 S; W% [4 ETIM_CHANNEL_2
' w& }( L$ |/ G, k3 ?( u3 d9 K* e* q; `( p
TIM_CHANNEL_30 U+ E9 j6 ]5 i

# F, _: b  Z9 R, W) d1 r' WTIM_CHANNEL_4% ]0 ], m1 K. Y2 `+ m

: Y1 |, F: G; v9 s2 E0 dTIM_CHANNEL_5" d' j8 Z0 b4 f7 I, {7 b# |
; B0 k/ J5 `, h" t* d
TIM_CHANNEL_6
( i( L$ t) m& P6 m# h0 m, C
/ }5 [4 P5 r& t$ r: q8 H/ u4 m  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
7 p9 n" G, t8 F. e8 j; E2 E0 i5 o7 x) e/ y/ F; X. U+ h
32.4.11   函数HAL_TIM_OC_Start+ m, s% y% _+ ~& [' i& |9 l
函数原型:" i7 u1 ?6 ]" L, s
2 T0 O! n. q! B7 K0 n1 y" m% B! w
  1. HAL_StatusTypeDef HAL_TIM_OC_Start(TIM_HandleTypeDef *htim, uint32_t Channel)) e- s" d9 u( U0 w$ X
  2. {
    ! i5 ?# e# V( H$ I
  3.   /* 检查参数 */
    8 a. U" d5 \$ w4 q4 y
  4.   assert_param(IS_TIM_CCX_INSTANCE(htim->Instance, Channel));$ ]6 M0 T$ f4 ~5 o

  5. 6 W1 [- i* T0 M5 T+ `# \$ I
  6.   /* 使能输出比较通道 */" G$ N, ], i* n5 h5 ^" ]  r
  7.   TIM_CCxChannelCmd(htim->Instance, Channel, TIM_CCx_ENABLE);
    # R/ p+ Z- ]3 s' t. j* b

  8. 3 c" q& L; u9 }. R
  9.   if(IS_TIM_BREAK_INSTANCE(htim->Instance) != RESET)  
    1 `$ j& h6 e" u0 e) p
  10.   {
    & N/ i0 _, S) l0 u% n' o
  11.     /* 使能主输出 */. D$ B8 _- N: G) `; T$ Z
  12.     __HAL_TIM_MOE_ENABLE(htim);+ A1 K0 `  g6 Q' }
  13.   }. Y+ Q7 f, |& s5 Z
  14. , K( I/ Q. h" v  i
  15.   /* 使能定时器 */
    + N3 n/ [& c% l! N: ^! B5 d7 {
  16.   __HAL_TIM_ENABLE(htim);
    ' F/ Y/ C2 K$ d

  17. ! f, T' F  x+ F& S- r+ P- Z, u
  18.   /* 返回状态 */
    ) U# t4 A% ^' J6 D
  19.   return HAL_OK;2 _$ n4 h& C+ p  k" ^1 s2 p) O
  20. }
复制代码
- ~8 `* S& e# W$ m
函数描述:- z) w( ^7 Q& ?. l+ I/ q4 j

/ k# v7 s/ y5 H- {3 M; X% O% g此函数用于启动定时器输出比较模式。
3 |! Y! `  |0 Q& z2 z) t' R1 T. c- ~( V5 S. t' Z
函数参数:* }8 q( h' V8 z
6 T9 _0 K& I/ q; }9 I2 E& G( G
  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。
: G, g" x3 b2 j" A) Z; K8 V  第2个参数是通道设置,支持以下参数:, ^) L, B. p  k1 q
TIM_CHANNEL_1) E% D, ~4 V9 n$ B

. l2 R4 }9 i# E: R; p! h/ R' {8 K* kTIM_CHANNEL_2
1 Q# P" S3 J. k  a
2 z/ Q( |, o: o9 }6 P# U: nTIM_CHANNEL_3
' G8 l) H8 N2 o7 l6 p. I
( _: N" V0 z0 D! wTIM_CHANNEL_4
1 i; c; [% L3 e/ \0 Z6 N3 _0 ^, U. H0 e2 P0 f
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
. Z% {8 E0 w* W2 W1 q  M6 M) ?
. p( k2 ]' A7 D  w32.5 总结+ S2 O4 D0 e0 ~7 s  n
本章节就为大家讲解这么多,建议大家将GPIO的驱动源码结合参考手册中的寄存器通读一遍,对于我们后面章节的学习大有裨益。
+ ?) Z2 F! D- \9 U+ a# |
# N! ~# t" M( L& a7 w) e$ j
- `6 q/ c3 {6 t$ J! e( F8 l
% R; O- F  g, V# v
赞 收藏 评论0 发布时间:2021-12-21 23:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

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