请选择 进入手机版 | 继续访问电脑版

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

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

[复制链接]
STMCU小助手 发布时间:2021-12-21 23:00
32.1 初学者重要提示2 t5 {4 U6 o$ y5 ~, f5 w3 x
  学习定时器外设推荐从硬件框图开始了解基本的功能特性,然后逐步深入了解各种特性,这种方式方便记忆和以后查阅。
9 c8 N3 m( y9 ]4 g. n+ T  STM32H7的定时器输出100MHz方波是完全没问题。
8 i8 u- F3 o1 u5 |  STM32H7定时器进出中断的速度能跑到12.5MHz,所有程序在TCM和Flash运行没差别。
5 g* {; G- X. ~" @  STM32H7的定时器输入捕获可以实现12MHz方波的双边沿捕获,单边沿可以做到24MHz。/ i; f. D) o8 k8 l
  特别注意STM32H7的TIM1,8,15,16,17才有RCR重复计数器,其它都没用的。$ A$ t* {* f/ Z' ]* P
  STM32H7的单个定时器中不同通道可以配置不同频率PWM。+ g( _. f+ G  w" f
  STM32H7的TIM1-TIM17中断入口函数名使用时要注意,别搞错了:
' `4 @1 e7 i2 C' I+ ]
  1. TIM1_BRK_IRQHandler            
    , u6 \8 y: B0 X/ j& ]
  2. TIM1_UP_IRQHandler              6 `2 `# M9 \; Y& b: i5 ?
  3. TIM1_TRG_COM_IRQHandler        
    $ J- Y. J- P& d
  4. TIM1_CC_IRQHandler                                                   
    ' \; y9 p1 r9 h4 f- l% Q
  5. TIM2_IRQHandler                                           9 t% d: Y2 c, n3 ^
  6. TIM3_IRQHandler                                                
    , s$ O/ r3 s5 K
  7. TIM4_IRQHandler                 
    & g8 n  y: R2 L' l8 K! L3 \5 f
  8. TIM5_IRQHandler            
    2 m$ Q% H8 g7 k  v% d
  9. TIM6_DAC_IRQHandler           <------------------要注意            
    . [& C9 B/ L# D, s' S
  10. TIM7_IRQHandler
    - T7 F5 a, U& y
  11. TIM8_BRK_TIM12_IRQHandler      <------------------要注意,定时器12也是用的这个
    % P" D  t, |+ i& O* n( Z$ t
  12. TIM8_UP_TIM13_IRQHandler       <------------------要注意,定时器13也是用的这个- Q. [! X' t5 `, J/ m( P* e
  13. TIM8_TRG_COM_TIM14_IRQHandler  <------------------要注意,定时器14也是用的这个
    " m. s$ W9 W% w2 h/ v8 \8 K
  14. TIM8_CC_IRQHandler         
    , Q0 u3 I4 H. m/ |: Q$ ?
  15. TIM15_IRQHandler
    . `5 ?$ L3 ^& J8 D. x; I4 G9 w
  16. TIM16_IRQHandler 5 E0 g' |0 f4 T+ n- V
  17. TIM17_IRQHandler
复制代码

: ]4 Q5 ^) [. M1 x7 w32.2 定时器基础知识
! W8 ^( a8 F- f, s+ ]# e0 K& H3 a注,不同定时支持的功能略有区别,基础定时器功能较少,TIM1和TIM8高级定时器功能多些。
- Q) N: I' u! d' \! r: _% \" _4 [& S
  TIM2和TIM5是32位定时器,其它定时器都是16位定时器。16位和32位的区别是CNT计数器范围不同,32位的范围是0 到2^32 – 1,而16位的是0到65535;它们支持的分频是范围是一样的,都是1到65535。7 p8 R6 g5 W" p3 y) R; r3 n& I( A
  计数器支持递增、递减和递增/递减二合一。
- u; C) o* t: P, t- e8 u  多个独立通道,可用于:4 v* h6 B9 P; S3 I* F
– 输入捕获。
3 l, O" \7 L+ V7 ^+ r& J: k. L9 J0 k
– 输出比较。
- I: t$ d* ?' G2 L
+ h+ u# W, R) p, h– PWM 生成(边沿和中心对齐模式)。
# [6 t! z3 p# K! I  @3 ?* v" {# U' I$ c
– 单脉冲模式输出。
; {9 c0 d4 X* r5 o3 z
4 Q4 w- R* P* j6 A, P: x  带死区插入,断路功能和PWM互补输出& C$ e1 K- x: x
  发生如下事件时生成中断/DMA 请求:/ e5 }2 G0 A7 z7 s7 J* K; N! b' R
– 更新:计数器上溢/下溢、计数器初始化(通过软件或内部/外部触发)
1 E8 ~# l' x, X' K1 |% w& l- t5 z
– 触发事件(计数器启动、停止、初始化或通过内部/外部触发计数)
3 [4 x' [) M; ]
: A: v+ e, |( W8 a, a– 输入捕获% P$ g9 d6 D- a1 w

6 V0 F/ j( G8 u* a0 \5 L– 输出比较2 _! \% f, n0 j% {, W

) k% t3 }0 Z6 Z& f  支持增量式编码器和霍尔传感器。! _  g; G2 ^8 C) S3 C% v
32.2.1 定时器TIM1-TIM17的区别/ A  \- S, a0 J9 ^
STM32H7支持的定时器有点多,要简单的区分下。STM32H7支持TIM1-TIM8,TIM12-TIM17共14个定时器,而中间的TIM9,TIM10,TIM11是不存在的,这点要注意。
% q4 j# ^6 P1 C6 \! @9 L/ @$ ?/ i3 P: U- t- x
粗略的比较如下:* U" o0 D. W+ O% O, \- M
" T2 {) r% s4 y" O0 Z; S: V+ s
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png

. K) \. ?7 c; u2 M# _
; Z7 c& A2 g1 U# I7 W
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png
0 W  Z- x3 z3 n$ [/ _  \9 e- _$ w
" ^: p, s; p" X0 C
通过上面的表格,至少要了解到以下两点:# m: G+ M  O* B; ^& L1 o
5 Q" b; D) L6 O
  STM32H7的定时器主要分为高级定时器,通用定时器,基础定时器和低功耗定时器。
5 q. c# F8 ]5 L0 H8 ^; m  TIM2和TIM5是32位定时器,其它都是16位定时器。6 e4 t% H5 v) N' g, F6 T8 e. }

. Y$ a# Z$ u7 D! z32.2.2 定时器的硬件框图
! g( m- d& `8 e& Z0 ^, O; `认识一个外设,最好的方式就是看他的框图,方便我们快速的了解定时器的基本功能,然后再看手册了解细节。; R5 a' |$ b7 p5 o& j, s) F+ f

4 F1 |7 l% B4 K9 v" ?4 J( K$ \下面我们直接看最复杂的高级定时器TIM1&TIM8框图:# w+ |1 P5 f% e- F" i  L, y

5 q% \! c& n1 l. i3 r8 s
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png
; I' c2 }; k/ Q7 ^% |( O2 M# j

, R6 v3 G  r7 e/ M' ^通过这个框图,我们可以得到如下信息:
5 A1 M: L6 C) w4 ~# n7 Z" x  I/ v7 d! b* u6 A
  TIMx_ETR接口
! w/ ~3 i& @2 b" e% d外部触发输入接口。ETR支持多种输入源:输入引脚(默认配置)、比较器输出和模拟看门狗。- j7 V* H, P+ L

; w6 [1 L1 q) K) c
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png
, ~4 o/ S2 }0 H0 p: T

8 @1 b+ i+ L& O* R- A) l  截图左侧的TIMx_CH1,TIMx_CH2,TIMx_CH3和TIMx_CH4接口7 |7 q) ?# d( t0 H) S
这四个通道主要用于输入捕获,可以计算波形频率和脉宽。                                                                                                                             ) U: M& a6 X& ]3 B

, B5 U/ O; c9 E+ |  TIMx_BKIN和TIMx_BKIN2接口7 i9 V: }, {( N; h( T! G; L2 V
断路功能,主要用于保护由 TIM1 和 TIM8 定时器产生的 PWM 信号所驱动的功率开关
2 W  ?9 n( G8 @/ {' B: l
& a  B: O  t+ U2 r  TRGO内部输出通道* O7 {& s3 ^  u
主要用于定时器级联,ADC和DAC的定时器触发。
+ [( Q9 `% n. |: z. x
& W" s, U8 z( k" \  6组输出比较单元OC1到OC6/ L7 a8 s' r1 E
OC1到OC4有对应的输出引脚,而OC5和OC6没有对应的输出引脚,主要用于内部控制。
& X! C! A1 ^$ n5 j! q% ?
  b- J* h- W' \3 G* y  截图右侧的输出比较通道TIMx_CH1,TIMx_CH1N,TIMx_CH2,TIMx_CH2N,TIMx_CH3,TIMx_CH3N和TIMx_CH4
0 d  g3 ?9 S7 u主要用于PWM输出,注意CH1到CH3有互补输出,而CH4没有互补输出。  r/ g! @$ S4 l7 I! J, C
3 t) J+ O% W' l  s3 h' ^  @
  其它框图里面未展示出来功能, s* ]0 g& s6 d0 _$ |
定时器TIM1&TIM8还支持的其它功能在用到的时候再做说明。6 L. w& J! p2 X/ J" ]' k; c" i
- b, U6 s3 {0 z& h# o4 g
32.2.3 定时器的时基单元
( Y$ }6 ~$ m4 {定时器要工作就需要一个基本时基单元,而基本的时基单元是由下面几个寄存器组成的:
& c* V6 Y; p8 |+ V( E1 |/ R8 R6 s* X. J) {1 l0 P
  预分频器寄存器 (TIMx_PSC)( k' k) B3 S6 |. q4 a8 @, X
用于设置定时器的分频,比如定时器的主频是200MHz,通过此寄存器可以将其设置为100MHz,50MHz,25MHz等分频值。+ S' D  ~9 d+ n! k1 @
* w- n  `1 L% M5 J( G3 m# |
注:预分频器有个缓冲功能,可以让用户实时更改,新的预分频值将在下一个更新事件发生时被采用(以递增计数模式为例,就是CNT计数值达到ARR自动重装寄存器的数值时会产生更新事件)。
4 r/ z/ c9 x" @) y  H2 Z9 l. Y& m
- v/ j7 P2 [' R  计数器寄存器 (TIMx_CNT)
: g( W, b2 X1 o- F, W计数器是最基本的计数单元,计数值是建立在分频的基础上面,比如通过TIMx_PSC设置分频后的频率为100MHz,那么计数寄存器计一次数就是10ns。1 \9 [% C  u# G. |* d' o4 e' ?

) Q- g: X! {& z5 S' o6 _: S  自动重载寄存器 (TIMx_ARR)
9 M" N# w' z& |0 Q自动重装寄存器是CNT计数寄存器能达到的最大计数值,以递增计数模式为例,就是CNT计数器达到ARR寄存器数值时,重新从0开始计数。
1 G; |0 \( Z+ X3 z' X$ z4 {; @
! w3 c4 V$ e; V/ c$ Z& h$ S注,自动重载寄存器是预装载的。对自动重载寄存器执行写入或读取操作时会访问预装载寄存器。预装载寄存器的内容既可以立即传送到影子寄存器(让设置立即起到效果的寄存器),也可以在每次发生更新事件时传送到影子寄存器。简单的说就是让ARR寄存器的数值立即更新还是更新事件发送的时候更新。3 {7 x9 i+ N: J( ~* K* ^2 i: d
% z) C3 w: W. q, Y4 {2 k: X
  重复计数器寄存器 (TIMx_RCR)- i3 S, ~9 o1 e" f, G; f* u
以递增计数模式为例,当CNT计数器数值达到ARR自动重载数值时,重复计数器的数值加1,重复次数达到TIMx_RCR+ 1后就,将生成更新事件。! Y8 [0 ~8 v$ |( d$ X, L
( \7 `" h+ K1 O7 \% g/ U8 H
注,只有TIM1,TIM8,TIM15,TIM16,TIM17有此寄存器。
) f% x3 d0 L2 n2 h5 l  r+ y
* V# Q5 i9 }) O比如我们要配置定时器实现周期性的中断,主要使用这几个寄存器即可。; b4 u* Q! A+ R6 x+ t" Y3 H+ I# s

6 d" d1 a% z/ S; d32.2.4 定时器输出比较(PWM): A6 @5 ~) l" L  y
使用定时器时基单元的那几个寄存器仅仅能设置周期,还不能设置占空比。针对这个问题,还需要比较捕获寄存CCR的参与,这样就可以设置占空比了。- S6 s' ~. p1 q4 e: Y6 T( U

+ e% F( U, I- L) P为了方便大家理解,以PWM 边沿对齐模式,递增计数配置为例:
: a7 d* ~; P* b- i* B  |
/ Y, r' A/ f4 S% c  当计数器TIMx_CNT < 比较捕获寄存器TIMx_CCRx期间,PWM参考信号OCxREF输出高电平。
- N' W" }3 {4 L! q% S) U2 G* W  当计数器TIMx_CNT >= 比较捕获寄存器TIMx_CCRx期间, PWM参考信号OCxREF输出低电平。
' u& R( E& B. B- P9 J! u& X  当比较捕获寄存器TIMx_CCRx > 自动重载寄存器TIMx_ARR,OCxREF保持为1。- z0 M- @8 x! a$ t
  当比较捕获寄存器TIMx_CCRx = 0,则OCxRef保持为0。% G4 ~1 I6 N3 K% t/ I. N& l/ B
下面是TIMx_ARR=8的波形效果:
9 w: c, W1 l- H# W8 K3 b) g4 ?  Y8 w* P0 f/ s' U. ~# S/ T
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png
' h+ f! m' H7 N5 s: \$ t
; E; `" C. t5 C# H0 d  y
32.2.5 定时器输入捕获
8 [2 s# O* ~! a0 S, n与PWM一样,使用定时器实现输入捕获,仅靠时基单元的那几个寄存器是不行的,我们需要一个寄存器来记录发生捕获时的具体时间,这个寄存器依然由比较捕获寄存器TIMx_CCRx来实现。( K' _- K: i5 v1 `
( {4 s6 Z7 H$ B( L
比如我们要测量一路方波的周期:+ I5 B, A, t, ^0 R  V! S& A7 D
' O% Z8 A4 W( D9 J- P/ S1 t
  配置定时器为输入捕获模式,上升沿触发,设置分频,自动重装等寄存器,比如设置的CNT计数器计数1次是1微秒。# u: J- I* J9 {/ B
  当有上升沿触发的时候,TIMx_CCRx寄存器就会自动记录当前的CNT数值,然后用户就可以通过CC中断,在中断复位程序里面保存当前的TIMx_CCRx寄存器数值。等下次再检测到上升沿触发,两次时间求差就可以得到方波的周期。8 G1 ~- u7 K; n
不过这里要特别注意一点,如果CNT发生溢出(比如16位定时器,计数到65535就溢出了)就需要特别处理下,将CNT计数溢出考虑进来。
" h( u0 x6 ?  ^: p' N$ {* `% }1 P# {
32.3 定时器的HAL库用法
8 P( u/ e9 S& ]' b5 O! ]/ L定时器的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置GPIO、时钟,并根据需要配置NVIC、中断和DMA。下面我们逐一展开为大家做个说明。3 ?/ J0 K5 G4 o; R9 U
7 G8 w4 g8 {4 o$ _  \' N
32.3.1 定时器寄存器结构体TIM_TypeDef5 @) o$ o* r0 W6 \8 j
定时器相关的寄存器是通过HAL库中的结构体TIM_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:
6 U0 Y4 L0 h' g+ u  @. S" E- \
$ q7 }: n, u5 R, T7 U1 g3 t
  1. typedef struct6 D& X, m) F2 G
  2. {9 Y- O: u( {& K4 q) T  R: K
  3.   __IO uint16_t CR1;         /*!< TIM control register 1,                   Address offset: 0x00 */4 }) s. b* r1 L$ {, @
  4.   uint16_t      RESERVED0;   /*!< Reserved, 0x02                                                 */
    ( m7 c% i8 c4 r3 c1 [$ C& I
  5.   __IO uint32_t CR2;         /*!< TIM control register 2,                   Address offset: 0x04 */
    $ A% k; c  C3 h* M0 T6 U
  6.   __IO uint32_t SMCR;        /*!< TIM slave mode control register,          Address offset: 0x08 */; F7 h" j- B: X" m  k
  7.   __IO uint32_t DIER;        /*!< TIM DMA/interrupt enable register,        Address offset: 0x0C */
    ) O  L+ O5 R, Z6 g. l- [! a0 h* ~
  8.   __IO uint32_t SR;          /*!< TIM status register,                      Address offset: 0x10 */0 B) w3 ~% f: y, m' o$ P2 v
  9.   __IO uint32_t EGR;         /*!< TIM event generation register,            Address offset: 0x14 */
    " \; Y3 B  a$ m7 m9 L5 H" j
  10.   __IO uint32_t CCMR1;       /*!< TIM capture/compare mode register 1,      Address offset: 0x18 */
    * C/ s; Z7 V7 P5 o' S% X
  11.   __IO uint32_t CCMR2;       /*!< TIM capture/compare mode register 2,      Address offset: 0x1C */+ [* x+ K9 z0 F. u/ Y, F+ v
  12.   __IO uint32_t CCER;        /*!< TIM capture/compare enable register,      Address offset: 0x20 */# G  d, m1 u4 g/ I% X5 N6 F; ~
  13.   __IO uint32_t CNT;         /*!< TIM counter register,                     Address offset: 0x24 */
    8 c2 ?' S( c* ~2 c( b. M
  14.   __IO uint16_t PSC;         /*!< TIM prescaler,                            Address offset: 0x28 */
    , G" q& q/ J# C# v/ T
  15.   uint16_t      RESERVED9;   /*!< Reserved, 0x2A                                                 *// u3 N+ S7 }+ L* S! }
  16.   __IO uint32_t ARR;         /*!< TIM auto-reload register,                 Address offset: 0x2C */9 X' l7 k" m3 Z# y+ S' w: R
  17.   __IO uint16_t RCR;         /*!< TIM repetition counter register,          Address offset: 0x30 */
    : S% p( }, V5 u6 K( a
  18.   uint16_t      RESERVED10;  /*!< Reserved, 0x32                                                 */6 d# o/ A7 Y0 Q, K2 Q6 b# T, H; [0 }
  19.   __IO uint32_t CCR1;        /*!< TIM capture/compare register 1,           Address offset: 0x34 */) R7 {- M7 d! O9 O( f' v3 }; {
  20.   __IO uint32_t CCR2;        /*!< TIM capture/compare register 2,           Address offset: 0x38 */
    % \* @: ]6 W. a
  21.   __IO uint32_t CCR3;        /*!< TIM capture/compare register 3,           Address offset: 0x3C */. [! ~8 |# y: M: L5 O7 q( l" T
  22.   __IO uint32_t CCR4;        /*!< TIM capture/compare register 4,           Address offset: 0x40 */
    # O- y5 ^7 V5 r. S9 m
  23.   __IO uint32_t BDTR;        /*!< TIM break and dead-time register,         Address offset: 0x44 */( _& B2 G; p8 m4 ?
  24.   __IO uint16_t DCR;         /*!< TIM DMA control register,                 Address offset: 0x48 */
    / c* f  b6 i" t2 \$ y1 o
  25.   uint16_t      RESERVED12;  /*!< Reserved, 0x4A                                                 */
    ( ~* n- o* z/ [% K. b2 f
  26.   __IO uint16_t DMAR;        /*!< TIM DMA address for full transfer,        Address offset: 0x4C */
    4 _  x; ?+ ~5 \% p
  27.   uint16_t      RESERVED13;  /*!< Reserved, 0x4E                                                 */
    2 w" ]5 u) K1 d- Y; V
  28.   uint16_t      RESERVED14;  /*!< Reserved, 0x50                                                 */
    ; R! P8 h* ], X; H
  29.   __IO uint32_t CCMR3;       /*!< TIM capture/compare mode register 3,      Address offset: 0x54 */. p7 @5 y% `! v6 e5 O' w3 \
  30.   __IO uint32_t CCR5;        /*!< TIM capture/compare register5,            Address offset: 0x58 */
    9 z% X  l; W" B3 q% D4 Q
  31.   __IO uint32_t CCR6;        /*!< TIM capture/compare register6,            Address offset: 0x5C */
    ' h. o: I+ q5 K$ q1 P" l
  32.   __IO uint32_t AF1;         /*!< TIM alternate function option register 1, Address offset: 0x60 */
    1 P5 W8 \2 m, G; X
  33.   __IO uint32_t AF2;         /*!< TIM alternate function option register 2, Address offset: 0x64 */: g# C6 h  u- X+ x8 g: f
  34.   __IO uint32_t TISEL;       /*!< TIM Input Selection register,             Address offset: 0x68 */
    0 U; l1 T5 e9 [' `) k" q
  35. } TIM_TypeDef;
复制代码
; j  e0 ~6 W2 U, n+ \" M3 p
这个结构体的成员名称和排列次序和CPU的定时器寄存器是一 一对应的。
+ g9 `# J  p- k" ]7 H
5 L( ~( e1 U3 Q! A__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:+ q, z) G- Q9 m- ?( u# k, p9 R

% J; Y8 }) @* q% A( Z" o  v, |
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */3 @4 w+ {2 ?, T' S/ v3 q- j2 C
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码

4 H' r) V' H! M9 m" X0 K下面我们看下定时器的定义,在stm32h743xx.h文件。$ \0 a; k1 a- N2 O
7 {: d; F7 W; u5 o  D2 A& ~& g
  1. #define PERIPH_BASE         ((uint32_t)0x40000000)
    6 J7 R  {( M! `& g! g
  2. #define D2_APB1PERIPH_BASE   PERIPH_BASE
    ! o8 M4 J* e; f: V
  3. #define D2_APB2PERIPH_BASE   (PERIPH_BASE + 0x00010000)
    " K% {: L. D8 t9 Z: O
  4. $ o7 j8 D1 n, w0 F" V6 b
  5. /*!< D2_APB1PERIPH 外设 */' g" F% Q& W1 c; [& O6 @
  6. #define TIM2_BASE             (D2_APB1PERIPH_BASE + 0x0000) <----- 展开这个宏,(TIM_TypeDef *) 0x400000009 l6 J1 x! m0 Q. ~0 y4 G
  7. #define TIM3_BASE             (D2_APB1PERIPH_BASE + 0x0400)
    " i7 q) Y3 L# M+ Z, l( Q4 R
  8. #define TIM4_BASE             (D2_APB1PERIPH_BASE + 0x0800)
    " B! R) t& `) B, A# D; ?; O, M
  9. #define TIM5_BASE             (D2_APB1PERIPH_BASE + 0x0C00)
    $ G/ A8 B" G1 E! m3 u
  10. #define TIM6_BASE             (D2_APB1PERIPH_BASE + 0x1000)
    7 m. l) ?# _9 j; G  Z) U
  11. #define TIM7_BASE             (D2_APB1PERIPH_BASE + 0x1400)% ^0 K6 W' B$ P4 V+ i* l$ G+ S/ y
  12. #define TIM12_BASE            (D2_APB1PERIPH_BASE + 0x1800)0 ]- F& j7 o, t
  13. #define TIM13_BASE            (D2_APB1PERIPH_BASE + 0x1C00)
    9 b6 |; V2 U6 i8 h& Y: _0 D
  14. #define TIM14_BASE            (D2_APB1PERIPH_BASE + 0x2000)2 c, f3 f: e: W- n( @$ h
  15. $ `% D, W7 I8 {6 P. _# V+ w
  16. /*!< D2_APB1PERIPH 外设 */
    2 d6 ~: t0 O# i+ a4 p. V1 @3 P
  17. #define TIM1_BASE             (D2_APB2PERIPH_BASE + 0x0000)
    * U& _7 R6 e5 O5 p, l  d
  18. #define TIM8_BASE             (D2_APB2PERIPH_BASE + 0x0400)
    $ Z! E: L" D+ `  M; J7 T6 p! b; y+ ]
  19. #define TIM15_BASE            (D2_APB2PERIPH_BASE + 0x4000)( y9 i# ?- a- V! j" J
  20. #define TIM16_BASE            (D2_APB2PERIPH_BASE + 0x4400)* b5 A! E( H, M. z% [
  21. #define TIM17_BASE            (D2_APB2PERIPH_BASE + 0x4800)* Z8 A# A; A; X0 I1 k

  22. " }+ B' e% O! b% L9 ]( W' `
  23. #define TIM1                ((TIM_TypeDef *) TIM1_BASE)
    2 z/ Y* J. T. D1 i: V5 {
  24. #define TIM2                ((TIM_TypeDef *) TIM2_BASE)
    " G0 l% q) v$ W' j$ y* R
  25. #define TIM3                ((TIM_TypeDef *) TIM3_BASE)
      N( r5 P; \' t
  26. #define TIM4                ((TIM_TypeDef *) TIM4_BASE)
    ) h& r0 C, k: B' l* A, ^$ {; ~! n
  27. #define TIM5                ((TIM_TypeDef *) TIM5_BASE)
    - d2 v3 I+ p$ J* B6 h, L/ S0 o2 P
  28. #define TIM6                ((TIM_TypeDef *) TIM6_BASE)
    " j$ X" J3 g. A: F! V; F1 @
  29. #define TIM7                ((TIM_TypeDef *) TIM7_BASE)4 G( X% j6 r1 n) |
  30. #define TIM8                ((TIM_TypeDef *) TIM8_BASE)
    ( H/ j" @7 C: r7 I6 ?+ c$ w2 l
  31. #define TIM12               ((TIM_TypeDef *) TIM12_BASE)1 \" n" J) w: ?$ D
  32. #define TIM13               ((TIM_TypeDef *) TIM13_BASE)
    9 Y2 ~" }2 @" E3 B0 j9 l( A) B
  33. #define TIM14               ((TIM_TypeDef *) TIM14_BASE)
    / `* |* b! ?) v
  34. #define TIM15               ((TIM_TypeDef *) TIM15_BASE)9 l2 L% K+ j6 N; I: ^9 _9 W
  35. #define TIM16               ((TIM_TypeDef *) TIM16_BASE)
    ' h) i0 J! K7 f, y) a: P' ^
  36. #define TIM17               ((TIM_TypeDef *) TIM17_BASE)
复制代码

0 _1 W4 J, w+ Y' ~+ N& G# V, [% C我们访问TIM2的CR1寄存器可以采用这种形式:TIM2->CR1 = 0;
; B0 x1 N) d/ E; a& u1 ^1 }8 q+ Q9 [2 _; n, A4 g1 P6 F
32.3.2 定时器句柄结构体TIM_HandleTypeDef" ?" M3 ~! E' ^* Y+ c- `" d. c/ w
HAL库在TIM_TypeDef的基础上封装了一个结构体TIM_HandleTypeDef,定义如下:
+ M9 A% L# H) z& d1 v2 a$ Y! c+ A) F/ \5 d' }) }# b
  1. typedef struct3 o: n4 E# A3 H1 V4 [8 E
  2. {& v7 O0 l$ q8 ?, `) n1 L/ B4 @# e
  3.   TIM_TypeDef              *Instance;     /*!< Register base address             */ & y) `8 g7 w! B
  4.   TIM_Base_InitTypeDef     Init;          /*!< TIM Time Base required parameters */% A7 b7 {8 O& l4 ]7 [' K
  5.   HAL_TIM_ActiveChannel    Channel;       /*!< Active channel                    */
    - s1 p1 G. V% u, r' B, r+ i7 h4 \
  6. + d- J& T) U, q) F6 {$ d
  7. /*!< DMA Handlers array This array is accessed by a @ref DMA_Handle_index */$ ]5 v9 Q7 X( Q  c
  8.   DMA_HandleTypeDef        *hdma[7];      
    ; Z0 D' a4 H, |( C; _3 S# `
  9.   HAL_LockTypeDef          Lock;          /*!< Locking object                    */
    3 |& `4 e4 B+ Y
  10.   __IO HAL_TIM_StateTypeDef   State;      /*!< TIM operation state               */  7 D6 {7 K/ e' {, w$ V5 e7 z
  11. }TIM_HandleTypeDef;
复制代码
4 c1 k- N$ ~6 ]  `9 q) G
这里重点介绍前四个参数,其它参数主要是HAL库内部使用的。% C+ r7 u( y' w7 \
% A, n3 L6 k9 p1 c" h- v9 T, N
  TIM_TypeDef  *Instance
  N8 C( X  T7 e+ L' q
2 n' t: T8 `, Q" z8 X- P% G7 G5 @$ [这个参数是寄存器的例化,方便操作寄存器,比如使能定时器的计数器。2 }/ K+ Z  ^* Z' q7 W2 R5 X  _

3 U( B( y6 S7 H* v0 XSET_BIT(huart->Instance->CR1,  TIM_CR1_CEN)。
( d. O+ P4 a7 \- {3 w. z! d, X/ `' u6 V) W5 ~* {
  TIM_Base_InitTypeDef  Init
: }( S3 q5 ~/ I
& H8 s# K8 s6 Y8 G7 C这个参数是用户接触最多的,用于配置定时器的基本参数。
" W4 E' A, e8 y( _9 m# f
7 n, e6 `' X0 t* |TIM_Base_InitTypeDef结构体的定义如下:* U0 h# }8 v1 d0 I, K
9 {& H3 B/ j, m/ C% i
  1. typedef struct2 }% @9 W& q3 E6 [! E
  2. {
    0 K6 X5 z+ b1 z/ M. O
  3.   uint32_t Prescaler;      
    4 W* C& @8 U' e+ M. _6 E% a8 P
  4.   uint32_t CounterMode;    # y( S  g3 r+ F" E1 ?
  5.   uint32_t Period;         
    / C, v$ H& ?2 k: c  U. x  Z) I
  6.   uint32_t ClockDivision;   
    , `0 ]5 V8 r. p3 t/ w* _
  7.   uint32_t RepetitionCounter; % N  k9 o2 h+ ]
  8.   uint32_t AutoReloadPreload;  
    ( M9 V0 e  X/ e5 N
  9. } TIM_Base_InitTypeDef;
复制代码

7 r+ i* `# }5 z" `- q6 G  T  成员Prescaler" o( j/ H6 A, z+ A& c
用于设置定时器分频,对于32位的TIM2和TIM5范围是0到0xFFFFFFFF,其它定时器是0到0xFFFF。
* \, e7 n- m: u* z8 S/ Y2 c0 m
% O; r0 x& L+ S4 Z  N  成员CounterMode
  F  X$ f( I. x3 ~用于设置计数模式,向上计数模式、向下计数模式和中心对齐模式。3 R4 a  d0 J: J! o: i" {

) v% R* [+ i% F' Q
  1. #define TIM_COUNTERMODE_UP                ((uint32_t)0x0000U)   /*!< Up counting mode */
    1 [9 M' Y! ?* s% f+ S* l  Q
  2. #define TIM_COUNTERMODE_DOWN               TIM_CR1_DIR          /*!< Down counting mode */6 u$ q. j2 f0 p6 [" ~" r
  3. #define TIM_COUNTERMODE_CENTERALIGNED1     TIM_CR1_CMS_0        /*!< Center-aligned counting mode 1 */, n" `: O" k8 [7 d9 V
  4. #define TIM_COUNTERMODE_CENTERALIGNED2     TIM_CR1_CMS_1        /*!< Center-aligned counting mode 2 */
    % M) Z: G5 c7 [* F; w6 y8 j
  5. #define TIM_COUNTERMODE_CENTERALIGNED3     TIM_CR1_CMS          /*!< Center-aligned counting mode 3 */
复制代码
7 o* L' w$ `8 F3 I) A6 X
  成员Period
: C* K, ~% s! D. @- q用于设置定时器周期,对于32位的TIM2和TIM5范围是0到0xFFFFFFFF,其它定时器是0到0xFFFF。
4 [3 G* j# \: R1 C+ i7 i% n3 J" H3 `) Z+ l, u) ~3 J8 e; T& u0 Q
  成员ClockDivision+ P2 }  D! G. s2 G# D
用于指示定时器时钟 (CK_INT) 频率与死区发生器以及数字滤波器(ETR、TIx)所使用的死区及采样时钟 (tDTS) 之间的分频比。
- V  t4 Y2 x: J+ G1 N7 C
7 @) x( z2 P# e. G9 M
  1. #define TIM_CLOCKDIVISION_DIV1       ((uint32_t)0x0000U)        /*!< Clock Division DIV1 */
    8 h- U8 @" M+ k" Z! _9 f8 O
  2. #define TIM_CLOCKDIVISION_DIV2       (TIM_CR1_CKD_0)            /*!< Clock Division DIV2 */1 ?8 E) D8 C+ v4 v% K7 i4 U! D' `
  3. #define TIM_CLOCKDIVISION_DIV4       (TIM_CR1_CKD_1)             /*!< Clock Division DIV4 */
复制代码

5 z: D" J" h, L) M# n+ j9 |  成员RepetitionCounter- h7 M, }/ o; V
用于设置重复计数器,仅TIM1和TIM8有,其它定时器没有。作用是每当计数器上溢/下溢时,重复计数器减1,当减到零时,才会生成更新事件,这个在生成PWM时比较有用。5 L( ~9 I8 l1 W$ t( B5 V1 A

* N: y6 d* K: T+ z$ @2 {; T6 V  成员AutoReloadPreload3 t9 T7 r9 I( I; K
用于设置定时器的ARR自动重装寄存器是更新事件产生时写入有效还是立即写入有效。如果使能了表示更新事件产生时写入有效,否则反之。
" a( k( y3 Q8 V' n5 K* y8 l
; Y# H1 R  A: i. A; k
  1. #define TIM_AUTORELOAD_PRELOAD_DISABLE   ((uint32_t)0x0000U)   /*!< TIMx_ARR register is not buffered */$ o, M0 ^9 H& \% g8 T' m$ b/ |- l
  2. #define TIM_AUTORELOAD_PRELOAD_ENABLE    (TIM_CR1_ARPE)        /*!< TIMx_ARR register is buffered */
复制代码

  M8 d9 ~6 y; Q( O6 X* }& @  HAL_TIM_ActiveChannel    Channel;
- G7 k7 a6 W3 J) S
" ~6 E3 F: U0 k3 |用于设置定时器通道,比如TIM1和TIM8都是6个通道。
& Q  t9 x7 G% _1 l- [0 ~0 Q* j& a( }. A' U3 h& w' k% s
  1. typedef enum
    , [; \5 k; p$ P' n! t' B
  2. {
    % }( o6 R% F/ f7 ]) `$ G: p
  3.   HAL_TIM_ACTIVE_CHANNEL_1        = 0x01U,    /*!< The active channel is 1     */
    " Y; [: y5 K$ Y5 l4 a- E$ y
  4.   HAL_TIM_ACTIVE_CHANNEL_2        = 0x02U,    /*!< The active channel is 2     */) k1 ~! k: b/ l1 b5 ~
  5.   HAL_TIM_ACTIVE_CHANNEL_3        = 0x04U,    /*!< The active channel is 3     */   
    / _4 a( g: `2 A+ {# }
  6.   HAL_TIM_ACTIVE_CHANNEL_4        = 0x08U,    /*!< The active channel is 4     */' o7 L0 J9 n/ U" L  k" w& D
  7.   HAL_TIM_ACTIVE_CHANNEL_5        = 0x10U,    /*!< The active channel is 5     */" {4 t; J: N" ]8 t  f
  8.   HAL_TIM_ACTIVE_CHANNEL_6        = 0x20U,    /*!< The active channel is 6     *// B* k9 E1 h( ~* w: r/ |. ~1 g
  9.   HAL_TIM_ACTIVE_CHANNEL_CLEARED  = 0x00U     /*!< All active channels cleared */    : b% N: p4 r5 {% p" n; Y4 ]
  10. }HAL_TIM_ActiveChannel;  j4 o% U9 |* c+ g! p) p
  11.   DMA_HandleTypeDef        *hdma[7];
复制代码
  a3 F6 F3 g$ K1 h1 O5 R) }
用于关联DMA。
( [, x$ ~5 \: z2 O/ g& h
8 B8 ?' Y, b" b" [; g  x配置定时器参数,其实就是配置结构体TIM_HandleTypeDef的成员。- C7 I: J4 e2 m$ i$ w' ?
, `3 u/ a4 f1 {7 l
  1. TIM_HandleTypeDef   TimHandle = {0};( B" x" \/ ^. Z% i4 t2 Y' c6 A
  2. * U2 o% d% X6 p
  3. /* , s. T3 p" K) d
  4.     定时器中断更新周期 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)- b* V; c4 E$ z  ~. y, W
  5. */( n+ f: T& @& P4 {' [
  6. TimHandle.Instance = TIMx;
    & P' a6 `5 t  h
  7. TimHandle.Init.Prescaler         = usPrescaler;# H5 p1 F) o4 o
  8. TimHandle.Init.Period            = usPeriod;        
    , s6 K" M: z; J7 j9 m7 j0 h) R$ e
  9. TimHandle.Init.ClockDivision     = 0;( x* ~3 ]; K, l
  10. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;* D* A) ]; w" O
  11. TimHandle.Init.RepetitionCounter = 0;
    3 H, r; G  n% _6 r2 h
  12. TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
    # }$ |- y( o5 Z% v
  13. if (HAL_TIM_Base_Init(&TimHandle) != HAL_OK)
    9 K4 \# E; c2 g. A0 Q
  14. {
    & C+ n7 Q& I" F1 e3 k; a
  15.         Error_Handler(__FILE__, __LINE__);" |. M% f7 q* B
  16. }
复制代码
9 F9 x4 G* }5 }) T6 ]# j
32.3.3 定时器输出比较结构体TIM_OC_InitTypeDef
0 e: R5 ^2 }3 f5 H! c- J! w8 O
此结构体主要用于定时器的输出比较,定义如下:
/ D& |1 C0 b8 `, a4 k( j
, V& N# @$ t1 R3 L  X' {6 Y* Z- ~
  1. typedef struct( [) G7 R, Q8 w; I
  2. {                                 , P3 q1 f3 L; m" E) p
  3.   uint32_t OCMode;      
    % N3 Q1 {' @3 q
  4.   uint32_t Pulse;       5 B) ?2 q6 \$ Y6 O
  5.   uint32_t OCPolarity;   
    6 ~: |* q9 [3 P9 W  _
  6.   uint32_t OCNPolarity;   
    , o  F: e0 H7 U/ k+ ?" W: a0 o9 c
  7.   uint32_t OCFastMode;  0 a! \2 w+ Q6 d2 L5 S
  8.   uint32_t OCIdleState;   
    , f$ c5 l% O: K' L6 x$ m
  9.   uint32_t OCNIdleState;  6 p& o+ \& Q/ P1 E: q% Q5 i0 |
  10. } TIM_OC_InitTypeDef;  
复制代码
. T" N( e- Z4 i7 W
下面将这几个参数一 一做个说明。
% l( S# x8 a- T1 \
$ G6 E) T6 X) u* r  OCMode
9 A3 u5 |" f6 w' `用于配置输出比较模式,支持的模式较多:5 k/ W: p1 i9 c; D! J

" ^7 d& X$ a9 h& g+ O9 J9 D
  1. /*!< TIM Output timing mode */3 G6 z; s5 V1 S. w. j. m/ n/ j4 T
  2. #define TIM_OCMODE_TIMING                ((uint32_t)0x0000U)       : w, L  Y. E. V: H5 ~  R1 R

  3. % ^& I8 ^; W/ F& |% I
  4. /*!< TIM Output Active mode */                          
    5 g" u1 j& b* f; ^6 d  F. ]
  5. #define TIM_OCMODE_ACTIVE                ((uint32_t)TIM_CCMR1_OC1M_0)
    6 d3 [: G' Z# B3 }) n

  6.   e. Z% {7 ?+ p: e
  7. /*!< TIM Output Inactive mode */                       
    * ~* O; T4 c2 G- l
  8. #define TIM_OCMODE_INACTIVE              ((uint32_t)TIM_CCMR1_OC1M_1)           
    ! h$ q& r& U! ?& d; ^3 K% O
  9. ( B* I+ ^0 p% K1 ]. P
  10. /*!< TIM Output Toggle mode */               , |! I$ c  z3 K: I
  11. #define TIM_OCMODE_TOGGLE                 ((uint32_t)TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_0)         
    6 T9 r; |0 P' u0 c  E5 k
  12. . {1 G8 b1 C' ^- `3 ]( y& @" A2 S
  13. /*!< TIM PWM mode 1 */' g) L+ D; x' ~$ A7 _
  14. #define TIM_OCMODE_PWM1                   ((uint32_t)TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1)
    8 a+ P0 B- Y4 T: h( b! K
  15. 5 @2 ^; n0 k) d5 P5 k$ D
  16. /*!< TIM PWM mode 2 */                    1 R8 y% @/ A  Q/ K5 i3 t# S
  17. #define TIM_OCMODE_PWM2                    ((uint32_t)TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_0)   & v% L5 \6 y( I$ F# Z- ]

  18. ; t$ c' Y7 l$ [% v  E
  19. /*!< TIM Forced Active mode */   - U2 W4 d+ B3 {' B
  20. #define TIM_OCMODE_FORCED_ACTIVE           ((uint32_t)TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_0)         
      `4 g0 l5 W4 o* b9 U1 L+ r. `
  21. 6 v, H! d# R8 g+ [3 k" ~) V: I
  22. /*!< TIM Forced Inactive mode */             : `, [& T" p& W) {# M  z' |
  23. #define TIM_OCMODE_FORCED_INACTIVE         ((uint32_t)TIM_CCMR1_OC1M_2)                                       
    ) d8 U7 u" \( ~  n: A
  24. % c; u3 \+ r, t7 b
  25. /*!< TIM Rettrigerrable OPM mode 1 */  
    6 _, o, m# \4 S. Q4 e. V$ u( P
  26. #define TIM_OCMODE_RETRIGERRABLE_OPM1      ((uint32_t)TIM_CCMR1_OC1M_3)   
    % ?+ Z- A# x# \

  27. ) |9 s) a3 o& q4 [" R7 ^( A
  28. /*!< TIM Rettrigerrable OPM mode 2 */                                        " Y' S3 ?0 S( b# M! i
  29. #define TIM_OCMODE_RETRIGERRABLE_OPM2      ((uint32_t)TIM_CCMR1_OC1M_3 | TIM_CCMR1_OC1M_0)    ! T7 U% I7 Y: C
  30. 8 t* T3 f% o. H) s, |
  31. /*!< TIM Combined PWM mode 1 */                     - B( z, j/ a6 j# @. A/ V/ ]" C; m
  32. #define TIM_OCMODE_COMBINED_PWM1           ((uint32_t)TIM_CCMR1_OC1M_3 | TIM_CCMR1_OC1M_2)     
    ( v; W; a/ |$ H0 P% \
  33.   {! c8 W2 F3 V9 w2 l2 m1 w
  34. /*!< TIM Combined PWM mode 2 */                  $ o1 u' ?$ r+ y) B$ @) y0 [
  35. #define TIM_OCMODE_COMBINED_PWM2           ((uint32_t)TIM_CCMR1_OC1M_3 | TIM_CCMR1_OC1M_0 | TIM_CCMR1_OC1M_2)   
    ; [) ?) M, \1 w5 E( d' Q2 q- J" V
  36. 4 h0 S8 N: k! \
  37. /*!< TIM Asymetruc PWM mode 1 */  
    7 O7 C4 q- E7 [' Q
  38. #define TIM_OCMODE_ASSYMETRIC_PWM1         ((uint32_t)TIM_CCMR1_OC1M_3 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2)  
    * Q% \( }# E; i+ K( c& h) I: U' h
  39. * n( n+ t* E$ a8 W  f
  40. /*!< TIM Asymetruc PWM mode 2 */    1 t) p6 Y7 R% n4 z8 o( B+ f
  41. #define TIM_OCMODE_ASSYMETRIC_PWM2         ((uint32_t)TIM_CCMR1_OC1M_3 | TIM_CCMR1_OC1M)  
复制代码
0 p% f4 _$ {/ W4 N6 G+ _0 `$ x
  1 w$ _2 E9 G) s, \/ l! p
  Pulse. x8 E! _( k( r3 G+ b, w
可用于设置占空比,对应定时器的CCR寄存器,32位的TIM2和TIM5范围是0到0xFFFFFFFF。# r8 e' q% H& Q6 ^

) k; c  j6 |2 L# n& i0 r8 X  OCPolarity6 f$ V. k+ v; y+ L
设置输出极性,可选高电平或低电平有效。$ J$ o. m+ s& B" _6 N

2 U; I) C' ^9 X
  1. #define TIM_OCPOLARITY_HIGH                ((uint32_t)0x0000U)
    ' f; t6 y4 C4 F( B! A
  2. #define TIM_OCPOLARITY_LOW                 (TIM_CCER_CC1P)
复制代码

7 u' W4 X5 V+ P/ T, w, A  OCNPolarity2 r# P1 l2 f  r
互补输出极性设置,可选高电平或者低电平有效。
/ _" G) \3 u" k
! q2 S6 {2 S, i- A- h* Z; e. H/ P
  1. #define TIM_OCNPOLARITY_HIGH               ((uint32_t)0x0000U)
    1 F' j- o6 o  V: Z4 {
  2. #define TIM_OCNPOLARITY_LOW                (TIM_CCER_CC1NP)
复制代码
; b; J. |% x+ d* `9 T4 {% Q
  OCFastMode
6 ]5 E- B/ q7 H% b. y3 n$ s快速输出模式使能,仅OCMode配置为PWM1或者PWM2模式时才有意义。2 Y2 V& i' W+ V3 g5 J  f# N$ O# m
1 U: j, U9 _8 a; y
  1. #define TIM_OCFAST_DISABLE                ((uint32_t)0x0000U)
      s  L( W) i; \; }
  2. #define TIM_OCFAST_ENABLE                 (TIM_CCMR1_OC1FE)
复制代码
! Q% J- |- X; K  k
  OCIdleState  T4 f( L1 _% d# |. S8 e0 U9 Q
空闲状态时,设置输出比较引脚的电平状态。
7 a0 h- a, g7 U, @) r- l
+ Z. o' H* ^6 N4 V: V2 U7 ~% n+ \
  1. #define TIM_OCIDLESTATE_SET                (TIM_CR2_OIS1)
    * J) ?; ~+ q! ^6 L
  2. #define TIM_OCIDLESTATE_RESET              ((uint32_t)0x0000U)
复制代码

" \/ o" X- b6 ^! j% ~0 ^7 r  OCNIdleState( a" E! i3 z2 j( u8 `3 m( ^' E- G
空闲状态时,设置互补输出引脚的电平状态。
' M: V2 Q  g3 X' M
$ W& |5 p  q4 h. H
  1. #define TIM_OCNIDLESTATE_SET               (TIM_CR2_OIS1N)
    , A- {. f; c; g; L3 I, L
  2. #define TIM_OCNIDLESTATE_RESET             ((uint32_t)0x0000U)
复制代码

. z, d; ?  C5 k9 X7 E% G. T, J( p32.3.4 定时器输入捕获结构体TIM_IC_InitTypeDef
) }, d. Z1 r6 s6 v0 u此结构体主要用于定时器的输入捕获,定义如下:" W( `* S4 v3 Y8 \. Z) [5 [
) ^  A" ]2 p0 l  y' q  e  j
  1. typedef struct
    8 n  [: E" X) ^' ?1 T6 H; R
  2. {                                  5 v1 o- h9 r6 t- j3 ?. f# \% @- P
  3.   uint32_t ICPolarity;   2 s6 `8 |( s3 W: y* g
  4.   uint32_t ICSelection;
      _. ~( @. X2 \0 T
  5.   uint32_t ICPrescaler; ; t, t: v% Y, \8 I
  6.   uint32_t ICFilter;   
    * c" A$ M( G, z' G0 J$ d0 o- R
  7. } TIM_IC_InitTypeDef;
复制代码
1 w7 q# m8 X; e2 c1 ?2 c9 @
下面将这几个参数一 一做个说明。2 N! K# ^4 y& `) C  j

4 h% w; \) Q+ ]7 B  t  ICPolarity
4 V- m- E% s0 a( ]输入触发极性,可以选择上升沿,下降沿或者双沿触发。& ^* P% w/ J" N( P  J
- ~% T  ^. u+ J! L! B' w7 @' U/ ^
  1. #define  TIM_ICPOLARITY_RISING             TIM_INPUTCHANNELPOLARITY_RISING! _- o) x3 Q. m8 |7 }
  2. #define  TIM_ICPOLARITY_FALLING            TIM_INPUTCHANNELPOLARITY_FALLING
    9 w" r  E( |( l+ \& ~) [
  3. #define  TIM_ICPOLARITY_BOTHEDGE           TIM_INPUTCHANNELPOLARITY_BOTHEDGE
复制代码
0 C9 P# d/ c7 h' D2 Z
  ICSelection. I% L, f2 a) z# t- i: v0 t
输入捕获通道选择,可以选择直接输入(即CC1选择TI1,CC2选择TI2等),间接输入(CC1选择TI2,CC3选择TI4等)或者TRC。
$ g' j& H0 Z  a9 j, [* [
9 ~4 ]2 P) @8 |
  1. #define TIM_ICSELECTION_DIRECTTI       (TIM_CCMR1_CC1S_0)   0 d+ P! L+ g* ?+ A- J1 F2 b$ \( q
  2. #define TIM_ICSELECTION_INDIRECTTI     (TIM_CCMR1_CC1S_1)  
    : R3 E7 @& L( w
  3. #define TIM_ICSELECTION_TRC            (TIM_CCMR1_CC1S)   
复制代码
0 ]5 ]0 ?% f6 ?/ n+ e1 u* E9 l; Z
  ICPrescaler
) i7 I4 J- |# u5 n1 I% V9 e输入捕获分频,表示每捕获1,2,4或8个事件后表示一次捕获。
' w( N% P  M' q1 A$ H, Y7 h: q' s) [* t$ l: l1 i+ T; E: X# @
  1. #define TIM_ICPSC_DIV1       ((uint32_t)0x0000U)                 6 q2 J, q. @& B* G6 m/ u' J; [9 [
  2. #define TIM_ICPSC_DIV2       (TIM_CCMR1_IC1PSC_0)    " G2 `: [9 {$ a1 K3 K6 n. `$ R6 @
  3. #define TIM_ICPSC_DIV4       (TIM_CCMR1_IC1PSC_1)   
    ) N+ S  e7 Q1 w( D0 ^6 y) Z
  4. #define TIM_ICPSC_DIV8       (TIM_CCMR1_IC1PSC)
复制代码

: g$ R- B. @2 {9 _# G  ICFilter
- a! i( \8 `% }3 w- J输入捕获滤波器,可以定义采样频率和多少个连续事件才视为有效的触发,参数范围0到15。具体定义如下,其中fCK_INT表示定时器时钟,fDTS表示死区时间采样率,N表示这么多个事件代表一次有效边沿。
0 c1 K& k( C. J) o
8 p% t  g4 s, y4 k5 ~
  1. 0000:无滤波器,按 fDTS 频率进行采样
    / i' e) a8 h* H7 Y: t
  2. 0001: fSAMPLING=fCK_INT, N=2# Q+ e$ S6 u2 q9 P1 c: M2 e* ]
  3. 0010: fSAMPLING=fCK_INT, N=4
    . }5 i7 A% k7 v. n
  4. 0011: fSAMPLING=fCK_INT, N=89 N' P0 @" p# \9 K! g" S. h
  5. 0100: fSAMPLING=fDTS/2, N=6
    5 [' B( ~' ^3 e+ v' A
  6. 0101: fSAMPLING=fDTS/2, N=8
    8 C9 a- b; N: S/ G( w4 o
  7. 0110: fSAMPLING=fDTS/4, N=62 E# L& Y, D! [9 o
  8. 0111: fSAMPLING=fDTS/4, N=8
    $ A: Y* y. Y; p, M" ?9 l# s  f& s7 k
  9. 1000: fSAMPLING=fDTS/8, N=6
    ' q2 M8 R! _+ J) t3 ?. w' `0 ^' f
  10. 1001: fSAMPLING=fDTS/8, N=8  J) |" h& Q9 @! S" \- S" J
  11. 1010: fSAMPLING=fDTS/16, N=5( g1 x( z0 o: V* q( L5 ]" N* I
  12. 1011: fSAMPLING=fDTS/16, N=6
    9 k; f( Y% Q; {, L! s+ M! x
  13. 1100: fSAMPLING=fDTS/16, N=82 z" \( O4 I: C# V. l4 v# o
  14. 1101: fSAMPLING=fDTS/32, N=5
    , Q6 c2 T; S' T4 N
  15. 1110: fSAMPLING=fDTS/32, N=6
复制代码
/ x! g/ O; W, ~
32.3.5 定时器的底层配置(GPIO,时钟,中断等)  t8 q% F& h& S* j2 [* h/ b( `
HAL库有个自己的底层初始化回调函数,比如调用函数HAL_TIM_Base_Init就会调用HAL_TIM_Base_MspInit,此函数是弱定义的。
' Z+ N% o) l" p& o5 n- s8 X5 ]" v& U, V1 b$ }
  1. __weak void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
    7 f4 Y) `9 C$ @! V' B' t
  2. {
    3 d+ r4 Y& V6 o. W; d( j: M& s; D
  3.   /* Prevent unused argument(s) compilation warning */- J3 K' X: j6 [  Q. y+ Z
  4.   UNUSED(htim);2 w* |  Y1 o$ u+ k. V
  5.   /* NOTE : This function Should not be modified, when the callback is needed,
    , G( K: N: o( r
  6.             the HAL_TIM_Base_MspDeInit could be implemented in the user file3 M, ^+ x6 P# W0 V; h% b% `4 N
  7.    */
    , A2 |2 E  ]3 u7 S; v& S9 W6 ]
  8. }
复制代码
. s! L8 Q# a5 l/ C; J, u
用户可以在其它的C文件重定向,并将相对的底层初始化在里面实现。对应的底层复位函数HAL_TIM_Base_DeInit是在函数HAL_TIM_Base_MspDeInit里面被调用的,也是弱定义的。; n/ ]1 J7 O/ E- {

0 n$ J! H' e4 ]5 r$ Q  Z! ~当然,用户也可以自己初始化,不限制必须在两个函数里面实现。
5 t1 Q, ~- z6 u& \  ^' S  P" h% }# c/ F- u9 r7 w
定时器外设的基本参数配置完毕后还不能使用,还需要配置GPIO、时钟、中断等参数,比如下面配置TIM1使用PA8做PWM输出。8 X3 r: r# B0 H: m- h

% B. s/ ~( J8 u/ _9 z
  1. void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
    - [) T& X7 o" {! i. l
  2. {  W% y2 E" P+ W5 I7 [( e
  3.   GPIO_InitTypeDef   GPIO_InitStruct;
    / }; O/ S  E2 K5 j+ d$ d

  4.   w% o  {0 ~3 k1 c
  5.   /* 使能TIM1时钟 */( V- Z+ Z9 a9 e3 D: c- Q' P5 K
  6.   __HAL_RCC_TIM1_CLK_ENABLE ();
    ' @* j+ |6 ~3 D7 @  g5 x

  7. - s0 d: _- @7 ^* [9 b1 r
  8.   /* 使能GPIOA时钟 */0 a- \1 z0 K# ^, S/ N+ S
  9.   __HAL_RCC_GPIOA_CLK_ENABLE ();: d8 C, d; ?' L" \( t% i' [% X

  10. 8 ]5 c0 {3 j1 W' k1 q
  11.   /* 设置TIM1使用PA8做PWM输出引脚,将其配置为输出,推挽,复用模式 */2 x+ R5 U1 ?- Z( e" p1 u
  12.   GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    ) L  P, c4 i" ^8 ^; y& C
  13.   GPIO_InitStruct.Pull = GPIO_PULLUP;* H1 C3 ^+ T+ B+ e
  14.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    3 P/ y# p; [$ G* J5 z

  15. 0 i8 K6 ~2 s4 \$ K2 W" g5 D8 y
  16.   GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;* ]( D7 c% v' J: ^" q. @
  17.   GPIO_InitStruct.Pin = GPIO_PIN_8;' K! t7 I: ~7 L9 H& l
  18.   HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    ( Q3 c" s! x. Q( w+ o
  19. : @+ P4 w0 Y! P6 q* T' N8 b
  20. }
复制代码

, i) f  @9 H% L3 ^0 ]& q) @总结下来就是以下几点:' n; S: l0 W# ^
1 V$ N- D4 t0 m! f7 E5 E
  配置TIM时钟。
, h, \- E0 {7 R  配置TIM所用到引脚和对应的GPIO时钟。
7 }7 Y" @( ~# T$ u1 J4 `7 p  如果用到定时器中断,还需要通过NVIC配置中断。
5 }, v  o5 D$ i/ \2 n" ]  如果用到DMA,还要配置DMA。
! b  |: p3 C! h关于这个底层配置有以下几点要着重说明下:9 _; B9 h2 @& e

0 m5 {5 f- P0 Y  定时器所使用引脚的复用模式选择已经被HAL库定义好,放在了stm32h7xx_hal_gpio_ex.h文件里面。比如TIM1有一个复用,
& D- h' z; i4 z* i: k' R& ^
  1. #define GPIO_AF1_TIM1      ((uint8_t)0x01)  /* TIM1 Alternate Function mapping */
复制代码
6 U6 d7 H" u( S# r  F
但是却有4个输出通道,每个通道都有几个支持的输出引脚:
  Z1 `0 s5 x/ _# @+ P# b
2 b1 N& a1 r8 H: F( g. n4 S; h
  1. TIM1_CH1,  PA8   PE9    PK18 }8 P: J4 d: f7 H" X
  2. TIM1_CH2,  PA9   PE11) }6 y0 ~+ f5 R/ I5 T
  3. TIM1_CH3,  PA10  PE13   PJ9
    3 J4 w" T: C1 K. Q+ G0 X
  4. TIM1_CH4,  PA11  PE14   PJ11
复制代码

- O% V' n2 _! s! i6 J8 s具体使用哪个,配置对应引脚的复用即可:
3 b+ R# l/ n% L2 U6 B: r( r- S9 P/ O" V1 r
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png
/ z. h; |2 P" I! g1 }
# V- h" h  w1 V" n4 a' Q* P
32.3.6 定时器的状态标志清除问题3 M1 M8 ^6 Z6 p6 i
下面我们介绍__HAL_TIM_GET_FLAG函数。这个函数用来检查定时器标志位是否被设置。
" ^, g; n" P% A  o
  1. ) H3 B& u7 N1 K1 {0 r" Q: C( s
  2. /** @brief  Check whether the specified TIM interrupt flag is set or not.
    6 ~& L% I1 z% e" C
  3.   * @param  __HANDLE__: specifies the TIM Handle.7 j% i4 R- W4 L2 x9 v
  4.   * @param  __FLAG__: specifies the TIM interrupt flag to check.3 D9 B( C' R" C  B8 J. Q
  5.   *        This parameter can be one of the following values:
    - ~# v1 c; D9 t" B
  6.   *            @arg TIM_FLAG_UPDATE: Update interrupt flag: w% `0 M. h/ i% E
  7.   *            @arg TIM_FLAG_CC1: Capture/Compare 1 interrupt flag1 ]" Y! k  h; T2 o7 j
  8.   *            @arg TIM_FLAG_CC2: Capture/Compare 2 interrupt flag
    & @( ]' A0 L. z9 k) o
  9.   *            @arg TIM_FLAG_CC3: Capture/Compare 3 interrupt flag- q: P% g, u. j8 l$ F# U1 b9 d
  10.   *            @arg TIM_FLAG_CC4: Capture/Compare 4 interrupt flag
    6 `6 U" P. v, H+ [3 h
  11.   *            @arg TIM_FLAG_CC5: Compare 5 interrupt flag- \- r, ?$ w1 {  D
  12.   *            @arg TIM_FLAG_CC6: Compare 6 interrupt flag  ~5 M! W! m5 X
  13.   *            @arg TIM_FLAG_COM:  Commutation interrupt flag
    + {) W9 g# W" V
  14.   *            @arg TIM_FLAG_TRIGGER: Trigger interrupt flag& o; ]- d* @6 G& [* H
  15.   *            @arg TIM_FLAG_BREAK: Break interrupt flag   ) J7 E. ^1 n. e
  16.   *            @arg TIM_FLAG_BREAK2: Break 2 interrupt flag                     & u' V: l/ w8 h$ d. z* u
  17.   *            @arg TIM_FLAG_SYSTEM_BREAK: System Break interrupt flag8 R' w% U, b% G0 T1 `: g% L
  18.   *            @arg TIM_FLAG_CC1OF: Capture/Compare 1 overcapture flag$ n. ]1 q7 {; d' D6 h$ v
  19.   *            @arg TIM_FLAG_CC2OF: Capture/Compare 2 overcapture flag
    " T( a: Y6 H. x4 u, E) d. Z, P0 k$ C
  20.   *            @arg TIM_FLAG_CC3OF: Capture/Compare 3 overcapture flag
    ' l9 t" x9 s# G5 F3 [
  21.   *            @arg TIM_FLAG_CC4OF: Capture/Compare 4 overcapture flag7 L: u' m3 i! o# [; n
  22.   * @retval The new state of __FLAG__ (TRUE or FALSE).4 c8 c; T  s: K. z4 r% ?
  23.   */
    . p# r8 |" I& d$ S. B2 ^" k
  24. #define __HAL_TIM_GET_FLAG(__HANDLE__, __FLAG__)   (((__HANDLE__)->Instance->SR &(__FLAG__)) == (__FLAG__))
复制代码
' m& o1 X# H) l, ~1 k% x* e
前5个是比较常用的中断标志。# a0 H" C, w) r: a. _

: c6 r; H9 v* i  C' M  TIM_FLAG_UPDATE
$ o& h, {4 l7 N5 x/ s6 K定时器更新标准,配置一个周期性的定时器中断要用到。
# q: d( |( b. v* H( E4 ?5 Q, U5 d8 ~0 t) W
     TIM_FLAG_CC1# ~* w/ x& Q# V2 C7 K$ h. D
TIM_FLAG_CC2  e9 P# W: i  Y  J3 Y

$ |8 ]) D8 T& F/ P7 K5 GTIM_FLAG_CC3
2 ~) `% F* c1 E: b8 L- n5 r. Y! O) ^
: j) m1 J( h. \; [: PTIM_FLAG_CC47 O* F, W) {9 G. J: |- T: |, B$ Y

; T$ t  _( `7 K# f3 G# ]1 W捕获/比较标志,配置了捕获/比较中断要用到。$ W7 H( f4 h/ u- ]0 N/ \! g/ t5 s

+ n! e( Y  `+ ]与标志获取函数__HAL_TIM_GET_FLAG对应的清除函数是__HAL_TIM_CLEAR_FLAG:1 Q, i6 Q5 S- I4 Q1 I! M  ~

+ m( B! i! s5 W" L' A
  1. /** @brief  Clear the specified TIM interrupt flag.9 K$ H% R$ {4 O  b
  2.   * @param  __HANDLE__: specifies the TIM Handle.
    $ |) z; W6 H& @/ Q4 e% v4 U% I) w) N
  3.   * @param  __FLAG__: specifies the TIM interrupt flag to clear.
    9 H2 k2 {* M4 X' i" ]2 u
  4.   *        This parameter can be one of the following values:
    3 {1 n. J' H( w4 j+ _. a$ B1 e! V
  5.   *            @arg TIM_FLAG_UPDATE: Update interrupt flag  f% H# O$ X! s2 J
  6.   *            @arg TIM_FLAG_CC1: Capture/Compare 1 interrupt flag
    : N  G8 e/ @7 W# P5 T
  7.   *            @arg TIM_FLAG_CC2: Capture/Compare 2 interrupt flag9 G$ l( C2 t# W4 z+ O6 ?
  8.   *            @arg TIM_FLAG_CC3: Capture/Compare 3 interrupt flag
    & w& x7 g( d$ E/ P/ P/ L) w
  9.   *            @arg TIM_FLAG_CC4: Capture/Compare 4 interrupt flag
    ' A6 H$ d/ k: a* `- l
  10.   *            @arg TIM_FLAG_CC5: Compare 5 interrupt flag" @1 B8 j  _8 e$ U+ e
  11.   *            @arg TIM_FLAG_CC6: Compare 6 interrupt flag
    - O0 ?4 R5 l& {, U
  12.   *            @arg TIM_FLAG_COM:  Commutation interrupt flag. S0 z3 I& X$ _; B* J
  13.   *            @arg TIM_FLAG_TRIGGER: Trigger interrupt flag# S1 Q+ }! e! w3 f+ O6 |
  14.   *            @arg TIM_FLAG_BREAK: Break interrupt flag   
    6 L+ C* z; ?) ]& ?5 A
  15.   *            @arg TIM_FLAG_BREAK2: Break 2 interrupt flag                     % ~. r: Y% N7 J4 {& A; v# o
  16.   *            @arg TIM_FLAG_SYSTEM_BREAK: System Break interrupt flag
    9 E. U6 G  C4 |2 z
  17.   *            @arg TIM_FLAG_CC1OF: Capture/Compare 1 overcapture flag; M* g5 _5 @7 x6 X
  18.   *            @arg TIM_FLAG_CC2OF: Capture/Compare 2 overcapture flag6 R, q5 U- D. v! ^
  19.   *            @arg TIM_FLAG_CC3OF: Capture/Compare 3 overcapture flag% l! g2 e8 B* u% {
  20.   *            @arg TIM_FLAG_CC4OF: Capture/Compare 4 overcapture flag
    " ]- S& [2 Q) m! N2 H" P
  21.   * @retval The new state of __FLAG__ (TRUE or FALSE).
    % e- p4 n* G, w1 b' P0 l( p
  22.   */% e' ~7 N$ V2 j9 l) S
  23. #define __HAL_TIM_CLEAR_FLAG(__HANDLE__, __FLAG__)       ((__HANDLE__)->Instance->SR = ~(__FLAG__))
复制代码

0 p+ G& Y% g+ ^6 B+ {清除标志函数所支持的参数跟获取函数是一 一对应的。除了这两个函数,还是定时器的中断开启和中断关闭函数用的也比较多。& F- s% s0 j1 P( s
! W, _6 R2 C# E( L- w. W9 S
  1. /** @brief  Enable the specified TIM interrupt.  K. a5 ?' c. O) l$ A& Q
  2. * @param  __HANDLE__: specifies the TIM Handle.( ~: W# ^) `, D3 h; ^; Q
  3. * @param  __INTERRUPT__: specifies the TIM interrupt source to enable.: N6 q' b. G( y+ l" c$ c
  4. *          This parameter can be one of the following values:
    / E: G* h' X( G/ P. O8 J
  5. *            @arg TIM_IT_UPDATE: Update interrupt
    " ?5 p1 ?/ N0 g) Z
  6. *            @arg TIM_IT_CC1:   Capture/Compare 1 interrupt
    , a1 m, Y4 O* R) I
  7. *            @arg TIM_IT_CC2:  Capture/Compare 2 interrupt
    % g' E9 I/ h0 Q3 V0 ^3 ]5 k
  8. *            @arg TIM_IT_CC3:  Capture/Compare 3 interrupt
    # W% a* ^% L- W. x2 Y
  9. *            @arg TIM_IT_CC4:  Capture/Compare 4 interrupt
    0 s: ?2 P! \" m$ ~" u  P
  10. *            @arg TIM_IT_COM:   Commutation interrupt9 l7 D9 s& Y1 L4 s8 l3 T
  11. *            @arg TIM_IT_TRIGGER: Trigger interrupt
    ; @; S  w5 X# Q( E( K  {, D: Z% M* c
  12. *            @arg TIM_IT_BREAK: Break interrupt$ k+ s" w6 s- b* Q
  13. * @retval None% n3 `9 e2 S$ }$ t- c6 u) j) P# U' D
  14. */2 ^2 U- {& D' U) j1 ]; I5 J4 G- s
  15. #define __HAL_TIM_ENABLE_IT(__HANDLE__, __INTERRUPT__)  ((__HANDLE__)->Instance->DIER |= (__INTERRUPT__))
    ) t3 E$ B. j- c: _6 n! O: t

  16. * C% c: ^+ p. t
  17.   /** @brief  Disable the specified TIM interrupt.
    5 R# d3 O' V+ h5 [% k# }2 h# t
  18.   * @param  __HANDLE__: specifies the TIM Handle.
    ! R/ a$ o+ b6 p7 |9 u  B7 d* D
  19.   * @param  __INTERRUPT__: specifies the TIM interrupt source to disable.
    3 ]' d) i  R. E  |% b, `( W
  20.   *          This parameter can be one of the following values:1 V  u  n! I% c0 T- \
  21.   *            @arg TIM_IT_UPDATE: Update interrupt% W% h& u( x8 v  {3 J4 b
  22.   *            @arg TIM_IT_CC1:   Capture/Compare 1 interrupt1 T  z. V$ R9 _  X& m/ s% t) O
  23.   *            @arg TIM_IT_CC2:  Capture/Compare 2 interrupt
    1 s" Q+ F/ ~# E# i0 v2 ?
  24.   *            @arg TIM_IT_CC3:  Capture/Compare 3 interrupt
    " A" z5 g- f. ^& p# c
  25.   *            @arg TIM_IT_CC4:  Capture/Compare 4 interrupt2 T7 T2 B8 o9 B. K
  26.   *            @arg TIM_IT_COM:   Commutation interrupt! }! M/ v( I2 b& l
  27.   *            @arg TIM_IT_TRIGGER: Trigger interrupt
    5 P; F3 N8 X8 r# v/ y0 d  N! b
  28.   *            @arg TIM_IT_BREAK: Break interrupt3 W  o9 n# P* [. N+ x
  29.   * @retval None3 I7 v- r  A' G" |1 M2 g% |
  30.   */
    1 |) q& k9 G9 O! m
  31. #define __HAL_TIM_DISABLE_IT(__HANDLE__, __INTERRUPT__)   ((__HANDLE__)->Instance->DIER &= ~(__INTERRUPT__))
复制代码

  i0 c9 k- o9 U5 p; m1 |% @  B常用的也是前五个参数,1个定时器更新中断以及4个CC中断 。5 ~% s: X' B# U1 F: g
! }* N0 b- g0 a8 _# y, }' ^
注意:操作定时器的寄存器不限制必须要用HAL库提供的API,比如要操作寄存器CR1,直接调用TIM1->CR1操作即可。; _) T7 k1 b+ A. A

  P& |4 b" u% k/ \32.3.7 定时器初始化流程总结! E2 {, G9 X$ C! Z
使用方法由HAL库提供:
/ i. K6 C" a/ ~, ?1 k! J- G  w) `9 [- R6 x' D: y6 f
  第1步:通过下面几个函数配置定时器工作在相应的模式
1 s! ~* h4 z8 x- l. P8 H
" O2 g2 @! [. K  HAL_TIM_Base_Init9 c# u- m: h; m5 @6 J. p* Y
简单的定时器时基础功能
8 Y: [4 z0 K; w
, j5 N2 w" K/ z5 L% b. j& P0 m0 }  HAL_TIM_OC_Init 和 HAL_TIM_OC_ConfigChannel' h& Y( l- d: H9 h) `7 X1 d! S
配置定时器产生输出比较信号
2 V- W% S9 `" _* J( j* O9 y# R
3 N: E, x9 q% t  HAL_TIM_PWM_Init 和 HAL_TIM_PWM_ConfigChannel
0 ^2 E+ u- R' @- K2 a% K配置定时器产生PWM信号. k& Y$ f4 M# H# K* n1 a: P: ?! E( ?
  p& ?3 s  i& Y
  HAL_TIM_IC_Init 和 HAL_TIM_IC_ConfigChannel
% D8 _% Z' W* M2 C7 R# }, X配置定时器测量外部信号2 G9 c  O+ Z/ I6 y2 y

# n; `! e& C( P1 P" Z+ ]( V  HAL_TIM_OnePulse_Init 和 HAL_TIM_OnePulse_ConfigChannel# q: M* P+ }8 ~' L7 _
配置定时器工作在单脉冲模式
, }5 {9 _% T1 ^9 c
5 K* F5 @' p( K+ J- w, ~  HAL_TIM_Encoder_Init( |+ m  _7 N/ {% ]8 H
配置定时器使用编码器接口9 C7 u* V2 {/ |# c) |/ {3 Z. Q* j

( n5 P2 |9 q8 J7 Y$ w% X  第2步:定时器几个常用功能的底层初始化API,这个里面需要用户自己填4 j9 c: v: u4 r/ t/ D( w! Y( H
5 k4 B- C/ u3 X! o+ I) y$ }: z$ {
第1步里面的几个函数会调用下面的API。
& w! u9 p6 i7 M0 A- P3 N
5 p1 n, ]) }( m7 n1 i  定时器基本功能 : HAL_TIM_Base_MspInit()
% b1 k0 Z; k' ^& j: J, v% r" P  输入捕获 : HAL_TIM_IC_MspInit()6 s5 Y. ^$ ]4 ?$ K' X8 W) e1 l- w
  输出比较 : HAL_TIM_OC_MspInit()! I& v: m8 h/ \, P1 Q. T
  PWM输出 : HAL_TIM_PWM_MspInit()
) E( K3 L* P2 F  S% J9 I+ G5 n  单脉冲输出模式: HAL_TIM_OnePulse_MspInit()' r, X  v/ W# c7 c3 p7 Z& ?+ m3 _
  编码器模式 : HAL_TIM_Encoder_MspInit()
/ x  L, d) N5 {/ B9 ^  第3步:底层初始化具体实现6 C( ^2 ~8 t& H2 F

+ i0 C3 z4 v2 k+ [2 y% U第2步中函数的具体实现。5 z# [  o1 l0 N9 Z6 C
% D  B! E5 Z" _4 S
  使用函数__HAL_RCC_TIMx_CLK_ENABLE()使能定时器时钟。
+ \+ _+ G6 K( D  使用函数__HAL_RCC_GPIOx_CLK_ENABLE()使能定时器使用到的引脚时钟。. Q& B0 ]* I+ s! U8 c0 V) n. c
  使用函数HAL_GPIO_Init()配置GPIO的复用功能。$ R  R% ]% K8 {; z
  如果使能了定时器中断,调用函数HAL_NVIC_SetPriority和HAL_NVIC_EnableIRQ配置。
' d1 I! K! g9 d: J. g5 Q8 A3 G  如果使能了DMA,还需要做DMA的配置。
& N! b8 e" z) i  [  定时器默认使用APB时钟,如果使用外部时钟,调用函数HAL_TIM_ConfigClockSource可以配置。, U; ]6 A" I* v& J0 \  A* B! _. g" I
  第4步:启动定时器外设
# z- _. M9 ~/ s  Q6 t+ U
, }% u+ h  ?# `* j6 r6 w$ z  定时器基础功能:& M1 V  ?0 ^1 q  A. U
HAL_TIM_Base_Start()
: r& D/ _6 F# I
* j) f- ?0 A3 I% y+ RHAL_TIM_Base_Start_DMA()
4 u( Q; V( X, V& U2 ]1 Z
( L$ J0 N- h) a( f4 @( V5 z; fHAL_TIM_Base_Start_IT()
5 g, B1 b/ F6 c- t0 r; O5 W2 N- }# A9 R
  输入捕获 :: q8 D) W9 K3 b% t$ [
HAL_TIM_IC_Start()* u6 X6 |# q5 b* p4 k7 m# Q
- A3 c0 w  Q5 D- M, o8 o
HAL_TIM_IC_Start_DMA()
( T9 L7 I1 {$ S4 l% Z/ a* ?6 [: E; N4 J- X/ A3 g$ G
HAL_TIM_IC_Start_IT()( c& n+ q" [. J* b- F' W5 o# z3 V( o5 X
- ~0 {7 J6 o# F* a1 P9 M! K& X
  输出比较 :
4 y1 Y- f8 ]; ^4 u4 E/ F- WHAL_TIM_OC_Start()7 G+ a3 d: v% ?! @3 N5 g" U

' o  T  D2 c, M4 YHAL_TIM_OC_Start_DMA()
/ H  @. O5 n& x
  o. f2 [3 \3 A0 I' F0 MHAL_TIM_OC_Start_IT()6 j+ J, A& T% s6 H5 C' |* H# G
) `/ J' `/ [* i- U- w8 p) j# U
  PWM输出:
$ b6 B! p0 f( P$ vHAL_TIM_PWM_Start()4 A% m: c) ]/ L" i

6 i' F. u3 G6 W- V$ {HAL_TIM_PWM_Start_DMA()5 q9 y" X+ j1 i; r& v8 N( A
! O3 ?1 |0 [5 e$ d
HAL_TIM_PWM_Start_IT()5 Z# ^4 @  Q  n) {7 r5 s: v% i

) D" T' U* _7 Z6 @  单脉冲模式:
" D7 v2 l8 |  G& p7 OHAL_TIM_OnePulse_Start()
0 `4 G8 z7 T! ^( {# Y' W$ T! e
. F! n+ q2 Z* b" Y# ]$ MHAL_TIM_OnePulse_Start_IT().
$ _" i, ~2 q! O* J6 b$ Y
4 z7 J/ M5 m/ a4 M1 _% j) C* ^1 D. V  编码器模式:
" o$ }9 P  y# z1 j0 ~2 U* HHAL_TIM_Encoder_Start(); u% y1 c2 v) Z: N
( A/ ~3 P* e6 V8 f. T; D; H0 C
HAL_TIM_Encoder_Start_DMA()
# ?& H& O. b4 {+ c& N. j2 e- Y% C2 E
HAL_TIM_Encoder_Start_IT()." H; H7 ?" t, R& g, K1 ?
, l( ]: }# j+ h  C
  第5步:定时器的DMA突发使用下面两个函数
- d  E0 i8 P+ m% l
, J, Z0 Q/ L! ~3 D- N  HAL_TIM_DMABurst_WriteStart()
* k8 N& K" h$ n; J4 n  HAL_TIM_DMABurst_ReadStart()" `3 X7 C' l5 w% z0 l: ]
定时器常用的功能,通过上面这几步即可实现。0 o/ b- v4 y: b. ^% z+ I
5 b* Y& a1 |5 j: H$ \0 r& z( N3 r
32.4 源文件stm32h7xx_hal_tim.c! T. B9 U% C* _, z! B) v, z) b' N
此文件涉及到的函数非常多,这里把几个常用的函数做个说明:
# I3 `* b( P* b* C. P1 S$ A, P' r" T3 ?: O, t
  HAL_TIM_Base_Init
8 d' i/ P  o4 C2 M  HAL_TIM_Base_Start
/ F" \1 d2 a( p  z, M  HAL_TIM_PWM_Init; {+ q+ K- K5 J, U+ B
  HAL_TIM_PWM_ConfigChannel
% a  r8 B8 i9 Q; e9 m  HAL_TIM_PWM_Start
. ]7 a3 v7 {6 S! ^& y6 n; K  HAL_TIM_IC_Init6 p, o. u2 ?3 \' y, S
  HAL_TIM_IC_ConfigChannel
6 o; H* n/ I! E+ @  HAL_TIM_IC_Start_IT
/ F% S3 C& R0 c9 c3 c3 F  a$ F  HAL_TIM_OC_Init$ a4 i3 D& {! v  w- j0 S6 D
  HAL_TIM_OC_ConfigChannel2 k( v6 z+ e" F) u( s
  HAL_TIM_OC_Start
) c" w! E! x. }! ~8 a: e2 a2 Q32.4.1 函数HAL_TIM_Base_Init6 ]; A; Z/ _. t0 t
函数原型:! M) d. i5 @2 z; W- ?

& a4 b/ ~% S( s9 R; e6 F6 p6 N
  1. HAL_StatusTypeDef HAL_TIM_Base_Init(TIM_HandleTypeDef *htim). j( ~$ m8 |$ n% X
  2. { ' j; ?* B3 `* [4 Y
  3.   /* 检测是否是有效句柄 */. ]( v4 o3 |. [5 k: r5 \
  4.   if(htim == NULL)
    : d' I5 a8 Y( @4 p
  5.   {9 B# `: A# O6 |- s+ f% G
  6.     return HAL_ERROR;
    & a* L% \% P+ j3 Z8 a
  7.   }  A: o: V4 Q- W3 b4 H" F% d( n9 a* N

  8. * A: B9 Q$ g, S9 v, N
  9.   /* 检测参数 */8 a$ {: d% d3 S9 d
  10.   assert_param(IS_TIM_INSTANCE(htim->Instance));
    ! y7 L8 H3 o0 t: M6 p2 t3 j2 `6 h
  11.   assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode));
    ; v/ O, L, A  i# k) c$ v7 S, X* b
  12.   assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision));
    + r( ^* U6 s  A5 {$ y# O

  13. / _% R: r3 U2 a  d* @
  14.   if(htim->State == HAL_TIM_STATE_RESET)
    9 ^( Q: \  w; |- A. ^" I+ \
  15.   { ' V$ q1 E/ r- J+ v9 r* `
  16.     /* 默认取消锁 */
    $ N2 v/ n9 S* G* }) u7 `
  17.     htim->Lock = HAL_UNLOCKED;0 m5 X. E; d5 q6 V. `& @
  18.     /* 初始化底层硬件 : GPIO, CLOCK, NVIC */2 t0 {1 k7 z% p- r9 d* V
  19.     HAL_TIM_Base_MspInit(htim);9 h$ C$ _9 u% L, t
  20.   }. p0 B* K# Y6 ?1 }& A# a

  21. ; U4 B3 e  r$ h
  22.   /* 设置TIM状态 */
    1 O% T5 Q( C7 }" g- l
  23.   htim->State= HAL_TIM_STATE_BUSY;
    , o' `" S5 z4 a/ A2 T6 h* T

  24. + A- j- F6 ?7 q5 S$ C6 N: ~
  25.   /* 基本参数配置 */4 D( g/ v' ?; r. w' F
  26.   TIM_Base_SetConfig(htim->Instance, &htim->Init);
    1 N/ P+ j* d* A8 X6 Q: V

  27. ; k- y/ q) j( v/ a) V9 N: _$ ~! y6 R
  28.   /* 设置TIM就绪 */
      F5 t  |+ Q, L2 z1 W1 b4 i
  29.   htim->State= HAL_TIM_STATE_READY;
    3 R; {4 G2 l* T  P

  30. 1 S; z9 o, U; ^9 A! A
  31.   return HAL_OK;/ @6 ~! w, F& r6 Q
  32. }
复制代码
. y1 Y5 s. N- N8 y
函数描述:: T; ~/ w( g1 r' @8 S3 F. a
* N4 s) R; l4 e9 l+ S
此函数用于初始化定时器用于PWM。( v9 J2 r! z$ I  T8 S. y

6 O  c9 o  A/ ]) F3 `6 I% W. q函数参数:5 F! d4 G& g  E6 I5 L5 c

8 I, n9 T. |3 Q2 {& Q  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。
" p: D& z7 F# y  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
# w5 a) U) o3 w8 E7 q3 m注意事项:
' @0 j. k( r6 I0 J
" D& y- c% H4 E6 p" T  p函数HAL_TIM_Base_MspInit用于初始化定时器的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能,由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
5 o7 Q- p' G& u) O, K如果形参htim的结构体成员gState没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量TIM_HandleTypeDef TimHandle。" W+ U$ u# u5 l( C8 N9 z- \( \4 G
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_TIM_STATE_RESET  = 0x00U。
1 J/ u3 ?9 B# s, v. M; r, V6 t  B9 m  n" J- [& `. i- L
解决办法有三:
8 v. d- I/ b7 V. a; X9 Y& V: Y" F$ ^# A% x" \6 ?
方法1:用户自己初始定时器和涉及到的GPIO等。8 C- E, J1 t$ }7 G6 Z4 n" r5 e- ~

$ d3 c0 X& N, ?* s1 [+ n0 c方法2:定义TIM_HandleTypeDef TimHandle为全局变量。2 H8 C: Q7 I! |1 A
% J6 w+ u8 V% g
方法3:下面的方法, b& K/ ?1 m# f: A$ [8 X
! q2 X! z0 [  y% n' |) H
  1. if(HAL_TIM_Base_DeInit(&TimHandle) != HAL_OK)
    9 a, u( x& \/ u3 t
  2. {
    + M+ c! {& Y6 V# }( }2 M4 b' o
  3.     Error_Handler();
    ) w. p5 s) t; m
  4. }  
    5 g: A1 _, S- G
  5. if(HAL_TIM_Base_Init(&TimHandle) != HAL_OK)
      |1 b) y. e) b. c6 S, W
  6. {
    ' u7 ?; y( S# _( \* w
  7.     Error_Handler();  m; V4 j! ]( f+ o) m5 ~
  8. }
复制代码

) S+ ^3 S$ I' i! D* F- \5 P使用举例:
/ y& m7 i& q; w5 t7 J! t5 r4 \8 ?) w0 K! Z) w7 w! o- e0 R
  1. TIM_HandleTypeDef   TimHandle = {0};
      D+ y1 {! ]2 W' Q$ a
  2. 2 z9 x7 ?' K: l+ \4 C3 z
  3. /* ! p5 H$ @/ I/ W7 f. [( w
  4.     定时器中断更新周期 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)
    6 G% D5 o' K6 F8 q9 p0 N7 d1 B! T
  5. */* Q7 ~# a. Q' t# p6 a; ]( P
  6. TimHandle.Instance = TIMx;
    2 x3 I1 L- k+ l& l4 b5 K
  7. TimHandle.Init.Prescaler         = usPrescaler;
    # x0 X2 L2 p9 q6 D
  8. TimHandle.Init.Period            = usPeriod;        2 y+ a: u; X; i! k/ E% l
  9. TimHandle.Init.ClockDivision     = 0;
    2 y! u! M& y, S: c0 X
  10. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;
    $ U$ N/ ~0 r+ f0 M/ y( o* ~$ I
  11. TimHandle.Init.RepetitionCounter = 0;' \3 B1 H# R1 g" @  w) U
  12. TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
    / l) k8 q$ z4 Q4 G3 N
  13. if (HAL_TIM_Base_Init(&TimHandle) != HAL_OK)
    * L& @2 Y" i* M( q& A3 s
  14. {
      s& j9 H. X, K; B0 s- a% H( {$ r4 F) g  u6 ]
  15.         Error_Handler(__FILE__, __LINE__);
    5 c+ |! C" E9 l1 x1 Z$ e3 S- p
  16. }
复制代码

, A4 V/ k2 r8 l. ~* Q32.4.2 函数HAL_TIM_Base_Start
& K, e" o0 q0 D$ F函数原型:
: ~2 `4 M. B% p& S8 y. J% r
0 J# _9 O. N5 I4 A$ G9 n5 r( g; u
  1. HAL_StatusTypeDef HAL_TIM_Base_Start(TIM_HandleTypeDef *htim)  z1 t: o  u; I; t! A: y4 w, J
  2. {* g9 Q& w& c( q1 B' {
  3.   /* 检测参数状态 */% Y; C! O7 Y' H- M1 j2 G; V
  4.   assert_param(IS_TIM_INSTANCE(htim->Instance));
    " Y1 g$ n9 i; {* i( i8 p9 P
  5. $ i4 u! z! y! w2 ^# f
  6.   /* 设置定时器状态 */
    - f: K( i, \+ D1 v3 ^& ?8 E
  7.   htim->State= HAL_TIM_STATE_BUSY;
    * m$ L& |; V# b; {

  8. 3 J+ ^+ o9 F" i9 r$ u$ W0 |
  9.   /* 使能定时器 */
    ; d) m8 E* G; H+ W6 H* }- y
  10.   __HAL_TIM_ENABLE(htim);" q6 V7 g# q3 p5 d1 W8 s

  11. ; M% o6 `/ _. G  P$ p
  12.   /* 设置定时器状态 */5 z% U. o3 ]; o; X) [! Y
  13.   htim->State= HAL_TIM_STATE_READY;+ H0 v  Z& A% z4 N' y6 Y" t5 \

  14. ' ^. e. V- u8 q
  15.   /* 返回HAL_OK */
    ! S( z- P! E2 k  a8 z8 g: v3 _- H
  16.   return HAL_OK;
    , |: o6 C8 E: A: c( p& K
  17. }
复制代码
; X3 a6 g3 X, [2 P- g6 M
函数描述:3 G" d+ q7 E& {6 U3 F; a0 A
; d  M# B9 s4 f8 k" E
此函数比较简单,调用函数HAL_TIM_Base_Init配置了基础功能后,启动定时器。
/ j  V: j" b2 N7 N5 D4 k
, w4 _1 E/ u  H9 A; k( U- s* `5 t函数参数:( T# C& e  _$ F0 ~" B. q* a

) Q7 L) n) J3 G9 F3 P1 F. c4 j  第1个参数是TIM_HandleTypeDef类型结构体指针变量。
, A. [- O' L' E" Y$ }. T% v& g3 j  返回值,固定返回HAL_OK,表示初始化成功。
5 V9 Q9 I" ]6 b5 O& L使用举例:) i/ }' R* ]0 ~

$ p5 I( `9 H( D
  1. TIM_HandleTypeDef   TimHandle = {0};/ n; N! i+ Z# ^3 y+ Y$ L
  2. 5 l1 D* F4 t7 B( d& ]) G
  3. /* 2 E! Z0 f; m3 _
  4.     定时器中断更新周期 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)
    , A# d. r- L. i* H+ A
  5. *// N2 E# V$ C5 ]/ I* \+ b( p
  6. TimHandle.Instance = TIMx;/ p1 z4 z* P7 M3 o
  7. TimHandle.Init.Prescaler         = usPrescaler;
    1 ~3 G, l& T6 z6 k7 u: t
  8. TimHandle.Init.Period            = usPeriod;        
    ) Q& W3 K0 C" c  u% {
  9. TimHandle.Init.ClockDivision     = 0;
    9 l3 q; `+ K2 ?% [" S6 k( n6 Z
  10. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;" n% \/ Z& u! H, }( b
  11. TimHandle.Init.RepetitionCounter = 0;6 g/ r$ g* ~1 M2 A  r' P1 T
  12. TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
      D8 P* U) H. E) ~4 [4 w
  13. if (HAL_TIM_Base_Init(&TimHandle) != HAL_OK)) J, b* Z2 E1 ?) G4 S1 [
  14. {
    * ]& E% k  G+ O9 [
  15.         Error_Handler(__FILE__, __LINE__);
    - _1 u7 g3 w3 k) R3 Q
  16. }
    8 T6 L  D- t8 Y9 k

  17. . g, Q1 W8 T' `' }% W. z9 R
  18. /* 启动定时器 */. o" n% {, y, L$ l
  19. if (HAL_TIM_Base_Start(&TimHandle) != HAL_OK)
    - G1 L8 i# y$ I3 m0 H* R  ~/ l
  20. {
    3 ~. J' P& H2 f' D2 _% ]  f) X
  21. Error_Handler(__FILE__, __LINE__);
    3 Y, y* e6 M) k: D  Q* s8 Q
  22. }
复制代码
8 U" ^* J8 i, G2 {3 o3 O. B; z
32.4.3 函数HAL_TIM_PWM_Init  g  d& ]$ \3 I7 T3 f# f/ O
函数原型:& t6 G; G: U& D! u* S/ K4 z
. Z- `0 J$ E+ k( u
  1. HAL_StatusTypeDef HAL_TIM_PWM_Init(TIM_HandleTypeDef *htim)
    9 F. h% s9 P- y3 c% M
  2. {. O  \1 c# _1 ?
  3.   /* 检查句柄是否有效 */
    # E2 v0 N! ^. T3 J4 v7 U# t
  4.   if(htim == NULL)
    ) I- d- H' y8 Z
  5.   {3 {/ ~4 c( m( p4 J1 @
  6.     return HAL_ERROR;  ^$ @+ b8 S  `% {, X7 f
  7.   }3 l& b+ S1 k4 P/ q1 A. C0 E& u
  8. 7 j' n- E) m& v& q1 K
  9.   /* 检测参数 */
    - q5 i' h9 b9 z' b( B' R; p& g" L# l
  10.   assert_param(IS_TIM_INSTANCE(htim->Instance));
    9 O8 A( W- U0 T+ ?) }
  11.   assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode));1 x1 n1 B5 `8 c. o: J  d# }
  12.   assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision));
    % o6 P4 M6 B! y# @9 M

  13. 3 e) o8 t  I  P& \! [2 \0 y
  14.   if(htim->State == HAL_TIM_STATE_RESET)
    + u# [4 ~+ l- i5 S$ F' ~9 T, O, }
  15.   {
    & w( w' y( g3 q8 {6 O. _* z! Y
  16.     /* 默认取消锁 */
    8 A' C: V' }5 N' A
  17.     htim->Lock = HAL_UNLOCKED;
    4 g: o" H7 \% c% \! R5 |3 a
  18. 5 i2 ]+ ^) B2 Q
  19.     /* 初始底层 : GPIO, CLOCK, NVIC 和 DMA */" h+ E& R' _1 L- l
  20.     HAL_TIM_PWM_MspInit(htim);
      b# M0 Q) u3 Y2 P
  21.   }
    8 x# z5 v6 k3 `2 R
  22. , e/ O0 ]; A: X9 ~. a6 w* ]. H
  23.   /* 设置定时状态 */  k1 r# C8 Z7 s, a
  24.   htim->State= HAL_TIM_STATE_BUSY;0 y' \  a& t. [; O2 x

  25. ! E# a: t' P4 d4 s
  26.   /* 配置定时器用于PWM */  
    ) ~3 `6 L) {$ E% C
  27.   TIM_Base_SetConfig(htim->Instance, &htim->Init); # A2 }4 Y$ X  A) t7 _& ^. Z
  28. $ L+ I& N2 D: \1 U( }: t
  29.   /* 设置定时器状态 */3 ?9 g2 \* r& Z' U; x
  30.   htim->State= HAL_TIM_STATE_READY;
    & m) i) _( U6 n, {2 }
  31. : z9 \8 J5 B1 `2 E% F5 E9 d
  32.   return HAL_OK;) Q# S3 a4 [8 C* q) `
  33. }
复制代码
7 j- {! A7 |6 q) j1 @; g
函数描述:
+ c% E, ], j4 M5 z/ O* \8 e. Q7 s* x6 `! B
此函数用于初始化定时为PWM方式。
# ?3 b& C; l: Y* F! M: L; l' P7 H5 [: f1 C; R
函数参数:
: \, Z5 {! I- v7 Y
- Y4 a( }* o9 r1 n& `, w8 Y  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。
( i5 X3 Z: M# Z: ~% L/ I  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
) k* Y- {: [, q/ J) n注意事项:
3 y4 a( }; W7 h
3 Z9 X8 D, ?% h( Z! n# n. u函数HAL_TIM_PWM_MspInit用于初始化定时器的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能,由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。2 y. r# G9 k5 l2 X  |1 q; J
如果形参htim的结构体成员gState没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量TIM_HandleTypeDef TimHandle。* k+ y% d: N0 o/ T' U0 v
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_TIM_STATE_RESET  = 0x00U。
1 e$ K1 X7 O  z5 P
$ w6 U* B# d( E+ m- V+ @7 _; P解决办法有三:5 C+ h0 ^6 j' l3 E" @$ r
% l, j# m$ B/ t0 y: G$ j( Q% ?+ O
方法1:用户自己初始定时器和涉及到的GPIO等。
' \& m. f( q' u9 H7 S) H+ y  x
( f  p- K4 R3 u0 P% P: R* V方法2:定义TIM_HandleTypeDef TimHandle为全局变量。
4 d$ M- `6 `6 I0 P+ G0 ^9 i& a& t
, x3 K; _) i  X1 j0 V方法3:下面的方法( Q* p8 \; Q  g. W. f) z8 R

2 ]% a4 l" c$ ?0 X( F& ?. x& c
  1. if(HAL_TIM_PWM_DeInit(&TimHandle) != HAL_OK)/ ], l4 l) ?" A
  2. {) t- s! _) F% ]8 f
  3.     Error_Handler();5 Z8 G& [' J0 P% D( M, S/ a; ?
  4. }  : `& G- D" u. Z8 r6 A
  5. if(HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)
    / P/ @+ u! v: L0 T8 b
  6. {. k! C, ^' h9 ]* }! W  J
  7.     Error_Handler();) G" f) u5 [& s! u  [
  8. }
复制代码
- b1 s* s' G# h$ m
使用举例:
) e0 f1 x8 Y$ c
& s( N5 V1 S2 i! x; L. B' q
  1. TIM_HandleTypeDef  TimHandle = {0};
    6 r: u3 j+ C2 R# U! E3 m

  2. 3 i0 B+ v2 N+ I) \3 l$ l
  3. /*  PWM频率 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)*/
    $ U8 ?" _' T9 b, k  O* {
  4. TimHandle.Instance = TIM1;
    * X% W( A0 ^+ v* X
  5. TimHandle.Init.Prescaler         = usPrescaler;; V- b4 H. c# G8 N# d& W
  6. TimHandle.Init.Period            = usPeriod;5 u8 s& v) u( n. h
  7. TimHandle.Init.ClockDivision     = 0;, l; B# A4 O% b' J$ {) P: t
  8. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;+ v# C1 A" b. T* h; ]) J' V6 V
  9. TimHandle.Init.RepetitionCounter = 0;
    , s: e/ G) g* i0 u/ r: _' s
  10. TimHandle.Init.AutoReloadPreload = 0;: g7 m, u$ ]: l3 X  P
  11. if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)- a& ~3 g& i4 |$ V
  12. {
    ; k$ c( M, [* e( P: x7 ?
  13.     Error_Handler(__FILE__, __LINE__);
      l0 l2 ]3 J* s  q7 X
  14. }
复制代码
" I. ^: o; \* @2 o% m" G6 E
32.4.4 函数HAL_TIM_PWM_ConfigChannel
+ b& ^: V& a0 x/ g函数原型:
1 `) m  _0 Z; ]( O4 q4 j$ ~+ j$ [2 j: R0 |4 n" \
  1. HAL_StatusTypeDef HAL_TIM_PWM_ConfigChannel(TIM_HandleTypeDef *htim,/ k; {! O. `, ?; L- t/ ^8 o6 f! h
  2.                                             TIM_OC_InitTypeDef* sConfig,' Z! l' N" h# J7 c- |2 s6 P& h
  3.                                             uint32_t Channel)
    ! K; m; C- x& [- G
  4. {' O3 d: D: n3 p! l! |* k
  5.    /* 省略 */) c; r* G" s# w1 {6 ^- t/ ?6 K$ _
  6. 8 i6 [/ z' F1 L3 o% t6 o4 I
  7.   /* 开锁 */* b6 r# j3 x; f2 g3 H3 Y, r
  8.   __HAL_LOCK(htim);
    : v  w& ]* y: k8 i  m

  9. 7 b# I; M# E1 k( `; y% s- w" j3 a
  10.   htim->State = HAL_TIM_STATE_BUSY;0 |8 e" |9 G$ |" v" W
  11. 6 v/ ^$ @! ~) q
  12.   switch (Channel)- G6 s0 J1 E  G& Q& B
  13.   {
    2 t4 u1 r/ s5 o/ \5 S; }
  14.     case TIM_CHANNEL_1:; `( F+ R2 w4 F) a- g1 r; R8 K
  15.     {
    6 Q8 Q  [* p% N8 A/ i
  16.       /* 检查参数 */1 ~! `# D; S1 g5 a" `1 b
  17.       assert_param(IS_TIM_CC1_INSTANCE(htim->Instance));# _& F4 I3 m0 l+ ^

  18. 8 k) p$ x% t7 Z  \
  19.       /* 配置通道1的PWM模式 */
    ; ^0 F8 J* n! O
  20.       TIM_OC1_SetConfig(htim->Instance, sConfig);  \) ~, P7 i1 S/ ^3 w+ b1 y  \* l

  21. ' H7 m9 l4 O$ ?' x, ]
  22.       /*预装载使能,更新事件产生时写入有效 */
    5 F2 N4 a7 j9 U" a
  23.       htim->Instance->CCMR1 |= TIM_CCMR1_OC1PE;( \( V: z& U/ _6 z5 F, {/ X

  24. 3 l. b$ a# s! x4 P# n  a. x8 U. J
  25.       /* 配置是快速输出模式 */9 T7 }# p$ H1 ^. V: Y, \9 X
  26.       htim->Instance->CCMR1 &= ~TIM_CCMR1_OC1FE;8 e/ T, ?5 W1 X4 ?+ y' a8 h
  27.       htim->Instance->CCMR1 |= sConfig->OCFastMode;* {/ P3 x1 S" m& M* Q; s
  28.     }% [  E) @5 a4 b; ?+ h
  29.     break;; u- r8 Y% K) x
  30. 9 y* M) d/ l2 t: b# q, {
  31.     case TIM_CHANNEL_2:* H3 w' T, ?2 D1 @0 c
  32.     {
    ) z- B5 L* [$ t' p7 s9 a
  33.        /* 省略 */7 M/ I* G1 L4 K8 ]/ j
  34.     }4 T3 T" v9 F" _0 ]8 m3 N2 p/ U
  35.     break;
    , t0 x! {% E) a8 J/ J' {8 m9 I* u
  36. 0 w! ]6 x/ k8 y& i1 C
  37.     case TIM_CHANNEL_3:0 `! M. Z; H. o  m( ^0 W
  38.     {5 o# h* w* T8 B  |" G
  39.        /* 省略 */% [0 I0 E- |2 R
  40.     }, Q0 u4 J1 a7 I2 P
  41.     break;
    . A$ i8 e5 r& B* r
  42. + E1 U/ Y% w* y. l4 ^
  43.     case TIM_CHANNEL_4:. G; B+ d( v- k. h
  44.     {: v3 P. M3 y) m  V" u' j# `$ I7 O
  45.       /* 省略 */: p$ u9 w8 v8 c: ]$ F1 L
  46.     }
    1 m! H3 S4 g3 {/ u" p; N# ~# e
  47.     break;2 B9 E1 }8 B' t4 Q- e
  48. 9 V1 s$ I: b4 P
  49.     case TIM_CHANNEL_5:& a) y2 {# h. I: e* w4 d
  50.     {
    1 H6 Y' X9 H: U
  51.        /* 省略 */2 B, i+ r8 b& h4 d! ~8 C
  52.     }
    2 U/ f/ u% T6 x! E4 |
  53.     break;' m( Q' g& Z7 [2 |
  54. , y  {* T9 g- s8 Z1 j! n
  55.     case TIM_CHANNEL_6:
    & k# |; ?9 P/ `( A! ?& \4 D
  56.     {2 Z/ P( j8 x3 q
  57.         /* 省略 */
    $ r% E) z1 X9 s2 K. J
  58.     }
    / I$ b' t  V/ h, |$ Q
  59.     break;
    4 H9 X( b* {9 T$ u* h) N( Q" l
  60. & ?1 @8 ^/ {3 q
  61.     default:. l  ^) w. B4 o7 w3 [4 U" t# `
  62.     break;
    + R- f! |1 u5 M4 \/ g2 U0 I' l* A1 J
  63.   }
    1 Z# M( v) D2 w% p4 g" ~

  64. & e# y- {$ \& I; \2 z
  65.   htim->State = HAL_TIM_STATE_READY;2 I9 `! W4 R- E
  66. 6 c: U0 l( M; A, u* t# G1 `$ f7 q
  67.   /* 关锁 */. f# G8 Z1 {+ f$ @
  68.   __HAL_UNLOCK(htim);
    " z  }- W9 o( _+ r$ E. M& ~
  69. : f  F: @  p4 O4 B; }( m
  70.   return HAL_OK;
    8 ^& k5 F5 g/ K3 B
  71. }
复制代码
. A! Y3 S6 f" C. h" j, r
函数描述:
3 J, L" L( P0 E+ r, ~+ e% T$ f9 t, ^4 ~/ U
此函数用于配置定时器的PWM通道。! l4 f7 L2 f: i8 s
2 o) }. W1 I8 J+ ?
函数参数:6 O! }3 X# s( t1 K0 `- q+ Y0 m
2 t+ x8 B0 ~( k5 v
  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于定时器基本参数配置。! G' r. R% W; F: [* k) ^" C: |
  第2个参数是TIM_OC_InitTypeDef类型结构体指定变量,用于定时器输出比较参数配置。; I7 [( `9 T* E
  第3个参数是通道设置,支持以下参数:
! ^5 U. z9 W/ M0 S% z; |1 d' a7 ]TIM_CHANNEL_1
0 a. b* @4 _& K6 r# n) J) s/ Q6 i# e0 ~' C
TIM_CHANNEL_2
) k$ H+ Y+ a1 `1 {. v
  ~/ e: K& w7 P) B4 E5 lTIM_CHANNEL_3
. z( U$ o$ c- `1 N/ s  {7 P4 {7 V# T# Z% p0 |8 ^: V+ n
TIM_CHANNEL_4
) Z" w7 M( w# i0 o  Z/ a* j3 c; }8 I- J' m3 b3 r; B) s1 D
TIM_CHANNEL_5: }. a4 G) h- u" _7 ?) ]

1 B0 ?& S& R1 L. hTIM_CHANNEL_6" [/ C  n- M: b6 |
- [2 b+ Y. y' T
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
5 l6 K& G1 z. q: p$ z  d* X$ r使用举例:: C: {8 D6 E& ?# {. j3 s* F

5 m5 H  \7 R( z# U
  1. TIM_HandleTypeDef  TimHandle = {0};
    . ]# W& |( C; H: ~
  2. 4 J! N1 Q  b: K, S+ J# y* d" i/ w* s
  3. /*  PWM频率 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)*/. S* ~8 P' c9 E  G9 C
  4. TimHandle.Instance = TIM1;* j! M- [& O; U% h  B
  5. TimHandle.Init.Prescaler         = usPrescaler;
    9 P3 g8 Z% o, q
  6. TimHandle.Init.Period            = usPeriod;  B1 b. i3 V2 Q$ V& P# c8 J9 F
  7. TimHandle.Init.ClockDivision     = 0;
    - e# R# `* Z  T2 P- P
  8. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;4 |2 u- h* h  d7 s
  9. TimHandle.Init.RepetitionCounter = 0;
    6 p2 M0 M7 R- T* h2 b% w
  10. TimHandle.Init.AutoReloadPreload = 0;
    / ^, Q9 i2 S* O; {- @
  11. if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)- b. G/ w" f2 }8 U0 V7 O- V. _
  12. {
    + [  R1 G8 u1 _' |
  13.     Error_Handler(__FILE__, __LINE__);; l  x1 o  V- ^0 I, C" ~
  14. }
    . }& L8 m4 f! J. \' y' S! q

  15. 1 _! Q+ F& ]# U
  16. /* 配置定时器PWM输出通道 */" K7 f7 O/ j! G  ~
  17. sConfig.OCMode       = TIM_OCMODE_PWM1;) N0 J% }) H, d0 y, R- g$ u8 }
  18. sConfig.OCPolarity   = TIM_OCPOLARITY_HIGH;
    5 z6 [- L. ^" B& ^7 D
  19. sConfig.OCFastMode   = TIM_OCFAST_DISABLE;% Y& t0 l/ y: x' Q2 r
  20. sConfig.OCNPolarity  = TIM_OCNPOLARITY_HIGH;8 J5 S' _+ r- B% |# X9 v
  21. sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;
    * g6 O5 n) P, _) z
  22. sConfig.OCIdleState  = TIM_OCIDLESTATE_RESET;
    8 }4 U& Z& {% o; E/ P5 t6 s

  23. % ^' T: ?2 ~. g! s- [5 \
  24. /* 占空比 */, a, X% X' e. y9 [' [' a" V
  25. sConfig.Pulse = pulse;
    3 Q1 e) M9 o& n+ w$ M2 F
  26. if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &sConfig, TimChannel[_ucChannel]) != HAL_OK)
    - Y+ u! _1 M* l7 N5 B$ ~. p8 [
  27. {
    4 M4 D  r% r7 p3 T" d( |
  28.     Error_Handler(__FILE__, __LINE__);
    + e) X% q+ v, j8 U
  29. }
