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

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

[复制链接]
STMCU小助手 发布时间:2021-12-21 23:00
32.1 初学者重要提示- q- M. h# W) |& Q* z2 X/ b' k, r
  学习定时器外设推荐从硬件框图开始了解基本的功能特性,然后逐步深入了解各种特性,这种方式方便记忆和以后查阅。
) E) F( ^, a9 a$ T! B  STM32H7的定时器输出100MHz方波是完全没问题。" X$ j# f3 A2 T+ v+ P8 S
  STM32H7定时器进出中断的速度能跑到12.5MHz,所有程序在TCM和Flash运行没差别。  W' Q) i. H, W; W
  STM32H7的定时器输入捕获可以实现12MHz方波的双边沿捕获,单边沿可以做到24MHz。" j, w, [+ k( I
  特别注意STM32H7的TIM1,8,15,16,17才有RCR重复计数器,其它都没用的。/ c( J0 a. p7 S$ c' `: \
  STM32H7的单个定时器中不同通道可以配置不同频率PWM。
5 H2 Z5 X) t) K5 x' d  STM32H7的TIM1-TIM17中断入口函数名使用时要注意,别搞错了:& N( M  w2 u0 j8 F1 c
  1. TIM1_BRK_IRQHandler            
    9 N% p7 Y1 d( D, O' ^1 x3 M
  2. TIM1_UP_IRQHandler                e2 _$ v- Y6 O# ~- K" \: \+ [
  3. TIM1_TRG_COM_IRQHandler        
    : X% @( ~+ v9 z0 {# r
  4. TIM1_CC_IRQHandler                                                    2 Q3 o- M& M6 e! l5 U' l. S
  5. TIM2_IRQHandler                                           4 q5 W) ]* m) @7 j7 U7 N1 e7 a/ \: i
  6. TIM3_IRQHandler                                                 " x, y+ U9 x( P2 y; ]" m; f
  7. TIM4_IRQHandler                 
    : h  U( e) t2 r  D7 R  @+ w0 E
  8. TIM5_IRQHandler            
    , E7 ]7 S. j) j% O& o( L  t9 D) S/ u& @/ D
  9. TIM6_DAC_IRQHandler           <------------------要注意            
    ' W* A& w% i* {4 K
  10. TIM7_IRQHandler
    & l$ n2 K* Y8 V+ N) S$ X: v
  11. TIM8_BRK_TIM12_IRQHandler      <------------------要注意,定时器12也是用的这个; ]9 d* K3 L' }8 L0 A
  12. TIM8_UP_TIM13_IRQHandler       <------------------要注意,定时器13也是用的这个
    $ L1 D, D" I+ }. |- d/ o7 B: G& p
  13. TIM8_TRG_COM_TIM14_IRQHandler  <------------------要注意,定时器14也是用的这个/ s( B9 s9 z) @2 _8 }+ z
  14. TIM8_CC_IRQHandler         
    7 T8 n! O( I. Y' u' A' Q" ]2 ~
  15. TIM15_IRQHandler
    4 l# H( G# V, {$ o
  16. TIM16_IRQHandler ' b' {+ x" g/ o; T
  17. TIM17_IRQHandler
复制代码

) S* K, y7 L* |, |6 l5 R32.2 定时器基础知识9 y) U: x, ~- L$ m2 c! P
注,不同定时支持的功能略有区别,基础定时器功能较少,TIM1和TIM8高级定时器功能多些。
: I5 Q) d7 z' X1 W& l+ e
/ |6 B3 T6 N- f2 a2 M4 Z  TIM2和TIM5是32位定时器,其它定时器都是16位定时器。16位和32位的区别是CNT计数器范围不同,32位的范围是0 到2^32 – 1,而16位的是0到65535;它们支持的分频是范围是一样的,都是1到65535。
* d* F( }- l3 r& e# w2 b  计数器支持递增、递减和递增/递减二合一。& R3 C- C; ?& v; a3 u4 D4 @
  多个独立通道,可用于:
& C/ ^0 b0 m  m9 p. X/ O) K! x– 输入捕获。
4 r9 @* R; L- p  G2 O9 C- X* Y( Y- D+ v7 n, T5 r% Y8 o4 A
– 输出比较。
# w; x. ^! o% ]6 q# [+ c, b( w4 V4 o4 w7 e2 P
– PWM 生成(边沿和中心对齐模式)。
5 i5 R' ?3 S- b1 h7 {: b( w" a0 \  g3 Y, a% z/ c) x
– 单脉冲模式输出。
1 T* h7 B; f3 x! L9 x4 R; d
! e; D% D$ c" R' N0 X  带死区插入,断路功能和PWM互补输出
0 c- X( M  O( \+ K  `9 q  O$ y1 v  发生如下事件时生成中断/DMA 请求:
9 ]8 m2 c* I2 q& O– 更新:计数器上溢/下溢、计数器初始化(通过软件或内部/外部触发)
; o1 j! T. j* [: |, i/ `$ l& U" P! |! ?& w
– 触发事件(计数器启动、停止、初始化或通过内部/外部触发计数)
6 Y- Z/ X. R% F9 V% m
7 |/ \0 u5 Y8 I9 g6 u5 M– 输入捕获
. C7 ?% Z2 d4 W1 q7 X7 F. J3 M0 x) C  i& I# v
– 输出比较
8 w) u5 U( {% F; W1 A! F
. \( m. h5 I7 n  支持增量式编码器和霍尔传感器。
) l% j* }! a! h; `" W: I32.2.1 定时器TIM1-TIM17的区别6 w/ K9 E+ ]3 D* i+ G* K+ ~# z
STM32H7支持的定时器有点多,要简单的区分下。STM32H7支持TIM1-TIM8,TIM12-TIM17共14个定时器,而中间的TIM9,TIM10,TIM11是不存在的,这点要注意。3 R( b2 \8 r$ p" T2 H2 F& E0 T. ]

- k9 Q* o7 N) k* b7 k7 }粗略的比较如下:9 e7 b- b# B8 ]  S& _" Z
$ i" h3 z' E; L& a: @& R9 k
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png

" ]+ O; D3 `3 ?* U
( j  G% q; P$ V, @2 Q  ~+ L4 D
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png

5 z; G0 [6 {# e1 L  r% Y6 A/ R! ~$ l
$ X( K) m* |* D通过上面的表格,至少要了解到以下两点:" [, k/ w1 L# L) q

  A6 V3 m5 H1 f  STM32H7的定时器主要分为高级定时器,通用定时器,基础定时器和低功耗定时器。) L/ k; |7 m( i/ r
  TIM2和TIM5是32位定时器,其它都是16位定时器。" G2 Z, q: k( i5 ^4 O- X& L

: m2 Q! {% v1 f. F32.2.2 定时器的硬件框图
8 A" Z! \9 p7 f7 H% w: A认识一个外设,最好的方式就是看他的框图,方便我们快速的了解定时器的基本功能,然后再看手册了解细节。
" `) V# f/ N, l6 r# U# Z5 [. h1 m* V" h
下面我们直接看最复杂的高级定时器TIM1&TIM8框图:1 q- [" ]5 j7 q7 G

/ }6 {! W8 q9 Z1 h* T" p# l
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png
6 \$ K/ _4 K2 B  G
  D+ m* n5 X; U) L- h
通过这个框图,我们可以得到如下信息:
! E6 I: p/ o9 y. V0 f- E) `  l; q4 p. r* N% W+ h) s1 F$ a
  TIMx_ETR接口+ I2 a: @/ N7 e- N9 P! l
外部触发输入接口。ETR支持多种输入源:输入引脚(默认配置)、比较器输出和模拟看门狗。
. Z& Z1 g* m6 Z# q7 f
3 [1 F, n& ]. O, `! M/ |
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png

% p$ `: A3 d8 c( F  n' v, W$ ]
9 X, ~$ w: c' D# F( U+ v  截图左侧的TIMx_CH1,TIMx_CH2,TIMx_CH3和TIMx_CH4接口1 D+ Y  z6 v  c6 R: y/ S9 d' |
这四个通道主要用于输入捕获,可以计算波形频率和脉宽。                                                                                                                             % Q8 g; P# k! h5 K  z1 B( v* W6 `

( M( _; R4 G( [  ]1 ^5 H  TIMx_BKIN和TIMx_BKIN2接口' R. L" R; u+ r4 _) L
断路功能,主要用于保护由 TIM1 和 TIM8 定时器产生的 PWM 信号所驱动的功率开关/ v0 Z) B' k, m+ A' l

0 D: `( `7 T7 D: X3 ?0 B+ W  q8 Z  TRGO内部输出通道8 I) I; [" f3 D
主要用于定时器级联,ADC和DAC的定时器触发。, `' }" x# k+ l: x
# y: D* O, k8 s/ o! [
  6组输出比较单元OC1到OC6; M. N& J: I, Y3 H
OC1到OC4有对应的输出引脚,而OC5和OC6没有对应的输出引脚,主要用于内部控制。  M. k6 P+ x8 }/ y; ~: _! X2 I6 g
8 J) X9 B$ g! G+ i. l# A
  截图右侧的输出比较通道TIMx_CH1,TIMx_CH1N,TIMx_CH2,TIMx_CH2N,TIMx_CH3,TIMx_CH3N和TIMx_CH4
' J6 U. K: b  ?. P. S主要用于PWM输出,注意CH1到CH3有互补输出,而CH4没有互补输出。3 r8 c: x. t" O4 L
& f  S6 k9 v1 Q- E5 K& J/ ~. x
  其它框图里面未展示出来功能
! u' m. H( v3 _9 ]9 Q4 ?, }定时器TIM1&TIM8还支持的其它功能在用到的时候再做说明。
% r6 g& @' N/ K7 \) f8 N  d# G
1 k9 M' s$ i/ P" a0 T# F32.2.3 定时器的时基单元, d6 z3 b+ [2 q  Y4 `* w5 c
定时器要工作就需要一个基本时基单元,而基本的时基单元是由下面几个寄存器组成的:
( I0 k" j+ D3 E5 _0 P/ u9 K2 v5 Z0 ], M" X, |! u# q
  预分频器寄存器 (TIMx_PSC), P, ]* p# O" `6 X) {. Y3 g9 I& K
用于设置定时器的分频,比如定时器的主频是200MHz,通过此寄存器可以将其设置为100MHz,50MHz,25MHz等分频值。9 p$ I( \' s# Y; J: J, {
! m( _* W9 w; _  V/ t& y' m7 e% a0 M, E
注:预分频器有个缓冲功能,可以让用户实时更改,新的预分频值将在下一个更新事件发生时被采用(以递增计数模式为例,就是CNT计数值达到ARR自动重装寄存器的数值时会产生更新事件)。
- G+ t3 `1 m1 z0 n! I! C2 ?
! n5 _6 y+ @4 c& I# ~; X% H  计数器寄存器 (TIMx_CNT)
4 ]0 z- e$ S; j. J; e计数器是最基本的计数单元,计数值是建立在分频的基础上面,比如通过TIMx_PSC设置分频后的频率为100MHz,那么计数寄存器计一次数就是10ns。" [% ?2 g" J2 X( w% n- @& M* y5 M

. T* _! \+ m  z+ z* n8 }  自动重载寄存器 (TIMx_ARR)
- S( r7 I6 L8 u2 X+ ?; ^自动重装寄存器是CNT计数寄存器能达到的最大计数值,以递增计数模式为例,就是CNT计数器达到ARR寄存器数值时,重新从0开始计数。
- [; Y; v0 H# x$ }% {7 o$ {7 s: a* t, ?
注,自动重载寄存器是预装载的。对自动重载寄存器执行写入或读取操作时会访问预装载寄存器。预装载寄存器的内容既可以立即传送到影子寄存器(让设置立即起到效果的寄存器),也可以在每次发生更新事件时传送到影子寄存器。简单的说就是让ARR寄存器的数值立即更新还是更新事件发送的时候更新。% {  j: u+ h! Z. s
# J9 |2 E- Y8 S0 {( E) v1 a0 k! Q
  重复计数器寄存器 (TIMx_RCR)
/ b7 f- D* G: B, u2 b: ^以递增计数模式为例,当CNT计数器数值达到ARR自动重载数值时,重复计数器的数值加1,重复次数达到TIMx_RCR+ 1后就,将生成更新事件。, p6 [* O8 q" c% F# {

9 x0 w$ V3 W% j: o' F; s: }注,只有TIM1,TIM8,TIM15,TIM16,TIM17有此寄存器。. h$ I4 t! R9 i  J  T- U

  z( a& o! c5 r  h6 F9 }比如我们要配置定时器实现周期性的中断,主要使用这几个寄存器即可。& M3 j8 U0 p; I* r2 E/ C4 b

0 s& x/ ~0 @- y) R, ]32.2.4 定时器输出比较(PWM)# v' Z8 }. X6 x
使用定时器时基单元的那几个寄存器仅仅能设置周期,还不能设置占空比。针对这个问题,还需要比较捕获寄存CCR的参与,这样就可以设置占空比了。+ m! a) F" _# P) f5 z

. H' U" J& W% m! G' E8 f* n- v9 F为了方便大家理解,以PWM 边沿对齐模式,递增计数配置为例:0 C$ _8 g/ H/ u

/ b8 B' z0 B: h& l2 i, D9 {  当计数器TIMx_CNT < 比较捕获寄存器TIMx_CCRx期间,PWM参考信号OCxREF输出高电平。
' X  g/ b$ A4 Z, P+ i  当计数器TIMx_CNT >= 比较捕获寄存器TIMx_CCRx期间, PWM参考信号OCxREF输出低电平。
: R# T7 M, E3 s, w1 M# d  当比较捕获寄存器TIMx_CCRx > 自动重载寄存器TIMx_ARR,OCxREF保持为1。
2 }* ^  x' t  Y/ n4 o5 W1 [  当比较捕获寄存器TIMx_CCRx = 0,则OCxRef保持为0。# r# \+ z- m5 X; B* y
下面是TIMx_ARR=8的波形效果:% R$ Z* |. Y3 R0 y3 z8 s' q

9 d" `  g) R- v$ R1 A6 ]
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png
2 ~! u) Q8 u3 d& O

3 B+ ]- s1 d( U8 J/ L32.2.5 定时器输入捕获
  t8 H9 f, `* F; u" O; W6 W与PWM一样,使用定时器实现输入捕获,仅靠时基单元的那几个寄存器是不行的,我们需要一个寄存器来记录发生捕获时的具体时间,这个寄存器依然由比较捕获寄存器TIMx_CCRx来实现。
; B/ E2 [0 K  U, @& s
) G! e/ G7 E8 w/ j- v比如我们要测量一路方波的周期:
' I0 a9 C: `& j1 v9 [/ Q. }/ a) |0 q  U
  配置定时器为输入捕获模式,上升沿触发,设置分频,自动重装等寄存器,比如设置的CNT计数器计数1次是1微秒。4 m$ H3 L+ A  u4 j/ Z" e2 g
  当有上升沿触发的时候,TIMx_CCRx寄存器就会自动记录当前的CNT数值,然后用户就可以通过CC中断,在中断复位程序里面保存当前的TIMx_CCRx寄存器数值。等下次再检测到上升沿触发,两次时间求差就可以得到方波的周期。  g8 S  e0 r. w
不过这里要特别注意一点,如果CNT发生溢出(比如16位定时器,计数到65535就溢出了)就需要特别处理下,将CNT计数溢出考虑进来。5 B4 H  q# A8 q. F% _0 O
0 ?7 b9 C% g* u
32.3 定时器的HAL库用法* ~8 Q( w0 v2 R: u8 i% Q1 J6 o
定时器的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置GPIO、时钟,并根据需要配置NVIC、中断和DMA。下面我们逐一展开为大家做个说明。6 i; t+ r% L' X; H

/ I- t$ c! c  M6 j2 o) [$ A! Z32.3.1 定时器寄存器结构体TIM_TypeDef! O( j' O, R+ @5 i+ m' F# }
定时器相关的寄存器是通过HAL库中的结构体TIM_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:
! N- ?2 A$ s! B+ q# _5 d7 j' ^1 a- @* x/ G
  1. typedef struct
    & j& @3 x% p0 |1 V; U7 D1 x5 s
  2. {
    : C( C* ^8 f& G$ a2 t# B$ S
  3.   __IO uint16_t CR1;         /*!< TIM control register 1,                   Address offset: 0x00 */
    5 k/ }3 j2 C# ^6 x* V1 _
  4.   uint16_t      RESERVED0;   /*!< Reserved, 0x02                                                 */  `4 f) Z/ F3 ^" X
  5.   __IO uint32_t CR2;         /*!< TIM control register 2,                   Address offset: 0x04 */* d* G- N* s  G# l1 z$ b
  6.   __IO uint32_t SMCR;        /*!< TIM slave mode control register,          Address offset: 0x08 */& w7 p- U8 H% M- s/ i
  7.   __IO uint32_t DIER;        /*!< TIM DMA/interrupt enable register,        Address offset: 0x0C */
    ' z. F; |/ ]2 z
  8.   __IO uint32_t SR;          /*!< TIM status register,                      Address offset: 0x10 */
    2 A  b" M# x5 r' K% o. b* ~
  9.   __IO uint32_t EGR;         /*!< TIM event generation register,            Address offset: 0x14 */
    % g9 f0 i  G! L9 ^5 `
  10.   __IO uint32_t CCMR1;       /*!< TIM capture/compare mode register 1,      Address offset: 0x18 */
    . W" F% p$ S7 X- S5 v7 S
  11.   __IO uint32_t CCMR2;       /*!< TIM capture/compare mode register 2,      Address offset: 0x1C */
    1 i% I( Y4 F3 W9 ]4 f$ t
  12.   __IO uint32_t CCER;        /*!< TIM capture/compare enable register,      Address offset: 0x20 */
    2 g4 z( y  Z" I
  13.   __IO uint32_t CNT;         /*!< TIM counter register,                     Address offset: 0x24 */
    4 U8 s8 j: X# B7 u2 Z  M9 S9 @
  14.   __IO uint16_t PSC;         /*!< TIM prescaler,                            Address offset: 0x28 */
    6 C) W& \: O+ d
  15.   uint16_t      RESERVED9;   /*!< Reserved, 0x2A                                                 */- O% G9 X  e. X  _$ b
  16.   __IO uint32_t ARR;         /*!< TIM auto-reload register,                 Address offset: 0x2C */
    , v) r& X; Y. `: {6 b
  17.   __IO uint16_t RCR;         /*!< TIM repetition counter register,          Address offset: 0x30 */) z' [6 @" u" Z( R5 z
  18.   uint16_t      RESERVED10;  /*!< Reserved, 0x32                                                 */  ?3 ^# ~5 K2 m5 v, B* `, M
  19.   __IO uint32_t CCR1;        /*!< TIM capture/compare register 1,           Address offset: 0x34 */
    * d+ k( i* h& _% ?, Y+ {  C- n
  20.   __IO uint32_t CCR2;        /*!< TIM capture/compare register 2,           Address offset: 0x38 */$ R: p% K! ]5 [0 }) \$ Y
  21.   __IO uint32_t CCR3;        /*!< TIM capture/compare register 3,           Address offset: 0x3C *// v) r# d; k; d. j: q. w/ R7 V
  22.   __IO uint32_t CCR4;        /*!< TIM capture/compare register 4,           Address offset: 0x40 */
    ' N3 M. J9 V* v2 [
  23.   __IO uint32_t BDTR;        /*!< TIM break and dead-time register,         Address offset: 0x44 */
    ; F/ X0 m. j5 x7 T
  24.   __IO uint16_t DCR;         /*!< TIM DMA control register,                 Address offset: 0x48 */
    , v! s. i5 |- X( g( B% h, V( r. l- g' U
  25.   uint16_t      RESERVED12;  /*!< Reserved, 0x4A                                                 */
    8 M& R4 l3 `- W* Z
  26.   __IO uint16_t DMAR;        /*!< TIM DMA address for full transfer,        Address offset: 0x4C */8 G9 G/ M( K$ j4 B# d* }, C) _
  27.   uint16_t      RESERVED13;  /*!< Reserved, 0x4E                                                 */% g5 ~6 r  D6 e( c) B! A- |
  28.   uint16_t      RESERVED14;  /*!< Reserved, 0x50                                                 */
    / ^/ Q! D7 X( E  {; n1 H  s9 b
  29.   __IO uint32_t CCMR3;       /*!< TIM capture/compare mode register 3,      Address offset: 0x54 */& j( D4 `- m2 n7 d* d6 m
  30.   __IO uint32_t CCR5;        /*!< TIM capture/compare register5,            Address offset: 0x58 */0 _( y2 U2 L) _. K
  31.   __IO uint32_t CCR6;        /*!< TIM capture/compare register6,            Address offset: 0x5C */
    * {% z0 {' v, o- _2 X9 q3 }6 s' ^
  32.   __IO uint32_t AF1;         /*!< TIM alternate function option register 1, Address offset: 0x60 *// E- H& `1 f% p
  33.   __IO uint32_t AF2;         /*!< TIM alternate function option register 2, Address offset: 0x64 */5 y9 T9 V8 u, J( e6 x2 y
  34.   __IO uint32_t TISEL;       /*!< TIM Input Selection register,             Address offset: 0x68 */. ^( H) B  F& i+ y) ~% Q
  35. } TIM_TypeDef;
复制代码
9 W+ {! f4 P" r
这个结构体的成员名称和排列次序和CPU的定时器寄存器是一 一对应的。# D7 i+ ~+ X# s6 U, n1 R+ u
2 B, F! m3 p: E" B
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:$ ]! b7 j. i% b/ U$ p

) K6 z2 ^! q6 n9 L  K4 E9 Q
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */7 `! `0 r4 R+ z2 l% a
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码
7 A' [( T! c. b; N! [. |! A- G/ @/ {
下面我们看下定时器的定义,在stm32h743xx.h文件。
2 ^+ y+ h% c) p/ D" A1 t8 w% l8 J5 v4 x9 K; u& F* e+ f
  1. #define PERIPH_BASE         ((uint32_t)0x40000000)* ]- G5 [) x$ s; q
  2. #define D2_APB1PERIPH_BASE   PERIPH_BASE
    0 H6 ]0 h( P: ]5 Q0 ^' H
  3. #define D2_APB2PERIPH_BASE   (PERIPH_BASE + 0x00010000), _. _% F; o' s" y
  4. 9 m1 f* k0 l7 S5 b
  5. /*!< D2_APB1PERIPH 外设 */* i% \/ i) }5 B7 z0 Z2 z% Z
  6. #define TIM2_BASE             (D2_APB1PERIPH_BASE + 0x0000) <----- 展开这个宏,(TIM_TypeDef *) 0x40000000
    - F; |) d8 P5 }# ]- A& I
  7. #define TIM3_BASE             (D2_APB1PERIPH_BASE + 0x0400)+ p6 ]+ b- F6 I8 ~' Z: V
  8. #define TIM4_BASE             (D2_APB1PERIPH_BASE + 0x0800)2 L0 x9 t  ?* A8 E2 t
  9. #define TIM5_BASE             (D2_APB1PERIPH_BASE + 0x0C00)7 t+ T/ J: K" J$ E0 y0 |
  10. #define TIM6_BASE             (D2_APB1PERIPH_BASE + 0x1000)
    7 B! E1 f  F5 B  X* c
  11. #define TIM7_BASE             (D2_APB1PERIPH_BASE + 0x1400)
    # E! n  j( s4 ~! t9 U# g% r0 S5 {
  12. #define TIM12_BASE            (D2_APB1PERIPH_BASE + 0x1800)' b4 k4 a$ _& s
  13. #define TIM13_BASE            (D2_APB1PERIPH_BASE + 0x1C00)
    * I( h/ L7 a# J" N2 i4 B
  14. #define TIM14_BASE            (D2_APB1PERIPH_BASE + 0x2000)* K/ I( J4 H7 i  w4 Y5 V  a& o
  15. . d8 k8 c* g. h- ^2 g% ]
  16. /*!< D2_APB1PERIPH 外设 */% b3 }9 _4 s% F; W' q
  17. #define TIM1_BASE             (D2_APB2PERIPH_BASE + 0x0000)9 @2 ?; z3 D5 [9 q. d4 c
  18. #define TIM8_BASE             (D2_APB2PERIPH_BASE + 0x0400)
    $ Z, S4 U0 I' C* E, B+ w: V
  19. #define TIM15_BASE            (D2_APB2PERIPH_BASE + 0x4000)
    4 R6 n' c6 M8 K
  20. #define TIM16_BASE            (D2_APB2PERIPH_BASE + 0x4400)# x; m4 ^6 k, Z
  21. #define TIM17_BASE            (D2_APB2PERIPH_BASE + 0x4800)- @" A2 p1 y2 ], x: t4 \

  22. ( e3 _  z/ W# t* ?7 C
  23. #define TIM1                ((TIM_TypeDef *) TIM1_BASE)
    1 P# V6 S  m+ G8 b! S
  24. #define TIM2                ((TIM_TypeDef *) TIM2_BASE)
    & }( i* t; c; c. d0 k
  25. #define TIM3                ((TIM_TypeDef *) TIM3_BASE)
    ! Z: Z% ]7 {. O$ z
  26. #define TIM4                ((TIM_TypeDef *) TIM4_BASE)
    4 `7 K* Q1 S# G" C
  27. #define TIM5                ((TIM_TypeDef *) TIM5_BASE)( g, g( K/ y* X+ B9 c
  28. #define TIM6                ((TIM_TypeDef *) TIM6_BASE)7 X% z  P9 e5 h
  29. #define TIM7                ((TIM_TypeDef *) TIM7_BASE), R5 ?2 I1 @0 R  k) Z% q9 Q' S
  30. #define TIM8                ((TIM_TypeDef *) TIM8_BASE)3 C9 N# ]) Q/ x7 e
  31. #define TIM12               ((TIM_TypeDef *) TIM12_BASE)
    # r& U) y# y8 W) c
  32. #define TIM13               ((TIM_TypeDef *) TIM13_BASE)) X( Y2 K, [3 X: K
  33. #define TIM14               ((TIM_TypeDef *) TIM14_BASE)
    7 q- g5 H8 H5 X# k3 O4 D* N
  34. #define TIM15               ((TIM_TypeDef *) TIM15_BASE)- H  |# y) O! z8 r  u# K
  35. #define TIM16               ((TIM_TypeDef *) TIM16_BASE)
    . C8 N/ y7 A1 t/ V& B
  36. #define TIM17               ((TIM_TypeDef *) TIM17_BASE)
复制代码
9 l- R2 [" [1 Z* r" w+ p
我们访问TIM2的CR1寄存器可以采用这种形式:TIM2->CR1 = 0;- g  E2 X" O7 S4 ^( p! q+ p
4 n0 {. E1 y+ R9 m1 }8 L! g; m' M
32.3.2 定时器句柄结构体TIM_HandleTypeDef
( a% Z0 x, [; m  F4 N: {2 GHAL库在TIM_TypeDef的基础上封装了一个结构体TIM_HandleTypeDef,定义如下:( [* d' J' J" n! m6 S

- d: Q/ V$ k! h! G
  1. typedef struct
    1 U: [, |! t( w- r! P
  2. {( |- J+ B! v) p5 i# X" N5 y+ ^
  3.   TIM_TypeDef              *Instance;     /*!< Register base address             */ ' G5 F% o0 W5 A
  4.   TIM_Base_InitTypeDef     Init;          /*!< TIM Time Base required parameters */
    ' I( i5 B7 W* D4 Q0 P$ Z  |* g
  5.   HAL_TIM_ActiveChannel    Channel;       /*!< Active channel                    */ 2 d) @' {' Q2 |0 s/ M3 H6 r: N
  6. ' L5 Z6 L! [; n6 o$ B: i8 n
  7. /*!< DMA Handlers array This array is accessed by a @ref DMA_Handle_index */
      o/ O8 D; v: o  }5 `
  8.   DMA_HandleTypeDef        *hdma[7];      
    6 R/ q" T6 O0 h7 M$ X4 K* H
  9.   HAL_LockTypeDef          Lock;          /*!< Locking object                    */6 `! ?7 I  }  w5 Y, N
  10.   __IO HAL_TIM_StateTypeDef   State;      /*!< TIM operation state               */  
    ( Q5 @8 F) w- {  E
  11. }TIM_HandleTypeDef;
复制代码

. a# l- t% u2 A4 {7 X- ~这里重点介绍前四个参数,其它参数主要是HAL库内部使用的。$ a, T8 o/ V9 s: r8 z, s
& J+ m6 |. |: i: s  U- U
  TIM_TypeDef  *Instance1 E, i  A& d# E8 a/ V( q4 c( h5 w

# s. Z: d) \0 Q' r9 ]这个参数是寄存器的例化,方便操作寄存器,比如使能定时器的计数器。/ d) v6 o. n2 y  E( f
( k4 A0 ?9 l2 P5 P
SET_BIT(huart->Instance->CR1,  TIM_CR1_CEN)。
0 m% W& C+ g- P" U$ q% e* ?
* z- B+ R* u2 M" E1 n  TIM_Base_InitTypeDef  Init$ }; M: w! N% Q8 j7 [0 ^5 K$ e) e
# [  P. V% e! B' J  s5 N' w
这个参数是用户接触最多的,用于配置定时器的基本参数。
8 I, _6 a: j6 b2 k4 C) V
& u% {& L; L5 c7 _% m& [" _8 CTIM_Base_InitTypeDef结构体的定义如下:
0 _# T, |, Q2 I, F0 F% x! U
# z& y% L: @0 k  h; L, M
  1. typedef struct
    + B/ v+ T0 k! g% u+ _& I7 S. @! J1 H
  2. {: j, N) W6 g% u9 u; Q% q" H: U* \1 k
  3.   uint32_t Prescaler;        x' s) d$ M8 u
  4.   uint32_t CounterMode;    5 a: Y+ |6 I0 i7 w( q
  5.   uint32_t Period;         - C4 `; `1 x# p6 h" j4 g7 A6 e4 j
  6.   uint32_t ClockDivision;   
    ; @9 U/ n( P! s7 }: m9 k/ b
  7.   uint32_t RepetitionCounter;
      \  r/ x1 Q4 g) z
  8.   uint32_t AutoReloadPreload;  ' M' y: _) |: i' E' p' {' S$ s
  9. } TIM_Base_InitTypeDef;
复制代码

7 E; w% h: l2 U6 J  成员Prescaler2 x% |  F3 H1 j' u' ^3 z5 @
用于设置定时器分频,对于32位的TIM2和TIM5范围是0到0xFFFFFFFF,其它定时器是0到0xFFFF。
' |) w) w6 Y) }/ {
5 X+ d4 m4 Q* V: B  成员CounterMode
, c1 Z6 D% f9 X; j8 d2 w) G4 w用于设置计数模式,向上计数模式、向下计数模式和中心对齐模式。3 J) C' C' {+ }
9 }- d- _9 l6 P
  1. #define TIM_COUNTERMODE_UP                ((uint32_t)0x0000U)   /*!< Up counting mode */
    4 l1 j0 ]8 q# n, {" U0 Q) J
  2. #define TIM_COUNTERMODE_DOWN               TIM_CR1_DIR          /*!< Down counting mode */
    % Q1 U( f: c9 `. W) c' |  {  U
  3. #define TIM_COUNTERMODE_CENTERALIGNED1     TIM_CR1_CMS_0        /*!< Center-aligned counting mode 1 */7 j% t* q' e& J1 E
  4. #define TIM_COUNTERMODE_CENTERALIGNED2     TIM_CR1_CMS_1        /*!< Center-aligned counting mode 2 */& G( x% x! a3 z/ Y& f" o& I# q
  5. #define TIM_COUNTERMODE_CENTERALIGNED3     TIM_CR1_CMS          /*!< Center-aligned counting mode 3 */
复制代码
" G! l. S1 d7 E* D; b1 c1 ^
  成员Period
% [5 l" l% [0 c! Y+ v+ D2 M用于设置定时器周期,对于32位的TIM2和TIM5范围是0到0xFFFFFFFF,其它定时器是0到0xFFFF。0 Q; S, P7 r' ]3 U/ B" q8 r% Y
' m: L7 n1 n! m# y& ]& F* d2 a# @
  成员ClockDivision
6 k3 X. }* @7 z' {用于指示定时器时钟 (CK_INT) 频率与死区发生器以及数字滤波器(ETR、TIx)所使用的死区及采样时钟 (tDTS) 之间的分频比。' \' l3 W% |; X- N% L: d- r
( m. {( n7 _+ D
  1. #define TIM_CLOCKDIVISION_DIV1       ((uint32_t)0x0000U)        /*!< Clock Division DIV1 */0 S# v% w; ^. K5 t5 \: o1 I# S1 Y
  2. #define TIM_CLOCKDIVISION_DIV2       (TIM_CR1_CKD_0)            /*!< Clock Division DIV2 */5 T& E+ O# H) q1 M
  3. #define TIM_CLOCKDIVISION_DIV4       (TIM_CR1_CKD_1)             /*!< Clock Division DIV4 */
复制代码

5 V3 [# E- I  S; ~5 w9 T1 v  成员RepetitionCounter8 w9 P. o4 h; e, E5 j4 L
用于设置重复计数器,仅TIM1和TIM8有,其它定时器没有。作用是每当计数器上溢/下溢时,重复计数器减1,当减到零时,才会生成更新事件,这个在生成PWM时比较有用。
2 g( g' W* C8 K" l  F8 B$ F
- |4 Y; w# |, @+ q: M1 r  成员AutoReloadPreload4 C0 m0 V; e  K. p1 D
用于设置定时器的ARR自动重装寄存器是更新事件产生时写入有效还是立即写入有效。如果使能了表示更新事件产生时写入有效,否则反之。
/ }* L$ w. Y- _' u( ]+ o: s3 X: X3 n' M  ~) m
  1. #define TIM_AUTORELOAD_PRELOAD_DISABLE   ((uint32_t)0x0000U)   /*!< TIMx_ARR register is not buffered */
    : S2 K. j: Q; R# C! f" n
  2. #define TIM_AUTORELOAD_PRELOAD_ENABLE    (TIM_CR1_ARPE)        /*!< TIMx_ARR register is buffered */
复制代码
& c# g9 p5 c: S" S& B! I' e
  HAL_TIM_ActiveChannel    Channel;* t  |% r  P: y5 B% `1 B+ Z

! Q" Z: H6 K: q  s+ |  b/ J# M用于设置定时器通道,比如TIM1和TIM8都是6个通道。
; z; {+ j( a5 f" R$ Z5 f6 e& w' r4 c7 y$ x
  1. typedef enum" o1 O3 [/ S0 K. V4 g. ]
  2. {* J1 k8 y; S: X9 ]
  3.   HAL_TIM_ACTIVE_CHANNEL_1        = 0x01U,    /*!< The active channel is 1     */" J6 B* _: I, Z- P# @7 }
  4.   HAL_TIM_ACTIVE_CHANNEL_2        = 0x02U,    /*!< The active channel is 2     */
    ) Y( T# A, O, k$ B% ^8 {
  5.   HAL_TIM_ACTIVE_CHANNEL_3        = 0x04U,    /*!< The active channel is 3     */   
    2 F' s; Y" u) l* |3 V  R
  6.   HAL_TIM_ACTIVE_CHANNEL_4        = 0x08U,    /*!< The active channel is 4     */
    $ T& P- M0 q2 S) v$ ?* R% u9 r) d
  7.   HAL_TIM_ACTIVE_CHANNEL_5        = 0x10U,    /*!< The active channel is 5     */! E3 {; A3 Q# E4 L: U- ?
  8.   HAL_TIM_ACTIVE_CHANNEL_6        = 0x20U,    /*!< The active channel is 6     */  }8 X0 L, N# F% S. @( C. l/ n
  9.   HAL_TIM_ACTIVE_CHANNEL_CLEARED  = 0x00U     /*!< All active channels cleared */    ( \+ i2 G% z) G4 `# q& C
  10. }HAL_TIM_ActiveChannel;
    + ^/ w+ r2 ^! H# m1 `3 m' c
  11.   DMA_HandleTypeDef        *hdma[7];
复制代码
9 E' m3 m# s! R/ `2 ~
用于关联DMA。
" l8 C3 U6 \4 M2 O  s
$ r: m  Z- K, g, R2 d, J7 ~* k( ?配置定时器参数,其实就是配置结构体TIM_HandleTypeDef的成员。
7 X9 v2 j1 r! q8 d
: h5 f5 ~( T* y: a% Q2 m
  1. TIM_HandleTypeDef   TimHandle = {0};  {+ y' ]" b6 k. c( p* i9 X6 |" {

  2. ' n5 W$ k: X6 A: a- P* W
  3. /* 0 v/ b3 w9 r" z
  4.     定时器中断更新周期 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)
    5 s8 z. r" q9 D
  5. */$ x( s- F7 X9 h" k3 E" `  P8 L; `
  6. TimHandle.Instance = TIMx;7 i! Y9 j9 D( u/ F2 G
  7. TimHandle.Init.Prescaler         = usPrescaler;: a5 D! _# Y4 T! Z5 H6 y$ Z
  8. TimHandle.Init.Period            = usPeriod;        ' p0 P+ j) N$ f$ Z! v( d1 w
  9. TimHandle.Init.ClockDivision     = 0;0 K! L6 P8 I2 W
  10. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;
    8 l1 S2 k. C3 y
  11. TimHandle.Init.RepetitionCounter = 0;- z8 ~; S* c7 V9 ?
  12. TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;; j: i- o" u2 I9 p6 r6 i' ?
  13. if (HAL_TIM_Base_Init(&TimHandle) != HAL_OK)
    8 w! v3 Z- `  }2 U  }
  14. {" j. Q1 A0 K* F8 C$ |
  15.         Error_Handler(__FILE__, __LINE__);
    , D- D3 v  E7 N8 B  E+ k# M0 F
  16. }
复制代码

! F9 F, |; e$ l1 d, i& ]. Z32.3.3 定时器输出比较结构体TIM_OC_InitTypeDef
4 R5 F+ J' m* J: X  O
此结构体主要用于定时器的输出比较,定义如下:
" z( o  z* A. g, D  a4 L! c1 [: @7 R$ s3 u* f6 o7 g" E) n8 O
  1. typedef struct
    7 J. ?4 x1 q6 `0 @# U: @
  2. {                                 
    / }. t" n9 J" Q+ h! a
  3.   uint32_t OCMode;       + W) G7 U. l. O" ?# ^2 {* G0 y! y
  4.   uint32_t Pulse;      
    8 J7 ]; m! _1 L& h1 r, \/ h" _
  5.   uint32_t OCPolarity;    % G5 D' |5 ~7 k* V$ q2 e
  6.   uint32_t OCNPolarity;   
    / t" A2 Z1 z  O6 v
  7.   uint32_t OCFastMode;  
    . k6 `2 U. D1 E: H0 c
  8.   uint32_t OCIdleState;   5 D/ z' R' P* x, H  a. s
  9.   uint32_t OCNIdleState;  4 v' O, I; C8 D" ~3 x" t% L
  10. } TIM_OC_InitTypeDef;  
复制代码

- s& x: n0 M7 h+ p/ o& g下面将这几个参数一 一做个说明。' m9 J- {  F; u% ~

( q2 x. z- t( S, ?6 \4 Q" J" X  OCMode$ v& o: }' H* y9 a# c3 n- e
用于配置输出比较模式,支持的模式较多:
# r& w- [$ p3 s) n: Q9 C+ B; Z
8 n! W9 R* _! ?+ }6 X2 Z6 p: ]+ g$ N
  1. /*!< TIM Output timing mode */) a2 V4 G  s* {
  2. #define TIM_OCMODE_TIMING                ((uint32_t)0x0000U)      
    5 z: G* B/ W+ i) ^7 p

  3. 9 O3 M2 h+ G. a4 n7 ]2 n
  4. /*!< TIM Output Active mode */                          
      O, d$ H# m" {
  5. #define TIM_OCMODE_ACTIVE                ((uint32_t)TIM_CCMR1_OC1M_0) # V0 K- Q  F( V% @* `

  6.   y; }: @- l) I4 G; J: X8 a& _* B  Y
  7. /*!< TIM Output Inactive mode */                       ' N; O/ d0 V& D5 Y4 C' Z5 _
  8. #define TIM_OCMODE_INACTIVE              ((uint32_t)TIM_CCMR1_OC1M_1)             w. Z' K& A0 u5 U  D1 P! i  u

  9. 2 a4 B  @. G5 a0 R0 b
  10. /*!< TIM Output Toggle mode */               ( Q: H- k$ q& h) R9 \
  11. #define TIM_OCMODE_TOGGLE                 ((uint32_t)TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_0)         
    % R  ^* k. w6 `) `' \' g/ A
  12. 9 d' h( u; w9 U4 a- T0 C/ v
  13. /*!< TIM PWM mode 1 */, _4 @1 \# T( c' W8 |
  14. #define TIM_OCMODE_PWM1                   ((uint32_t)TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1)   k5 W7 R) R7 O. H) J8 i5 x, C

  15. ! Y0 y" b5 U' |% P5 X# G, V* ^. e
  16. /*!< TIM PWM mode 2 */                    
    6 ]% X- k, d  }, G# `9 M
  17. #define TIM_OCMODE_PWM2                    ((uint32_t)TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_0)   
    8 t9 S2 p; V2 X6 K+ f

  18. 3 i0 ~; I5 w/ N6 D) I% K
  19. /*!< TIM Forced Active mode */   - D- |9 k1 ^, o  P
  20. #define TIM_OCMODE_FORCED_ACTIVE           ((uint32_t)TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_0)         
    % U! C/ h/ _: s2 j- [2 W& K
  21. & T& t+ E: J3 m# `1 ~
  22. /*!< TIM Forced Inactive mode */            
    - ~3 w6 s# a: h7 V+ i
  23. #define TIM_OCMODE_FORCED_INACTIVE         ((uint32_t)TIM_CCMR1_OC1M_2)                                        8 X( Q: ?6 [, Y1 \" k

  24. 9 R$ P8 \* U$ d- M- |
  25. /*!< TIM Rettrigerrable OPM mode 1 */  9 V5 A/ x' R3 f+ s) u! I
  26. #define TIM_OCMODE_RETRIGERRABLE_OPM1      ((uint32_t)TIM_CCMR1_OC1M_3)   + [7 Q: A' J  S4 g% u& u: Q$ z

  27. ' ~. r! F" r* T: b8 e7 U+ `
  28. /*!< TIM Rettrigerrable OPM mode 2 */                                        0 @. V( W  C9 e: ]( X" U5 B
  29. #define TIM_OCMODE_RETRIGERRABLE_OPM2      ((uint32_t)TIM_CCMR1_OC1M_3 | TIM_CCMR1_OC1M_0)    7 t# d3 _2 W+ _) B( |) n1 d1 Q& H
  30. 5 q) {0 k, B4 T) ?* ]" n0 @+ n& Q
  31. /*!< TIM Combined PWM mode 1 */                     ' N4 k) U& X& L; f/ r4 ~* g
  32. #define TIM_OCMODE_COMBINED_PWM1           ((uint32_t)TIM_CCMR1_OC1M_3 | TIM_CCMR1_OC1M_2)     
    ' v- N0 \+ [' z
  33. 8 x5 }  f! K+ z* `$ D
  34. /*!< TIM Combined PWM mode 2 */                  : u% V$ g  l( T" G7 {* j( X! K
  35. #define TIM_OCMODE_COMBINED_PWM2           ((uint32_t)TIM_CCMR1_OC1M_3 | TIM_CCMR1_OC1M_0 | TIM_CCMR1_OC1M_2)   0 t3 _% T' C5 E4 V

  36. ( o  N2 g3 S) M
  37. /*!< TIM Asymetruc PWM mode 1 */  
    % R: E) ~  }- ]" N# c$ I' b- E  c
  38. #define TIM_OCMODE_ASSYMETRIC_PWM1         ((uint32_t)TIM_CCMR1_OC1M_3 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2)  
    $ n6 _5 a* A# n7 e( c

  39. 7 o  b& s" T2 B( o* {
  40. /*!< TIM Asymetruc PWM mode 2 */   
    * w9 P/ K, Y( B% d* m: r
  41. #define TIM_OCMODE_ASSYMETRIC_PWM2         ((uint32_t)TIM_CCMR1_OC1M_3 | TIM_CCMR1_OC1M)  
复制代码

- l) |: n6 W8 ]" V9 W  
6 K7 l% w/ t% H( _  Pulse
4 ?! L) J% }/ ^1 }  n2 q可用于设置占空比,对应定时器的CCR寄存器,32位的TIM2和TIM5范围是0到0xFFFFFFFF。
, t* n( x5 g. m( e) `2 u; l3 s) e7 d3 N" Z
  OCPolarity4 y& l7 {) {! ?. V% b
设置输出极性,可选高电平或低电平有效。
9 y! e! {, ]' z& ^, o0 c/ r: N1 Z
4 r8 Z+ S& _: C
  1. #define TIM_OCPOLARITY_HIGH                ((uint32_t)0x0000U)
    & n/ w+ R9 r2 [7 R, D, V
  2. #define TIM_OCPOLARITY_LOW                 (TIM_CCER_CC1P)
复制代码
" H' _* o9 s- Z) m4 o9 M
  OCNPolarity
" V5 Q* c% {5 A1 I" p互补输出极性设置,可选高电平或者低电平有效。5 w. P9 q* O2 {! U) P9 G
8 L$ D$ j( z9 z9 R! S
  1. #define TIM_OCNPOLARITY_HIGH               ((uint32_t)0x0000U)
    1 S( Z7 v# R0 L/ I3 n. l
  2. #define TIM_OCNPOLARITY_LOW                (TIM_CCER_CC1NP)
复制代码

4 h+ n9 J9 S$ b# L3 ?) t, g  OCFastMode6 f( w9 a  u) W' i5 ]: u+ y
快速输出模式使能,仅OCMode配置为PWM1或者PWM2模式时才有意义。( [0 ^5 N/ z$ E- t, t+ y

% m9 T' y2 B- J4 t7 g- d$ A
  1. #define TIM_OCFAST_DISABLE                ((uint32_t)0x0000U)4 u# M. @; V# t1 _
  2. #define TIM_OCFAST_ENABLE                 (TIM_CCMR1_OC1FE)
复制代码

; X8 q: e8 n* ]  T; d6 ~. c  OCIdleState
( C4 i- \0 N% g+ x空闲状态时,设置输出比较引脚的电平状态。
3 h7 i9 v" [. g$ c
3 G/ Q& X5 T% F# c
  1. #define TIM_OCIDLESTATE_SET                (TIM_CR2_OIS1)) ~9 ]( r) ]+ u9 ~
  2. #define TIM_OCIDLESTATE_RESET              ((uint32_t)0x0000U)
复制代码

% e% \: {4 O9 S2 |0 l  OCNIdleState. H( H% j; y) c/ H0 a& j
空闲状态时,设置互补输出引脚的电平状态。
# M7 j" [0 G1 N7 D* d- C! m% ~0 ^7 ~/ K
  1. #define TIM_OCNIDLESTATE_SET               (TIM_CR2_OIS1N)
    ! k) n' u$ V' R
  2. #define TIM_OCNIDLESTATE_RESET             ((uint32_t)0x0000U)
复制代码
+ I5 ~; E; Q' j- N, h5 @5 o$ k
32.3.4 定时器输入捕获结构体TIM_IC_InitTypeDef
& q( u- i5 z2 C$ A2 G) k此结构体主要用于定时器的输入捕获,定义如下:! N. O9 Y7 V2 [

: b+ j  B  l) P: t' T
  1. typedef struct
    ) o1 x: C% z  q/ c9 c: M
  2. {                                 
    7 \+ ^; B8 E& p  l
  3.   uint32_t ICPolarity;   ) j3 v) Q! q( B- E; j
  4.   uint32_t ICSelection;
    ; v: n, ^) [, K% A' F$ s; J
  5.   uint32_t ICPrescaler;
    & n5 Z1 m0 W! v6 n0 N
  6.   uint32_t ICFilter;    9 ]$ p8 R( C7 X; D8 h5 q
  7. } TIM_IC_InitTypeDef;
复制代码
4 ]7 i7 }+ V( c. |# z: @7 E
下面将这几个参数一 一做个说明。2 L. R& y1 `; r/ h, X6 n7 @

+ W  g, z4 r9 u% s  ICPolarity
  b* q6 k. n/ P% }- Z7 y输入触发极性,可以选择上升沿,下降沿或者双沿触发。
' I+ k$ V* R$ d1 j6 ^, l! W) R# `2 `( e6 [2 S% x
  1. #define  TIM_ICPOLARITY_RISING             TIM_INPUTCHANNELPOLARITY_RISING
    6 R1 e) \% R: n( @! m
  2. #define  TIM_ICPOLARITY_FALLING            TIM_INPUTCHANNELPOLARITY_FALLING; n) [! E1 a& F% D- B& y
  3. #define  TIM_ICPOLARITY_BOTHEDGE           TIM_INPUTCHANNELPOLARITY_BOTHEDGE
复制代码
5 X4 A2 _: R) W. |2 T
  ICSelection" L1 j( M8 X/ R$ [
输入捕获通道选择,可以选择直接输入(即CC1选择TI1,CC2选择TI2等),间接输入(CC1选择TI2,CC3选择TI4等)或者TRC。% e" j0 M: s; L# L
& t  N$ w1 M* ]2 j  b
  1. #define TIM_ICSELECTION_DIRECTTI       (TIM_CCMR1_CC1S_0)   ( W2 I* L) t; x6 C) f% A
  2. #define TIM_ICSELECTION_INDIRECTTI     (TIM_CCMR1_CC1S_1)  " ~& s3 a* Q1 _( s" O* Q
  3. #define TIM_ICSELECTION_TRC            (TIM_CCMR1_CC1S)   
复制代码
6 t9 W2 L1 C- Z: r8 s9 J. P0 ]* C
  ICPrescaler
: j; c0 }1 ]& ^" Y3 w, E输入捕获分频,表示每捕获1,2,4或8个事件后表示一次捕获。
3 N7 Z% ~0 }% `, U# D3 f4 r( b4 l+ o; Q9 s; O
  1. #define TIM_ICPSC_DIV1       ((uint32_t)0x0000U)                 + Q( }( l; g7 u" g  j% t
  2. #define TIM_ICPSC_DIV2       (TIM_CCMR1_IC1PSC_0)    8 c9 E  e5 y8 o# e
  3. #define TIM_ICPSC_DIV4       (TIM_CCMR1_IC1PSC_1)    ; S- J; ?2 y+ _$ S! p, H0 q
  4. #define TIM_ICPSC_DIV8       (TIM_CCMR1_IC1PSC)
复制代码

' ]7 Y( V2 H8 ]9 U( E: ?3 V  ICFilter
: `& P$ m) o  s5 W' m3 Z4 n. K, h输入捕获滤波器,可以定义采样频率和多少个连续事件才视为有效的触发,参数范围0到15。具体定义如下,其中fCK_INT表示定时器时钟,fDTS表示死区时间采样率,N表示这么多个事件代表一次有效边沿。
8 V! B% N7 `; b1 a' @7 J
' S2 v" A& S5 ]1 l3 B: O
  1. 0000:无滤波器,按 fDTS 频率进行采样
    + N1 [% I8 i; V4 i+ a- a. I
  2. 0001: fSAMPLING=fCK_INT, N=26 p& a8 k6 v* [
  3. 0010: fSAMPLING=fCK_INT, N=4
    " \1 \0 b+ H% q5 m! k4 o/ o2 g% B* A
  4. 0011: fSAMPLING=fCK_INT, N=8
      B/ k% [+ \$ h2 e
  5. 0100: fSAMPLING=fDTS/2, N=6
    - H" n& w: f0 s8 c& f# ?
  6. 0101: fSAMPLING=fDTS/2, N=8/ e5 h5 ~$ J1 ~% p4 H4 r4 H
  7. 0110: fSAMPLING=fDTS/4, N=60 i: o. d) S9 K" ]" T
  8. 0111: fSAMPLING=fDTS/4, N=87 ]8 x: v: y, }1 h3 Y1 ]' f
  9. 1000: fSAMPLING=fDTS/8, N=6
    ! H1 t. S! b2 k6 P" V* H
  10. 1001: fSAMPLING=fDTS/8, N=8* s3 S$ I2 s8 A0 S' J
  11. 1010: fSAMPLING=fDTS/16, N=5
    ' Y; H2 \  ]6 ?% W; F
  12. 1011: fSAMPLING=fDTS/16, N=6
    1 ~' m2 c. b  D# q% G. T
  13. 1100: fSAMPLING=fDTS/16, N=8
    1 a8 w# a; ?! [/ ?
  14. 1101: fSAMPLING=fDTS/32, N=5
    ! e7 x" ~8 K( A5 m) b5 Z
  15. 1110: fSAMPLING=fDTS/32, N=6
复制代码

: e2 R5 @. a! f32.3.5 定时器的底层配置(GPIO,时钟,中断等)
8 |/ R8 Y# l, s4 V% u( n. `HAL库有个自己的底层初始化回调函数,比如调用函数HAL_TIM_Base_Init就会调用HAL_TIM_Base_MspInit,此函数是弱定义的。
4 z& E6 F( l  \: k" B' R0 [* P, o  x: s' O; p
  1. __weak void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
    7 ^8 M' H7 e: P' B6 ?: b: U, N
  2. {
    1 F- n: y3 r8 A8 M( M# X
  3.   /* Prevent unused argument(s) compilation warning */
    7 J. l4 Z5 D) ?6 ^( g
  4.   UNUSED(htim);- j+ m0 D5 e6 N8 R. p
  5.   /* NOTE : This function Should not be modified, when the callback is needed,% ~# P# l8 u/ t* H- f8 O
  6.             the HAL_TIM_Base_MspDeInit could be implemented in the user file% B3 P; v% q3 v* Y* W
  7.    */
    2 W% C& n" k3 x7 k( C
  8. }
复制代码

, `, X. H. S. |: I, l0 i用户可以在其它的C文件重定向,并将相对的底层初始化在里面实现。对应的底层复位函数HAL_TIM_Base_DeInit是在函数HAL_TIM_Base_MspDeInit里面被调用的,也是弱定义的。
: G; Y  e7 |! E. f8 |% N' y9 l( D: ?/ I7 A  n' S
当然,用户也可以自己初始化,不限制必须在两个函数里面实现。) f6 y8 w' {/ s" j& g- ^

" B5 S" {. ~5 \. Z5 R( U, U5 O定时器外设的基本参数配置完毕后还不能使用,还需要配置GPIO、时钟、中断等参数,比如下面配置TIM1使用PA8做PWM输出。
+ u4 s: m. P) c+ S3 x
& O" {& g, n" l" Q
  1. void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)3 ]/ ~. D: V7 Z  J: }
  2. {
    3 J) g  l1 J% z/ n) e
  3.   GPIO_InitTypeDef   GPIO_InitStruct;' c1 ]# H2 v! z2 y8 u: y
  4. ) I' z, t3 v" y
  5.   /* 使能TIM1时钟 *// f9 O2 R- Y: |. H% j
  6.   __HAL_RCC_TIM1_CLK_ENABLE ();
    & |3 a9 Y( k, E3 ?; P4 g/ I9 y
  7. ; N4 P& h) K; `1 n  Q7 ?
  8.   /* 使能GPIOA时钟 */
    ! i9 v( u  Y. X* d1 l+ n
  9.   __HAL_RCC_GPIOA_CLK_ENABLE ();* ^* N9 c: Z/ \; G

  10. 3 S9 [) A, O. I& Q. M( a
  11.   /* 设置TIM1使用PA8做PWM输出引脚,将其配置为输出,推挽,复用模式 */* K8 }9 z; v& R$ v8 H
  12.   GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;( [8 [! {  i: O
  13.   GPIO_InitStruct.Pull = GPIO_PULLUP;3 G7 B; e# Q. O
  14.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    9 }/ N  b! d& {' l  U  k" E2 D
  15. 2 y2 X: _# W7 A
  16.   GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;5 R1 J2 W8 E3 f( m; q; @% o
  17.   GPIO_InitStruct.Pin = GPIO_PIN_8;) s2 v. ]% L( P0 Q! n
  18.   HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    , B" b1 u+ X8 X' {$ u9 \2 q
  19. 1 k/ q- N9 p+ F6 w$ r' I
  20. }
复制代码
/ B; Q/ V  _- C! m7 Z0 Y
总结下来就是以下几点:
5 ^' p3 e. j+ l# x
8 ^( x9 z7 R+ A7 w  配置TIM时钟。
; \, u' b, t+ v- a" n! e* \- h  配置TIM所用到引脚和对应的GPIO时钟。
2 s* |, m2 s9 ?+ A. A& P  如果用到定时器中断,还需要通过NVIC配置中断。
- G. }6 N; P( p# j" y/ \  如果用到DMA,还要配置DMA。, b! n9 P5 C! I% F3 d* `4 _
关于这个底层配置有以下几点要着重说明下:
% p7 ^. a5 C& l  |4 W# f
6 b- r2 Q  j0 G  定时器所使用引脚的复用模式选择已经被HAL库定义好,放在了stm32h7xx_hal_gpio_ex.h文件里面。比如TIM1有一个复用,
$ k. V7 {& V* Z0 H- J& A3 ?  W
  1. #define GPIO_AF1_TIM1      ((uint8_t)0x01)  /* TIM1 Alternate Function mapping */
复制代码

, ?  y; h7 h' @; ]但是却有4个输出通道,每个通道都有几个支持的输出引脚:
) t3 p% ?: u$ x2 g/ K1 I2 B, C5 W. w, U; \. P
  1. TIM1_CH1,  PA8   PE9    PK1% j6 r. U0 }: ^0 Y& D
  2. TIM1_CH2,  PA9   PE11
    / K. N7 f. H) G, W6 f- X4 T0 N1 s
  3. TIM1_CH3,  PA10  PE13   PJ9
    . q8 M% X, c4 u/ Q2 P( R5 k  A5 m5 e
  4. TIM1_CH4,  PA11  PE14   PJ11
复制代码
& d1 N4 P! E8 m. ~9 ]3 t# p" @
具体使用哪个,配置对应引脚的复用即可:
9 M& L  e+ Q# l# _1 E  H. x+ f9 g% ~' Q8 v0 d% G
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png

$ R, N1 @8 a5 h. r. y3 M. t$ d  R. g8 Y' H9 P
32.3.6 定时器的状态标志清除问题4 \) z/ ^2 X" j8 P& `
下面我们介绍__HAL_TIM_GET_FLAG函数。这个函数用来检查定时器标志位是否被设置。3 D4 T, l" B5 ~# L9 S. n& T- ?

  1.   ~- V" C- ]9 k+ a' Z
  2. /** @brief  Check whether the specified TIM interrupt flag is set or not.
    : k# C4 @, e1 U
  3.   * @param  __HANDLE__: specifies the TIM Handle.' I8 `$ x9 K- U8 s
  4.   * @param  __FLAG__: specifies the TIM interrupt flag to check.$ z! G4 a* Q4 E  W. |9 N1 ?1 ?
  5.   *        This parameter can be one of the following values:
    9 a/ p; b, P" ?/ `1 f0 d! p
  6.   *            @arg TIM_FLAG_UPDATE: Update interrupt flag
    : N4 ~+ M6 Q$ u( C7 }
  7.   *            @arg TIM_FLAG_CC1: Capture/Compare 1 interrupt flag
    ) Q. Q" I& v* W' m: {/ u
  8.   *            @arg TIM_FLAG_CC2: Capture/Compare 2 interrupt flag( l% \) ?  C  G( D2 e  l& l
  9.   *            @arg TIM_FLAG_CC3: Capture/Compare 3 interrupt flag
    9 _  B! u* H; U- n  S' |/ {: c; Z
  10.   *            @arg TIM_FLAG_CC4: Capture/Compare 4 interrupt flag
    " p6 c4 p1 T1 d3 F% h* s
  11.   *            @arg TIM_FLAG_CC5: Compare 5 interrupt flag/ W+ K7 K% K4 P% i5 e
  12.   *            @arg TIM_FLAG_CC6: Compare 6 interrupt flag! K& s# Y, g$ [" N
  13.   *            @arg TIM_FLAG_COM:  Commutation interrupt flag6 {' T6 n! U0 [: r# `' t
  14.   *            @arg TIM_FLAG_TRIGGER: Trigger interrupt flag" o" V$ l1 b) t! A
  15.   *            @arg TIM_FLAG_BREAK: Break interrupt flag   % U# t! [. B" b
  16.   *            @arg TIM_FLAG_BREAK2: Break 2 interrupt flag                     
    ) a% n9 H# G) l) I0 [8 ~. A
  17.   *            @arg TIM_FLAG_SYSTEM_BREAK: System Break interrupt flag$ N$ {! t0 z" _" G9 X
  18.   *            @arg TIM_FLAG_CC1OF: Capture/Compare 1 overcapture flag
    2 ~* L$ ^: {! W9 S
  19.   *            @arg TIM_FLAG_CC2OF: Capture/Compare 2 overcapture flag9 _3 H/ K$ {2 D
  20.   *            @arg TIM_FLAG_CC3OF: Capture/Compare 3 overcapture flag; a- `7 ~( z9 K
  21.   *            @arg TIM_FLAG_CC4OF: Capture/Compare 4 overcapture flag, O. l. i0 d) w) }7 \: r
  22.   * @retval The new state of __FLAG__ (TRUE or FALSE).
    4 T: G7 j  g- `; j+ @" x
  23.   */5 I. D- }2 d6 w
  24. #define __HAL_TIM_GET_FLAG(__HANDLE__, __FLAG__)   (((__HANDLE__)->Instance->SR &(__FLAG__)) == (__FLAG__))
复制代码
7 w  F. C: ?6 \( h% ]' k; R
前5个是比较常用的中断标志。
) K" p& U% {  H" k) V
$ S2 y2 d9 p( Z4 F% g  TIM_FLAG_UPDATE
$ U* [/ z" d& K2 f定时器更新标准,配置一个周期性的定时器中断要用到。
0 e- P# B: N$ A+ W% R: o/ a) t' h
( }2 E4 _1 R* m% P7 s  M     TIM_FLAG_CC1
; U' H4 F- G4 s& e6 W, [; E" Q7 ATIM_FLAG_CC2
8 L  Z, a# I( `, n9 w
+ P9 }3 F$ j, r7 z) VTIM_FLAG_CC33 |9 D+ A' C3 _6 p  x& {

. y5 @6 o" Q0 u/ q9 J" Q3 rTIM_FLAG_CC4
  J- z9 V) j) B$ I. A1 c3 V, l: ^- E/ u( i" x$ v
捕获/比较标志,配置了捕获/比较中断要用到。3 B5 q+ F& U/ o7 S% M1 w; C
  Z8 E' @; x3 t/ f% r3 ?" u/ N
与标志获取函数__HAL_TIM_GET_FLAG对应的清除函数是__HAL_TIM_CLEAR_FLAG:) L6 e( h, ]4 j6 K  S
# a* x/ @4 X. u+ N+ K# C5 M9 X
  1. /** @brief  Clear the specified TIM interrupt flag.. U+ H: M+ ^' r# h+ d# \
  2.   * @param  __HANDLE__: specifies the TIM Handle.3 u  j2 N3 r0 j/ H4 c
  3.   * @param  __FLAG__: specifies the TIM interrupt flag to clear.$ g" _+ ?8 @9 |/ z% K( R. C, g, x
  4.   *        This parameter can be one of the following values:, A& y# Q3 p. o* H+ _
  5.   *            @arg TIM_FLAG_UPDATE: Update interrupt flag4 H% Z7 S) K; H. C% ?& y
  6.   *            @arg TIM_FLAG_CC1: Capture/Compare 1 interrupt flag
    3 F& B8 [5 o# d: r3 F) \' G2 j0 r# Z
  7.   *            @arg TIM_FLAG_CC2: Capture/Compare 2 interrupt flag% v$ C+ Y2 V% c# j& u8 S
  8.   *            @arg TIM_FLAG_CC3: Capture/Compare 3 interrupt flag
    0 j- V" v9 |# Q# d: J$ V6 I5 L
  9.   *            @arg TIM_FLAG_CC4: Capture/Compare 4 interrupt flag: R6 ^9 l$ {. @* [; j* s: S
  10.   *            @arg TIM_FLAG_CC5: Compare 5 interrupt flag2 a2 f, p, |4 V' c, G
  11.   *            @arg TIM_FLAG_CC6: Compare 6 interrupt flag
    4 `) q; z% }) i* `8 g% X( L/ T
  12.   *            @arg TIM_FLAG_COM:  Commutation interrupt flag
    % L1 P4 T/ i( |. h
  13.   *            @arg TIM_FLAG_TRIGGER: Trigger interrupt flag4 Q% ]  Q. {" X8 f+ b
  14.   *            @arg TIM_FLAG_BREAK: Break interrupt flag   . R9 U2 e/ [6 P4 M5 W" A
  15.   *            @arg TIM_FLAG_BREAK2: Break 2 interrupt flag                     
    * a4 O+ }0 v+ b- q- \
  16.   *            @arg TIM_FLAG_SYSTEM_BREAK: System Break interrupt flag2 X: J( |5 u+ c  y& [) p
  17.   *            @arg TIM_FLAG_CC1OF: Capture/Compare 1 overcapture flag2 x2 O* e, x, q9 \+ }6 A
  18.   *            @arg TIM_FLAG_CC2OF: Capture/Compare 2 overcapture flag
    5 ?, @% {4 R+ Q3 J: `( c; S
  19.   *            @arg TIM_FLAG_CC3OF: Capture/Compare 3 overcapture flag
    / E8 I) s5 m- U
  20.   *            @arg TIM_FLAG_CC4OF: Capture/Compare 4 overcapture flag
    - Z3 r+ X7 M# w2 U$ I" ]) S, i+ i: x
  21.   * @retval The new state of __FLAG__ (TRUE or FALSE).
    " Z+ p- R! p6 O, I+ x
  22.   */5 ]4 a, k& C9 C2 h( f% ?9 g
  23. #define __HAL_TIM_CLEAR_FLAG(__HANDLE__, __FLAG__)       ((__HANDLE__)->Instance->SR = ~(__FLAG__))
复制代码

* u- @6 c& f: r& ~' B1 Z% o清除标志函数所支持的参数跟获取函数是一 一对应的。除了这两个函数,还是定时器的中断开启和中断关闭函数用的也比较多。1 V0 O, @4 y. u6 N7 l

- |/ _/ }5 m# E' {) P
  1. /** @brief  Enable the specified TIM interrupt.
    # z7 }4 @9 e5 Z, B( p
  2. * @param  __HANDLE__: specifies the TIM Handle.
    + e. T1 G) Q  |3 J7 A& |
  3. * @param  __INTERRUPT__: specifies the TIM interrupt source to enable.
    ! Q( ~! K: [  h1 }+ h0 f
  4. *          This parameter can be one of the following values:
    % \+ Z) B- D- A5 q1 p
  5. *            @arg TIM_IT_UPDATE: Update interrupt
    $ o/ I* b9 T& g! s9 l
  6. *            @arg TIM_IT_CC1:   Capture/Compare 1 interrupt
      t% a5 ~) j5 n5 k3 y! M& u
  7. *            @arg TIM_IT_CC2:  Capture/Compare 2 interrupt) z8 x4 G, L4 i& Y# B
  8. *            @arg TIM_IT_CC3:  Capture/Compare 3 interrupt% K- h" R7 C9 t4 Q# t8 m/ j* |. E
  9. *            @arg TIM_IT_CC4:  Capture/Compare 4 interrupt7 z& Y5 g, N* z: l% j
  10. *            @arg TIM_IT_COM:   Commutation interrupt
    . P# E! x  F% Y+ F+ g  g& I
  11. *            @arg TIM_IT_TRIGGER: Trigger interrupt
    9 ], D2 p- e3 E7 _/ W" H
  12. *            @arg TIM_IT_BREAK: Break interrupt, l' a! X0 L& j+ b
  13. * @retval None
    # I7 r. I- o( u, f
  14. */. ~( P8 K. W2 r& z* G: P9 p* C
  15. #define __HAL_TIM_ENABLE_IT(__HANDLE__, __INTERRUPT__)  ((__HANDLE__)->Instance->DIER |= (__INTERRUPT__))
    3 J6 n$ e2 X2 f
  16. - r) R: v, p" _) d% |( V
  17.   /** @brief  Disable the specified TIM interrupt.0 Y5 X6 M' }4 P- g6 ]
  18.   * @param  __HANDLE__: specifies the TIM Handle.- ]8 l( O& j( W0 O1 Z
  19.   * @param  __INTERRUPT__: specifies the TIM interrupt source to disable.
    ; a3 h6 x- S) r, v
  20.   *          This parameter can be one of the following values:- t4 \2 t1 d) @0 b
  21.   *            @arg TIM_IT_UPDATE: Update interrupt
    " ^- Q6 ]7 @+ f4 `' p7 H* K4 w
  22.   *            @arg TIM_IT_CC1:   Capture/Compare 1 interrupt
    # q" D! J& n& }/ f  G3 d* m6 S
  23.   *            @arg TIM_IT_CC2:  Capture/Compare 2 interrupt6 \% l7 ?" Z7 y
  24.   *            @arg TIM_IT_CC3:  Capture/Compare 3 interrupt
    9 B+ U# P. r) D0 m6 o+ K
  25.   *            @arg TIM_IT_CC4:  Capture/Compare 4 interrupt
    2 u* @9 |/ \: M" @3 m: `
  26.   *            @arg TIM_IT_COM:   Commutation interrupt3 r1 H/ ^" \/ L, {
  27.   *            @arg TIM_IT_TRIGGER: Trigger interrupt1 ]$ a- t; }+ }0 a" \( |+ S) V5 R
  28.   *            @arg TIM_IT_BREAK: Break interrupt) s5 ?# g4 I- `( e
  29.   * @retval None
    . H) o* I5 y0 _0 W( m; q) y
  30.   */
    " w% q  v' W3 x# q1 i8 @3 O
  31. #define __HAL_TIM_DISABLE_IT(__HANDLE__, __INTERRUPT__)   ((__HANDLE__)->Instance->DIER &= ~(__INTERRUPT__))
复制代码

' z3 r7 `1 e: y/ `6 _常用的也是前五个参数,1个定时器更新中断以及4个CC中断 。
; y9 t' I0 V- G' I( J) E3 U' O& m. V6 q2 [- b5 }/ H
注意:操作定时器的寄存器不限制必须要用HAL库提供的API,比如要操作寄存器CR1,直接调用TIM1->CR1操作即可。+ b: w. V* R; `, F* i9 E

) i2 y- C1 A% Z% U6 s+ X32.3.7 定时器初始化流程总结
5 N0 M' z3 i. n使用方法由HAL库提供:
$ M$ c0 e& z8 X7 D1 ?% h& k2 z3 M) z3 c
  第1步:通过下面几个函数配置定时器工作在相应的模式
5 c: ~9 v3 X  X
/ f% \1 _8 T) P3 v0 F3 T  HAL_TIM_Base_Init  c: J, v+ {; m. J  j6 X1 N
简单的定时器时基础功能; R$ j& M/ ~: Z! C0 H/ E
2 a6 ]" H) a/ _# G
  HAL_TIM_OC_Init 和 HAL_TIM_OC_ConfigChannel. S6 X+ Z: e! M. X7 H; L. J
配置定时器产生输出比较信号
4 n( M/ a! E! q" K* F" ^1 v6 ~. W! m" {- e) b
  HAL_TIM_PWM_Init 和 HAL_TIM_PWM_ConfigChannel0 @6 I* l; a5 B% Z% t3 Y
配置定时器产生PWM信号8 \& c0 p, s# b0 Z- @' p: o

4 p6 t3 U7 i8 \) x  HAL_TIM_IC_Init 和 HAL_TIM_IC_ConfigChannel
1 e+ h2 Z1 Q+ }4 b, u配置定时器测量外部信号
0 |! j4 c% Y8 {0 f/ u2 @0 B& C6 ^  w. V+ G, o! H3 I/ @0 h
  HAL_TIM_OnePulse_Init 和 HAL_TIM_OnePulse_ConfigChannel+ e  u& e9 x( S3 D! P2 g0 G" I/ D" l! K
配置定时器工作在单脉冲模式
/ x1 h% s' C+ \1 [
* ?" H, V  ~& |2 C; ~  HAL_TIM_Encoder_Init
- \! }* a2 C, P; v) w2 K配置定时器使用编码器接口
2 h  L; x$ H8 p4 Z/ S4 t7 Z  J
$ \/ N9 {- `1 [  第2步:定时器几个常用功能的底层初始化API,这个里面需要用户自己填
; G3 m* V' _+ h( H( K. t1 r0 o9 {  ?5 f
第1步里面的几个函数会调用下面的API。
! W, w6 o0 b* j
( {4 b6 ~( o5 C9 l1 z6 D. u+ m  定时器基本功能 : HAL_TIM_Base_MspInit()( u. Q1 s2 y$ x* c0 l
  输入捕获 : HAL_TIM_IC_MspInit()8 a$ b6 o4 p: o* C! Y% h
  输出比较 : HAL_TIM_OC_MspInit()
0 @$ t# Z* V  n9 i5 x* n. o- U  PWM输出 : HAL_TIM_PWM_MspInit()
+ l3 W/ w7 K1 P" {5 e4 L) @  单脉冲输出模式: HAL_TIM_OnePulse_MspInit()* {" X7 y4 z/ L$ [. o0 W
  编码器模式 : HAL_TIM_Encoder_MspInit()+ c1 W6 B& Q% P1 w3 m
  第3步:底层初始化具体实现
! P; S! ]) G" Y; _% D' [2 b8 ?8 b, Y+ N
第2步中函数的具体实现。
; i+ u; J3 N% z4 y: n5 [2 M: a/ R, `  u% {
  使用函数__HAL_RCC_TIMx_CLK_ENABLE()使能定时器时钟。
: k, u4 x1 p& l* W5 ?5 [  使用函数__HAL_RCC_GPIOx_CLK_ENABLE()使能定时器使用到的引脚时钟。
* N& |  C/ z8 M) [  使用函数HAL_GPIO_Init()配置GPIO的复用功能。% R' b$ t0 p& X! n, q. F
  如果使能了定时器中断,调用函数HAL_NVIC_SetPriority和HAL_NVIC_EnableIRQ配置。
) _; g+ n6 ]! c  如果使能了DMA,还需要做DMA的配置。( a1 n0 t. N2 D1 `
  定时器默认使用APB时钟,如果使用外部时钟,调用函数HAL_TIM_ConfigClockSource可以配置。6 a) K/ [2 W# R+ E
  第4步:启动定时器外设# d* i$ d% K: [) B  z" }6 d* c' [

) C2 r% b8 O, s' @% o# X  定时器基础功能:0 q. F9 r4 G0 [7 T+ y
HAL_TIM_Base_Start()" N  _1 m9 W8 A- J) d# \

# M4 ~' k. z) p- D, dHAL_TIM_Base_Start_DMA()
6 o2 y/ h- z" O+ Q6 |, O' a
* Y. x* s3 n; o/ DHAL_TIM_Base_Start_IT()8 W3 W  u- E+ o% @1 T, q3 B
% z' V, ~; p7 w
  输入捕获 :/ W# q2 m" x* E( V5 g, y; u
HAL_TIM_IC_Start()' L  Q1 E& L4 ]7 l  N3 s- t- j( e9 [
/ O2 n, N* a- V& L5 j- `
HAL_TIM_IC_Start_DMA()
3 z. j$ R2 x5 N4 J
9 |+ a/ H+ @$ w+ C, @HAL_TIM_IC_Start_IT()
+ M# w: m  L% C  `! A+ E3 A
. ~6 j7 v" X- A) X* D  输出比较 :
9 p' H- O; F$ G, sHAL_TIM_OC_Start()
+ B" e/ W7 x  P' k8 X& F' V) ?. q# f2 K  v" P( D2 y" x1 N/ I
HAL_TIM_OC_Start_DMA()
' ~, l: u4 N! m
% r. A% s: P$ }! |8 s. gHAL_TIM_OC_Start_IT()
' }  x* A. y) _0 @# \
* q  k5 s# y$ O: F7 p; U' A" f  PWM输出:$ R5 f  g% x# G+ [: u6 N% O' x
HAL_TIM_PWM_Start()7 T  H$ N  m4 x& u! W! U
  c& b5 }8 Z- a  G1 X6 R
HAL_TIM_PWM_Start_DMA()- j; w, C4 C' ?' K* _
; y# l+ `4 G0 c0 V+ u8 P
HAL_TIM_PWM_Start_IT()
: d' a! \! m+ N# I3 b! {7 S! p, o, ~$ d" S0 _7 g
  单脉冲模式:
7 H& S5 x9 y5 ?- D6 b8 lHAL_TIM_OnePulse_Start()& p6 |$ s6 f! ]

0 J, k7 A- _( ^4 _5 bHAL_TIM_OnePulse_Start_IT().1 c3 P$ m$ K  Z0 @4 X
" a' B8 r! a# K3 Y+ a
  编码器模式:; `, L1 _$ _$ Q# U/ [
HAL_TIM_Encoder_Start()) I6 B9 V4 D% q) o
" v; P$ \8 d+ s
HAL_TIM_Encoder_Start_DMA()  m* B' p5 J& N2 Y+ p! `

: x/ X3 O- c" z! i) CHAL_TIM_Encoder_Start_IT().; |& p3 a3 C6 p' R1 o6 r

+ o% d, H5 k9 x4 M  第5步:定时器的DMA突发使用下面两个函数7 t- e3 p5 a  p3 v
! E4 v/ n7 W/ k
  HAL_TIM_DMABurst_WriteStart()
) I% g+ T! r: p9 h5 }+ t  HAL_TIM_DMABurst_ReadStart()! S* |) \( G3 K( u7 e! o
定时器常用的功能,通过上面这几步即可实现。
2 X2 p- y; g+ i$ N& U/ [, R; `% h9 P0 {
32.4 源文件stm32h7xx_hal_tim.c/ [( W" Q" o  L: `
此文件涉及到的函数非常多,这里把几个常用的函数做个说明:
# x6 t& S; @8 N$ J
6 \4 @1 a* Y& n+ U: I* v  HAL_TIM_Base_Init4 z' @; i( v/ A3 k
  HAL_TIM_Base_Start
2 I4 N! U' k6 D+ k  HAL_TIM_PWM_Init& u$ J5 s. {3 ~! M
  HAL_TIM_PWM_ConfigChannel8 l+ C+ x6 p' C. ]# B. {, W7 _; H
  HAL_TIM_PWM_Start
3 g* e' H" ?7 y: D* A  HAL_TIM_IC_Init
& }# F6 I; m% J3 V, Q! G* U  HAL_TIM_IC_ConfigChannel
% D3 f+ u9 R  ^, @  HAL_TIM_IC_Start_IT3 M' R, u! @8 S% _8 l. Y1 y: w. v
  HAL_TIM_OC_Init$ B4 i% F- b$ a2 s+ ?. J' a
  HAL_TIM_OC_ConfigChannel
& S3 n$ y# V& c: g  HAL_TIM_OC_Start- c9 l5 X7 W; N' ~. `: h
32.4.1 函数HAL_TIM_Base_Init
# S* N% T7 M1 C7 Z- R" J函数原型:. e5 O# M) n" x. T, M& H9 d
* y0 M' F1 K+ [; `0 H, s! }) E
  1. HAL_StatusTypeDef HAL_TIM_Base_Init(TIM_HandleTypeDef *htim)+ r4 n6 N% U) j8 }/ [
  2. { 2 l( h* [) j* k$ E$ {4 A
  3.   /* 检测是否是有效句柄 */! ~% t# m( H9 L3 S  p  q
  4.   if(htim == NULL)
    / d' C5 @5 o# R5 u3 r
  5.   {
    8 L+ i" s# I7 `; g* i3 j- g' k
  6.     return HAL_ERROR;+ x( t- `1 u% i+ e* Z
  7.   }( F* Z% _) D: l3 O

  8. - J, i0 }6 Z. p2 B7 R
  9.   /* 检测参数 */
    4 e1 l* ~4 h5 j: |
  10.   assert_param(IS_TIM_INSTANCE(htim->Instance));
    $ X- ~5 e: m; H& b( O
  11.   assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode));; V; v! }* [4 s* u+ c+ O! H
  12.   assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision));0 [0 R9 q8 N% y9 T4 S

  13. 1 F0 R1 t+ A% {3 B7 R
  14.   if(htim->State == HAL_TIM_STATE_RESET)
      S) Z# S/ |+ u. a! ^* D, W- G: |) n
  15.   { ' h9 H1 M- K8 h' u0 r
  16.     /* 默认取消锁 */
    & T! T% L  C8 W0 C" `2 z
  17.     htim->Lock = HAL_UNLOCKED;
    - R3 l5 ]2 W9 t) c. |) Q- @
  18.     /* 初始化底层硬件 : GPIO, CLOCK, NVIC */
    & Y& T4 \9 s) m( v2 O9 g
  19.     HAL_TIM_Base_MspInit(htim);& M) Q7 \) }! e3 B. u5 B
  20.   }
    : N# [$ S" }4 R
  21. 8 J; [9 Y, C% A7 j3 J* M
  22.   /* 设置TIM状态 */
    7 ^* X3 {" x  A* i7 F0 ^
  23.   htim->State= HAL_TIM_STATE_BUSY;
    4 L2 p; f! @# x! U4 g

  24. 6 g  K# r  V9 U" n; ]3 I( G
  25.   /* 基本参数配置 */
    ! `# Q3 [: u+ e1 x# m- n9 ^9 e
  26.   TIM_Base_SetConfig(htim->Instance, &htim->Init); 3 _9 R8 w  n: L4 V) D
  27. * t* n) c; [$ o: m/ }
  28.   /* 设置TIM就绪 */
    + F( [, e$ Q% C) a
  29.   htim->State= HAL_TIM_STATE_READY;
    ! ^8 L! m3 o" Y, h

  30. . T$ N! w2 V" D0 |7 O- m
  31.   return HAL_OK;
    ' C" ]8 [! v8 Z7 Q
  32. }
复制代码
" u9 b+ F% u5 q; j: f, J
函数描述:
& }: o, L- h& r  C
7 m% ^  Y9 O. `6 Y/ ^5 O5 j  C此函数用于初始化定时器用于PWM。
+ t' R* I3 L! \  D9 b: n2 m5 H2 Y/ b8 s+ H' E* o
函数参数:
$ W, M" j" b: y' w
2 i+ V- n, |0 k% Y8 o* u1 ?" J  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。5 v7 X5 l5 G9 L1 j3 s
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。( O) E6 n% t( a  B+ u
注意事项:& I! r- M& c# Y
1 P  D, m  ^7 ~0 k- m- [! m4 b: W
函数HAL_TIM_Base_MspInit用于初始化定时器的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能,由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。8 u$ m# S- d. y9 W6 b5 e0 ?$ _
如果形参htim的结构体成员gState没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量TIM_HandleTypeDef TimHandle。8 H; R+ s1 L# @- a- E  e( q3 B8 {: y3 o
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_TIM_STATE_RESET  = 0x00U。
% f; v6 |6 n7 I% ?6 Q+ {/ B
" ?  @% x( L5 Q+ y. L% z解决办法有三:
( q# ]! x+ c! }( n: f* p9 H$ N- q& F$ V5 J9 W- J
方法1:用户自己初始定时器和涉及到的GPIO等。
+ c- E1 D" ]- S8 k$ [% p  Z4 v# i' i! T
方法2:定义TIM_HandleTypeDef TimHandle为全局变量。
, D. N, z4 u6 r' Z) t6 E9 P+ r! A. i6 w9 q
方法3:下面的方法% D- |8 W5 [  e! ]* x

9 h1 E' G4 V5 X% V
  1. if(HAL_TIM_Base_DeInit(&TimHandle) != HAL_OK)% C0 H3 B4 e# M3 c7 e( n
  2. {
    9 q3 ~# S2 w; A" w5 z! e% _8 y! t
  3.     Error_Handler();
    - N1 _) r: d# q
  4. }  : H6 V: g% c. H+ v3 s3 o$ C- h
  5. if(HAL_TIM_Base_Init(&TimHandle) != HAL_OK)
    ) Z! o: A3 C( q- U. }/ w0 T
  6. {2 n. C5 I. H: u: ]0 X0 n
  7.     Error_Handler();  _9 g9 a$ o. B) p) e4 W3 M$ }
  8. }
复制代码
5 y1 K1 u0 J% j$ |+ X
使用举例:
' L( j2 v/ d9 _/ z
1 l6 w. w6 K) y$ s) p
  1. TIM_HandleTypeDef   TimHandle = {0};
      ?% w% `% [8 q/ R

  2. ' E) M! Z' Y# k4 v' Q9 f2 G
  3. /*   B  ~8 L, Y- Y+ a% R' ^8 q' s
  4.     定时器中断更新周期 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)
    ' a* h  T) l$ y
  5. */7 _' [5 F  K) U: ?6 M
  6. TimHandle.Instance = TIMx;
    : Z. h: }& t, a6 z( w+ v
  7. TimHandle.Init.Prescaler         = usPrescaler;' v3 e5 E- S9 d& q. i# \: k' F0 [
  8. TimHandle.Init.Period            = usPeriod;        , r3 m( F) s/ h9 y' r
  9. TimHandle.Init.ClockDivision     = 0;
    ' Z3 O# I+ B8 |- v! g. }
  10. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;$ I1 @9 `9 P5 V8 S7 e
  11. TimHandle.Init.RepetitionCounter = 0;
    2 O) C  Z% ^3 G/ d  D( K
  12. TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;0 n. ]) d# g2 W/ U7 Z* P! c
  13. if (HAL_TIM_Base_Init(&TimHandle) != HAL_OK), c3 c: Q  C* U5 }' p
  14. {
    4 ^. T( ^5 T6 S+ o
  15.         Error_Handler(__FILE__, __LINE__);& ^0 Z) D5 ~1 c0 v8 J2 o
  16. }
复制代码

) ?, r4 }& O- x# w32.4.2 函数HAL_TIM_Base_Start3 U+ U! F0 z  j3 C
函数原型:
9 `" |% {- H0 P7 u& l. ^
- B7 c7 z6 O6 t& X# y6 U+ p4 }' ]
  1. HAL_StatusTypeDef HAL_TIM_Base_Start(TIM_HandleTypeDef *htim), h" B8 E: f& l* U' m# M
  2. {
    2 v0 X; ?6 P% H" Y4 G
  3.   /* 检测参数状态 */
    / _: W9 h! H. p* W+ H/ c# a* O
  4.   assert_param(IS_TIM_INSTANCE(htim->Instance));8 t1 b: \# A! y7 B1 a. ]
  5. 2 h7 H) r7 T  l; i" D- b
  6.   /* 设置定时器状态 */
    ; {+ G$ y) B/ b* _
  7.   htim->State= HAL_TIM_STATE_BUSY;5 @1 U2 P4 g5 s* j+ t0 j- L) |

  8. 7 I) C0 L5 Z# U; d
  9.   /* 使能定时器 */
    # @) R$ n) |. W
  10.   __HAL_TIM_ENABLE(htim);
    % O6 g" M! F2 ~  v: Q& P
  11. + D" l" F* i+ Q, c& a3 I+ G
  12.   /* 设置定时器状态 */2 E# }5 @& Z, H$ `7 e
  13.   htim->State= HAL_TIM_STATE_READY;
    9 I7 P. f) f7 c' n9 J

  14. 8 T" b1 Q% A) P/ C' q
  15.   /* 返回HAL_OK */
    , s/ C5 y8 I* b; L6 f2 V
  16.   return HAL_OK;6 n/ j% S! x5 r1 a
  17. }