复制代码
% H  g0 m( G8 L' y/ U/ O5 I
32.4.5 函数HAL_TIM_PWM_Start2 |- m; \  i" H0 b# M
函数原型:
- `) E( A1 T( x% q/ X
# b- K' `  y) D9 U
  1. HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel)
    3 _: ^  l5 U5 D2 N$ v# x; [
  2. {0 k& m2 D1 _, O( o( y# {8 T
  3.   /* 检测参数 */
    # d. M) o7 V( s) b- J
  4.   assert_param(IS_TIM_CCX_INSTANCE(htim->Instance, Channel));
    : |& ~: {6 i' [* {

  5. ) R9 R! [( c: n- V6 z6 I
  6.   /* 使能捕获比较通道 */
      ?4 T; H6 Q: V$ D
  7.   TIM_CCxChannelCmd(htim->Instance, Channel, TIM_CCx_ENABLE);1 A7 Y  _" p$ e& X3 h

  8. 6 r7 a& B$ H, a; S, @
  9.   if(IS_TIM_BREAK_INSTANCE(htim->Instance) != RESET)  
    ! s# O+ b2 Q( O
  10.   {
    1 m& x9 o0 o2 Y8 Z& M3 J8 N) T, B
  11.     /* 使能主输出 */2 H. @6 f5 x) D1 E* h# Q3 y! }  X
  12.     __HAL_TIM_MOE_ENABLE(htim);
    ! {; Z' q6 K, d
  13.   }1 [' B" A$ D+ s  B. W
  14. / @/ K2 y# y4 _1 J4 U2 G. x% }
  15.   /* 使能定时器 */$ U4 ]' [- B4 U$ n
  16.   __HAL_TIM_ENABLE(htim);# [, ?/ ^: V. S3 q. P4 n7 A( N" d

  17. 5 ?7 H0 B" ?! x; Q
  18.   /* 返回状态*/& M; u8 u  _& x) q0 @+ l) i4 t
  19.   return HAL_OK;
    5 i4 |; R9 q- s( c: v1 |
  20. }
复制代码
9 A  M+ a9 ?* L1 q$ P7 N/ b
函数描述:; \- L$ V# [* q3 K' C" e

4 F; f2 s9 ^  k# p5 Q此函数用于启动PWM。
2 ]7 k- Y( ]4 U% n& {( ^
. M$ R" B8 d  ~* B: D, `  e函数参数:
6 s- A3 p1 T6 v& a4 E) _' H- Z5 G
  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。3 {% V) Z& U9 {6 D- X5 b* j( E4 L
  第2个参数是通道设置,支持以下参数:
1 J4 O$ F5 p* E& ETIM_CHANNEL_18 ~+ w9 }, l! z/ F
9 R. l8 l. R0 {$ m! P& J% N
TIM_CHANNEL_2  h' ?' x" H4 |$ e" Q+ y6 X8 K
7 b3 w4 K+ F  F, k) d* E) X" ~/ }
TIM_CHANNEL_38 L( m* j. {+ G0 X  t
) f4 P: h) r" W! F2 U
TIM_CHANNEL_4) C; o6 w5 i9 _# Q* \  W6 |

6 b( l1 ^& ]+ V; }. i  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
" |1 `3 t0 k+ D2 l! B) G使用举例:- N7 N5 }7 z7 H  N# P