复制代码

) o. g9 w, [0 h1 o函数描述:0 k* B# K5 E+ q8 y* D

2 C" r9 f3 C$ @7 l4 e% y此函数比较简单,调用函数HAL_TIM_Base_Init配置了基础功能后,启动定时器。
  W5 |* Q) g! ?' h+ [) I4 j
9 f" C4 B6 D9 U9 m: o, g3 l函数参数:
; R5 x! ^7 |7 }
* _" d8 K1 b3 h  第1个参数是TIM_HandleTypeDef类型结构体指针变量。: k% B3 o* I9 e. j6 \# d
  返回值,固定返回HAL_OK,表示初始化成功。
( Q5 u5 u8 _* ?' B' Q+ ], S使用举例:( m, c- f# G6 g6 F; g
8 t: L2 E# Z+ V5 W5 U# m9 s, a# P  z
  1. TIM_HandleTypeDef   TimHandle = {0};
    , N- c# w8 O0 i9 E: C8 G
  2. ) u" a6 O: |/ W
  3. /* 7 q* ~+ E; c# d1 G* R
  4.     定时器中断更新周期 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)
    2 w# H* g& I5 o& N
  5. */
    6 t/ f& q" k' n1 E" q8 s. o4 Z% f7 M
  6. TimHandle.Instance = TIMx;8 m" L0 a9 g' M1 \% X: o
  7. TimHandle.Init.Prescaler         = usPrescaler;
    : l5 q. n2 B' J3 w. n
  8. TimHandle.Init.Period            = usPeriod;          D4 C5 {( A6 w+ \/ E
  9. TimHandle.Init.ClockDivision     = 0;
    # @  u1 B+ }8 i1 U
  10. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;1 c4 N% a" l3 ^2 Y$ _- r- K1 ?4 r
  11. TimHandle.Init.RepetitionCounter = 0;
    8 h7 m; R5 m& c& t
  12. TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
    # d; t3 b: D& V' [% F
  13. if (HAL_TIM_Base_Init(&TimHandle) != HAL_OK)
    % k2 |! g2 I0 A' `% J- U3 J
  14. {
    $ A+ g) t; b7 [; Q; m8 F
  15.         Error_Handler(__FILE__, __LINE__);% [# N# K9 @" t2 f; i& s
  16. }0 J# |( h( G2 K( F9 E$ {& ~
  17. & O# C9 h4 i# n& E5 T* H( j5 F4 R
  18. /* 启动定时器 */
    $ x6 ^  k) a" l0 X- V0 D2 ]) o: o$ ?
  19. if (HAL_TIM_Base_Start(&TimHandle) != HAL_OK)( G! i6 a# M" V
  20. {% L) h* N" B  q
  21. Error_Handler(__FILE__, __LINE__);- L+ t% i9 _8 [
  22. }
复制代码

( f/ B. @) F  I* c7 z% @/ e5 m+ l32.4.3 函数HAL_TIM_PWM_Init/ p! F3 U' Y2 Y$ O" {
函数原型:
8 X5 g) g0 f5 ]/ ?  M
4 J( d. h) U9 w  B% Q* I  A0 M/ B' y
  1. HAL_StatusTypeDef HAL_TIM_PWM_Init(TIM_HandleTypeDef *htim)! e+ T4 m* J# Y% J4 ~
  2. {
    4 c/ c9 O8 C+ ^: w
  3.   /* 检查句柄是否有效 */
    " D5 K/ A7 m+ ~. u1 ]3 a
  4.   if(htim == NULL)7 H, B1 w5 v5 x7 w
  5.   {4 K, p& b$ ^) Q0 N3 c# R: |+ z+ ~
  6.     return HAL_ERROR;
    9 h/ e6 w5 |& d0 u# D
  7.   }+ F4 p7 r( n! l; ^
  8. & Z6 U4 `( H3 [0 y0 i6 D+ n
  9.   /* 检测参数 */' i. F# z- {+ l9 {/ z
  10.   assert_param(IS_TIM_INSTANCE(htim->Instance));, q$ U; [" f- I
  11.   assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode));6 i' }% s8 {5 F6 K/ K7 t. U
  12.   assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision));  e& @5 I8 E  S$ ?* C6 [+ h
  13. 8 O: b2 Q- ]2 n$ l9 o. K- ~
  14.   if(htim->State == HAL_TIM_STATE_RESET)7 X) ~# F7 V7 u- U1 G$ T/ w
  15.   {" m* y. q5 H5 @3 l0 l
  16.     /* 默认取消锁 */
    + z2 m0 }- G+ h4 e7 v' K+ j/ e
  17.     htim->Lock = HAL_UNLOCKED;
    : V9 C* j  _/ A2 L. Z# L
  18. ) O5 S. p& s5 ~# T# C
  19.     /* 初始底层 : GPIO, CLOCK, NVIC 和 DMA */
    6 @1 i) @2 `% v# k
  20.     HAL_TIM_PWM_MspInit(htim);
      o8 C, Q) P5 Z" e4 A; L
  21.   }
    & c+ I( H: C1 e8 I4 _$ u$ v6 f! U. s

  22. 1 {! P6 O. r: Y
  23.   /* 设置定时状态 */
    & |4 v: s) `, ~, ?' w# y9 w
  24.   htim->State= HAL_TIM_STATE_BUSY;
    & I- b7 B+ Y" o- C# w
  25. , c3 {/ q. ]  a& J3 j
  26.   /* 配置定时器用于PWM */  
    : c/ Y% A% U  P+ N
  27.   TIM_Base_SetConfig(htim->Instance, &htim->Init); , J2 U7 _6 N* P& `
  28. 6 t+ Q! ^1 w+ ~1 N' w
  29.   /* 设置定时器状态 */
    6 h# y" P: }# I/ t9 k8 f
  30.   htim->State= HAL_TIM_STATE_READY;
    ; @1 |) ~+ O% n/ p8 X# z

  31. $ ]2 j' E8 }1 a  t: J7 R
  32.   return HAL_OK;
    ) e( `  F! W3 t; \% j2 \
  33. }
复制代码

. j, Z8 N3 {" l) O# I: T函数描述:/ |- M# h3 }* P
) _; ?9 r, j* |2 Z: A! O
此函数用于初始化定时为PWM方式。2 N7 w8 \+ M; C: U2 i5 j: y
$ i% |) i3 v' W2 Z( E& z% R
函数参数:* F! v# T: i: |* u/ c2 V
. v+ N5 _  s4 D7 p) M
  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。
8 I) s  T- k* Z  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
8 X5 b# R8 G% Y9 c4 R0 C注意事项:6 i- k" O' H) D: J

$ `4 I& @$ ?+ t" g函数HAL_TIM_PWM_MspInit用于初始化定时器的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能,由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
: l+ @; z5 m* r& r9 P如果形参htim的结构体成员gState没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量TIM_HandleTypeDef TimHandle。
  I. k3 s' Q3 |对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_TIM_STATE_RESET  = 0x00U。" A, c4 C5 a/ \6 v5 T7 l

3 i, A/ ]1 l; ?2 y5 S解决办法有三:: P' {7 d8 [9 `" R7 Z2 X