8 n2 l& F8 _3 A8 V! u8 I, w
  1. TIM_HandleTypeDef  TimHandle = {0};# k. V1 g; Z& I) G+ ^5 S1 J/ U/ @

  2. ( v/ B7 P- Q# I6 q, X
  3. /*  PWM频率 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)*/
    ) A& K  `* L/ G' X" q4 C' Q
  4. TimHandle.Instance = TIM1;! v) o8 a! |- I5 h# Y
  5. TimHandle.Init.Prescaler         = usPrescaler;! p5 T& S4 x8 `: V
  6. TimHandle.Init.Period            = usPeriod;  _6 B8 r7 b5 a3 r+ `, E
  7. TimHandle.Init.ClockDivision     = 0;% }* H+ ~9 Z8 J& R" `
  8. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;
    0 c+ ?. a* T* J1 {- X
  9. TimHandle.Init.RepetitionCounter = 0;/ ], c- Y6 q6 F# h3 s
  10. TimHandle.Init.AutoReloadPreload = 0;! I' U$ z* M4 F, R
  11. if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)7 Z6 I. a( F7 W$ _& u: N
  12. {
    / b0 `7 _/ o7 M5 ~, a
  13.     Error_Handler(__FILE__, __LINE__);
    " e& ]6 U/ W( G% X4 D
  14. }
    ( ?: d+ I! \8 o0 o

  15. $ P1 m& h% s1 y, y- x1 B
  16. /* 配置定时器PWM输出通道 */
    * ]7 l1 x0 U) ^4 l: T
  17. sConfig.OCMode       = TIM_OCMODE_PWM1;
    0 A; K8 \! t2 \
  18. sConfig.OCPolarity   = TIM_OCPOLARITY_HIGH;" y0 |& x: k% M/ w; _3 g1 R
  19. sConfig.OCFastMode   = TIM_OCFAST_DISABLE;: P* u8 Q/ k" f& \! G* R
  20. sConfig.OCNPolarity  = TIM_OCNPOLARITY_HIGH;; X5 R8 ]& b8 K! _; S, I( x+ J
  21. sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;# A$ h- b- R0 L/ r! T9 \- @: m# f
  22. sConfig.OCIdleState  = TIM_OCIDLESTATE_RESET;; G1 L. J+ _: m6 l9 n' U
  23. * V* R. l& P5 j; Y- F+ L8 |7 D6 O8 {
  24. /* 占空比 */2 U! |; Q# H3 |4 ^/ q5 H  M
  25. sConfig.Pulse = pulse;0 e- B/ F! ?. N  n5 c
  26. if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &sConfig, TimChannel[_ucChannel]) != HAL_OK)
    ( X7 f# m( r+ k8 G" c" h
  27. {+ C! o* m1 H6 @9 o) v5 M! K
  28.     Error_Handler(__FILE__, __LINE__);8 }  v* x* A1 j1 [$ w
  29. }
    : b. T5 v/ f; \- i) a
  30. " X* ?& L' B$ T, r, |! L* V
  31. /* 启动PWM输出 */) k$ d4 V0 |# J! ~; M" }& X8 F+ X
  32. if (HAL_TIM_PWM_Start(&TimHandle, TimChannel[_ucChannel]) != HAL_OK)
    + {: |# S- b3 M7 N. Z( L
  33. {: f, Y: F/ Z* U: B$ n
  34.         Error_Handler(__FILE__, __LINE__);5 {- D) ?. i- S5 D1 e: g- X7 a
  35. }
复制代码

/ G% f9 B) k$ `- U! a32.4.6 函数HAL_TIM_IC_Init2 ]3 P2 l: W  ^" P
函数原型:8 G. d! w% ?, x6 ]" _