4 J5 f7 R* ^+ ~! E方法1:用户自己初始定时器和涉及到的GPIO等。* ?0 G# x+ J, h) q* y
5 m( b; A* J4 P4 R6 f; a6 M
方法2:定义TIM_HandleTypeDef TimHandle为全局变量。$ D0 D9 |! \6 S1 ?/ X  c, L

( p0 P9 [) |' ^- t5 B$ E- E方法3:下面的方法8 M$ O5 |1 O% g( y0 k) V& N

1 n% g+ p) h3 e: a/ p
  1. if(HAL_TIM_PWM_DeInit(&TimHandle) != HAL_OK)
    . U4 Z" P7 u; A1 M* \
  2. {
    2 [( s0 ^- R6 _1 h
  3.     Error_Handler();
    ' U3 {( p5 _  y
  4. }  - i% Z. }) N! |4 }/ W. p
  5. if(HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)
    4 t+ `+ i6 m* l9 {3 A# j
  6. {8 A' _7 C- {4 o6 J8 B. ?0 {
  7.     Error_Handler();
    # P" Q5 d- [) d2 p" b7 i
  8. }
复制代码
' W0 V; J' X* W  m3 \
使用举例:
* J# o% I! L  i' z8 Q. A5 U
  ~( C! @$ }0 M) ?/ e8 V& X5 v4 C; a/ A
  1. TIM_HandleTypeDef  TimHandle = {0};
    + e- _( z7 x( T4 Q( k, L0 M* Z

  2. 2 j7 |5 ^1 i) P: f. _
  3. /*  PWM频率 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)*/1 `6 g2 K8 y# |) E/ }
  4. TimHandle.Instance = TIM1;
    & Z4 w8 `0 d# ^  S6 R# D3 Z" H
  5. TimHandle.Init.Prescaler         = usPrescaler;9 j- Y0 Q7 C6 |; Z
  6. TimHandle.Init.Period            = usPeriod;1 O) @( x, U: I# B
  7. TimHandle.Init.ClockDivision     = 0;$ O+ C. i' {2 c
  8. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;
    % @& P- }0 \* }+ d3 I
  9. TimHandle.Init.RepetitionCounter = 0;
    8 m' m* U( x0 M: j
  10. TimHandle.Init.AutoReloadPreload = 0;
    / u9 x* C! u( \
  11. if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)- r9 |) l6 R* s2 R: V9 z
  12. {8 D1 ~' \" p8 {; N' C, R
  13.     Error_Handler(__FILE__, __LINE__);7 D  p5 _/ N, t; R( X' ~
  14. }
复制代码
/ T2 l4 W' d) S+ i$ a, z) u
32.4.4 函数HAL_TIM_PWM_ConfigChannel3 \+ ~2 E: h; H6 W9 T( l
函数原型:. a* I! i2 B. G2 c$ |9 h* d

# g: w  _$ t, }, c
  1. HAL_StatusTypeDef HAL_TIM_PWM_ConfigChannel(TIM_HandleTypeDef *htim,
    ( R4 ~7 I* V' I& d8 R  e
  2.                                             TIM_OC_InitTypeDef* sConfig,! j. Z! `  v* b3 |/ g
  3.                                             uint32_t Channel)
    $ Q! n$ ^% B/ B
  4. {
    # P: H' f' y" z& @) B8 [
  5.    /* 省略 */( r$ t$ f% M6 F9 W" P7 {

  6.   Y& b: }8 Y% }5 C
  7.   /* 开锁 */
    5 V& _. v& j$ c8 A4 s+ b- f
  8.   __HAL_LOCK(htim);
    0 N3 W$ z4 t+ K6 J: J7 ?- h3 ^

  9. 9 n. S) w0 N) n3 H+ n" K: D2 g
  10.   htim->State = HAL_TIM_STATE_BUSY;
    . ~% k* E3 U; o7 O7 P6 U
  11. 0 R% v$ m0 P3 U8 u2 ]7 ~1 |% b
  12.   switch (Channel)
    8 Z! E, t. W& D* n/ P; R5 q
  13.   {
    " p: H8 J9 u( ~% t
  14.     case TIM_CHANNEL_1:
    & ], a0 g) e- T  o
  15.     {
    / w- }" u  V) m+ Z, C
  16.       /* 检查参数 */( u$ y' h* N! ], R
  17.       assert_param(IS_TIM_CC1_INSTANCE(htim->Instance));: s( O1 c$ E6 ^4 ?. L
  18. 9 j, f1 Q  |+ o
  19.       /* 配置通道1的PWM模式 */
    , I0 F5 |: S# y
  20.       TIM_OC1_SetConfig(htim->Instance, sConfig);- j( e* w) ?/ m* L( W+ _

  21. & k0 a7 H' J& v4 c. w5 {
  22.       /*预装载使能,更新事件产生时写入有效 */
    ! b* ]/ E, _- Y6 b) B9 A0 k4 X
  23.       htim->Instance->CCMR1 |= TIM_CCMR1_OC1PE;$ P. k# a7 A8 @+ l, H1 K6 w/ b
  24. ; h( ~% I, |* {5 D5 T4 W' g& C: x
  25.       /* 配置是快速输出模式 */
    : I4 p/ Z7 e# J0 c  a+ _( V
  26.       htim->Instance->CCMR1 &= ~TIM_CCMR1_OC1FE;1 d& P  Y  }. y& k
  27.       htim->Instance->CCMR1 |= sConfig->OCFastMode;( o1 x. e! j9 B9 N$ c! G5 b; x
  28.     }
    1 a* f+ D1 B8 t9 Z, a# t
  29.     break;. |, R/ ~4 Y) B7 z

  30. : s3 ~$ B# \# S& B" o  W
  31.     case TIM_CHANNEL_2:
    3 l' p1 x" |5 ^
  32.     {6 Q, T+ k% j! c( R& Z6 |
  33.        /* 省略 */- H& t& n# `2 u: Q8 \3 P8 w# O% D
  34.     }
    - c9 P8 \  P, O- d
  35.     break;
    6 M4 e! ?, w4 z0 {
  36. & P! i4 z5 [: @0 `7 H' D
  37.     case TIM_CHANNEL_3:
    ( v: x2 a9 g* c* i, r: I# E
  38.     {
    & {& i* a/ {" J# M( s/ s* A* ?% Y
  39.        /* 省略 */
    , l2 ^9 l5 @6 r
  40.     }) u. G( ~3 h5 z! ~1 v1 |
  41.     break;) {. ]0 v! b  |2 B, z
  42. 6 Z# O& y5 d5 y" s0 D
  43.     case TIM_CHANNEL_4:3 X1 j% A* b* q1 C
  44.     {) n- @" B7 I4 l. Y
  45.       /* 省略 */
    $ n1 l7 E9 g; f0 y0 M9 l
  46.     }
    & m: w( }* s/ r! P6 O8 x" S
  47.     break;* G% N  b5 N" a1 }1 t, V- A; h/ o

  48. ' K& W0 b* O; v$ K, Z
  49.     case TIM_CHANNEL_5:4 A2 Y6 {0 P6 U5 F, J- h
  50.     {
    9 {8 q/ k$ K& g7 Y1 z
  51.        /* 省略 */9 X6 U6 K0 N; _, ~
  52.     }
    % V7 w9 A. q% K; |
  53.     break;% u0 N. U6 P0 N  J, S% r
  54. ! `- B, |4 v$ n& L' e( t
  55.     case TIM_CHANNEL_6:3 i2 A/ J  m7 ~; g! v
  56.     {
    ' [0 g1 p/ Y" z5 F# O6 Q- l$ r$ _7 D
  57.         /* 省略 */
    1 r& r" h" [; l7 m
  58.     }& i: A+ [, h. d' {* e! ^5 {
  59.     break;. S1 q7 X% w4 ?6 Y3 m7 @1 @1 ~* A

  60. 0 p. X, }! q( ?! l' L1 l7 y+ ^
  61.     default:
    ( s  v0 I: G2 `. k" T; K" d$ a' C
  62.     break;* ?; A, P* P) M
  63.   }; j" \! l/ W" |
  64. - ~0 Z& K* P8 g2 a! l+ V6 d
  65.   htim->State = HAL_TIM_STATE_READY;
    6 a2 c2 r+ ?: W' J. J( O5 m. ]% V
  66. $ t- D1 s) P1 _: g3 c
  67.   /* 关锁 */
    0 }( s# z/ r: T  w" G
  68.   __HAL_UNLOCK(htim);$ B0 y) z) P: z' V( R) f
  69. ) ?; n* i5 g$ _5 q4 s; q" I
  70.   return HAL_OK;7 f, v. O. ^3 |4 U' y
  71. }
复制代码
# t* |/ W' ]1 ^2 P6 r2 t; \- ~
函数描述:
: S" y8 x; K7 V: f
7 [9 q! Y2 b1 B& _9 o此函数用于配置定时器的PWM通道。' i5 P  J. R# X6 i" ~6 y  [2 M

* J: w0 |! d! r5 v# P$ m函数参数:
3 u( H) G. `9 A3 Q  W5 j. v
( i! L! _# d" c7 t! l  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于定时器基本参数配置。
! q$ B1 T1 s3 P4 k7 ]  第2个参数是TIM_OC_InitTypeDef类型结构体指定变量,用于定时器输出比较参数配置。! A6 {+ O+ b! E, L$ w
  第3个参数是通道设置,支持以下参数:
) S! D2 X9 |$ ]) z9 ITIM_CHANNEL_1! O7 f; @$ Q% c6 R% k

( D2 b) p# i, S4 ~- h4 }TIM_CHANNEL_2/ W5 M5 {4 p  D, i( i: r

- h* w, W( C0 ~+ r) jTIM_CHANNEL_3
/ M. y; W& c+ ]  g4 ?! A, n4 c/ \1 \- m+ i' Y
TIM_CHANNEL_4
' J9 j6 A! K! w" v% e- Y
5 |8 n5 Z2 ?1 r/ vTIM_CHANNEL_5
7 r7 Z. @1 J2 I
7 M- m: }! v; ?+ f. \- M3 Y" uTIM_CHANNEL_6
7 b4 b0 }0 h) e8 O+ `  I% H
- p/ u) ~, W0 m7 j. V" a  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。/ P6 V4 x( q% Z: K8 \# Y
使用举例:! A; E0 ]5 D& a

3 ?3 ?% S) J6 B4 P4 A
  1. TIM_HandleTypeDef  TimHandle = {0};
    + h6 y' P& z, H, I* R
  2. . ^/ A6 m) B8 w3 J* H
  3. /*  PWM频率 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)*/
    6 m# U% F4 w) T, f* y
  4. TimHandle.Instance = TIM1;1 ?- z- e3 d. a
  5. TimHandle.Init.Prescaler         = usPrescaler;
      m& G5 Q' m! K7 L7 _6 P
  6. TimHandle.Init.Period            = usPeriod;- {9 C; D  Y  {/ ?! i2 L! p
  7. TimHandle.Init.ClockDivision     = 0;8 b  h( S! o! K8 {; ~
  8. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;
    ; e) x8 j0 C; F0 g+ N# z
  9. TimHandle.Init.RepetitionCounter = 0;- R) k. Y; [3 s6 ]1 g; ]0 d: V* }
  10. TimHandle.Init.AutoReloadPreload = 0;- `2 a$ |+ Z$ o: o4 F$ e: x
  11. if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)
    0 G8 h! o  d; S) m# z
  12. {
    : J5 o( {: E6 d3 y/ n$ T# X4 n
  13.     Error_Handler(__FILE__, __LINE__);" w6 t4 U1 o; y# c
  14. }
    7 @8 M" p; z  `

  15. ' z( E# ?8 H1 e' y
  16. /* 配置定时器PWM输出通道 */% [+ |7 O% L' {) D$ Z# k/ k
  17. sConfig.OCMode       = TIM_OCMODE_PWM1;
    # e9 @8 W) q4 z% ^* i( [$ c
  18. sConfig.OCPolarity   = TIM_OCPOLARITY_HIGH;
    $ M! Y0 F1 \# ^1 q' y) E- n/ U& d
  19. sConfig.OCFastMode   = TIM_OCFAST_DISABLE;
    3 @3 w: `! g) G( [; ^( B/ y# K  }
  20. sConfig.OCNPolarity  = TIM_OCNPOLARITY_HIGH;
    & @% O! X  h$ m9 T$ x( u4 }3 t
  21. sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;- }6 ^1 i  x: y* P
  22. sConfig.OCIdleState  = TIM_OCIDLESTATE_RESET;
    ! o- @/ t; Y9 H4 N. X" Z! S

  23. + V% N5 u5 a: m8 z8 G! U
  24. /* 占空比 */$ h: R, \0 Q4 y1 \& v
  25. sConfig.Pulse = pulse;
    0 _. b7 V1 |( z2 {$ M% f( l
  26. if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &sConfig, TimChannel[_ucChannel]) != HAL_OK)) W6 T6 }* @% I
  27. {  Z- ^3 n* E7 c& `5 f- i* q. H
  28.     Error_Handler(__FILE__, __LINE__);, k) Y" v. Y; d: h
  29. }
复制代码

4 V" f: `0 h. |/ X( o- F5 T32.4.5 函数HAL_TIM_PWM_Start9 c9 I0 E& l( U
函数原型:: n; N) o, |& s" Q7 }% u4 {6 ^/ F
' Z+ q4 S9 W! ~1 T. \
  1. HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel)
    * C5 @! l1 [. c" m/ d/ ]1 ?
  2. {
    % T2 D1 @. _- @. t% L" Q, y
  3.   /* 检测参数 */1 F4 q* }$ {4 O3 |! R5 ~* q) N( r
  4.   assert_param(IS_TIM_CCX_INSTANCE(htim->Instance, Channel));% w" N/ I: r! _9 T1 d

  5. $ j. k9 l- n+ t0 d7 j
  6.   /* 使能捕获比较通道 */
    " }  U; M1 t1 A
  7.   TIM_CCxChannelCmd(htim->Instance, Channel, TIM_CCx_ENABLE);
    " G- \3 Q8 A7 M! Z4 c) n

  8. 0 {1 j  {, {9 T, M
  9.   if(IS_TIM_BREAK_INSTANCE(htim->Instance) != RESET)  # q9 d* l) V- R& Q, E
  10.   {
    $ g" ?# P5 A$ |3 h7 I& q8 Q
  11.     /* 使能主输出 */
    # ~& q: E, U/ h5 S2 }
  12.     __HAL_TIM_MOE_ENABLE(htim);
    . S7 H3 @, C0 U5 C8 @# i
  13.   }/ g: K7 y( {9 R6 S9 C
  14. . D$ `$ G) m/ `& R* b/ W' F2 q
  15.   /* 使能定时器 */, N! Y: T6 l/ V5 ~, F' r
  16.   __HAL_TIM_ENABLE(htim);
    1 F  ]& T8 c" q2 u) p: d" `. K' _

  17. 8 F5 a& O7 _7 @  V/ c; j
  18.   /* 返回状态*/6 ]" ~! V- L& n) D
  19.   return HAL_OK;; r: H  M* {4 t' Z% H. `( x
  20. }
复制代码

  p5 W- L* }* ?1 l函数描述:! [; [2 c/ |. M/ Y
+ j! K* S( _1 s( e/ N1 g
此函数用于启动PWM。' `( h& ?8 O" z) B
, K- s. t+ }5 O8 k: A
函数参数:0 S. d# A; ?* Z
( z9 c& b7 z9 k3 r" D  K
  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。
( n; j- p" L, T4 _% n" ~* Q  第2个参数是通道设置,支持以下参数:
5 F. h; D# j' X8 h9 nTIM_CHANNEL_1
- U  y9 m1 |  t# y! M+ a- u, k
; U, r# r& q4 O0 M) W: ZTIM_CHANNEL_2: S6 t% g$ }0 N7 [6 v5 M; |1 H

3 v# K& w* J1 B# g; L& ]TIM_CHANNEL_3/ y& s% e4 u- [4 z7 C% g
+ \5 f9 L( y8 ^7 Z, e
TIM_CHANNEL_4$ Q  q1 G0 Y% _4 z( _" e

+ c' P7 A: D$ ~/ a7 A! E  f) J2 `  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
5 {& M, R- @  s4 P, F6 @  a( U/ Q使用举例:0 J! i9 J" ~4 p- f
# ^" n$ O, f, ^: ~3 h( n
  1. TIM_HandleTypeDef  TimHandle = {0};
    $ T! a4 s2 q7 K  E) e: u
  2. 4 H' w' F' q: z4 w1 i
  3. /*  PWM频率 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)*/
    % \' ^' a, n' S1 G5 R8 K) l
  4. TimHandle.Instance = TIM1;
    - h2 N- l. d0 W
  5. TimHandle.Init.Prescaler         = usPrescaler;
    1 L1 f( _/ D7 v5 l- a
  6. TimHandle.Init.Period            = usPeriod;
      u4 o! s& ]; R$ O* F
  7. TimHandle.Init.ClockDivision     = 0;
    $ b; b5 p2 ~# E( Q& F5 }$ _: r/ i
  8. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;$ e5 |. K+ E7 k% F/ v+ n& G, C
  9. TimHandle.Init.RepetitionCounter = 0;
    / g0 j; Z. j- _% h  ^1 l
  10. TimHandle.Init.AutoReloadPreload = 0;
    ) x- r6 Q( d6 c- }
  11. if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)
    8 I7 u; p7 J5 H: m3 _
  12. {( ?, ]( I& F1 M
  13.     Error_Handler(__FILE__, __LINE__);
    7 Q" w  d; w7 F
  14. }
    & ?" }( @! t# x) [
  15. : F" l5 b2 p, q1 K+ K6 J' N2 H1 ~
  16. /* 配置定时器PWM输出通道 */0 X+ r. t8 B) E$ T& n1 c1 u
  17. sConfig.OCMode       = TIM_OCMODE_PWM1;
    2 W$ R, W1 Z9 ~3 ?% w4 Q
  18. sConfig.OCPolarity   = TIM_OCPOLARITY_HIGH;: Z" O. o- ]- s
  19. sConfig.OCFastMode   = TIM_OCFAST_DISABLE;% Y1 X5 g, B9 m% S* @6 s- g
  20. sConfig.OCNPolarity  = TIM_OCNPOLARITY_HIGH;9 i! ]% {8 z; v( x  R7 b; W8 N4 c
  21. sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;
    6 T1 O( Z9 y& |/ o
  22. sConfig.OCIdleState  = TIM_OCIDLESTATE_RESET;) ~+ o3 o3 U& U% R# @$ ~. H
  23. 2 h- Y$ |( z5 Q6 A7 }" S  Z
  24. /* 占空比 */
    ! L& @2 Z. k  a' D9 c
  25. sConfig.Pulse = pulse;
    , x- Y2 s0 P0 i6 C9 W3 Q% u' M
  26. if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &sConfig, TimChannel[_ucChannel]) != HAL_OK)
    - `* \' t# {: b
  27. {
    : e; y& G' S/ \% r: }
  28.     Error_Handler(__FILE__, __LINE__);
    $ @* a8 f* k& ~  D& n
  29. }0 C  F. Q/ V& y+ Y5 \4 @% h% O" z
  30. 1 O. M$ a" S7 Q7 H% H$ Y: ?
  31. /* 启动PWM输出 */' C7 W' j! A. r/ H
  32. if (HAL_TIM_PWM_Start(&TimHandle, TimChannel[_ucChannel]) != HAL_OK)
    - k* @2 Z/ _0 H5 @' f
  33. {
    % R, h' U6 [: W  M3 P- t4 v
  34.         Error_Handler(__FILE__, __LINE__);- {; o% f# A  F- v
  35. }
复制代码
- F1 h2 C  D7 a& W1 [
32.4.6 函数HAL_TIM_IC_Init( Y1 o7 p1 I' x+ I% A7 m
函数原型:% }. x( G! B. u) w4 F
: w3 j' ?. A# W- v7 }
  1. HAL_StatusTypeDef HAL_TIM_IC_Init(TIM_HandleTypeDef *htim)& d6 n' N* G$ h; J2 J" S- Y
  2. {
    6 P- H. N4 C5 a5 r
  3.   /* 检测形参是否有效 */
    5 C9 R% s/ T& R9 ^( p5 B
  4.   if(htim == NULL)! X5 U& L2 W5 n
  5.   {
    " `5 f  Y+ X1 @2 ]1 f( t" ]
  6.     return HAL_ERROR;. J$ F2 V% p1 |
  7.   }; e) C  D* |' x- E
  8. 1 H7 o; Q% D1 O! z" T
  9.   /* 检测参数 */
    * l+ @6 I: K6 ]( N/ {/ u7 \: _0 }$ A
  10.   assert_param(IS_TIM_INSTANCE(htim->Instance));6 X0 [1 k3 R$ Y
  11.   assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode));4 W% @" _, f* \  X
  12.   assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision));
    9 e) U( O/ c& y" L7 _$ ?
  13. * V; Q- E3 n  h5 D7 V# S
  14.   if(htim->State == HAL_TIM_STATE_RESET)& a5 G) v( o% e. Z: R
  15.   {
    6 Q! l* t* P3 ]( c% N% I" i( ^
  16. /* 默认取消锁 */$ f# [5 j; C9 A( h4 P1 P
  17.     htim->Lock = HAL_UNLOCKED;' Z1 ?/ q% B) t6 d4 ?

  18. / S5 p, G' d" C1 o, h
  19.      /* 初始底层 : GPIO, CLOCK, NVIC 和 DMA */5 W  |$ Q9 U5 c+ S: m' c3 S' Z
  20.     HAL_TIM_IC_MspInit(htim);
    $ R5 [: U  K& k8 ^, q
  21.   }
    ; ^/ ?# `; N9 v: O, |. s
  22. - r) Z  P( E4 {2 C
  23.   /* 设置定时器状态 */
    7 }1 n" l) R) n6 L, x1 A* _1 U
  24.   htim->State= HAL_TIM_STATE_BUSY;
    & q) |8 J! [' c# ^7 f6 O
  25. , T' E( j; Z. G+ O
  26.   /* 配置定时器为输入捕获模式 */  9 ~# p3 j. j9 ^" H$ }
  27.   TIM_Base_SetConfig(htim->Instance, &htim->Init); * q% F1 z; Z- {
  28. , e  j! G$ @- a: O1 ~: T9 Z
  29.   /* 设置定时器状态 */
    , R6 ]# z; N4 h) |/ ~1 z' h  w
  30.   htim->State= HAL_TIM_STATE_READY;
    / P: [8 y3 e: _7 f5 F

  31. & ?" m& t! m0 R) k* G
  32.   return HAL_OK;4 C" n0 C, f8 I: l6 J* L, e: a
  33. }
复制代码
/ C1 g# s4 z7 c$ X3 o
函数描述:
7 `& {( \7 s) S) M" g# N( U+ F
# |) h5 k) X$ _7 ~( [此函数用于定时器输入捕获初始化。
% G  w% a6 }% H, t% e
; P0 R( Z' x' G8 w函数参数:4 a" V6 a0 r/ O. e
5 n3 C5 x; S" J+ I, Z- v
  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。
7 t) O( Y0 f  _" w" o) R: C8 U8 e4 A2 l  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。' J' e  C9 d, g4 a
注意事项:
  s5 y0 U5 D- ?/ F, s3 T
7 X1 Z" Z* h5 R3 Q$ ]函数HAL_TIM_IC_MspInit用于初始化定时器的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能,由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
: a: y3 f. m0 T8 U+ Y如果形参htim的结构体成员gState没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量TIM_HandleTypeDef TimHandle。
- o! w$ ^# {% d2 [( J+ \. ]对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个HAL_TIM_STATE_RESET  = 0x00U。2 y4 F* M# d. v5 K- F$ W  _

7 Y4 R4 J# I: K! A$ B  L% B# C6 c解决办法有三:
- `* ~2 N. N* g  n: O$ R* K
$ \" D$ I" Z% o/ l方法1:用户自己初始定时器和涉及到的GPIO等。/ M3 f" v3 k6 w) [
( i. |+ I# ]3 S+ G5 J
方法2:定义TIM_HandleTypeDef TimHandle为全局变量。
* }7 h7 t! W3 p4 i% j# \$ }$ D8 @* K3 A2 e  h7 B! Y$ f9 T
方法3;下面的方法
$ |. v9 D- Y( V  l1 _$ S& @% V/ L4 s# I
  1. if(HAL_TIM_IC_DeInit(&UartHandle) != HAL_OK)
    - }4 o. Z7 [; p' l  B
  2. {
    / S2 W9 d4 I, c: H
  3.     Error_Handler();1 z% S* i% z! Z7 m" {
  4. }  
    1 v  {; }; U0 t
  5. if(HAL_TIM_IC_Init(&UartHandle) != HAL_OK); |& ~8 R* f6 a' y
  6. {( q6 m$ n  ^" U
  7.     Error_Handler();, Y/ d7 N3 u" \0 Y$ B1 X. A4 C
  8. }
复制代码
; X2 G8 R8 ~2 T/ g/ ~1 f0 J
32.4.7 函数HAL_TIM_IC_ConfigChannel5 k* I9 @- M% q& O1 B$ z5 B- `
函数原型:
+ c9 V" ]. h. ?  R$ V; K9 m
5 r! P: U5 B( u
  1. HAL_StatusTypeDef HAL_TIM_IC_ConfigChannel(TIM_HandleTypeDef *htim, TIM_IC_InitTypeDef* sConfig, uint32_t Channel)" o3 t" h$ d6 X: ~$ ~
  2. {6 X! \, r, b& }, h4 s
  3.   /* 检查参数 */
    8 i# |8 d7 @) W9 f" T
  4.   assert_param(IS_TIM_CC1_INSTANCE(htim->Instance));- F( e5 f8 w9 H, T
  5.   assert_param(IS_TIM_IC_POLARITY(sConfig->ICPolarity));- m% ^- U% N6 i
  6.   assert_param(IS_TIM_IC_SELECTION(sConfig->ICSelection));. Y# |6 c/ r$ `7 l7 G* t  b
  7.   assert_param(IS_TIM_IC_PRESCALER(sConfig->ICPrescaler));; L: P+ q* u* u6 M8 e5 T
  8.   assert_param(IS_TIM_IC_FILTER(sConfig->ICFilter));
    + w/ I, V" Y! M! b# r. `$ w

  9. + R% `. i6 g% }1 p+ Q! t7 f
  10.   /* 开锁 */  " l. m' I( C2 R, I. Q
  11.   __HAL_LOCK(htim);( Y9 L/ A1 Y+ c3 K0 \4 A
  12. ! A' Y! {3 b5 }. H0 i+ O# z0 n% i
  13.   htim->State = HAL_TIM_STATE_BUSY;$ r5 ?/ O( `* b2 m( M
  14. 7 [4 F4 J) b% Q7 \" F8 Y4 ?. d
  15.   if (Channel == TIM_CHANNEL_1)% N, Q/ m, I1 B: b
  16.   {
    ( L/ A  `) n  A- y
  17.     /* 配置输入通道1 */
    9 k6 G0 M* H, a% f6 h; Q
  18.     TIM_TI1_SetConfig(htim->Instance,
    3 J% R, ]% _+ z2 \
  19.                sConfig->ICPolarity,4 j7 J2 ~. G; [  J3 A
  20.                sConfig->ICSelection,6 E8 \* o: G) {2 _% ]3 B
  21.                sConfig->ICFilter);- ^, P2 O' ?4 t7 A; i- X3 H
  22. 9 ^% V  S, f9 M) u& u3 j; v8 \
  23.     /* 清零IC1PSC位 */
    - ]1 F0 d# i! t, \2 q' z/ [% K: z
  24.     htim->Instance->CCMR1 &= ~TIM_CCMR1_IC1PSC;
    4 K  V2 z& ^& v6 S5 z2 `
  25. 6 y7 j* I7 k% t  @4 N  X1 w
  26.     /* 根据用户配置,设置分频 */
    - l4 U0 _) r0 z% Y6 e
  27.     htim->Instance->CCMR1 |= sConfig->ICPrescaler;
    ! G9 M3 t" M2 `
  28.   }
    + ^; ^: [  {: a! {! ^
  29.   else if (Channel == TIM_CHANNEL_2)" o9 Y8 I. s, s; @# l% ]' d0 x
  30.   {
    7 u1 ]' \: ]7 ]. j  ~0 T
  31. /* 省略 */' W6 k# f: B9 p5 {; m& @6 Z
  32.   }0 \2 A8 s) ^2 m& T% T$ L. i
  33.   else if (Channel == TIM_CHANNEL_3)% m! L" c# \6 C) V
  34.   {5 ]: h: \! g  M2 ]0 ^, I5 h$ I
  35.      /* 省略 */
    $ g6 g7 R% w5 D! v( }, }
  36.   }/ F8 k5 t9 ?+ e8 m
  37.   else+ g5 U& j* ^* A3 }4 J; L6 h% N$ L0 R
  38.   {  N- a- r9 w  I
  39.      /* 省略 */+ A( X, P1 r9 r( p
  40.   }, L1 `' P1 b, v' y

  41. 0 J+ Z% k" D! I/ ~' M
  42.   htim->State = HAL_TIM_STATE_READY;4 ^6 _3 h' r7 E
  43. ; n$ _" z+ b( I( \
  44.   __HAL_UNLOCK(htim);( T. [$ ^* J  K

  45. # S/ Q# U- F) k) P( |( `
  46.   return HAL_OK; 0 d0 D; W0 X2 }& V7 O& j
  47. }
复制代码

2 W+ Y! \9 D+ P8 |# J7 |, v6 c函数描述:/ k( {) t5 |6 N9 f5 Q+ k6 o" J

0 ]8 C% r+ ]7 ?此函数用于配置定时器的输入捕获通道。8 ]; Y9 ^4 N% ~& F9 @# ?2 M
- @3 d- a- V/ k' `' U) ^
函数参数:
! [& ~; E  e) X
3 G# E' J% Y( S7 Q3 U; B  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于定时器基本参数配置6 j5 O5 s; P1 X- Z
  第2个参数是TIM_IC_InitTypeDef类型结构体指定变量,用于定时器输出比较参数配置。: M- Q2 x5 {, e/ a; H
  第3个参数是通道设置,支持以下参数:7 z3 N) v5 S+ o. `& q* V  u( C
TIM_CHANNEL_1) Q' j" Q7 \; A& Y" N

3 Z) S0 c% U9 Z- xTIM_CHANNEL_2
4 j' S8 {  a& D- O$ F- k5 @: x/ f% ]: p  I2 ~8 ]
TIM_CHANNEL_3
3 K' t8 V7 Q# ^9 J" }9 M$ R! ~
TIM_CHANNEL_4
6 M' S7 I1 ^4 V9 {+ G" |( L7 L& d2 G% Y! |  P& D6 G
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。9 U/ F4 C, X6 ]" @) w

' J7 R: [1 x8 e32.4.8 函数HAL_TIM_IC_Start_IT
* x3 V! `: f" L; n7 f1 X9 j函数原型:. R1 u7 P; }8 P+ b! J/ v4 K4 m

3 p1 e) B9 K! z* t0 a
  1. HAL_StatusTypeDef HAL_TIM_IC_Start_IT (TIM_HandleTypeDef *htim, uint32_t Channel)
    8 x; B6 }6 g8 R$ y5 B
  2. {
    7 B; R! P3 R% {& i* z5 j6 ~
  3.   /* 检查参数 *// n2 }" M' I+ x5 A
  4.   assert_param(IS_TIM_CCX_INSTANCE(htim->Instance, Channel));
    : z5 O2 e5 A* G/ p+ ?
  5. 8 F0 ]- L' ?$ \9 E3 }
  6.   switch (Channel)5 t: Q% {# E  c0 U" r; W5 h
  7.   {, h) F6 w6 ~6 X# @( j& ?: l7 j
  8.     case TIM_CHANNEL_1:2 }, x; m' J& B+ S# \, k
  9.     {      
    " j8 k, A$ i+ R* C3 T( j  r! Q
  10.       /* 使能CC1(Capture/Compare 1)中断 */
    " Q' B$ n: s$ h5 ]
  11.       __HAL_TIM_ENABLE_IT(htim, TIM_IT_CC1);
    - P$ }) l" q8 v8 u' Y. E! i6 b% G1 m
  12.     }
    - D6 O1 Y# L* C6 t) K1 w% {* d9 T. y
  13.     break;
    " R4 t% F2 J" H" x% [

  14. ! f- L6 l0 K' K1 a! C& H  o) e0 v
  15.     case TIM_CHANNEL_2:
      r) }  K1 s9 u' q( Y% H9 A
  16.     {
    6 D& f. g$ U8 l1 @
  17.    /* 省略 */' _3 i" {! P3 C$ E9 O* [
  18.     }# _7 d5 b2 v! T# k+ ?! s
  19.     break;/ f9 t/ s. M3 j+ ^- [3 @
  20. 7 Z! q" }7 C  |! ^6 W7 t
  21.     case TIM_CHANNEL_3:% F* c- v9 B7 M, M- P2 i
  22.     {: f. E% L8 _9 r# D7 b" n$ J- D
  23.   /* 省略 */
    ' A. _9 ]. X8 U  e
  24.     }0 q7 P( V. C; i  W
  25.     break;
    . X( E9 U' `0 K! {  i$ h
  26. 2 D3 _0 B% c$ n
  27.     case TIM_CHANNEL_4:
    9 z3 Q9 h' T6 ^4 k* C. |( u  Y! F
  28.     {& Z& _' Z5 d' @4 F6 l5 ]8 O
  29.   /* 省略 */. E+ @% @4 ~% b$ {: Z- B
  30.     }+ F7 L' Z9 g* T4 h( \3 u+ X
  31.     break;% ~. ]5 N* Z2 b5 J" t

  32. 6 ?( {5 E/ e4 F& k
  33.     default:
    7 u' j/ O- G* _9 d, a
  34.     break;! I: p5 W4 M2 L
  35.   }  " N7 o! P( o7 {1 [
  36.   /* 使能输入捕获通道 */6 n- J- [5 @+ `9 b. c4 t$ P
  37.   TIM_CCxChannelCmd(htim->Instance, Channel, TIM_CCx_ENABLE);
    9 M9 ^; l% i0 |' H
  38. $ R0 @3 l3 m. x% T6 g; D
  39.   /* 使能定时器 */' f9 ~0 L/ \2 C" Z/ ^6 L
  40.   __HAL_TIM_ENABLE(htim);  6 i0 o4 t( s8 P7 D+ k/ w1 o
  41. . J  r6 v, V- [4 h+ g" [
  42.   /* 返回状态 */
    ) Q; \: @& b+ k/ Z+ F4 u
  43.   return HAL_OK;  
    % |' t' u( C, L5 [) U2 L5 M) h% q5 I
  44. }
复制代码
2 l! k. I8 w2 T/ \, \
函数描述:
4 `! C+ B4 A3 b, |8 y0 @) B
& u4 m+ E( h+ O) J& \) z+ ?4 {此函数用于启动定时器输入捕获模式,采用定时器方式。
: ]6 v$ h6 k: a& I, q$ f
1 u  c9 T# D4 I3 {# {2 r0 I函数参数:! P6 M7 |& G& d9 _

$ C5 \$ n' n: _' W" _9 A# Z" B0 U  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。
/ j6 o; g7 j+ O3 K  第2个参数是通道设置,支持以下参数:) _+ I7 V# {0 p3 T  K. N& A9 q
TIM_CHANNEL_1
. Q# S( J: H# B( l3 }! F- Z8 u# j+ K8 f2 Z5 ^
TIM_CHANNEL_2
! ^: G7 L* P- z7 |, Y& D
* F9 @' J+ k. f& c; @2 r$ _0 ?% QTIM_CHANNEL_35 |5 T. Y3 S9 q2 i9 M/ D
' `- |4 e1 X& @/ L4 G
TIM_CHANNEL_4
+ L- X$ w4 v; k9 e* j4 }) P; f% i, V" e* B# D5 K) y" X
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。% t$ c( U/ E7 U" {
! l8 Z' y0 p2 \0 W. T
32.4.9 函数HAL_TIM_OC_Init
/ I3 Q, S  ^7 i4 m" g+ P7 T/ }1 m函数原型:
1 y4 v1 o0 t2 `6 f' X8 }- }  n7 }4 T( U, q
  1. HAL_StatusTypeDef HAL_TIM_OC_Init(TIM_HandleTypeDef* htim)
    6 x0 ]/ \. J+ ^* ^; V; `
  2. {/ Y( t8 l3 z7 `8 n7 N. o5 ^
  3.   /* 检测形参是否有效 Check */
    : ]) _# z$ e/ i+ ^! F0 }- Y
  4.   if(htim == NULL)6 r6 I* V% `, j+ k4 D
  5.   {% u5 V9 I1 i4 e. J; @3 a# B
  6.     return HAL_ERROR;
    % v! H/ M" }7 r( m1 N7 ~% i8 l
  7.   }
    7 ]4 s; [2 v. m% @8 t1 @3 Q
  8. 6 R. n+ z. Y1 i, d; A
  9.   /* 检查参数 */
    7 S6 O* f! h, t, P
  10.   assert_param(IS_TIM_INSTANCE(htim->Instance));
    % g8 j/ m. n" `
  11.   assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode));3 y; M  K1 K; ?4 h! I
  12.   assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision));2 g/ F5 ^) `) l& `  y2 u

  13. . _- ]- Q. O) F8 ?
  14.   if(htim->State == HAL_TIM_STATE_RESET)& Z* h1 I+ c6 c# Y- c* K
  15.   {
    3 j. s" z- o: v
  16. /* 默认取消锁 */
    ! P/ O( ^, o- j8 J
  17.     htim->Lock = HAL_UNLOCKED;
    & h! S; _! h, J8 i4 I7 H" @4 c5 g8 _: ~

  18. ) ?9 l* `. A1 k8 A* w. h0 B* z: Q! d  d
  19. /* 初始底层 : GPIO, CLOCK, NVIC 和 DMA */
    9 D3 v2 Y! k) G7 K
  20.     HAL_TIM_OC_MspInit(htim);
    % A, n/ [1 v2 C5 i( u% f
  21.   }
    " P) y( N/ k3 x' v8 b" a

  22. . S; i8 m3 v9 ]9 H3 l
  23.   /* 设置定时器状态Set the TIM state */) f% M7 j3 j' \/ C. G8 r/ h7 {
  24.   htim->State= HAL_TIM_STATE_BUSY;
    ; t8 z6 R. D) K  i

  25. 9 {% {( T8 ^' {" ?
  26.   /* 配置定时器为输出比较模式Init the base time for the Output Compare */  ( R1 ?9 H4 S8 m
  27.   TIM_Base_SetConfig(htim->Instance,  &htim->Init);
    9 L5 T9 |( B) {

  28. + n8 p" q" q9 m7 N; h% H
  29.   /* 设置定时器状态 */
    8 _5 S& c) _# I3 G# y7 v' \
  30.   htim->State= HAL_TIM_STATE_READY;
    % K9 a& p7 t( d- Z' [; j, h; m

  31. ( P' Z7 J- h" ~- a) f
  32.   return HAL_OK;$ q+ a! L: |  z  K6 K
  33. }
复制代码
4 E2 [% a! Q( s' a
函数描述:
' M2 {: S4 a  @; T; E
" G7 ?) a5 W  Y此函数用于定时器输出比较初始化。
- x+ c2 I- s4 x
# t( K) M# ]9 ]9 I7 A/ H% ?6 o函数参数:
9 t7 D* J% o; j( ~
( a2 p/ W1 T, Y  l3 F  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。  W) q0 N' B8 G- K
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。/ C7 v, l" x" R4 `# M! u
注意事项:) p, ^0 s9 _5 m. ~3 q