% |4 s+ G( g, x+ Y3 F3 W6 u
  1. HAL_StatusTypeDef HAL_TIM_IC_Init(TIM_HandleTypeDef *htim)
    2 U" f$ ?! B$ B6 u: b5 B( J
  2. {
    ( g5 Z' V) |1 D# v+ y7 j  J
  3.   /* 检测形参是否有效 */+ N- ^0 A) p! Y, x" U8 C' C
  4.   if(htim == NULL)
    " F) J* i" g; L' |
  5.   {
    9 G0 D3 S$ `. Q( o
  6.     return HAL_ERROR;& u3 _" a8 J/ X# F# \( E
  7.   }0 u& R, U3 s" y3 f2 b: e

  8. + A( c' y5 h7 V/ C" S* H
  9.   /* 检测参数 */2 r% [( d$ X) b/ |' |% e5 r$ u
  10.   assert_param(IS_TIM_INSTANCE(htim->Instance));
    : Q1 |. S, N4 L/ l( R" M
  11.   assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode));
    ! w% i* I. r( M1 W% a
  12.   assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision));
    $ e& v) h- F7 _$ g: C. V" ^( ]; P

  13. ' [# j" K9 o# M* L
  14.   if(htim->State == HAL_TIM_STATE_RESET)
    8 }; R- l* Q$ S
  15.   {, D3 `6 ?8 d4 w
  16. /* 默认取消锁 */
    " p: l* C* F8 a1 l
  17.     htim->Lock = HAL_UNLOCKED;
    7 @9 F% q$ F6 C0 A+ Q) g

  18. 2 `) P$ s, t7 S8 u/ L9 Q1 K5 ~' L
  19.      /* 初始底层 : GPIO, CLOCK, NVIC 和 DMA */
    9 r$ U0 l4 o4 x9 x- C- C/ r
  20.     HAL_TIM_IC_MspInit(htim);4 ~$ }, s: k# k2 ~+ L$ G
  21.   }; R! W3 R! E7 e+ b* }% o& U; q9 e
  22. 1 d- A$ f4 z$ n
  23.   /* 设置定时器状态 */
    8 f- U# L6 x/ Y1 p) U- I0 H
  24.   htim->State= HAL_TIM_STATE_BUSY;
    5 }( b  B+ S. W

  25. * b& f: g4 g1 S# U$ b; \
  26.   /* 配置定时器为输入捕获模式 */  
    & Y* I% m. ]$ J
  27.   TIM_Base_SetConfig(htim->Instance, &htim->Init);
    ( q* x# @3 G; ?

  28. . J& F0 F% G' z( T# t" ~
  29.   /* 设置定时器状态 */. n& O5 S* A7 s# F8 h5 X
  30.   htim->State= HAL_TIM_STATE_READY;2 h* o, a6 N% d1 M) b6 p

  31. . B: r4 R% o" I2 {' ~+ |& J
  32.   return HAL_OK;
    2 l: j* `* o2 V# p1 o0 Q
  33. }
复制代码
* ~, V* m$ G8 f, c0 a4 i& t
函数描述:6 H2 n& u* m- D3 e9 d

; u! G) G' K! z4 |' O+ c0 n此函数用于定时器输入捕获初始化。
: }# a" ?! f4 b6 E
# e8 ?+ @! s& S0 T; ~6 h6 w函数参数:6 c+ ~! @& O- n
+ e8 L# ^, E3 e9 z+ v4 y
  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。  G* n( j: ~- _* x9 b3 M* G' ?) l" a
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。! t3 b$ M- B" u' b8 l
注意事项:; ]: i. W: r; u3 J! |& L