/ a& Q* Y& @. Z, H. S函数HAL_TIM_OC_MspInit用于初始化定时器的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能,由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
' s, V" N. w( ?如果形参htim的结构体成员gState没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量TIM_HandleTypeDef TimHandle。8 N# c1 `& T8 L
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个HAL_TIM_STATE_RESET  = 0x00U。
: Z7 d* U# b' [4 o" i' d, j/ V
0 K/ h7 U6 h% j解决办法有三:# ]! A' C8 {5 ]# U5 M* ~" g

7 A+ O. j' {2 t! o  R! M方法1:用户自己初始定时器和涉及到的GPIO等。
1 g; r& Y8 b0 M5 T  T
( U. L0 ]0 r$ W5 j+ |; E: G方法2:定义TIM_HandleTypeDef TimHandle为全局变量。
" F. J" t7 P' B+ O; g5 y, r# i
方法3;下面的方法
7 U1 T- z  q6 \) N3 ]% z- E
1 P2 s3 N  I! d+ D; j  f* q2 _3 B
  1. if(HAL_TIM_OC_DeInit(&UartHandle) != HAL_OK)
    5 Y# F( l" ?' M! P" E: x7 F# a
  2. {
    4 }7 Z+ q7 I; W
  3.     Error_Handler();
    + ]& j5 N2 b: G4 E5 P" a( F  Y
  4. }  
    + v* d1 t3 Q8 }! |% _9 ]( O
  5. if(HAL_TIM_OC_Init(&UartHandle) != HAL_OK)9 B: a+ e1 T3 m! V& _5 @8 h  `  |
  6. {
    * k# k2 _* S1 t7 R1 D
  7.     Error_Handler();
    9 {/ P! M3 _0 y; O
  8. }
复制代码

0 h! a' |5 |' h4 x9 [32.4.10   函数HAL_TIM_OC_ConfigChannel3 F$ B" S  R/ V- `$ ~
函数原型:
- t. M: q: R4 D0 n; {- a! p
1 Y/ H5 Y$ f% T& G1 s
  1. HAL_StatusTypeDef HAL_TIM_OC_ConfigChannel(TIM_HandleTypeDef *htim,
    $ T' ^& }8 }, o/ L3 |9 a
  2.                                            TIM_OC_InitTypeDef* sConfig,
    % V. N% R6 O) V, j# `' G9 h3 i+ A
  3.                                            uint32_t Channel)
    ( f7 _$ t  q9 X) ?& M8 a6 E9 q
  4. {  
    % Y6 o$ F: R) V. ~# y( Z$ ?
  5.   /* Check the parameters */
    3 T# Z& I5 \2 D8 `8 }: O
  6.   assert_param(IS_TIM_CHANNELS(Channel));
    1 F  h: X9 L( a! @
  7.   assert_param(IS_TIM_OC_MODE(sConfig->OCMode));: I3 G6 J2 ?$ u$ g
  8.   assert_param(IS_TIM_OC_POLARITY(sConfig->OCPolarity));+ E6 `7 u$ z8 l/ H: g0 J) k

  9. / D' P0 u0 u$ r4 a
  10.   /* Process Locked */$ m% J2 h: w4 D& X' K& ?/ x% U9 o
  11.   __HAL_LOCK(htim);
    4 `2 N5 i) r8 ^. ], w6 O0 p: w
  12. . P* @3 U& U# W1 ]; ~' R
  13.   htim->State = HAL_TIM_STATE_BUSY;
    % A1 i3 z, x% g/ s- C9 d

  14. 7 Y- l, W# f* X/ o4 y& q0 t! u8 K! i
  15.   switch (Channel)0 u! S. Z0 e( L
  16.   {7 u  h* I' I/ g; j/ F( H# P
  17.     case TIM_CHANNEL_1:2 j6 J3 c! k2 [8 |, P
  18.     {! d3 S7 m3 J. ]% B; ~
  19.       /* 检测参数Check the parameters */$ l; g# o5 \3 X* F3 O/ h1 y
  20.       assert_param(IS_TIM_CC1_INSTANCE(htim->Instance)); " J+ q/ f0 m# P% a. p2 Z, M
  21. 8 G" G1 b& t% ?* Y* q
  22.      /* 配置定时器输出比较通道1 */0 H6 e0 @: b" g6 e  o7 `7 L% l8 l! y
  23.       TIM_OC1_SetConfig(htim->Instance, sConfig);
    # E  [8 ]$ U! a, S
  24.     }
    & R2 o. b1 |! G( X8 S1 S
  25.     break;
    6 ^2 r$ z- w7 H6 Q# B

  26. 5 A' A6 Y/ C- d. p" {! _6 j& Z  |) T1 y& l
  27.     case TIM_CHANNEL_2:* U/ }3 ~" o# w# R; {" ~
  28.     {
    $ n. @8 N" }4 p! y) H! R! z$ x6 m  t# Q
  29.       /* 省略 */
    ( t3 J' O7 ^. f& o! k% ^# y) e
  30.     }, O3 f9 ?! n* I4 ^+ S
  31.     break;, s) @: `% \1 M9 T; F

  32. 8 X7 I% @" L; T
  33.     case TIM_CHANNEL_3:( D7 ^5 q$ w6 W$ V, P
  34.     {
    , m- m7 T$ `. a% `' E1 `
  35.       /* 省略 */* Y9 Z7 d& d% k* J7 _; Y% W
  36.     }
    ) g  f( s" N# t3 I8 N
  37.     break;' w* L' t# E: Q8 H1 R: |
  38. + t, H) \' T0 k" K/ B) R8 L
  39.     case TIM_CHANNEL_4:
    9 Q. d! S5 K" ?1 J( z$ K
  40.     {$ V5 G! |; W) {0 B0 x+ ~
  41.       /* 省略 */
    / q/ r- C/ J* I/ R
  42.     }
    * `$ W* f  y: H6 T& ^! R
  43.     break;
    8 J0 C7 X- w, E" ^1 g: ?
  44. # z3 M4 o+ ?" C
  45.     case TIM_CHANNEL_5:$ c6 t6 R1 Y$ j. T2 S4 c* U+ l3 Q1 R/ G
  46.     {
    / Y, B  h! Z" P1 }/ L: a$ ]
  47.       /* 省略 */5 l2 o+ ~! n5 H; a8 h% i: i( p4 r) S) i
  48.     }
    ! b& _; w  F7 l0 I5 x
  49.     break;
    5 j! {, s3 @3 `) j+ ?! h
  50. 1 f: c  l, _+ C. H
  51.     case TIM_CHANNEL_6:% [5 u' m) [  F: ]# M
  52.     {
    & d- ~- u: M& g5 d8 z$ J5 _
  53.       /* 省略 */
    0 I/ J. u& v" o; T# S. U
  54.     }+ ^( g. ?8 R% M6 `6 y, G
  55.     break;
    ' v: w- f+ Q2 w* e* a% _. z$ d% ]

  56. ! Y6 p3 D& C6 |$ Z' W% b
  57.     default:8 j8 n# }; B  U9 g& F
  58.     break;   
    + F+ H! s& O7 O. l, U
  59.   }6 m" h& L/ b' W. n+ S( B2 B
  60. 0 n7 ~- D' Q1 C/ r- k) Y* K6 m
  61.   htim->State = HAL_TIM_STATE_READY;
    / t+ ?7 L& q* ^3 ^" _

  62. 6 ?- D9 U% Y" B
  63.   __HAL_UNLOCK(htim); ! w' w% T7 J' ]
  64. " E$ y$ y* F& w3 n* }) `
  65.   return HAL_OK;+ N/ u0 Z" N3 e3 T* n) F6 v8 l+ v
  66. }
复制代码
! o9 a6 l0 t: n
函数描述:1 m! c4 a; W8 r
6 D% P0 w8 d; @! a: [4 W
此函数用于初始化串口的基础特性和高级特性。
5 Z2 ?& Z) J& k1 W5 A
  `+ o% g( L) b0 K0 \, n函数参数:; n3 Y9 ?, P+ ]$ Z9 Z' L, c

' e. j. K- @0 _4 r- E  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于定时器基本参数配置。
. w7 {- ]8 d& W4 t, X/ V1 h6 T. n  第2个参数是TIM_OC_InitTypeDef类型结构体指定变量,用于定时器输出比较参数配置。# j1 \) ?, z2 }; r. o1 `
  第3个参数是通道设置,支持以下参数:) X' u% f- ^0 n% E