8 h, e  U5 Z# L) R* ^5 A函数HAL_TIM_IC_MspInit用于初始化定时器的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能,由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
5 w( W; f7 u* l+ m. d如果形参htim的结构体成员gState没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量TIM_HandleTypeDef TimHandle。6 z; {0 [5 ?5 u5 Y% V9 L5 d+ @
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个HAL_TIM_STATE_RESET  = 0x00U。
4 E0 N4 G3 f9 g% L' {# r1 ]6 `2 G; r( ]* p4 A% h1 d: `
解决办法有三:  D1 M/ b) l8 g9 _7 D/ ~
3 Q1 Q7 S7 z& n6 N) J9 V# H
方法1:用户自己初始定时器和涉及到的GPIO等。, p# L: A, O" F0 u
9 `4 Y8 k9 `7 ]) Q9 ^5 ]
方法2:定义TIM_HandleTypeDef TimHandle为全局变量。3 a9 H' D# [1 b; f
& M. Y1 ~2 R$ I+ K& W% S
方法3;下面的方法
2 f9 `+ B) a% ?% o! j& i+ a* `4 o7 o# {2 l4 F
  1. if(HAL_TIM_IC_DeInit(&UartHandle) != HAL_OK)' u0 D( J' _/ z) T6 ^' `! S) w
  2. {
    & S9 z& v7 u1 e9 r/ V7 V7 H
  3.     Error_Handler();4 ?5 ]1 D& F3 y! q
  4. }  
    # C" [& X8 O5 E3 b9 |8 K  L
  5. if(HAL_TIM_IC_Init(&UartHandle) != HAL_OK)
    ' U. d; T$ S0 H4 U6 l8 }* p
  6. {% L1 w7 i' P$ b7 x* J4 x
  7.     Error_Handler();
    6 @' a/ u0 I, r
  8. }