TIM_CHANNEL_1
% X1 O; N" ?( O+ C- B9 }0 j5 b: |4 i6 l- P0 O% ~- t* }
TIM_CHANNEL_21 X/ \  f8 m; A1 a/ [

5 [6 U% \4 ?' b/ NTIM_CHANNEL_3
8 J# w  P) J1 `
* L4 Z, u- C& J% c4 E7 t# q5 `TIM_CHANNEL_4
) ?$ G0 s* u) d5 Y2 d8 |6 v- R( ^/ U( [
TIM_CHANNEL_5
; {, \% @: [7 f$ u) s$ f& Z" n% p, \' m3 r. p
TIM_CHANNEL_6
: R5 i9 F' c2 T% w6 ?8 ?
; T, p2 w2 E: w( S$ t1 [' U( ?1 u6 m  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。3 M/ V6 R+ a) t
: [; o: I0 f* n) @& F6 Y  v- R
32.4.11   函数HAL_TIM_OC_Start+ z7 ^; I- R0 K
函数原型:
$ C2 n2 O8 P+ c6 h6 Y& s8 j$ u( j0 \
  1. HAL_StatusTypeDef HAL_TIM_OC_Start(TIM_HandleTypeDef *htim, uint32_t Channel)
    7 L3 ~9 r! C# @. Z. a
  2. {: z' v6 l/ t2 S0 I, P; {6 ^$ P
  3.   /* 检查参数 */4 d2 ~' ^/ c% H0 X3 r5 S( Z
  4.   assert_param(IS_TIM_CCX_INSTANCE(htim->Instance, Channel));# K, z7 p/ a8 p6 `* E8 z
  5. $ x  a7 G; J7 ]% Q& B
  6.   /* 使能输出比较通道 */1 d- q) X- t5 R! A' G1 o6 z
  7.   TIM_CCxChannelCmd(htim->Instance, Channel, TIM_CCx_ENABLE);
    / J4 q$ c* j* O) l

  8. 7 L7 H9 B7 D( r
  9.   if(IS_TIM_BREAK_INSTANCE(htim->Instance) != RESET)  
    , z, B  s' b* O- R& Y& l( S
  10.   {) i: B# o2 ?+ H! x' R1 v* W- |
  11.     /* 使能主输出 */7 b5 u! r, S) l% }
  12.     __HAL_TIM_MOE_ENABLE(htim);
    4 c+ y3 T$ i2 E6 V0 z" X
  13.   }
    2 a& Y, x5 q6 R: l

  14. 7 y9 j4 u0 ^! Z6 d
  15.   /* 使能定时器 */
    5 w: J3 E) O; C5 `- U6 T% u/ d
  16.   __HAL_TIM_ENABLE(htim);
    2 J0 z9 @$ m0 u: J
  17. $ j. S+ h5 v0 _& o: h0 o
  18.   /* 返回状态 */
    : o3 K8 `( B5 M1 I+ m
  19.   return HAL_OK;( \0 a/ U  F, z# J* }: b
  20. }
复制代码
; r. S/ G: g9 W8 N- |- H
函数描述:
/ E( a6 B6 k) b# r9 m6 X  d( l+ N8 {( i8 f# S
此函数用于启动定时器输出比较模式。+ G; l: O2 @+ R: x

5 h6 m4 Y3 D3 g. F函数参数:
3 B2 o* w( A; X6 }, ^
2 r6 R7 P  N  a0 J  Y) _  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。
4 ]) f& E- U* _  H  第2个参数是通道设置,支持以下参数:/ \( G0 L" C% F: z- `2 R
TIM_CHANNEL_19 ?) h0 ]0 c# L" t( y

+ K1 `+ q. o0 L) P9 @: hTIM_CHANNEL_26 X8 k1 v( r; y% v) z  R: `& C
0 S+ L, ]5 |1 O% L
TIM_CHANNEL_36 w$ O- H. O6 T1 N! w

- q) R+ x/ y0 bTIM_CHANNEL_4
) G4 d! h  ~6 {0 n& f
4 p1 H0 s. i- t; `  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
( l4 C5 U+ f; r/ d6 C1 Y
; m8 [5 y; v3 O+ p& w7 F+ ]32.5 总结% Z3 i6 T% d# ]5 O. g6 i2 E
本章节就为大家讲解这么多,建议大家将GPIO的驱动源码结合参考手册中的寄存器通读一遍,对于我们后面章节的学习大有裨益。, b+ U! G; _  E* v. G1 @

) T/ V' b! P: s7 I7 k% X6 G5 r4 D) [, ?% q2 z) i% ?0 t' [
5 a# W1 U' p+ {
赞 收藏 评论0 发布时间:2021-12-21 23:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

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