复制代码
* |& R$ c5 `9 l8 |! ~% ^; H& T8 I% G
32.4.7 函数HAL_TIM_IC_ConfigChannel" N. c. U3 i$ J( c4 T
函数原型:
+ s4 K: K0 T% K' F- n" j9 F4 z8 U/ N6 A% ?& x8 g0 G
  1. HAL_StatusTypeDef HAL_TIM_IC_ConfigChannel(TIM_HandleTypeDef *htim, TIM_IC_InitTypeDef* sConfig, uint32_t Channel)
    2 y1 A9 b- ?/ T$ O. w0 K
  2. {, H" c* k* q4 J0 ^6 u
  3.   /* 检查参数 */
    9 U8 u& V1 G- u  S8 I9 m: `
  4.   assert_param(IS_TIM_CC1_INSTANCE(htim->Instance));" N( o$ F& [" C
  5.   assert_param(IS_TIM_IC_POLARITY(sConfig->ICPolarity));
    & w$ C( i2 V; _0 A
  6.   assert_param(IS_TIM_IC_SELECTION(sConfig->ICSelection));* Q  N' u9 h% R8 ~+ C
  7.   assert_param(IS_TIM_IC_PRESCALER(sConfig->ICPrescaler));
    " O# a4 o9 B" E7 _
  8.   assert_param(IS_TIM_IC_FILTER(sConfig->ICFilter));
    % H  i( k& q: U# u$ u% o2 M

  9. + _2 j4 W7 z3 c* P$ W" ^
  10.   /* 开锁 */  
    - _2 w! w- y3 A# `$ `+ o
  11.   __HAL_LOCK(htim);
    4 g" l$ C( l% R3 k/ ^& @

  12. # w3 a% U) l  @  K4 O, \! o
  13.   htim->State = HAL_TIM_STATE_BUSY;
    2 b  @1 S* D" N/ \* K" Z
  14. 7 `% x3 z1 u9 ~: i
  15.   if (Channel == TIM_CHANNEL_1)! x6 B' V! l# s: D& K) @
  16.   {" Y- j2 Y) A+ B& R5 D4 O- s
  17.     /* 配置输入通道1 */  w  M+ u6 M) z" I1 g" G
  18.     TIM_TI1_SetConfig(htim->Instance,7 _9 U6 {; \+ @8 B
  19.                sConfig->ICPolarity,
    8 z& j! s3 e& G1 z; R/ [- z0 q
  20.                sConfig->ICSelection," V( [9 [$ T" }) ^7 m7 D7 z
  21.                sConfig->ICFilter);* l/ L; |# e) G, O% z
  22. : i& h/ C: [3 ~4 d% I' n
  23.     /* 清零IC1PSC位 */
    ! ^) ]) H6 p. t/ a3 w
  24.     htim->Instance->CCMR1 &= ~TIM_CCMR1_IC1PSC;
    7 |9 I0 {1 \7 a9 m# [
  25. , s# [% [5 T1 `
  26.     /* 根据用户配置,设置分频 */
    ' V0 p+ B7 z, e$ O
  27.     htim->Instance->CCMR1 |= sConfig->ICPrescaler;) [; O% d! w6 I) l
  28.   }- e3 E1 p" l2 m5 `5 c, D, p
  29.   else if (Channel == TIM_CHANNEL_2)  v) z% a6 b" k! O
  30.   {
    3 @% C8 D9 f: N4 ?: x
  31. /* 省略 */7 x. y$ B7 [: Z$ \
  32.   }
    & ^* L% o$ E: C: \
  33.   else if (Channel == TIM_CHANNEL_3)7 T( T4 ~; b2 t  u
  34.   {. C' w1 U  R: p& k( z
  35.      /* 省略 */2 Q1 N1 ~2 w3 ?! |% n% P7 b
  36.   }; t! a: G6 q0 ~, N7 x
  37.   else
    " [6 r, B3 |8 D2 b& H$ R) n) |
  38.   {( Z" y3 ~# R+ r! x# O4 J6 N  ^
  39.      /* 省略 */( g1 S, e" m' n7 \) `6 m: C
  40.   }
      Z2 d# M* V; ?* Q1 |& L  [

  41. # S6 L' H9 b' s3 q0 W+ C6 \
  42.   htim->State = HAL_TIM_STATE_READY;
    3 f6 j) j2 p  o: ]7 ^

  43. ) k- E( R1 X, N& c* g$ Q
  44.   __HAL_UNLOCK(htim);
    8 _( d/ k6 S: N5 {5 z7 W

  45. 5 k- F, X, A! R: q" R  T) P
  46.   return HAL_OK; ! o6 a, r( N3 E
  47. }
复制代码
7 ?' l8 g) B) u5 h) \2 y3 s
函数描述:
5 ?$ x: U" P) u9 M' R/ [! W$ O+ B+ [3 o. F, ?& E8 C
此函数用于配置定时器的输入捕获通道。
& B' e) m4 V) j8 K0 e5 R6 `1 V
' L8 ?8 d, p. e+ f函数参数:& m: r7 h4 W' m3 k+ z$ E
# e! S6 x) ~4 m7 c1 [
  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于定时器基本参数配置9 u5 W8 g6 Y6 m7 Y9 P0 Q: ~
  第2个参数是TIM_IC_InitTypeDef类型结构体指定变量,用于定时器输出比较参数配置。! t9 a9 j/ f3 ?
  第3个参数是通道设置,支持以下参数:
5 B; z6 U8 C+ q- y9 ]4 S7 TTIM_CHANNEL_1
5 ^$ ?( l& ?$ o9 a8 b: k) P" n$ i
TIM_CHANNEL_2
" W. q" M: G$ C) x1 L3 r6 e6 V8 F( G2 d2 _2 Z
TIM_CHANNEL_35 y0 `! A9 m6 i8 `3 i
" ^( H0 s: N7 x) z% i) V( t$ U' L
TIM_CHANNEL_4) S0 ]2 g7 G* E1 p
4 t* t3 ]! t3 t; S
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。4 a: B  _1 i! @1 d' ^, c6 J4 U

5 `$ y9 z# q0 i32.4.8 函数HAL_TIM_IC_Start_IT
$ J% P, q) y& _0 O( o) l函数原型:
/ \- J1 D0 X: l! w. K3 h9 V: l2 ~1 ?" J+ ~% X+ C
  1. HAL_StatusTypeDef HAL_TIM_IC_Start_IT (TIM_HandleTypeDef *htim, uint32_t Channel)8 H% Z0 i' l) N
  2. {
    & h; ^- [( c9 h6 L, V
  3.   /* 检查参数 */$ G1 z% [. H! }: b1 I: m
  4.   assert_param(IS_TIM_CCX_INSTANCE(htim->Instance, Channel));& B) x" p) z+ w* D9 |

  5. & B4 P# o) Z) @1 _- ~2 C
  6.   switch (Channel)
    + a4 z. b. p  S3 L* s/ l/ [
  7.   {3 t( T6 F) @5 D
  8.     case TIM_CHANNEL_1:
    % K/ O9 V  Q9 ]% P
  9.     {      
    6 n0 s  E5 \  A8 D4 Q
  10.       /* 使能CC1(Capture/Compare 1)中断 */
    2 s7 H" P0 w" c5 Z
  11.       __HAL_TIM_ENABLE_IT(htim, TIM_IT_CC1);! L! i0 B6 r1 o! d8 ]$ L
  12.     }
    9 N* j+ l+ ]5 C% g) x' w& W% }
  13.     break;
    / Y# m  d! G# \3 H8 q6 [3 _

  14. " z! P# |$ D! ]3 L
  15.     case TIM_CHANNEL_2:7 o; G7 y7 T, ?# }8 u6 t; T# q  k
  16.     {
    & Q& k0 ~$ E) @$ B
  17.    /* 省略 */$ T  l! b/ ], B( R2 n
  18.     }
    4 A0 ^; r- p+ V4 F4 P# p
  19.     break;; }) v  B; A; J/ W. {

  20. 2 t) ~5 R* ?5 P& \9 ]1 ^* j! m
  21.     case TIM_CHANNEL_3:
    7 U) C, T! s7 i+ ]3 G. T
  22.     {7 E7 ?0 {: M( \1 m5 d& l
  23.   /* 省略 */5 q' X  x; [% @# D
  24.     }( _" R- i% Q( N; ]
  25.     break;
    : b3 n4 Z5 p& u$ e2 \
  26. : x6 L8 p2 E1 z; [
  27.     case TIM_CHANNEL_4:& f+ b5 o! L8 b% l5 X" }
  28.     {
    4 s: \* g) z3 S) u% ~$ d. J- i
  29.   /* 省略 */
    9 _1 _# C! j3 \8 \/ ~
  30.     }
    - l8 x9 {4 J) v" ?& C
  31.     break;
    5 G' {  a. j+ C6 {8 g9 D
  32. 3 E4 A4 f; `3 N# d( C
  33.     default:$ x# ]' Z/ d: L2 T! q# T4 {
  34.     break;$ ^5 S, j9 p1 G2 T) n
  35.   }  ; c6 w* v6 Y, D' |
  36.   /* 使能输入捕获通道 */
    ) m3 k: ]1 f5 ^4 v! \' \
  37.   TIM_CCxChannelCmd(htim->Instance, Channel, TIM_CCx_ENABLE);
    ( {1 P9 x1 [) s% `
  38. 2 i9 h  }, p7 G" \
  39.   /* 使能定时器 */
    , p8 Z% U, E$ E$ v, k8 @
  40.   __HAL_TIM_ENABLE(htim);  
    ! s) H% j3 a5 i0 \2 A; R9 S! n

  41. ; _3 v1 E5 L% L
  42.   /* 返回状态 */
    ' F" z# h! ~! v; k. Q+ D
  43.   return HAL_OK;  7 J+ T4 @5 a% u! k
  44. }
复制代码

6 p  ~4 k/ s3 V) {5 P+ s函数描述:1 v+ i: m" d. t
. `0 T# @( }  u+ T2 C
此函数用于启动定时器输入捕获模式,采用定时器方式。
* V; v$ a2 b& J, J( A$ `
8 h& [0 q' T6 |. K5 N函数参数:
8 J, H$ U# M: t" @
/ f3 Y( j" y* M! u0 q$ I, @/ Z+ m  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。
; s# @5 F3 g+ X* ~/ u% b6 t) L  第2个参数是通道设置,支持以下参数:# V# ^+ X2 ?7 s; f
TIM_CHANNEL_1- Q0 }- `* M. F+ Q; b

! L) v2 \5 q' b# I! r6 L  t: ITIM_CHANNEL_2
/ x8 X: ^* G3 i6 k4 W5 y
. I. o" @1 I2 B, ?0 k: ZTIM_CHANNEL_3
. E! Y" |+ J6 X/ A+ t- G2 m+ \
7 C: |4 T* W1 {) Z! u. g& mTIM_CHANNEL_4
# D; u" p4 J% L; D& _/ m
' g; c- z) s+ {3 F) `  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
0 l* E6 B! H, Q$ p5 H+ }1 s# T) m6 v! u
32.4.9 函数HAL_TIM_OC_Init; G6 G: H" @# O  v8 [0 g. d5 }
函数原型:0 S! j7 r( Q) ^6 |/ ?& f/ p3 D
9 u! X) e2 T$ ], ?
  1. HAL_StatusTypeDef HAL_TIM_OC_Init(TIM_HandleTypeDef* htim): _- z) k5 H3 O& ~4 p2 v
  2. {% T) \. i/ [. A) o7 E( m& i
  3.   /* 检测形参是否有效 Check */. @# Z1 y0 P2 ], ~5 _  h
  4.   if(htim == NULL)
    9 ?7 Y6 d1 f- q3 P& I5 k' r/ u
  5.   {
    , a. K) N& s: I
  6.     return HAL_ERROR;7 c2 t6 \! u# Z  d' V
  7.   }
    8 \9 b4 U: R$ I1 u' a* ^: G5 b

  8.   O% w9 m& }. B2 S8 X/ P, ~7 g/ v
  9.   /* 检查参数 */' M5 R5 T* X5 ]. t8 U: b
  10.   assert_param(IS_TIM_INSTANCE(htim->Instance));0 @$ Y. Y/ i$ F9 L+ w
  11.   assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode));* g0 i4 I1 `5 N/ N# E5 K" r
  12.   assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision));
    - Q" _$ T! j! ?4 H6 U& @, ^

  13. # ]' o- h' p) l9 i5 L
  14.   if(htim->State == HAL_TIM_STATE_RESET)5 J5 b, l2 b6 N
  15.   {
    5 B; w+ E1 V, o9 u2 d& j
  16. /* 默认取消锁 */
    $ h0 c, G6 S: h- z
  17.     htim->Lock = HAL_UNLOCKED;1 G9 m2 h8 [! w6 Y* o6 B3 d: g

  18. " l8 q- g' k$ S$ p1 K6 \
  19. /* 初始底层 : GPIO, CLOCK, NVIC 和 DMA */
    $ `: z! o3 w) h0 O/ u! D
  20.     HAL_TIM_OC_MspInit(htim);
    1 C5 v3 E$ j+ ~2 U7 H6 b
  21.   }
    # V- j1 J& \/ l$ ~; R8 V3 Q. s

  22. , ~+ \1 k" j! K3 `1 G; }+ h
  23.   /* 设置定时器状态Set the TIM state */( z0 p6 k' A+ w+ |: O
  24.   htim->State= HAL_TIM_STATE_BUSY;5 j. Z8 ~8 |9 k+ p, O( m
  25. ! Z% ^1 D3 L/ `* _8 J
  26.   /* 配置定时器为输出比较模式Init the base time for the Output Compare */  
    7 e' X) s# i5 J1 d1 d+ t
  27.   TIM_Base_SetConfig(htim->Instance,  &htim->Init); # z! l% U  ~. R
  28. / L; a7 S- ]7 k9 y" ]
  29.   /* 设置定时器状态 */
    ) |! |+ v2 J' C3 K, P5 r0 k. J6 m) a
  30.   htim->State= HAL_TIM_STATE_READY;: L/ ]0 H" l" F% Q

  31. 4 q7 }1 F' V1 q( g
  32.   return HAL_OK;1 w/ h9 w; z' v/ m
  33. }
复制代码

% ~9 E! d( D$ K* C函数描述:: L5 ]! e1 O# [/ u% g

8 J8 I& J) ]( p6 ^: F/ B- t此函数用于定时器输出比较初始化。
# a# J0 }* b" O. `
  O: J0 Y; L2 v4 w. }% q6 {函数参数:6 t" }! b& A: M6 h
0 i6 r, H1 L4 x$ V0 w2 E
  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。
% c. v" }6 q. d) S! v  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。) j3 T' ~! X9 K9 E% F+ J
注意事项:1 ?" u8 H7 E+ J0 g9 N; z' O
4 c) W. @% C3 x
函数HAL_TIM_OC_MspInit用于初始化定时器的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能,由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。% l( \) p3 S3 z
如果形参htim的结构体成员gState没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量TIM_HandleTypeDef TimHandle。
- E0 X# I7 W# n7 C  o对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个HAL_TIM_STATE_RESET  = 0x00U。
* J, j/ L" M6 ~( ]! {8 L/ z8 v) s: K6 Y' [& K3 r
解决办法有三:; {0 F7 |8 Y2 S0 |" ?2 a
( h* q# x* D6 v
方法1:用户自己初始定时器和涉及到的GPIO等。& i% C+ J3 R  ^, y# |5 Y

0 V# g4 S% g& I8 i" @方法2:定义TIM_HandleTypeDef TimHandle为全局变量。
! e& `# U$ ]# `
: w, Z7 y9 [4 l' r# i方法3;下面的方法
# ^( @# p% o+ }- \% u7 O4 q/ M: I( t6 d
  1. if(HAL_TIM_OC_DeInit(&UartHandle) != HAL_OK)6 b% V* m+ x4 m
  2. {& V+ e2 a! E( Y5 x" g) y- S8 U& X
  3.     Error_Handler();' L2 a: `/ \+ c/ ~9 L; w
  4. }  
    * j6 q6 ~8 |$ a" X. @, H: N. j2 H
  5. if(HAL_TIM_OC_Init(&UartHandle) != HAL_OK)9 S! l4 n1 E  Z; u! [
  6. {
      A7 P. ~5 Y* {6 d' x$ a, m
  7.     Error_Handler();
    0 C* @0 H" o0 X6 v$ Q
  8. }
复制代码

" A# _9 w6 g7 V1 s; t  f% j32.4.10   函数HAL_TIM_OC_ConfigChannel
" D& p4 j7 B" `( w% Z6 d函数原型:
4 z0 [& z9 w0 }5 d: {, v
: ^' U/ T& e( Y6 {5 |
  1. HAL_StatusTypeDef HAL_TIM_OC_ConfigChannel(TIM_HandleTypeDef *htim,
    ; |/ r" \8 e* g% ?( I
  2.                                            TIM_OC_InitTypeDef* sConfig," E* |* p+ ]  U# Y$ D7 G: \
  3.                                            uint32_t Channel)
    * B7 x; v1 o3 q
  4. {  
    " \/ ?9 m7 Q. v0 I# w! Y
  5.   /* Check the parameters */
    5 E( E) ?5 c0 i- a
  6.   assert_param(IS_TIM_CHANNELS(Channel)); # t6 y  C3 N' f& I3 G
  7.   assert_param(IS_TIM_OC_MODE(sConfig->OCMode));' n/ B, f* F( G! Y5 x* D( F  {
  8.   assert_param(IS_TIM_OC_POLARITY(sConfig->OCPolarity));
    9 v1 Z- A, `0 T  C' y2 l$ y

  9. # z; n/ L& g  Q- M5 p/ G2 f
  10.   /* Process Locked */% k+ G# Q2 A% w$ q" B3 S! o/ R
  11.   __HAL_LOCK(htim); * s( V; D6 \, M% x4 e, N# R
  12.   ~. K% h  x7 E/ h
  13.   htim->State = HAL_TIM_STATE_BUSY;' R2 D4 C4 Z# \' A* ~
  14. ' \1 m( m1 S: }+ h% u+ F, D9 _0 e
  15.   switch (Channel)
    7 i2 O+ E  ^8 M+ z4 v: c9 a, Z
  16.   {! m! ]: b5 H+ I6 P4 f/ W& [, O
  17.     case TIM_CHANNEL_1:
    8 O7 o9 y6 c1 u
  18.     {6 B  D% L1 A2 p/ Q$ T
  19.       /* 检测参数Check the parameters */3 f8 Y" [( _; C
  20.       assert_param(IS_TIM_CC1_INSTANCE(htim->Instance));
    ( h+ t5 Y7 \1 }( i2 s8 e
  21. 9 a, B6 f4 Z' z4 |% I  F
  22.      /* 配置定时器输出比较通道1 */
    8 ^" z1 _$ Z* y/ b4 P! h
  23.       TIM_OC1_SetConfig(htim->Instance, sConfig);
    8 Y( O! `2 n* F: t7 ^, y
  24.     }
    % |$ J) @( S6 R! q
  25.     break;+ d( G+ ^9 j; ?8 y4 s3 `
  26. % x) ?" N3 R1 k1 _( \
  27.     case TIM_CHANNEL_2:: t/ E- h  G; q; O8 L% H5 @0 n
  28.     {+ n- x. l) K8 Q* f: M
  29.       /* 省略 */
    7 i' O% L  s  W  P
  30.     }( F9 Q1 a3 f! A8 M) M, Z0 l
  31.     break;
    9 }- i2 ~1 i. q
  32. 5 Z* H1 O, E" H
  33.     case TIM_CHANNEL_3:
    " b9 f5 [9 _: o! Z8 h
  34.     {/ k& `& [' W9 U  A
  35.       /* 省略 */
    - f! v4 Q/ I' w5 J4 j
  36.     }
    4 V( C+ k& m" k) H5 x
  37.     break;4 G. O7 [9 b4 n( c3 r
  38. 0 W; W! w+ G( ]' w1 i6 X2 n1 f
  39.     case TIM_CHANNEL_4:
    ( T+ R% U/ B  b: \& ?# T( M
  40.     {/ r) B: _4 r6 \2 X
  41.       /* 省略 */
    " C$ `* c1 \' r& n+ f( D
  42.     }
    % t# Q7 k1 \- |  J/ L  C; d/ b
  43.     break;! o3 h# }* I) P2 Q& A

  44. , G* g/ y& W7 X: j' S* x
  45.     case TIM_CHANNEL_5:9 d6 J# v# b$ f* @
  46.     {
    1 W+ b) d6 ?( A+ P* ^
  47.       /* 省略 */* X- c4 E! d3 ]' ]1 U+ w
  48.     }
    $ M8 ~  S* r( h
  49.     break;
    7 a, y7 g3 ?7 ~! V
  50. " u) y+ b1 g6 Z& I4 _
  51.     case TIM_CHANNEL_6:
    5 k  n% [3 ]  t3 E' P5 o
  52.     {& [% G5 ^0 w/ i
  53.       /* 省略 */
    , o% D9 H! V/ i1 o% n3 z- i, D7 }1 E
  54.     }$ P5 s9 ^' T* O) R& ~4 D& O5 t
  55.     break;
    7 K/ s) G9 N2 b+ d$ L) ?4 n
  56. 9 s9 U3 p& o* j% V% |' }
  57.     default:
    ; f" A" f* @; G/ k7 R7 h
  58.     break;   
    6 M4 @3 h, D6 S+ X# E& i. Y4 R
  59.   }( I0 c  j" k+ i$ i

  60. & Y7 o) `6 m6 j
  61.   htim->State = HAL_TIM_STATE_READY;
    5 ?' X2 x) Y" M5 l
  62. ; b% _# G4 r, c( G
  63.   __HAL_UNLOCK(htim); 1 s: h1 \3 u7 q$ Z. F* T

  64. ' @% P( i. |1 D. q" K, ^0 s0 D
  65.   return HAL_OK;
    - _) p7 r; \0 V; o+ U& O
  66. }
复制代码
3 v( L' X: _/ F4 k, L, G
函数描述:5 w, l$ f" D3 Z8 d0 h* U( O
1 |* V6 T" c0 Y6 ?6 H
此函数用于初始化串口的基础特性和高级特性。6 ~. ~! j' U. H- g
& o/ F7 c7 {9 I+ c. O
函数参数:+ R( e% s) u$ w4 Y! O- D
" D, \' B( i$ V! j
  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于定时器基本参数配置。
- I! \* a% ]- J4 G" P6 N; `  第2个参数是TIM_OC_InitTypeDef类型结构体指定变量,用于定时器输出比较参数配置。
* o! r2 t# _; F. Q$ @! D  第3个参数是通道设置,支持以下参数:6 y2 e- q# [- P& T0 u; \, H! t* W
TIM_CHANNEL_10 b7 K. A( c: ]* t7 G
# _* A$ I' T5 ~  \. p" T0 L: ]
TIM_CHANNEL_2
7 w! B8 U  P! N: {0 {+ z& \. ~7 d& z. Y/ a* P8 d0 q
TIM_CHANNEL_3
* X2 O$ T  R. j6 E2 k, M! _' x/ e7 K4 h0 @1 Z$ R
TIM_CHANNEL_4
2 A0 `' l' M: y$ c8 B" m2 n4 Z8 x5 l- g5 M4 Z
TIM_CHANNEL_5' k# T+ y2 R, @  b

3 V3 b) C9 c7 m# z/ B! K- cTIM_CHANNEL_6! T; a6 X  n& i& m8 V% x3 B$ e
6 l  {) l! E  i3 e! y5 V0 o  ]
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。4 C3 c/ m7 W: G6 f# L/ k
) y7 i, \7 B, }* a* c5 ]) D# m) l9 G, o1 D
32.4.11   函数HAL_TIM_OC_Start
/ r( J# E/ o# d2 \/ U函数原型:
" w6 w. ?) q- e1 `
( ]$ n2 W! n0 }9 i, b* e
  1. HAL_StatusTypeDef HAL_TIM_OC_Start(TIM_HandleTypeDef *htim, uint32_t Channel)
    7 @# [1 y4 c+ n1 }1 O- F+ N5 ]
  2. {
    , @4 f. `- u/ J- V5 ]
  3.   /* 检查参数 */) R) Z8 X. E* j% g: \# ?
  4.   assert_param(IS_TIM_CCX_INSTANCE(htim->Instance, Channel));( J. Q+ W6 N: c/ K7 G( e0 a
  5. ) c$ O! p! n1 f* t% {
  6.   /* 使能输出比较通道 */% f4 e" D' X7 F
  7.   TIM_CCxChannelCmd(htim->Instance, Channel, TIM_CCx_ENABLE);" j, U8 l, I4 m: {8 v9 z2 K( G
  8. 0 m' q0 K; ?# A% D9 \# n
  9.   if(IS_TIM_BREAK_INSTANCE(htim->Instance) != RESET)  5 n9 s  C' W: N5 x& M* f) Y' C7 n0 w
  10.   {$ n& v) w8 O% k! t) Q0 G
  11.     /* 使能主输出 */
    - ~  D2 J, x: C; l4 I& W/ D
  12.     __HAL_TIM_MOE_ENABLE(htim);' I8 p- v( m/ o9 W& f! Z/ \
  13.   }
    $ u; y( B, j3 ?/ W6 {

  14. & ?) _+ V( P# ~7 X& P% [9 d( R
  15.   /* 使能定时器 */
      U3 G' \  [9 X# w$ c: o6 @  ^& V
  16.   __HAL_TIM_ENABLE(htim); * k; g# f, ~' V1 j' Z
  17. 6 O- \% U+ B9 ?% p& e7 s% z
  18.   /* 返回状态 */: I6 w5 E5 ]7 x, X1 Y
  19.   return HAL_OK;
    # Z" `$ T* m$ f9 s% f
  20. }
复制代码
6 G9 g- L& |$ [' D: I# t* A  o9 \
函数描述:- s6 ^+ m5 J( y# t" t3 C

2 s0 Z) e. d$ b1 b; t% {此函数用于启动定时器输出比较模式。$ e: {2 c! X/ @/ B. ~# b

' K6 s+ M1 n+ C! W. i函数参数:: u! a7 A; s/ \6 ~$ |

( }$ d& u- {# `; r) V: y+ n  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。2 \/ G# T. A( z9 r
  第2个参数是通道设置,支持以下参数:5 |3 u2 B1 z0 C' @, U6 t
TIM_CHANNEL_1$ |( Q5 M0 T  i. Q
5 h7 r$ D5 F9 n' l* `+ h  K1 g
TIM_CHANNEL_24 i9 |: c$ V( X, B# }7 R
. @' C* O. E2 o
TIM_CHANNEL_3
2 }4 v' J6 Z6 v, r% w. k% \9 z4 k% N# h$ e) {9 R
TIM_CHANNEL_4$ ?$ ~  ?& T. Y/ {

0 W$ j' ]6 h7 J/ t  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
3 L8 l4 Q* ?3 `) Z& ~; d
' U& X0 j8 [7 L2 s32.5 总结
; C) F" R! ?4 ?! k3 X本章节就为大家讲解这么多,建议大家将GPIO的驱动源码结合参考手册中的寄存器通读一遍,对于我们后面章节的学习大有裨益。
2 ^% Y) d$ G% `
; U2 f2 h% o7 q
$ Z& J/ y* U! ^& g3 y# a
' J2 A4 _( g3 ]  c; {
收藏 评论0 发布时间:2021-12-21 23:00

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版