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

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

[复制链接]
STMCU小助手 发布时间:2021-12-21 23:00
32.1 初学者重要提示  N; e$ \/ M# n) p
  学习定时器外设推荐从硬件框图开始了解基本的功能特性,然后逐步深入了解各种特性,这种方式方便记忆和以后查阅。
  ?! L: h. e' I8 v  STM32H7的定时器输出100MHz方波是完全没问题。
3 R  }0 `, k2 u0 h2 d; \% n  STM32H7定时器进出中断的速度能跑到12.5MHz,所有程序在TCM和Flash运行没差别。- H+ y+ w( R7 k! _+ W
  STM32H7的定时器输入捕获可以实现12MHz方波的双边沿捕获,单边沿可以做到24MHz。
6 Z' n8 ^  T! Z  特别注意STM32H7的TIM1,8,15,16,17才有RCR重复计数器,其它都没用的。
' P: J6 Y% u' K) G+ @  ?: g* p4 k  STM32H7的单个定时器中不同通道可以配置不同频率PWM。' X' C# k. D' W/ ?
  STM32H7的TIM1-TIM17中断入口函数名使用时要注意,别搞错了:
. A0 d; T6 ^& I1 C; }) i  {/ g* {
  1. TIM1_BRK_IRQHandler             2 I5 s* e- `, N' d$ O
  2. TIM1_UP_IRQHandler              
    , D- d2 P* T+ G2 h+ H. q& v! ^* \
  3. TIM1_TRG_COM_IRQHandler        % ^, D1 o3 O  h3 c8 o
  4. TIM1_CC_IRQHandler                                                   
    2 t, i' D8 J2 R1 p) n/ B
  5. TIM2_IRQHandler                                          
    ( X$ r7 r( J7 b$ m' }
  6. TIM3_IRQHandler                                                 : V6 E1 S/ M# z2 }
  7. TIM4_IRQHandler                 3 K( s( O: M6 f0 L* P
  8. TIM5_IRQHandler            $ l& X1 @0 O. d6 z
  9. TIM6_DAC_IRQHandler           <------------------要注意            8 r  m6 v1 e# W. u. B3 k! {2 e
  10. TIM7_IRQHandler . w0 |" }( o' |+ @+ @" I. ]
  11. TIM8_BRK_TIM12_IRQHandler      <------------------要注意,定时器12也是用的这个. x; p& |. z% `8 V1 [
  12. TIM8_UP_TIM13_IRQHandler       <------------------要注意,定时器13也是用的这个
    8 W- ]6 y) p! j! Y* g
  13. TIM8_TRG_COM_TIM14_IRQHandler  <------------------要注意,定时器14也是用的这个
    ' u3 {' {) T' `0 p) |* b
  14. TIM8_CC_IRQHandler          8 J, B1 s( r+ k" k' N
  15. TIM15_IRQHandler
    % N. a3 L( Z- X
  16. TIM16_IRQHandler
    4 B7 g8 L" {, T5 m3 k% @
  17. TIM17_IRQHandler
复制代码

$ O! d' s' O0 I' o32.2 定时器基础知识
( U5 n: f4 B. o+ N5 B/ Z) b注,不同定时支持的功能略有区别,基础定时器功能较少,TIM1和TIM8高级定时器功能多些。" H+ W% ~( a1 s$ F. T0 f

5 f7 s  I: }8 i2 G, S  TIM2和TIM5是32位定时器,其它定时器都是16位定时器。16位和32位的区别是CNT计数器范围不同,32位的范围是0 到2^32 – 1,而16位的是0到65535;它们支持的分频是范围是一样的,都是1到65535。
% C# _7 Z! V( E2 w" g8 U4 d6 Z  计数器支持递增、递减和递增/递减二合一。
* a! ?' K$ L2 X  t2 E$ Q- j( z  多个独立通道,可用于:/ w# F- u1 b* @' A  v% g1 Q
– 输入捕获。
% S& D3 _0 d% y4 d: l6 Y7 v+ r4 b# j& O% v5 O& |& V$ i4 ^7 U) E, i
– 输出比较。
* v6 D( N* }$ W: P; I! [: ~& v* f& m
– PWM 生成(边沿和中心对齐模式)。
0 q, Q: P! }# V: q3 }/ h
1 \3 w& f  ]# q– 单脉冲模式输出。& Q6 m, l/ y, N$ q& z4 D% M
2 [9 G' ?! U/ B9 g$ f0 m
  带死区插入,断路功能和PWM互补输出% `0 t8 x! F" U: J% U4 u0 z
  发生如下事件时生成中断/DMA 请求:: y6 l8 g  ^( ^" b+ d) h
– 更新:计数器上溢/下溢、计数器初始化(通过软件或内部/外部触发); L- _" D0 z: I# I9 `
( A  p+ z* `2 [% x4 [" ]
– 触发事件(计数器启动、停止、初始化或通过内部/外部触发计数)+ t3 m3 n: m1 F* |$ ~. w

, s' Z+ ?* r! [+ ^3 g– 输入捕获
# ?* R8 B" p" t: L% X
$ l: Z/ o8 l% V# m4 B- `8 E– 输出比较5 R" C, v( F2 G$ O
  a3 B7 v3 x( b$ u% g
  支持增量式编码器和霍尔传感器。2 P# l% Q1 ^* R2 V$ G1 E- s; t% ^
32.2.1 定时器TIM1-TIM17的区别
! E8 n1 g7 o7 ySTM32H7支持的定时器有点多,要简单的区分下。STM32H7支持TIM1-TIM8,TIM12-TIM17共14个定时器,而中间的TIM9,TIM10,TIM11是不存在的,这点要注意。3 R6 V( w( U' t. t9 d& M

+ W, a# U6 N8 X5 a! Q粗略的比较如下:/ p( O1 W: h( L7 W9 t" F  o' H

# \" I9 T7 V2 K0 c6 R# f/ s2 V
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png
+ d8 u+ y2 c* ^( N, H6 ?4 j8 w* I* C
! g$ t# s2 n+ w& M- @; Q; u# t
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png

- F* s: v4 U& L: S+ r/ v- ]+ O) x# G
通过上面的表格,至少要了解到以下两点:
- \1 c9 q- l% s# i4 |, ~
7 M& r: Q+ C" U" ^5 t* J  STM32H7的定时器主要分为高级定时器,通用定时器,基础定时器和低功耗定时器。
( _. o, T* Y" [$ u  TIM2和TIM5是32位定时器,其它都是16位定时器。5 I- Z( f6 _0 P

0 f8 H2 g1 b  C5 x* Q% C0 Y6 r9 }5 [32.2.2 定时器的硬件框图8 ]* I) V$ v1 m
认识一个外设,最好的方式就是看他的框图,方便我们快速的了解定时器的基本功能,然后再看手册了解细节。
; I. K8 ?9 m( W
3 n2 p" W7 H4 `下面我们直接看最复杂的高级定时器TIM1&TIM8框图:
& j- H/ |5 n* c" R, b
& V8 {. R; y6 v# D" P9 D( g8 A
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png

9 E& r% s& @. A/ ?: ~
* }/ _8 d1 R$ A% v* P通过这个框图,我们可以得到如下信息:
- l. r$ Q+ i$ ~. C* k& I4 V0 x0 ~7 z$ [1 y6 c7 w" G* i' P' e/ Z9 z
  TIMx_ETR接口
/ P; |  X3 S. V& h3 g; U8 f外部触发输入接口。ETR支持多种输入源:输入引脚(默认配置)、比较器输出和模拟看门狗。. I6 k/ I, Z+ D% r+ N2 A& L
+ ^$ y2 b; C& ?7 K  R5 T
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png

3 @( p+ K; \3 o7 p! d
+ j! J! Y8 I+ x9 F! b# m3 |  截图左侧的TIMx_CH1,TIMx_CH2,TIMx_CH3和TIMx_CH4接口7 I( j3 B6 b7 d9 s
这四个通道主要用于输入捕获,可以计算波形频率和脉宽。                                                                                                                             5 J" Q: V! U$ d

9 w  ~0 R" F% I0 |4 `. h  TIMx_BKIN和TIMx_BKIN2接口8 ^5 Q, F. I1 G: G
断路功能,主要用于保护由 TIM1 和 TIM8 定时器产生的 PWM 信号所驱动的功率开关6 D. z" o2 G: D- a" s2 k

: u3 Q1 J8 f2 T8 {  TRGO内部输出通道
# U; `. k5 r( u' ]8 x5 ^主要用于定时器级联,ADC和DAC的定时器触发。
" f4 b( X% j1 v- y: f4 Z: E7 M7 Q. Q" o8 h$ m0 n
  6组输出比较单元OC1到OC6; o7 M1 e; e; N8 a
OC1到OC4有对应的输出引脚,而OC5和OC6没有对应的输出引脚,主要用于内部控制。
/ a: i& g0 G( a5 E9 o3 B
7 `. \4 d5 e  e. Y: u, L; X0 a  截图右侧的输出比较通道TIMx_CH1,TIMx_CH1N,TIMx_CH2,TIMx_CH2N,TIMx_CH3,TIMx_CH3N和TIMx_CH4' h6 |9 B$ o4 c) A1 e0 d
主要用于PWM输出,注意CH1到CH3有互补输出,而CH4没有互补输出。. X1 N% T+ x. ?0 q0 a/ g5 _/ v  D

4 U: r% x) W+ V. d& o  其它框图里面未展示出来功能; Y! I' h4 [+ r+ ~9 _
定时器TIM1&TIM8还支持的其它功能在用到的时候再做说明。
+ H3 r' n* d: b% J3 U# W, C+ `1 S! _/ `9 W- K: q* `( H$ |
32.2.3 定时器的时基单元
: h1 N' S, U6 [) k+ L3 c9 E9 H4 G定时器要工作就需要一个基本时基单元,而基本的时基单元是由下面几个寄存器组成的:( W  X7 x5 R- W) K/ P8 _$ }
0 e* j& m1 D) z2 T- |) s9 g
  预分频器寄存器 (TIMx_PSC)3 d+ S" n/ I% \" J% G6 f+ ]
用于设置定时器的分频,比如定时器的主频是200MHz,通过此寄存器可以将其设置为100MHz,50MHz,25MHz等分频值。! O! F3 @1 Y2 W4 C& p$ v

$ B* }3 w" @: s) V* x$ v注:预分频器有个缓冲功能,可以让用户实时更改,新的预分频值将在下一个更新事件发生时被采用(以递增计数模式为例,就是CNT计数值达到ARR自动重装寄存器的数值时会产生更新事件)。. b* L+ G7 h6 n: J
, V8 S4 n3 e/ L' [
  计数器寄存器 (TIMx_CNT): T* R1 t& V3 e
计数器是最基本的计数单元,计数值是建立在分频的基础上面,比如通过TIMx_PSC设置分频后的频率为100MHz,那么计数寄存器计一次数就是10ns。, P8 I1 s" z+ y; F3 `: u' i
7 e2 j% H5 D# R" ~6 Z
  自动重载寄存器 (TIMx_ARR)5 U6 b! c3 x( k; t1 V% d1 L
自动重装寄存器是CNT计数寄存器能达到的最大计数值,以递增计数模式为例,就是CNT计数器达到ARR寄存器数值时,重新从0开始计数。
2 r  \4 p$ q0 y, B" J  A+ K
/ r: z" j/ W; E" ^7 ?注,自动重载寄存器是预装载的。对自动重载寄存器执行写入或读取操作时会访问预装载寄存器。预装载寄存器的内容既可以立即传送到影子寄存器(让设置立即起到效果的寄存器),也可以在每次发生更新事件时传送到影子寄存器。简单的说就是让ARR寄存器的数值立即更新还是更新事件发送的时候更新。
; G- R* x0 a5 K% }( g5 g
! s9 t+ p- U/ `3 p# T. Q  t  重复计数器寄存器 (TIMx_RCR)
" f+ D0 ?6 |7 E2 j8 @以递增计数模式为例,当CNT计数器数值达到ARR自动重载数值时,重复计数器的数值加1,重复次数达到TIMx_RCR+ 1后就,将生成更新事件。
+ K! ?- k+ `- U5 [& Q- }: }
' g1 S; p2 q6 A0 t+ r" N注,只有TIM1,TIM8,TIM15,TIM16,TIM17有此寄存器。0 ^) k2 ^+ c) K6 Q+ d
' C; M% Z; {7 m4 M
比如我们要配置定时器实现周期性的中断,主要使用这几个寄存器即可。* k. m. \9 M7 S- H1 w! K
3 ]8 t% R7 F8 V" ^% B- `5 o
32.2.4 定时器输出比较(PWM)
' C4 k( W: U5 |% N0 h使用定时器时基单元的那几个寄存器仅仅能设置周期,还不能设置占空比。针对这个问题,还需要比较捕获寄存CCR的参与,这样就可以设置占空比了。- @+ r, d+ _- D$ L7 o
2 i; x! H$ G9 w" N  D0 A
为了方便大家理解,以PWM 边沿对齐模式,递增计数配置为例:
6 t( V$ s5 W: d: E" |
+ @1 ~( W& H0 \6 ]6 N9 d7 b  当计数器TIMx_CNT < 比较捕获寄存器TIMx_CCRx期间,PWM参考信号OCxREF输出高电平。
9 @) G" W1 Q* h1 `+ _  当计数器TIMx_CNT >= 比较捕获寄存器TIMx_CCRx期间, PWM参考信号OCxREF输出低电平。
4 C8 S7 C5 g/ U, K, d: u  当比较捕获寄存器TIMx_CCRx > 自动重载寄存器TIMx_ARR,OCxREF保持为1。
* d- x% T& ^. ~, z  V/ y  当比较捕获寄存器TIMx_CCRx = 0,则OCxRef保持为0。; n+ ]/ b  m* a7 O/ I2 _/ v
下面是TIMx_ARR=8的波形效果:
# ^7 T: Y0 f/ q8 b0 ~& Q# ~; p
; Z+ X8 s# p5 K& f  P4 `) j1 J% e
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png

$ I6 V' m9 E4 m8 ~
- M" w5 {# N( s7 F: {$ J32.2.5 定时器输入捕获
' _  g6 u9 V( D+ q+ x; O% o与PWM一样,使用定时器实现输入捕获,仅靠时基单元的那几个寄存器是不行的,我们需要一个寄存器来记录发生捕获时的具体时间,这个寄存器依然由比较捕获寄存器TIMx_CCRx来实现。
( h8 n3 v: W7 p0 D& f! k. x  q- x+ r7 i3 R5 A; G# ]5 r7 h6 G
比如我们要测量一路方波的周期:
2 K2 M9 m% ^5 p+ W( ?
: D! K: H$ S* B- T  配置定时器为输入捕获模式,上升沿触发,设置分频,自动重装等寄存器,比如设置的CNT计数器计数1次是1微秒。& L" E! n" U2 b, B5 H: _; v% A
  当有上升沿触发的时候,TIMx_CCRx寄存器就会自动记录当前的CNT数值,然后用户就可以通过CC中断,在中断复位程序里面保存当前的TIMx_CCRx寄存器数值。等下次再检测到上升沿触发,两次时间求差就可以得到方波的周期。1 {" _# A1 x/ Z" ?5 @8 u! {/ M
不过这里要特别注意一点,如果CNT发生溢出(比如16位定时器,计数到65535就溢出了)就需要特别处理下,将CNT计数溢出考虑进来。
( m. U. G5 O  H9 J( ^  E7 V9 K% n: n. T( u4 l: w. A# B
32.3 定时器的HAL库用法
. D9 ?' P1 M" j/ S; Z* t定时器的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置GPIO、时钟,并根据需要配置NVIC、中断和DMA。下面我们逐一展开为大家做个说明。9 E7 w4 |% q' M. a5 I8 J: c
9 T- X  F$ W( S, F
32.3.1 定时器寄存器结构体TIM_TypeDef9 k/ A# S" R/ j. J% R- a
定时器相关的寄存器是通过HAL库中的结构体TIM_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:
2 M: Q6 O; C# ]3 |, \/ W! g) d  R5 {) x: C+ w9 F( j6 c" V( k
  1. typedef struct0 v  i1 R6 u8 i% \
  2. {# {* f! y6 g1 n2 F" @7 m% D
  3.   __IO uint16_t CR1;         /*!< TIM control register 1,                   Address offset: 0x00 */
    + ~4 ]# N8 g0 P3 `8 K
  4.   uint16_t      RESERVED0;   /*!< Reserved, 0x02                                                 */
    2 W) m! j; F* t( P
  5.   __IO uint32_t CR2;         /*!< TIM control register 2,                   Address offset: 0x04 */
    + t2 v: y) ~7 t* C% M) ^
  6.   __IO uint32_t SMCR;        /*!< TIM slave mode control register,          Address offset: 0x08 */( ]8 m8 [" I! a6 w- {6 ?3 ^
  7.   __IO uint32_t DIER;        /*!< TIM DMA/interrupt enable register,        Address offset: 0x0C */1 L1 O5 y% s7 M' s& }  Q
  8.   __IO uint32_t SR;          /*!< TIM status register,                      Address offset: 0x10 */
    . `/ v# z  E* b. G
  9.   __IO uint32_t EGR;         /*!< TIM event generation register,            Address offset: 0x14 */" ~5 L$ K. h+ Q( d0 _
  10.   __IO uint32_t CCMR1;       /*!< TIM capture/compare mode register 1,      Address offset: 0x18 */
    * K' n7 e) }7 R/ n, ~
  11.   __IO uint32_t CCMR2;       /*!< TIM capture/compare mode register 2,      Address offset: 0x1C */
    2 Z4 N0 H: ?' V1 b! J4 H) b+ {
  12.   __IO uint32_t CCER;        /*!< TIM capture/compare enable register,      Address offset: 0x20 */
    2 b/ C, j2 k: }
  13.   __IO uint32_t CNT;         /*!< TIM counter register,                     Address offset: 0x24 */$ O) p+ w' D) I# R  d+ C& P8 b
  14.   __IO uint16_t PSC;         /*!< TIM prescaler,                            Address offset: 0x28 */
    ) m; @3 [' ~- f
  15.   uint16_t      RESERVED9;   /*!< Reserved, 0x2A                                                 */
    ! Z$ @4 Q2 Z6 Z( T1 F! k
  16.   __IO uint32_t ARR;         /*!< TIM auto-reload register,                 Address offset: 0x2C */
    8 }9 y. Q7 y/ @% e: D4 _% v% j$ H
  17.   __IO uint16_t RCR;         /*!< TIM repetition counter register,          Address offset: 0x30 */* |2 u; O" y3 J- u5 d8 j
  18.   uint16_t      RESERVED10;  /*!< Reserved, 0x32                                                 */  z' X% ^8 Q1 ?  J
  19.   __IO uint32_t CCR1;        /*!< TIM capture/compare register 1,           Address offset: 0x34 */
      d' z1 q# o# ^
  20.   __IO uint32_t CCR2;        /*!< TIM capture/compare register 2,           Address offset: 0x38 */0 V; x, l- C5 U! k5 c& N
  21.   __IO uint32_t CCR3;        /*!< TIM capture/compare register 3,           Address offset: 0x3C */
    7 z/ U3 B! Z) z  }0 g) P5 O! v
  22.   __IO uint32_t CCR4;        /*!< TIM capture/compare register 4,           Address offset: 0x40 */# C7 V8 K% p. X! g- K! w
  23.   __IO uint32_t BDTR;        /*!< TIM break and dead-time register,         Address offset: 0x44 */
    ) p& I6 f0 E- h8 H
  24.   __IO uint16_t DCR;         /*!< TIM DMA control register,                 Address offset: 0x48 */6 U$ a+ G  x6 v+ F  w
  25.   uint16_t      RESERVED12;  /*!< Reserved, 0x4A                                                 */
    1 q3 r# r) R  t* T: |( y
  26.   __IO uint16_t DMAR;        /*!< TIM DMA address for full transfer,        Address offset: 0x4C */% c, X8 ~$ A8 \, A7 Q' B
  27.   uint16_t      RESERVED13;  /*!< Reserved, 0x4E                                                 */
    ; {: k  E0 c& @+ v
  28.   uint16_t      RESERVED14;  /*!< Reserved, 0x50                                                 */7 Y5 T5 }) ^, \, D/ d2 t- F! }
  29.   __IO uint32_t CCMR3;       /*!< TIM capture/compare mode register 3,      Address offset: 0x54 */. \4 t" M: {1 H& H, H) V3 J5 ^
  30.   __IO uint32_t CCR5;        /*!< TIM capture/compare register5,            Address offset: 0x58 */5 H- S  P- b5 Z; t
  31.   __IO uint32_t CCR6;        /*!< TIM capture/compare register6,            Address offset: 0x5C */
    7 M2 C3 o, A( z% v3 X3 `
  32.   __IO uint32_t AF1;         /*!< TIM alternate function option register 1, Address offset: 0x60 */1 g4 `# n' y7 h0 }9 _$ m
  33.   __IO uint32_t AF2;         /*!< TIM alternate function option register 2, Address offset: 0x64 */7 R0 F! o. ?" M5 P
  34.   __IO uint32_t TISEL;       /*!< TIM Input Selection register,             Address offset: 0x68 */8 H8 _0 p$ g1 Q4 R" U! \
  35. } TIM_TypeDef;
复制代码
- K. m1 G/ m+ N% [. j5 A9 b
这个结构体的成员名称和排列次序和CPU的定时器寄存器是一 一对应的。
+ j, z# S, r- E- f* K" x, r; ]* n, w
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:/ }. f; Z$ l0 D

( G: t$ l/ G5 W1 P) f; e: A
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */0 E  Y$ J: b: O' f/ z% m
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码

/ _+ p( L" Y2 ]. e1 d下面我们看下定时器的定义,在stm32h743xx.h文件。* g& D! m4 b9 c7 q
  i, E$ g6 E! y% U
  1. #define PERIPH_BASE         ((uint32_t)0x40000000)
    , y) @; X% M' ^, ], C( `
  2. #define D2_APB1PERIPH_BASE   PERIPH_BASE
    1 Q1 x& V+ ~7 O+ h5 k) z- {8 B
  3. #define D2_APB2PERIPH_BASE   (PERIPH_BASE + 0x00010000)- j) o9 U3 p, J3 w# P: V) A

  4. : }' h! Q. q" P( U: R* [$ d
  5. /*!< D2_APB1PERIPH 外设 */
    ' y5 j& n' J, {( M  \
  6. #define TIM2_BASE             (D2_APB1PERIPH_BASE + 0x0000) <----- 展开这个宏,(TIM_TypeDef *) 0x40000000* r' X. I/ Z2 u/ L9 C8 D" ?
  7. #define TIM3_BASE             (D2_APB1PERIPH_BASE + 0x0400)$ s4 x1 s- @' T' t  i0 D6 G
  8. #define TIM4_BASE             (D2_APB1PERIPH_BASE + 0x0800)
    + A1 j; V# _, V$ Q2 {
  9. #define TIM5_BASE             (D2_APB1PERIPH_BASE + 0x0C00)9 R5 W4 g, y+ f" a: E6 p& @4 \
  10. #define TIM6_BASE             (D2_APB1PERIPH_BASE + 0x1000)0 V% N5 u. P2 S. @; l
  11. #define TIM7_BASE             (D2_APB1PERIPH_BASE + 0x1400), S, C& I) Q9 ^$ D. `5 r
  12. #define TIM12_BASE            (D2_APB1PERIPH_BASE + 0x1800)3 F1 z/ l, a) M& y4 h
  13. #define TIM13_BASE            (D2_APB1PERIPH_BASE + 0x1C00)
    2 x5 K2 Z; p1 F2 b
  14. #define TIM14_BASE            (D2_APB1PERIPH_BASE + 0x2000)% a7 I6 [. \5 |* a/ ]1 J( O* `
  15.   V  f( f* ?" ?: N
  16. /*!< D2_APB1PERIPH 外设 */
    + \! \: }+ `2 s1 r
  17. #define TIM1_BASE             (D2_APB2PERIPH_BASE + 0x0000)8 H8 {- }( J8 G( v
  18. #define TIM8_BASE             (D2_APB2PERIPH_BASE + 0x0400)
    4 k2 ^8 [9 |3 i* z' ?# W
  19. #define TIM15_BASE            (D2_APB2PERIPH_BASE + 0x4000)
    4 X5 _) \" x& S
  20. #define TIM16_BASE            (D2_APB2PERIPH_BASE + 0x4400)  n% S  I- q1 T* l6 b; H) g; D" j
  21. #define TIM17_BASE            (D2_APB2PERIPH_BASE + 0x4800)" m! V% O$ O, a  H0 {% A9 ]7 P
  22. 0 H) Z% V5 ?& v& }" n" y7 B
  23. #define TIM1                ((TIM_TypeDef *) TIM1_BASE)
    2 k( i( s' \/ k  Z
  24. #define TIM2                ((TIM_TypeDef *) TIM2_BASE)/ g4 t6 f0 t4 L6 C. g
  25. #define TIM3                ((TIM_TypeDef *) TIM3_BASE)
    , S" ?7 l7 r! V' R1 P) b+ ]9 B
  26. #define TIM4                ((TIM_TypeDef *) TIM4_BASE), u1 J- a+ K) ^+ [
  27. #define TIM5                ((TIM_TypeDef *) TIM5_BASE)
      t/ H, n0 Y( J3 p3 i
  28. #define TIM6                ((TIM_TypeDef *) TIM6_BASE)/ T% r9 [8 `7 Z1 x. }, u! I: j
  29. #define TIM7                ((TIM_TypeDef *) TIM7_BASE)6 N3 @; w# H7 o. L# H$ H5 n
  30. #define TIM8                ((TIM_TypeDef *) TIM8_BASE)
    5 J) K0 [! }( l8 w- I* y( s
  31. #define TIM12               ((TIM_TypeDef *) TIM12_BASE)
      I  T4 r. k8 _+ c  V  \# _) D
  32. #define TIM13               ((TIM_TypeDef *) TIM13_BASE)- V/ e, O) Z4 ~$ h6 Y  l
  33. #define TIM14               ((TIM_TypeDef *) TIM14_BASE)" q6 p/ R6 K1 Q: `# H
  34. #define TIM15               ((TIM_TypeDef *) TIM15_BASE)9 l+ I. u: `( ~/ q, z" t& y
  35. #define TIM16               ((TIM_TypeDef *) TIM16_BASE)
    3 ]3 S# G) @. o- d* p
  36. #define TIM17               ((TIM_TypeDef *) TIM17_BASE)
复制代码
& B3 i( {2 I1 R% s0 j
我们访问TIM2的CR1寄存器可以采用这种形式:TIM2->CR1 = 0;) m  H4 c) J& R  B

1 E7 Z* e* z4 r0 b: G32.3.2 定时器句柄结构体TIM_HandleTypeDef; @0 _9 @! ?) d$ D3 F7 n
HAL库在TIM_TypeDef的基础上封装了一个结构体TIM_HandleTypeDef,定义如下:7 u3 k! X: b( Y# o8 C& `
) P' o. F7 H* `; F& N
  1. typedef struct
    9 q. V. D9 X& Y& ~0 e9 U2 C9 B
  2. {% z6 h& X+ _* o2 B; p
  3.   TIM_TypeDef              *Instance;     /*!< Register base address             */ ( Q1 L! T. }. V. T
  4.   TIM_Base_InitTypeDef     Init;          /*!< TIM Time Base required parameters */
    ! p+ M: F8 e/ ]9 t
  5.   HAL_TIM_ActiveChannel    Channel;       /*!< Active channel                    */
    ' m/ G/ x) x2 x' ]8 S, @, ]) X- z

  6. & r: J3 t& E2 E% S. R- c
  7. /*!< DMA Handlers array This array is accessed by a @ref DMA_Handle_index */1 Z0 A$ c5 b2 j
  8.   DMA_HandleTypeDef        *hdma[7];      ) |- ~; v/ V( e* s
  9.   HAL_LockTypeDef          Lock;          /*!< Locking object                    */' N; R% Z$ D# O2 q, W
  10.   __IO HAL_TIM_StateTypeDef   State;      /*!< TIM operation state               */  
    ' F' g8 _3 ^$ s+ a* Z! s$ W! f' [, L9 O. x
  11. }TIM_HandleTypeDef;
复制代码
2 h$ q% y& D! a# Y& @
这里重点介绍前四个参数,其它参数主要是HAL库内部使用的。
6 b6 a% f- V, }) N" L4 a: o# y0 ~) Z) O1 ?. n. h9 @& a
  TIM_TypeDef  *Instance% e; L$ b- g" ?# t& B1 {

+ C" _+ v6 l$ S7 ]& B0 O$ m- E' N这个参数是寄存器的例化,方便操作寄存器,比如使能定时器的计数器。
2 W9 c/ T3 ?# G  n4 M. ~
( I) R# n7 E' O# ?' ySET_BIT(huart->Instance->CR1,  TIM_CR1_CEN)。. {# [2 |; y+ @

/ L7 [+ U! Y( p  TIM_Base_InitTypeDef  Init- @; X* b3 G4 J& N! S2 ?0 W
5 V4 E( \  {$ e
这个参数是用户接触最多的,用于配置定时器的基本参数。
' k* m* i4 |, \& v+ ?2 f/ k
# E. |* I+ \/ [* p. U/ N  DTIM_Base_InitTypeDef结构体的定义如下:
4 K: P# `! n, ^$ k. l1 Z
& k" f; _( {, u( g" F
  1. typedef struct  V) i& s  y. z3 ^
  2. {
    $ S  e1 V* w2 O% d2 O
  3.   uint32_t Prescaler;      0 H+ W8 \; L+ m' G7 G! b6 {
  4.   uint32_t CounterMode;   
    , |" V# D3 H$ b1 l* E3 ?( M
  5.   uint32_t Period;         ! x7 V+ h; v' D
  6.   uint32_t ClockDivision;    6 l* x# ?/ h" ]5 j  W) ?, P
  7.   uint32_t RepetitionCounter;
    + n: @. i  B' C. y$ _8 P8 z
  8.   uint32_t AutoReloadPreload;  
    ! M: \- D# ~8 x! @
  9. } TIM_Base_InitTypeDef;
复制代码

& q+ |' m" g# l0 g$ i, j  成员Prescaler5 H  S  P% q/ V/ \
用于设置定时器分频,对于32位的TIM2和TIM5范围是0到0xFFFFFFFF,其它定时器是0到0xFFFF。
" n3 y' h7 R/ f7 g0 v$ b) n8 K
5 \# x! O0 L6 ]9 O  成员CounterMode: Y/ }* X" Q( x8 ~* {, ?# [. J
用于设置计数模式,向上计数模式、向下计数模式和中心对齐模式。! G! R/ |9 K7 h

2 j7 P; t+ y- t% y% D) `8 }
  1. #define TIM_COUNTERMODE_UP                ((uint32_t)0x0000U)   /*!< Up counting mode */
    6 e9 u' J2 }4 Z% M
  2. #define TIM_COUNTERMODE_DOWN               TIM_CR1_DIR          /*!< Down counting mode */6 @7 Q% h: Z% F  `1 \% H, z) z
  3. #define TIM_COUNTERMODE_CENTERALIGNED1     TIM_CR1_CMS_0        /*!< Center-aligned counting mode 1 */; M4 V7 d" J9 W8 B
  4. #define TIM_COUNTERMODE_CENTERALIGNED2     TIM_CR1_CMS_1        /*!< Center-aligned counting mode 2 */
    ) H* Z* _) _# \$ \( ^8 M! W
  5. #define TIM_COUNTERMODE_CENTERALIGNED3     TIM_CR1_CMS          /*!< Center-aligned counting mode 3 */
复制代码
  y6 R! V$ ]; t
  成员Period
) W  D/ G  D: \- o用于设置定时器周期,对于32位的TIM2和TIM5范围是0到0xFFFFFFFF,其它定时器是0到0xFFFF。
2 D+ d- f! k; X! _% [# @* H4 q9 |) g8 K/ Q7 X
  成员ClockDivision  _& J8 t: b4 e2 S4 C9 j# Q% p
用于指示定时器时钟 (CK_INT) 频率与死区发生器以及数字滤波器(ETR、TIx)所使用的死区及采样时钟 (tDTS) 之间的分频比。, d) g1 H% G8 d. J* F
; x9 @& v2 v5 l6 r3 G9 q
  1. #define TIM_CLOCKDIVISION_DIV1       ((uint32_t)0x0000U)        /*!< Clock Division DIV1 */
    - O( t) w: I* s$ S! k) E# e- U
  2. #define TIM_CLOCKDIVISION_DIV2       (TIM_CR1_CKD_0)            /*!< Clock Division DIV2 */
    & ~1 f$ W9 o4 ^2 e6 [
  3. #define TIM_CLOCKDIVISION_DIV4       (TIM_CR1_CKD_1)             /*!< Clock Division DIV4 */
复制代码

: M! }2 s% l+ m) q5 F7 U8 w  成员RepetitionCounter
3 \+ ]$ K5 q$ I$ P用于设置重复计数器,仅TIM1和TIM8有,其它定时器没有。作用是每当计数器上溢/下溢时,重复计数器减1,当减到零时,才会生成更新事件,这个在生成PWM时比较有用。6 f8 p2 Q& u( Q
: h! k% L6 k4 ?% R
  成员AutoReloadPreload
1 z- t4 B- D5 T8 f6 ~" }" P, n8 Q0 e8 W; r用于设置定时器的ARR自动重装寄存器是更新事件产生时写入有效还是立即写入有效。如果使能了表示更新事件产生时写入有效,否则反之。  K1 z$ R7 W+ |+ o$ `/ @
- w9 V& {" t9 m/ I: Z; c
  1. #define TIM_AUTORELOAD_PRELOAD_DISABLE   ((uint32_t)0x0000U)   /*!< TIMx_ARR register is not buffered */
    * u2 i) K# a5 H1 r
  2. #define TIM_AUTORELOAD_PRELOAD_ENABLE    (TIM_CR1_ARPE)        /*!< TIMx_ARR register is buffered */
复制代码

  ]4 P/ i5 g7 z; H6 `  HAL_TIM_ActiveChannel    Channel;
4 k8 o5 h* {9 @3 S+ l& f; t6 s% v, C6 U
用于设置定时器通道,比如TIM1和TIM8都是6个通道。
1 W3 E4 n$ o' G' J2 h
$ l" [. I9 v3 F) K0 _2 w5 j3 Z: f3 ^
  1. typedef enum& W2 |+ e# Y* ~' ^. E
  2. {( ~4 D2 Z+ i- G3 V9 i  d
  3.   HAL_TIM_ACTIVE_CHANNEL_1        = 0x01U,    /*!< The active channel is 1     */2 u! o" J* [- _% `1 y
  4.   HAL_TIM_ACTIVE_CHANNEL_2        = 0x02U,    /*!< The active channel is 2     */7 _5 j3 H! v$ `* f. M' ^
  5.   HAL_TIM_ACTIVE_CHANNEL_3        = 0x04U,    /*!< The active channel is 3     */   9 c8 ?+ O7 N/ {6 m7 ?# ]
  6.   HAL_TIM_ACTIVE_CHANNEL_4        = 0x08U,    /*!< The active channel is 4     */* {/ g4 D% m- Q. M
  7.   HAL_TIM_ACTIVE_CHANNEL_5        = 0x10U,    /*!< The active channel is 5     */1 `3 k# @2 T5 O: M+ s9 g9 j
  8.   HAL_TIM_ACTIVE_CHANNEL_6        = 0x20U,    /*!< The active channel is 6     */
    6 S: L! J* Q' G
  9.   HAL_TIM_ACTIVE_CHANNEL_CLEARED  = 0x00U     /*!< All active channels cleared */   
    1 d. S' l. L  _$ G$ `8 c
  10. }HAL_TIM_ActiveChannel;
    ! Z& H# c5 i8 O+ f" G, U# J
  11.   DMA_HandleTypeDef        *hdma[7];
复制代码

1 r" q( s% `2 J$ r6 a用于关联DMA。
2 E# M& p  W# G# V! L  v( W% r9 k' [, o6 [% Q! U& G
配置定时器参数,其实就是配置结构体TIM_HandleTypeDef的成员。
, D* m9 ~+ ]/ [3 M% f. e9 e/ e' O" f% j( y* J
  1. TIM_HandleTypeDef   TimHandle = {0};6 H; j1 [4 ~3 V: R
  2. ( ]; l! _/ x1 u7 R
  3. /* 5 u8 N: u9 {' u* N9 Q/ }
  4.     定时器中断更新周期 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)
    1 v# Y* T) J. L
  5. */
    ; ^+ P( @2 Z; k3 k/ @8 Y" r
  6. TimHandle.Instance = TIMx;
    : ]9 r2 Q" L) N; W7 n1 t! B: J5 y7 i
  7. TimHandle.Init.Prescaler         = usPrescaler;
    ! G% L8 J8 i8 n
  8. TimHandle.Init.Period            = usPeriod;        
    ' b8 C2 c  q9 f; K% d) k
  9. TimHandle.Init.ClockDivision     = 0;5 c6 _0 z( N# A  a$ C! W1 g+ ~
  10. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;0 J# z& i  R* v
  11. TimHandle.Init.RepetitionCounter = 0;
    ! u! B% X4 d( E
  12. TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;: p1 H) Q0 r9 x! \
  13. if (HAL_TIM_Base_Init(&TimHandle) != HAL_OK)$ t' d* i3 U( t7 K1 R
  14. {
    ' s+ p3 R( n  ]5 z/ f0 a1 d1 R
  15.         Error_Handler(__FILE__, __LINE__);2 E( N# ~, R' v% ]# A5 B
  16. }
复制代码

& K, B  y8 ^1 y, r32.3.3 定时器输出比较结构体TIM_OC_InitTypeDef

* c  }; W5 Q# L9 d此结构体主要用于定时器的输出比较,定义如下:- z9 Y5 m, b, E. e' M

& @7 H9 |! p! K2 a0 @6 {
  1. typedef struct: O; D7 G8 y& ~6 ^. k: N6 p+ F
  2. {                                 
    0 |& T6 r. N6 O* l& C
  3.   uint32_t OCMode;       $ n( l; b0 P6 A4 g$ g' S  {  d
  4.   uint32_t Pulse;      
    8 ], U( I' x( }+ _( ^0 j
  5.   uint32_t OCPolarity;   
    ! O" V: g. w8 B! u: |( k
  6.   uint32_t OCNPolarity;   : R: `, v# N6 s$ \1 I( i9 D8 Y. U
  7.   uint32_t OCFastMode;  
    & R3 L$ e! l  E; N" c& v# c. r! e) n  W
  8.   uint32_t OCIdleState;   ! q# B. e" s# L- e$ \' y
  9.   uint32_t OCNIdleState;  
    2 ?- d1 g" y9 j$ A
  10. } TIM_OC_InitTypeDef;  
复制代码
* z3 U& X! A0 ?5 v; o% ]3 _
下面将这几个参数一 一做个说明。
4 }7 Z+ f4 C6 `0 r& y( p) ~1 b" d  h, ^, L& S' O
  OCMode0 c. C/ h! i6 K, j
用于配置输出比较模式,支持的模式较多:& Q$ H7 t8 [  z  w* r
8 ^- t! q7 O& |6 ^& `
  1. /*!< TIM Output timing mode */+ g  ~, k/ c9 k# z4 V; [
  2. #define TIM_OCMODE_TIMING                ((uint32_t)0x0000U)       5 f, G7 \1 E2 ~& B6 k- M3 l" Q% y

  3. 3 D: `+ U. s$ O" a* i' H$ `, ?
  4. /*!< TIM Output Active mode */                          2 u6 `# I3 W' z1 d9 r
  5. #define TIM_OCMODE_ACTIVE                ((uint32_t)TIM_CCMR1_OC1M_0)
    % x5 U" C& R0 l9 M# @1 s& e
  6. & L' T% o, l9 F$ S; ]6 f
  7. /*!< TIM Output Inactive mode */                       
    ) ]$ M& _) ~6 m, w
  8. #define TIM_OCMODE_INACTIVE              ((uint32_t)TIM_CCMR1_OC1M_1)           0 ]. l4 d) @* N$ T8 ]

  9. 6 P( V( w9 k4 z" p7 a
  10. /*!< TIM Output Toggle mode */               
    , \; D; E5 \" q4 |/ T" F) h
  11. #define TIM_OCMODE_TOGGLE                 ((uint32_t)TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_0)         , w5 Q- h3 y6 U: M8 C

  12. 7 _3 |. j# o) w, e  z1 t
  13. /*!< TIM PWM mode 1 */
    # o5 T+ n5 N( r: q8 g; \4 |- P) R
  14. #define TIM_OCMODE_PWM1                   ((uint32_t)TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1) 7 i5 D8 W" Y+ ]" V8 c! B
  15. * v( a" z" [0 e! @3 U3 R$ V
  16. /*!< TIM PWM mode 2 */                    / @" q" Y1 X$ y" \/ @
  17. #define TIM_OCMODE_PWM2                    ((uint32_t)TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_0)   " a' L, Z; r0 X( G1 C

  18. . C; q! g. F& R/ x- ]
  19. /*!< TIM Forced Active mode */   
    # U$ Q' u# B3 h( `1 I
  20. #define TIM_OCMODE_FORCED_ACTIVE           ((uint32_t)TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_0)         * M( t& a5 B# A& K" C

  21. , v) E# |" u- r
  22. /*!< TIM Forced Inactive mode */            
    3 }! u( B3 p. h$ m2 X
  23. #define TIM_OCMODE_FORCED_INACTIVE         ((uint32_t)TIM_CCMR1_OC1M_2)                                        . n( W6 r; R' o* Y+ o) }+ W
  24. 7 f$ W' B0 ?3 k  g9 E3 o5 q/ u* N: v
  25. /*!< TIM Rettrigerrable OPM mode 1 */  
    . q0 L4 m, C& C/ q) P
  26. #define TIM_OCMODE_RETRIGERRABLE_OPM1      ((uint32_t)TIM_CCMR1_OC1M_3)   * g- l& a0 e! U0 }3 [& U0 m, U- C2 c
  27. 9 Q/ X4 x  ^% Y' A$ j% r
  28. /*!< TIM Rettrigerrable OPM mode 2 */                                       
    4 P, f* o$ G: ^, s
  29. #define TIM_OCMODE_RETRIGERRABLE_OPM2      ((uint32_t)TIM_CCMR1_OC1M_3 | TIM_CCMR1_OC1M_0)    4 S5 h; n  {7 a' F: ~; ]

  30. ! X2 G$ O6 i" h9 g2 m
  31. /*!< TIM Combined PWM mode 1 */                     9 U" Q% K$ ~/ t% S
  32. #define TIM_OCMODE_COMBINED_PWM1           ((uint32_t)TIM_CCMR1_OC1M_3 | TIM_CCMR1_OC1M_2)     
    9 M3 i. [4 i  T

  33. 0 J4 Y/ z0 K% J2 ?8 D% [! F. G
  34. /*!< TIM Combined PWM mode 2 */                  
    , i4 O1 Z6 a7 B4 l( `* p: h1 Y8 I/ Q3 @
  35. #define TIM_OCMODE_COMBINED_PWM2           ((uint32_t)TIM_CCMR1_OC1M_3 | TIM_CCMR1_OC1M_0 | TIM_CCMR1_OC1M_2)   $ ?% u' s( K, W

  36. + C+ e% j: J' H' b% g
  37. /*!< TIM Asymetruc PWM mode 1 */  
    1 u6 H; g( |4 W& q' e) k
  38. #define TIM_OCMODE_ASSYMETRIC_PWM1         ((uint32_t)TIM_CCMR1_OC1M_3 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2)  
    3 n5 K! F% v$ h0 k! U6 j( w# Q
  39. # P& ?( V$ }. R9 {" C; z: s( \
  40. /*!< TIM Asymetruc PWM mode 2 */    & w4 a5 j5 \: `  E- ?! U8 o
  41. #define TIM_OCMODE_ASSYMETRIC_PWM2         ((uint32_t)TIM_CCMR1_OC1M_3 | TIM_CCMR1_OC1M)  
复制代码

% X1 g* v" T! h3 b* [  ( W# g) x( K* K$ r8 \4 T
  Pulse) h) L, p. Z3 u. ^: r
可用于设置占空比,对应定时器的CCR寄存器,32位的TIM2和TIM5范围是0到0xFFFFFFFF。
/ `4 C7 o( V. u: z$ H! b& [2 W9 J8 x  N* @7 Z' [5 m+ m- K) I
  OCPolarity
/ G, y# B9 r1 }1 x设置输出极性,可选高电平或低电平有效。' G1 j( [- g" B4 D% v; B2 d* V# A

# R/ A' x. _  K, P
  1. #define TIM_OCPOLARITY_HIGH                ((uint32_t)0x0000U)
    7 A9 h' J! y& E+ X# G
  2. #define TIM_OCPOLARITY_LOW                 (TIM_CCER_CC1P)
复制代码

1 M$ P0 Z+ t1 U3 W/ [  OCNPolarity& O' j5 R  b' D4 r: W/ j& H$ L
互补输出极性设置,可选高电平或者低电平有效。
* n! R  Z/ M, o% G, T) F0 g$ C+ E, C+ o" [: X1 S
  1. #define TIM_OCNPOLARITY_HIGH               ((uint32_t)0x0000U)
    " Y+ f3 D' E  L2 I2 J3 |* Y
  2. #define TIM_OCNPOLARITY_LOW                (TIM_CCER_CC1NP)
复制代码
8 Q! m$ f4 }! p# M  |* ~4 j9 u
  OCFastMode5 W  Z5 w! U0 D: K9 T6 V3 @0 r) Q) }
快速输出模式使能,仅OCMode配置为PWM1或者PWM2模式时才有意义。
0 C8 d$ J: o" O. H1 p$ |1 l1 y/ p) l6 P; R3 y" i% J, k
  1. #define TIM_OCFAST_DISABLE                ((uint32_t)0x0000U)! f# G& n3 u3 T' G, G
  2. #define TIM_OCFAST_ENABLE                 (TIM_CCMR1_OC1FE)
复制代码
* D) P& {0 }& h1 V$ e4 s
  OCIdleState- E8 k( x4 `, ]) d5 S' I
空闲状态时,设置输出比较引脚的电平状态。( V' X  n' Y$ p2 r& ~) ?
! U9 |- c" _# i7 B, H
  1. #define TIM_OCIDLESTATE_SET                (TIM_CR2_OIS1)
    ! D/ n0 U; k4 A7 ~3 X9 x
  2. #define TIM_OCIDLESTATE_RESET              ((uint32_t)0x0000U)
复制代码
( w! L  w* C& ^
  OCNIdleState5 ?" M$ x% K/ n: ~4 B+ O- s
空闲状态时,设置互补输出引脚的电平状态。% a; h1 i& t, @7 g3 f, w

) a; M, O+ `( j2 V
  1. #define TIM_OCNIDLESTATE_SET               (TIM_CR2_OIS1N)* K8 G" K: C6 n, U3 p6 P* C9 k
  2. #define TIM_OCNIDLESTATE_RESET             ((uint32_t)0x0000U)
复制代码

. g% I6 V7 Y4 @5 @32.3.4 定时器输入捕获结构体TIM_IC_InitTypeDef* E7 f+ i7 Y% [" [7 s0 M& Y) H
此结构体主要用于定时器的输入捕获,定义如下:9 z3 ~& N( u+ T  }, {

' |5 P! {4 X! G+ {. B
  1. typedef struct
    & n% o; I3 }! E9 W
  2. {                                 
    + i4 I! N: \) ^
  3.   uint32_t ICPolarity;   
    * X" ?- n6 ^' o0 c
  4.   uint32_t ICSelection; ; i( C- z& R% l6 l- r
  5.   uint32_t ICPrescaler; & [% E8 u+ t7 z8 v4 e  N4 V9 j
  6.   uint32_t ICFilter;   
    2 s/ }4 d. B4 O$ h
  7. } TIM_IC_InitTypeDef;
复制代码
8 Q& C+ X  a7 [/ w
下面将这几个参数一 一做个说明。' o* J" Q/ M/ J6 H7 p9 ]- a

. z* n5 f, S/ q2 R/ A' l: K( ?  ICPolarity
3 G0 A+ d$ @5 e, z; y8 n) v3 ^3 `& y输入触发极性,可以选择上升沿,下降沿或者双沿触发。: S3 F9 @# U4 d' E& u1 i
+ s( N( r. p/ I2 X
  1. #define  TIM_ICPOLARITY_RISING             TIM_INPUTCHANNELPOLARITY_RISING
    % N# Q/ n7 h- ~( q2 n
  2. #define  TIM_ICPOLARITY_FALLING            TIM_INPUTCHANNELPOLARITY_FALLING
    8 C) f0 a4 s9 Q% j
  3. #define  TIM_ICPOLARITY_BOTHEDGE           TIM_INPUTCHANNELPOLARITY_BOTHEDGE
复制代码

; j2 B. f1 N/ G2 V: I% ^  ICSelection
- ?; c0 U. _7 B输入捕获通道选择,可以选择直接输入(即CC1选择TI1,CC2选择TI2等),间接输入(CC1选择TI2,CC3选择TI4等)或者TRC。
; `; x: v+ y. E! K; R& I
; D% {# \8 I6 ^! T, e
  1. #define TIM_ICSELECTION_DIRECTTI       (TIM_CCMR1_CC1S_0)   . y* I# f" o( H' {9 {
  2. #define TIM_ICSELECTION_INDIRECTTI     (TIM_CCMR1_CC1S_1)  + [3 H- H1 j6 V) N! b. t9 w
  3. #define TIM_ICSELECTION_TRC            (TIM_CCMR1_CC1S)   
复制代码

! m' x" `: V5 P, d  ICPrescaler  e. r4 h: t  K  u! S# M7 s; G
输入捕获分频,表示每捕获1,2,4或8个事件后表示一次捕获。
. R7 \: C5 F* Z: P
% H) I. d/ P  l8 d8 \4 {0 I
  1. #define TIM_ICPSC_DIV1       ((uint32_t)0x0000U)                 , l3 z- {( E; ]) j, r
  2. #define TIM_ICPSC_DIV2       (TIM_CCMR1_IC1PSC_0)    ( c+ X6 X/ |- {& B; ]
  3. #define TIM_ICPSC_DIV4       (TIM_CCMR1_IC1PSC_1)   
    * O% n( G% R& ^+ j
  4. #define TIM_ICPSC_DIV8       (TIM_CCMR1_IC1PSC)
复制代码
  i+ a' V0 z2 Z2 m, R$ q
  ICFilter
9 z& W! A$ p1 Q5 F& [& C输入捕获滤波器,可以定义采样频率和多少个连续事件才视为有效的触发,参数范围0到15。具体定义如下,其中fCK_INT表示定时器时钟,fDTS表示死区时间采样率,N表示这么多个事件代表一次有效边沿。
" J; F' I6 n  [7 x$ L: C7 C- |% D9 J6 [( m
  1. 0000:无滤波器,按 fDTS 频率进行采样
    . s1 a2 k  M8 s& g
  2. 0001: fSAMPLING=fCK_INT, N=2* u5 v' }" h/ ?# A
  3. 0010: fSAMPLING=fCK_INT, N=4
    ( `& W/ Z6 l+ @0 b" ~
  4. 0011: fSAMPLING=fCK_INT, N=8* V8 Y  U6 s, {' C
  5. 0100: fSAMPLING=fDTS/2, N=66 P) \5 d- V# x: x4 o
  6. 0101: fSAMPLING=fDTS/2, N=8
    3 w7 o1 F7 C1 b' z$ E( k
  7. 0110: fSAMPLING=fDTS/4, N=62 @$ V% u& t1 o
  8. 0111: fSAMPLING=fDTS/4, N=8
    9 h4 j. P# K! a# |8 w$ P% f
  9. 1000: fSAMPLING=fDTS/8, N=6
    * C! Q9 v# ^) o' p4 \
  10. 1001: fSAMPLING=fDTS/8, N=8
    9 z0 x! |. o& t( I  V
  11. 1010: fSAMPLING=fDTS/16, N=5
    / M2 b3 Q( b1 y3 F
  12. 1011: fSAMPLING=fDTS/16, N=6
    , _4 e" M( T; i
  13. 1100: fSAMPLING=fDTS/16, N=8
    5 [' _; W) a, F( n; r4 m8 P
  14. 1101: fSAMPLING=fDTS/32, N=5
    4 h" @7 n* q; a$ J
  15. 1110: fSAMPLING=fDTS/32, N=6
复制代码
4 O' D5 C) F3 Q7 T& `  ^6 c+ r2 H
32.3.5 定时器的底层配置(GPIO,时钟,中断等)
# ^; G6 r: w1 S0 ^$ VHAL库有个自己的底层初始化回调函数,比如调用函数HAL_TIM_Base_Init就会调用HAL_TIM_Base_MspInit,此函数是弱定义的。3 e+ J0 T, p1 z; D& h' [$ {4 g
! l( t/ Y1 x2 M
  1. __weak void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
    0 d1 U, M8 K) ]9 ~# Z
  2. {$ V# u& z* I' M3 S: `: p
  3.   /* Prevent unused argument(s) compilation warning */
    9 {8 m8 F$ e. Z3 z! e
  4.   UNUSED(htim);
    , U  N; B* K# L2 l3 c( {  l
  5.   /* NOTE : This function Should not be modified, when the callback is needed,
    " F/ h5 C/ V/ F
  6.             the HAL_TIM_Base_MspDeInit could be implemented in the user file' \* r! K; m( L9 W9 U7 l
  7.    */- K1 N3 S  K7 d4 M9 r  k8 a
  8. }
复制代码
4 L8 p: P/ D' O6 @8 g# F
用户可以在其它的C文件重定向,并将相对的底层初始化在里面实现。对应的底层复位函数HAL_TIM_Base_DeInit是在函数HAL_TIM_Base_MspDeInit里面被调用的,也是弱定义的。& O0 g7 F# o* ]1 }, ^/ n
& x* s' x: o) y# U' F; z/ z
当然,用户也可以自己初始化,不限制必须在两个函数里面实现。
- z9 m$ ^5 p0 g  W8 M# t7 f
- i* c% Z4 d! Y! \; B; O定时器外设的基本参数配置完毕后还不能使用,还需要配置GPIO、时钟、中断等参数,比如下面配置TIM1使用PA8做PWM输出。
4 g$ G2 ]+ L* `) q8 C
' ^& r/ W8 I7 \6 a, G. D7 g  ?
  1. void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)8 I9 h+ K' h3 n- N; m8 w  }# s9 G
  2. {$ L4 n% X0 E8 h3 T
  3.   GPIO_InitTypeDef   GPIO_InitStruct;
    3 o# P; G- w3 ~

  4. 8 m/ Y" J' g! e
  5.   /* 使能TIM1时钟 */
    7 h7 C9 Z# T; e
  6.   __HAL_RCC_TIM1_CLK_ENABLE ();
    7 T( z. c) t" Z; p* N$ x; A

  7. 2 m2 X- p  Q1 c7 ~- ]. `! z
  8.   /* 使能GPIOA时钟 */( c# x' n3 n5 |9 Z
  9.   __HAL_RCC_GPIOA_CLK_ENABLE ();3 Y3 _4 N: B$ f+ _9 W9 @# V4 R
  10. # ?, c; B7 j/ T3 D+ w9 p* F' @
  11.   /* 设置TIM1使用PA8做PWM输出引脚,将其配置为输出,推挽,复用模式 */
    - [7 v: t' U3 r7 g( u( S
  12.   GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    & ]& H; ^2 g  ~
  13.   GPIO_InitStruct.Pull = GPIO_PULLUP;: @' P+ K& q0 {6 f
  14.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;4 o3 q# p) V. S$ g2 P

  15. 0 h2 W/ O- n3 E( e* _' ~$ g
  16.   GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;
    3 j# M# E  G$ ?2 ^( K
  17.   GPIO_InitStruct.Pin = GPIO_PIN_8;
    - Y% U: A% d$ H
  18.   HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    & `/ U, G" X& b5 e  Z
  19. 8 h% _" k- y1 S' l, N2 J4 A
  20. }
复制代码

3 [! M2 t/ R* G" j3 k1 [总结下来就是以下几点:
, J2 j8 b/ k. H4 l% ^0 i2 W- j! B& K6 o, t/ O
  配置TIM时钟。
$ x, \1 e' [' D! [2 ~  配置TIM所用到引脚和对应的GPIO时钟。
9 }( \  G7 k% y  如果用到定时器中断,还需要通过NVIC配置中断。
, J# T$ s) ]' }* Q9 E  如果用到DMA,还要配置DMA。
# e0 V/ e% n$ \( V关于这个底层配置有以下几点要着重说明下:
" _3 O; H. C; o' p) d: c2 @/ ]1 A2 u* `6 ]( o
  定时器所使用引脚的复用模式选择已经被HAL库定义好,放在了stm32h7xx_hal_gpio_ex.h文件里面。比如TIM1有一个复用,
9 d! y4 V% f  F
  1. #define GPIO_AF1_TIM1      ((uint8_t)0x01)  /* TIM1 Alternate Function mapping */
复制代码

0 }- [' N  P$ f9 E# b但是却有4个输出通道,每个通道都有几个支持的输出引脚:1 L  A9 _- X7 V* Z: X. F/ E& W

( l+ l3 k. c0 h5 N# M+ I
  1. TIM1_CH1,  PA8   PE9    PK18 W( r4 i2 |) c) W( Q* k
  2. TIM1_CH2,  PA9   PE11% B6 M) ]% J9 y. k- K' i. q- G
  3. TIM1_CH3,  PA10  PE13   PJ9
    # Z& Q1 p0 `/ X. a+ B5 v! t
  4. TIM1_CH4,  PA11  PE14   PJ11
复制代码

% e- h4 m, I& H3 t" s: G4 L具体使用哪个,配置对应引脚的复用即可:
% L- c3 |! s- u/ v$ |( y7 W. p2 S6 ?
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDcvMTM3OTEwNy0yMDE5.png
1 o' v: ^7 q& f; m0 n
* t* A6 j+ q% Y
32.3.6 定时器的状态标志清除问题! W& N7 T- o% r0 M9 x* e6 {4 W$ f/ z
下面我们介绍__HAL_TIM_GET_FLAG函数。这个函数用来检查定时器标志位是否被设置。
# |4 h& Y$ d' O
  1. 4 Y0 m+ M0 ?; X% I1 I
  2. /** @brief  Check whether the specified TIM interrupt flag is set or not.6 J2 H; K( Q" {6 [, I* n  _: Y
  3.   * @param  __HANDLE__: specifies the TIM Handle., ?. S0 X/ \/ q( T3 D1 ]
  4.   * @param  __FLAG__: specifies the TIM interrupt flag to check.5 Q1 R! R8 S2 e( s0 j& c5 p/ [6 N
  5.   *        This parameter can be one of the following values:
    8 f' \2 u9 G% p0 p" d
  6.   *            @arg TIM_FLAG_UPDATE: Update interrupt flag! W$ `# ]! m4 F: K
  7.   *            @arg TIM_FLAG_CC1: Capture/Compare 1 interrupt flag" C& _* W* R4 P* T- c- n" a
  8.   *            @arg TIM_FLAG_CC2: Capture/Compare 2 interrupt flag
    # f$ S5 R" S) Z
  9.   *            @arg TIM_FLAG_CC3: Capture/Compare 3 interrupt flag+ M' R8 }7 a2 q5 l! M
  10.   *            @arg TIM_FLAG_CC4: Capture/Compare 4 interrupt flag
    6 @" ~# `& T7 V/ S( Q4 x
  11.   *            @arg TIM_FLAG_CC5: Compare 5 interrupt flag( O1 m. g, W* B3 Z
  12.   *            @arg TIM_FLAG_CC6: Compare 6 interrupt flag4 Q) t- N/ X/ j5 u6 {4 F
  13.   *            @arg TIM_FLAG_COM:  Commutation interrupt flag
    2 s$ c; J- ?* @! Z8 d& A1 o
  14.   *            @arg TIM_FLAG_TRIGGER: Trigger interrupt flag, z' D: Q& `. b8 |
  15.   *            @arg TIM_FLAG_BREAK: Break interrupt flag   
    ; T/ K6 A# ~3 q. J2 B4 W
  16.   *            @arg TIM_FLAG_BREAK2: Break 2 interrupt flag                     
    - L; o: H# g) J- U' Z
  17.   *            @arg TIM_FLAG_SYSTEM_BREAK: System Break interrupt flag! C8 Z, r, i+ n1 \- `8 B
  18.   *            @arg TIM_FLAG_CC1OF: Capture/Compare 1 overcapture flag( h6 n" t6 v3 C/ I8 ?
  19.   *            @arg TIM_FLAG_CC2OF: Capture/Compare 2 overcapture flag
    + O: z5 c1 |  ]/ a1 {1 B9 s! b& P: H- w4 T
  20.   *            @arg TIM_FLAG_CC3OF: Capture/Compare 3 overcapture flag
    ) U" R, z0 Y- t
  21.   *            @arg TIM_FLAG_CC4OF: Capture/Compare 4 overcapture flag# ]& S9 _$ z* ^+ Z# s) m
  22.   * @retval The new state of __FLAG__ (TRUE or FALSE).. I) E7 G+ i6 R/ h8 q7 ?
  23.   */
    + {& m) r' w, t1 J$ b
  24. #define __HAL_TIM_GET_FLAG(__HANDLE__, __FLAG__)   (((__HANDLE__)->Instance->SR &(__FLAG__)) == (__FLAG__))
复制代码

9 n2 g5 G/ u+ _/ Q前5个是比较常用的中断标志。) L& @6 c. ~3 f' _
4 n* i6 z! J' q5 L
  TIM_FLAG_UPDATE
' [0 S4 r* S2 T6 X定时器更新标准,配置一个周期性的定时器中断要用到。
4 e5 Q# I" F7 i/ ]9 @$ ?' _
! S1 j9 o$ g+ n2 d( E( X     TIM_FLAG_CC1
! A& {7 k4 [' u8 cTIM_FLAG_CC2
& s+ \4 Q6 N, F: R( w# }0 ~3 Q* P$ A# {4 d& @
TIM_FLAG_CC3. k! x6 g) J" F5 h  f

7 p% ^. H: o1 ~4 ZTIM_FLAG_CC4
4 \6 Y& w( z9 t8 d4 Z1 P
/ q& f& a( s; h" y捕获/比较标志,配置了捕获/比较中断要用到。
4 ~8 ?; t- C% M$ X" a1 ^4 x' P7 x* z) ]& `5 e2 W& |2 _  L
与标志获取函数__HAL_TIM_GET_FLAG对应的清除函数是__HAL_TIM_CLEAR_FLAG:
" b- O0 a. s, X4 t9 w# `: j
, g, P( V5 Z- Y, c: q
  1. /** @brief  Clear the specified TIM interrupt flag.
    8 W' I* J5 u) W( P
  2.   * @param  __HANDLE__: specifies the TIM Handle.
      u9 F0 Z, n! G2 d
  3.   * @param  __FLAG__: specifies the TIM interrupt flag to clear.
    $ N4 d; d4 i* `0 X- q
  4.   *        This parameter can be one of the following values:, O% }9 e2 x" [) N  L. n, j
  5.   *            @arg TIM_FLAG_UPDATE: Update interrupt flag# A' _( v3 V: Y0 a$ s# Y
  6.   *            @arg TIM_FLAG_CC1: Capture/Compare 1 interrupt flag
    0 _: u* W9 y! k( r
  7.   *            @arg TIM_FLAG_CC2: Capture/Compare 2 interrupt flag5 u6 [1 Q7 b) I: a5 A* E0 w* z
  8.   *            @arg TIM_FLAG_CC3: Capture/Compare 3 interrupt flag
    3 ^6 `! m8 o: ~( V
  9.   *            @arg TIM_FLAG_CC4: Capture/Compare 4 interrupt flag
    5 v# q+ x5 ]+ s& r5 v2 z
  10.   *            @arg TIM_FLAG_CC5: Compare 5 interrupt flag
    + C# Q  w/ Z3 C3 Q4 [$ F
  11.   *            @arg TIM_FLAG_CC6: Compare 6 interrupt flag! c* U+ w* c  }; i1 R; O$ i
  12.   *            @arg TIM_FLAG_COM:  Commutation interrupt flag. m+ O* `0 O: O1 X' H- R
  13.   *            @arg TIM_FLAG_TRIGGER: Trigger interrupt flag
    9 R3 W2 S0 L, @
  14.   *            @arg TIM_FLAG_BREAK: Break interrupt flag   : Y0 `! l' Q" A
  15.   *            @arg TIM_FLAG_BREAK2: Break 2 interrupt flag                     % ~! H7 O" z# Q- Z7 {3 y( B
  16.   *            @arg TIM_FLAG_SYSTEM_BREAK: System Break interrupt flag
    - ?8 ?: y; J9 v+ x8 q
  17.   *            @arg TIM_FLAG_CC1OF: Capture/Compare 1 overcapture flag
    4 ~% C5 z! n# K% V* C
  18.   *            @arg TIM_FLAG_CC2OF: Capture/Compare 2 overcapture flag* [6 n! `7 [. h" I
  19.   *            @arg TIM_FLAG_CC3OF: Capture/Compare 3 overcapture flag
    8 ^  e' ?4 @& Z' @' f1 o/ `" S
  20.   *            @arg TIM_FLAG_CC4OF: Capture/Compare 4 overcapture flag+ ~8 I; e! q! G% L* A
  21.   * @retval The new state of __FLAG__ (TRUE or FALSE).% U, G3 b. G8 [4 _
  22.   */
    ) Z2 [3 v, I* K
  23. #define __HAL_TIM_CLEAR_FLAG(__HANDLE__, __FLAG__)       ((__HANDLE__)->Instance->SR = ~(__FLAG__))
复制代码

4 g4 ?: E& o- M4 D. L6 E3 S清除标志函数所支持的参数跟获取函数是一 一对应的。除了这两个函数,还是定时器的中断开启和中断关闭函数用的也比较多。" e7 {/ _( }- F) m

4 S  S& r% @! b/ I9 e
  1. /** @brief  Enable the specified TIM interrupt.% o: j4 m" {4 v5 x6 V, ^
  2. * @param  __HANDLE__: specifies the TIM Handle.
    8 j$ o, H8 L' r8 n) f) n: C
  3. * @param  __INTERRUPT__: specifies the TIM interrupt source to enable.
    . V- T4 [/ M$ U3 }  D' ], e
  4. *          This parameter can be one of the following values:3 h' G8 a& I' t- B* @6 Z+ p5 r+ U8 n
  5. *            @arg TIM_IT_UPDATE: Update interrupt, r: C$ L5 u! j9 u8 P9 P" K9 d
  6. *            @arg TIM_IT_CC1:   Capture/Compare 1 interrupt( d2 Z) j) a  H& a
  7. *            @arg TIM_IT_CC2:  Capture/Compare 2 interrupt
    7 f0 K6 n3 Q9 @- C. e  O( l7 ^
  8. *            @arg TIM_IT_CC3:  Capture/Compare 3 interrupt
    4 I& N; o  _0 T8 @2 n1 w5 H
  9. *            @arg TIM_IT_CC4:  Capture/Compare 4 interrupt" }9 S$ a& Z" z2 r
  10. *            @arg TIM_IT_COM:   Commutation interrupt
    % a6 t3 A) N. V. M& ]% w  T  a9 p# u
  11. *            @arg TIM_IT_TRIGGER: Trigger interrupt
    7 F, [+ @3 w, w* Q8 Y7 |
  12. *            @arg TIM_IT_BREAK: Break interrupt
    4 ]9 p/ [1 g8 ]
  13. * @retval None
    - m& `" _6 j) I" w
  14. */  {  t& c5 p1 b/ A  P  {. o% A
  15. #define __HAL_TIM_ENABLE_IT(__HANDLE__, __INTERRUPT__)  ((__HANDLE__)->Instance->DIER |= (__INTERRUPT__))
    ; U( V. ?: [& C

  16. 0 ?5 ~& y0 L5 S- k. G) y1 D: d
  17.   /** @brief  Disable the specified TIM interrupt.
    . M! Y: |7 d% K( H
  18.   * @param  __HANDLE__: specifies the TIM Handle.
    / E' H( }0 f3 o* C% Z* g* I$ H! p+ j
  19.   * @param  __INTERRUPT__: specifies the TIM interrupt source to disable.& \( F- [$ ~) O0 U
  20.   *          This parameter can be one of the following values:
    5 ]( ?0 T( q3 m
  21.   *            @arg TIM_IT_UPDATE: Update interrupt
    ) e: K7 K  c- E, _6 o
  22.   *            @arg TIM_IT_CC1:   Capture/Compare 1 interrupt
    % {$ R7 f5 X. n+ L9 M7 q
  23.   *            @arg TIM_IT_CC2:  Capture/Compare 2 interrupt
    + x) D& [6 l8 n
  24.   *            @arg TIM_IT_CC3:  Capture/Compare 3 interrupt/ A7 a' S& Y4 H' q# u; S( O. f
  25.   *            @arg TIM_IT_CC4:  Capture/Compare 4 interrupt
    3 i- p* f- B: D' ^3 _
  26.   *            @arg TIM_IT_COM:   Commutation interrupt3 z, h) e* t. Y
  27.   *            @arg TIM_IT_TRIGGER: Trigger interrupt  z) D; E5 i5 Q" k3 |& w
  28.   *            @arg TIM_IT_BREAK: Break interrupt
    / X& V. Q/ U7 q" E  {
  29.   * @retval None5 }2 k9 L. S) W
  30.   */  b4 z1 O- Y7 }7 ?% j
  31. #define __HAL_TIM_DISABLE_IT(__HANDLE__, __INTERRUPT__)   ((__HANDLE__)->Instance->DIER &= ~(__INTERRUPT__))
复制代码

. }; j' F' Y% T$ x1 H常用的也是前五个参数,1个定时器更新中断以及4个CC中断 。3 @/ C9 k( q$ ], x# B8 q7 q
8 _3 l9 u) P3 }3 |
注意:操作定时器的寄存器不限制必须要用HAL库提供的API,比如要操作寄存器CR1,直接调用TIM1->CR1操作即可。
/ h8 P" a* _. t, s, _* }; A
- w1 S* B- H4 b3 e% d32.3.7 定时器初始化流程总结8 K0 {  Y& l" X. t, I) d, e* o
使用方法由HAL库提供:
, a+ P' h1 m2 M$ B& t9 \/ Y: G. g0 W* B
  第1步:通过下面几个函数配置定时器工作在相应的模式
$ N5 A: j2 R+ ^  @
9 Q& t" ?8 o; n" \0 J3 d% s  HAL_TIM_Base_Init! j0 W+ X: G& V6 ]9 k0 I
简单的定时器时基础功能: U7 M  c# X& M9 A. P
( s& B5 y6 f& g4 t& A
  HAL_TIM_OC_Init 和 HAL_TIM_OC_ConfigChannel/ X. E' O' A& s# n& ~4 x9 _2 [
配置定时器产生输出比较信号5 Q# z; G9 ?/ a0 H8 o8 z  q- ^" U
9 z+ i1 @$ N- ~8 H7 g# |0 N
  HAL_TIM_PWM_Init 和 HAL_TIM_PWM_ConfigChannel. _6 o6 C- r4 A. |# G% K3 i4 f
配置定时器产生PWM信号
  j1 b5 ?) N! q9 W! N  V" ?2 k+ p! p9 s# n9 I3 e9 i4 Z
  HAL_TIM_IC_Init 和 HAL_TIM_IC_ConfigChannel
7 L. i' E6 W" ?" C. t1 p5 T' o7 j. ]9 I配置定时器测量外部信号
1 x. q, X2 ]& ?- W0 X  `3 y
9 h$ u' ?- x( Z/ `' B  HAL_TIM_OnePulse_Init 和 HAL_TIM_OnePulse_ConfigChannel
  d5 L' F1 v' y8 S! s8 {配置定时器工作在单脉冲模式
- L+ K- S9 V; Y+ K6 h
, D& |0 g5 _1 _  HAL_TIM_Encoder_Init6 S; s3 @5 I! `$ P8 x
配置定时器使用编码器接口5 Z7 W  f4 ^! J+ O+ V  S; ^) S
3 m* }. u( b1 t$ D) U
  第2步:定时器几个常用功能的底层初始化API,这个里面需要用户自己填
' T1 f  g1 S: Y1 {- B+ v% w( l/ }6 |/ K; w
第1步里面的几个函数会调用下面的API。
3 k/ s" H+ P/ h6 n$ O) q" ?2 V6 c. O; {2 g
  定时器基本功能 : HAL_TIM_Base_MspInit()
0 Q7 M: o3 F' {6 ]; W: K+ I  输入捕获 : HAL_TIM_IC_MspInit()
" @4 p+ [2 l' l! F  输出比较 : HAL_TIM_OC_MspInit()" k. u" V: R& i8 n
  PWM输出 : HAL_TIM_PWM_MspInit()$ Q2 e5 A5 d' w* G3 Q
  单脉冲输出模式: HAL_TIM_OnePulse_MspInit()  b0 J9 n. l9 D& W
  编码器模式 : HAL_TIM_Encoder_MspInit()
: d6 X/ H  e5 j8 W! w4 f  第3步:底层初始化具体实现4 D0 s/ S2 w1 [8 E6 G
7 Z4 G) R: u# D: q7 g
第2步中函数的具体实现。" v+ s7 T4 {  Z" @

- @' y, T4 \, O: ^  使用函数__HAL_RCC_TIMx_CLK_ENABLE()使能定时器时钟。+ Z3 {3 F$ I4 r! k6 z( C
  使用函数__HAL_RCC_GPIOx_CLK_ENABLE()使能定时器使用到的引脚时钟。
! K) ^$ V8 _! a' x  使用函数HAL_GPIO_Init()配置GPIO的复用功能。
  h  W! _* Q' j! q6 Z0 i% J  如果使能了定时器中断,调用函数HAL_NVIC_SetPriority和HAL_NVIC_EnableIRQ配置。
! b8 w7 @7 |) d; n8 q9 D  如果使能了DMA,还需要做DMA的配置。
: S) q! g9 }5 R" ^  定时器默认使用APB时钟,如果使用外部时钟,调用函数HAL_TIM_ConfigClockSource可以配置。
! ]8 l6 D& w5 t3 O0 B( `  第4步:启动定时器外设
# ^; G* _& K5 y4 u6 b$ |) {8 M
+ u+ ^/ Q" |* c6 A  L2 I  定时器基础功能:
, X& a( @7 J* G! |/ S" ?3 iHAL_TIM_Base_Start(). f: y$ ]5 J' v0 U$ T( P; K: O
) t2 `9 D1 V* x3 B: R) I
HAL_TIM_Base_Start_DMA()
6 x! x$ S5 j. u/ Y0 N+ Q
  n) I  w. t* w* _+ FHAL_TIM_Base_Start_IT()
; D/ u% C5 c- o/ Y3 }; p4 y9 r( e) d! R  o2 ?$ C
  输入捕获 :4 [( e$ N$ M9 u# t# R8 W* {$ I
HAL_TIM_IC_Start()# y+ u& \; ^7 ]% |  w. x9 I
! b* c- w  @  k" L' T# H& Y
HAL_TIM_IC_Start_DMA()3 ~5 G, w6 U# u5 p8 n) W
4 w3 }& O, D+ [/ X
HAL_TIM_IC_Start_IT()
+ i  _; @! G9 `4 w) C% x
  _+ c! Q! z' m4 f6 X, C6 g% k  输出比较 :
- {9 i- H3 J$ j' jHAL_TIM_OC_Start()3 |' C7 a8 ?& i+ {3 t
: n5 h( _+ V- M% B8 a
HAL_TIM_OC_Start_DMA()
% O' M$ ^6 q+ t! |' F  V- b
7 K6 \, U: D+ v6 [- {5 n% H) gHAL_TIM_OC_Start_IT()
$ ~* ?+ y& @: r7 l' h+ G/ d4 M* ^* N
  PWM输出:
3 t* _6 p& F0 xHAL_TIM_PWM_Start()/ L! {7 B9 ^# q- j& R8 M
# q8 ~# ^) o9 x' z
HAL_TIM_PWM_Start_DMA()9 f2 ~" ]" d: d% {' v( B& p6 k! ^. C
  S1 A& |1 b) j; o; p5 z/ e
HAL_TIM_PWM_Start_IT()
% B; a7 F% {+ Q- L" o. h
$ T& t0 F; @- |  g/ X  单脉冲模式:1 R6 H! i3 N9 k2 c) @* Z
HAL_TIM_OnePulse_Start()+ {, e; i! E! A4 r$ Z, g; X$ x

" F2 g7 ?( v" }1 ?/ i3 AHAL_TIM_OnePulse_Start_IT().
0 V1 e; M  L6 ?: N2 c! M( L5 k- Z; [+ L1 Y$ S' E- M
  编码器模式:
: K# X$ M& W2 x  A/ l. PHAL_TIM_Encoder_Start()6 A* q( H$ x& q5 p& ]7 a$ e

4 u( Q1 M' `$ N7 y8 uHAL_TIM_Encoder_Start_DMA()
- j# x. b4 W+ F, }! b: J% H2 [/ [# J# t! K4 `# L: ?" c
HAL_TIM_Encoder_Start_IT().
7 {) G9 j: y, e* i8 A* ]5 u5 l. A) r( t3 P  y9 j
  第5步:定时器的DMA突发使用下面两个函数
" ]1 T' M+ L, E2 V" `0 T. y* ^
, ^# Q8 p. u9 a% Q  HAL_TIM_DMABurst_WriteStart()
! T0 k! c* z1 _2 U8 Z  HAL_TIM_DMABurst_ReadStart()
( U& l  L. L  }3 n; A# C定时器常用的功能,通过上面这几步即可实现。
* S: W  a; H7 P' S/ ?1 W& m- Q0 U% H% E+ g' x) R# \
32.4 源文件stm32h7xx_hal_tim.c: u, r2 r' m& H. i
此文件涉及到的函数非常多,这里把几个常用的函数做个说明:
3 m8 f* Q- F" q4 b* C, z: \; M2 d) E' D$ T& R' |+ p# ?
  HAL_TIM_Base_Init
. u* v2 u1 L0 o3 Q! U  HAL_TIM_Base_Start8 y7 v; ]1 k( Q
  HAL_TIM_PWM_Init7 h' g+ `9 w- L5 g6 L' W- ?) o/ C: Z
  HAL_TIM_PWM_ConfigChannel
8 g5 q1 w- l- e- E) i  HAL_TIM_PWM_Start; c: \$ w8 C3 f2 X5 `2 F& p' @
  HAL_TIM_IC_Init- }: B+ G$ o3 J& ~4 `# L& z
  HAL_TIM_IC_ConfigChannel
2 u0 q/ [' `- F. S* o1 ]  HAL_TIM_IC_Start_IT" r( x! x. ?$ {. L6 G4 Z: x
  HAL_TIM_OC_Init
8 s2 O& f- q+ n2 v( F4 l& g+ y  HAL_TIM_OC_ConfigChannel* I- b5 C3 {7 ]
  HAL_TIM_OC_Start
/ T# l% a) [3 y5 v5 S# s32.4.1 函数HAL_TIM_Base_Init
) b6 m3 N. K& |函数原型:2 _  P' V2 k5 G4 F7 l' `4 N

! ^+ ~$ w( f0 z* l8 |
  1. HAL_StatusTypeDef HAL_TIM_Base_Init(TIM_HandleTypeDef *htim)  u9 Q& E, ~! E2 G
  2. {
    8 w7 \! {/ @& R7 s5 j
  3.   /* 检测是否是有效句柄 */0 K; K, y! Z5 `/ G3 _/ Z/ f
  4.   if(htim == NULL). @5 {& e( q, c$ P3 Q/ `
  5.   {
    # h( z5 x! s3 X9 Z, V' `8 |
  6.     return HAL_ERROR;1 M; l8 v3 Q9 [6 T
  7.   }
    7 a+ S& ~: R) L9 Y* m5 s
  8. ; J" k/ ^/ n) Y' B9 P
  9.   /* 检测参数 */+ b1 I: y( r; ^1 E
  10.   assert_param(IS_TIM_INSTANCE(htim->Instance));
    * O5 z7 J% [3 B/ K: l, M; l
  11.   assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode));
    + F3 P* U/ J) e$ P+ a9 F) l
  12.   assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision));
    7 V; q3 x1 T# f. S4 H% I; p
  13. 6 ^5 b1 w3 B& D+ \  [
  14.   if(htim->State == HAL_TIM_STATE_RESET)
    ' S3 c& m: j3 |) b1 b2 w
  15.   { 4 w% w  @; m+ ^1 h3 L  G
  16.     /* 默认取消锁 */
    " w6 R1 y+ p" W' @: x
  17.     htim->Lock = HAL_UNLOCKED;
    % C4 Z9 {' S% n) T' G' J% T# K3 S
  18.     /* 初始化底层硬件 : GPIO, CLOCK, NVIC */  v; Q% C4 k# K( H# k$ v0 w
  19.     HAL_TIM_Base_MspInit(htim);! E1 o1 P) |! Y& \/ S1 D. n! M
  20.   }/ r6 N# @/ [: z6 L3 Y& ]$ ~

  21. & I+ a+ }; \7 [9 q3 O, _4 J9 r
  22.   /* 设置TIM状态 *// H6 i: r0 a  l0 ^/ U
  23.   htim->State= HAL_TIM_STATE_BUSY;
    ( b" n* p2 g/ [% h  e: b6 l
  24.   O$ o2 o3 p/ p  Y" }
  25.   /* 基本参数配置 */
    0 V, C+ L/ W! m9 t
  26.   TIM_Base_SetConfig(htim->Instance, &htim->Init); ) v) w' ]& ~5 R

  27. 5 m; a' O2 J+ K$ L
  28.   /* 设置TIM就绪 */+ Z( X) k9 j( I: ^$ \/ h9 J, y
  29.   htim->State= HAL_TIM_STATE_READY;
    / I# Y( A# K: V
  30. ! ]% c0 y4 q. J* Y6 K( ?5 x
  31.   return HAL_OK;
    . X# Q+ a! S7 w) A5 q9 t
  32. }
复制代码

: ~( e2 P) M/ z! b函数描述:! O7 g5 {6 g( H2 w' l
5 h# Z/ ?- k7 X! {
此函数用于初始化定时器用于PWM。! G8 u5 s4 Z3 F

% Z* n+ U/ V7 A2 S; q% B* `! |函数参数:6 a$ G3 r8 K, u* _4 v8 c2 ]
5 f5 h. t. W/ M/ U8 f
  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。0 j& f& q' M: M# {
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。" A$ @; Y/ H4 Q) y1 w
注意事项:
1 G2 U5 F+ y2 f! c" |
* f, N$ J( m9 V! Q函数HAL_TIM_Base_MspInit用于初始化定时器的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能,由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
& h) U3 J6 O7 }/ e) R7 T5 W) S如果形参htim的结构体成员gState没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量TIM_HandleTypeDef TimHandle。
. f+ D( u6 t* {# O% L! z对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_TIM_STATE_RESET  = 0x00U。2 |/ Y  A0 L6 s' L0 R8 Y

) g% L2 `4 c5 c7 I解决办法有三:3 Z4 a: r) B/ Z2 t; X+ e7 ?
( J0 e+ d) Q  H6 P+ i
方法1:用户自己初始定时器和涉及到的GPIO等。( e# Q& q: E+ A5 T7 o8 S
$ i% g) Z& {" i3 ]. c3 H
方法2:定义TIM_HandleTypeDef TimHandle为全局变量。
) {! f1 o! h# Y
, s" Y; ]. \2 D- D" l; d0 q方法3:下面的方法4 U3 X- y- f- Z- e+ y4 }) l& i& n7 k7 P
$ B# m% X7 J8 p( f% `( G6 S
  1. if(HAL_TIM_Base_DeInit(&TimHandle) != HAL_OK)
    4 S3 w; F$ Q/ G% H' c
  2. {. ^, P0 u( `' w1 n4 ?0 g
  3.     Error_Handler();
    8 g+ w) A0 O6 V8 P. O/ s1 a
  4. }    Z- j8 L7 O$ a" V+ ], s9 u
  5. if(HAL_TIM_Base_Init(&TimHandle) != HAL_OK)
    2 X( Y+ u/ w7 s) F/ a7 K
  6. {
    " ]. i6 I4 U- @) ^! o9 Q  u2 R
  7.     Error_Handler();
    ! X4 i- X1 v; e! ?& X
  8. }
复制代码
5 Y% E3 b9 {9 E# K( `/ i
使用举例:6 [# P4 i; l: g* X" C/ t. j& K( k
' o' _: }9 A3 b1 H1 N0 ~& f% ~
  1. TIM_HandleTypeDef   TimHandle = {0};$ l6 @4 {* X/ ~
  2. " B$ o2 L4 Z+ Z* l$ T2 d
  3. /*
    - M1 g" B: R8 o1 s& V3 O) G
  4.     定时器中断更新周期 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)
    - b: N( V" t* ^& u/ L
  5. */
    ' K: o' b/ m' W5 `5 X
  6. TimHandle.Instance = TIMx;
    ) X7 b6 I. Y+ u7 d3 ~
  7. TimHandle.Init.Prescaler         = usPrescaler;
    & g# v8 X% K- d
  8. TimHandle.Init.Period            = usPeriod;        6 c2 ^2 k2 _5 q8 `  N
  9. TimHandle.Init.ClockDivision     = 0;5 O: w" E$ ^, h
  10. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;
    0 i: w+ x+ Q) S( W7 D
  11. TimHandle.Init.RepetitionCounter = 0;
    5 K% m. W7 `& [( i; o) _
  12. TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
    2 z8 b3 b$ R5 y' z& }' ~
  13. if (HAL_TIM_Base_Init(&TimHandle) != HAL_OK)
    ) w" n( }% }+ Z0 m9 u3 |# k4 I7 Q8 o
  14. {" ?  l2 m) o: V4 H
  15.         Error_Handler(__FILE__, __LINE__);
    0 o! r% D3 }: ^) D7 U
  16. }
复制代码
7 g- ~" A/ X% R; H6 B# E3 W2 ~
32.4.2 函数HAL_TIM_Base_Start( [+ U0 m. L7 b7 T
函数原型:: r" o: q0 A0 s
9 ?& O8 z  ^* f& n* f& V: F
  1. HAL_StatusTypeDef HAL_TIM_Base_Start(TIM_HandleTypeDef *htim)4 m6 c% N# q* l* {, N0 w5 }5 K
  2. {
    : ~( s/ j, j# E) O7 v  [% N6 Q% P
  3.   /* 检测参数状态 */# f, }  g& a  C% t5 [
  4.   assert_param(IS_TIM_INSTANCE(htim->Instance));
    5 k( X# n" o3 w, z! X. H

  5. " D5 c  y5 J% c  ?& |9 F. n
  6.   /* 设置定时器状态 */$ H1 `9 K7 J8 d
  7.   htim->State= HAL_TIM_STATE_BUSY;
    ' H* L- J! D* O
  8. 7 j& W: z. s$ ^
  9.   /* 使能定时器 */3 J' B! v: G" I) i& J1 U
  10.   __HAL_TIM_ENABLE(htim);. a0 }: ?+ F! E
  11. : N! B" t) q4 l7 R0 {, c+ C( o" o
  12.   /* 设置定时器状态 */
    - c. W) v! G: Q
  13.   htim->State= HAL_TIM_STATE_READY;" y% ]" z# F3 ]7 J* X5 b5 P
  14. 6 i9 S  v/ p1 Y8 q7 c; T
  15.   /* 返回HAL_OK */
    + I& r& B- G) D8 D0 j
  16.   return HAL_OK;: R" J/ |& ?4 S/ ?
  17. }
复制代码

7 X" O0 H+ j% P2 R) J: H函数描述:
' E4 O9 y( x, ~" R% O- L/ K( b0 T' E7 Y4 E0 I1 g; R& T
此函数比较简单,调用函数HAL_TIM_Base_Init配置了基础功能后,启动定时器。
( x9 U: Y0 C! W  ~2 a9 i# x1 |& n4 t& o* J9 U' F2 V1 h% `
函数参数:0 w, h/ U% P( W) C* t3 K: ?; T
8 B2 r( X- Q$ V! I8 ^& e0 y
  第1个参数是TIM_HandleTypeDef类型结构体指针变量。2 r% o4 Q. \5 C3 z) o9 z
  返回值,固定返回HAL_OK,表示初始化成功。
$ k  E, ~& H, {4 C: j/ }( o2 |2 y使用举例:: g4 x# e! |; A- L

3 t( u& U, @; J" @* N& u' }4 q
  1. TIM_HandleTypeDef   TimHandle = {0};
    " H  A  x1 Z( T: [- g& t
  2. : P0 ]& X# f- P7 g' Y$ C3 d
  3. /*
    . S! R0 E7 c& L' B1 }
  4.     定时器中断更新周期 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)
    : [3 M  s( i$ j" F) w, i( {  p( y
  5. */. d' ?3 O- U! s0 o
  6. TimHandle.Instance = TIMx;8 [) \8 {' D7 _& g$ w" k1 s+ N* Z
  7. TimHandle.Init.Prescaler         = usPrescaler;
    * E) `3 g) K, B4 m8 [
  8. TimHandle.Init.Period            = usPeriod;        # C) |4 t5 c1 Q; U0 Y1 g3 F, W* G
  9. TimHandle.Init.ClockDivision     = 0;" R5 c$ b+ S! L4 ^, c
  10. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;
    0 p) D3 p0 h& J% D. ]
  11. TimHandle.Init.RepetitionCounter = 0;7 {% k" V0 A5 ]+ l  `
  12. TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
    7 w# Q. y5 y$ g; Z
  13. if (HAL_TIM_Base_Init(&TimHandle) != HAL_OK)
    5 v5 j% I& p3 t$ g; m
  14. {
    % G5 m0 n6 \/ a0 l
  15.         Error_Handler(__FILE__, __LINE__);
    " F9 A5 T  q& E  n  e8 a5 p3 C
  16. }0 z% V# u9 U3 Y( ?
  17. # T$ _3 T; @  X
  18. /* 启动定时器 */' M7 g: }* l3 [, c8 a/ t6 q* O2 d
  19. if (HAL_TIM_Base_Start(&TimHandle) != HAL_OK)
    7 Z- ?, I" u4 \, Z
  20. {
      r+ B! e6 Y6 w6 V; h6 o
  21. Error_Handler(__FILE__, __LINE__);8 X/ O1 |$ [6 U& R0 r( B
  22. }
复制代码
% ^  s& \, K& H# p8 q+ K
32.4.3 函数HAL_TIM_PWM_Init$ u; D, y0 S& f3 ]3 T
函数原型:& \6 \3 O+ N) R( J- D; ~; n
7 x$ a, S- r8 ?( J7 z
  1. HAL_StatusTypeDef HAL_TIM_PWM_Init(TIM_HandleTypeDef *htim)' b( x' ^* c2 n; f7 X
  2. {
    - u- s, D3 {9 Q3 i3 q( r8 d
  3.   /* 检查句柄是否有效 */
    / `& J$ W- S, j1 g* U& V/ f
  4.   if(htim == NULL)
    ) R1 L6 n. @% E( Z/ z5 i
  5.   {0 C9 `- @1 s1 b% y9 N  x! Q
  6.     return HAL_ERROR;
    ! r/ }; L# d5 ^! t. v
  7.   }
    " e3 {8 {. C7 u! U$ A  k
  8. / T- v8 H! v% F
  9.   /* 检测参数 */
    9 |( K; P& _/ B% Z7 O) q6 H
  10.   assert_param(IS_TIM_INSTANCE(htim->Instance));
    3 l  X4 N6 D; b* e
  11.   assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode));) U6 T1 p% p/ t! l0 S3 j9 ?
  12.   assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision));
    6 r2 F, O; D: j+ C1 d
  13. 6 N9 S% R/ Y% x2 n
  14.   if(htim->State == HAL_TIM_STATE_RESET)
    # }, s: X- w. r: b4 [# U
  15.   {: c! I% a# b3 `9 d( Y0 `! L
  16.     /* 默认取消锁 */$ V7 [, F3 I- r2 O
  17.     htim->Lock = HAL_UNLOCKED;
    + P: T! M6 R# Y2 t6 O

  18. & F; ]. s) }' t- `$ s- j# m9 `0 K
  19.     /* 初始底层 : GPIO, CLOCK, NVIC 和 DMA */
    9 U  t  x. O9 e# X
  20.     HAL_TIM_PWM_MspInit(htim);
    2 w% J- \0 r( Y; U
  21.   }$ W( A3 k' g6 u+ l4 U: x' k
  22. 4 z- U+ L2 d; M6 o" O
  23.   /* 设置定时状态 */
    8 n+ G# c+ n. m8 x9 d
  24.   htim->State= HAL_TIM_STATE_BUSY;
    / \; ]5 U& N! R

  25. , [4 x, G( u+ T) n. Q
  26.   /* 配置定时器用于PWM */  
    % h* S! Y2 D( J$ m- H: }
  27.   TIM_Base_SetConfig(htim->Instance, &htim->Init); ( R) W) E2 M) @3 d$ n6 e
  28. / u& G- {; N  v) ^* a# e7 @
  29.   /* 设置定时器状态 */* A) t) o3 r. D; v8 i& W9 l+ u  d) v
  30.   htim->State= HAL_TIM_STATE_READY;9 p  ?' P* S; y5 u# d

  31. % G0 I* D+ U  P) u/ j2 t5 R0 @
  32.   return HAL_OK;; S& L' T/ h: s; w
  33. }
复制代码

2 j: F8 g' O8 h) N; [, f! s& G! P函数描述:
) ~7 {* X+ `- E* Z! [
$ e+ h1 U8 a9 M* o  ]7 r此函数用于初始化定时为PWM方式。! S4 d6 j2 O6 k: D" r7 S
% b  u: t2 F5 b# a% }0 {
函数参数:5 A5 e$ N+ J' s' C/ V
$ [' e, ^, `9 y+ z, D) H. s, ?
  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。
6 v) z  t- k0 f3 p0 `$ @  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
- c- a) Z) |0 Q5 j+ F注意事项:
( W, ^. X) ^2 g" v/ ^+ b& p' E* z5 I" K' e0 y2 n/ {
函数HAL_TIM_PWM_MspInit用于初始化定时器的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能,由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
4 L! S: u& i8 ^如果形参htim的结构体成员gState没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量TIM_HandleTypeDef TimHandle。9 m' f6 K- f' A2 U6 D
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_TIM_STATE_RESET  = 0x00U。/ e2 [, W3 @1 w' k* A, Y
( M9 F1 \5 l5 ~- x
解决办法有三:1 x: [1 y. K; |$ l
1 R6 E+ g, P. s( _6 H5 M' ?$ ^
方法1:用户自己初始定时器和涉及到的GPIO等。
: r0 D# _; E. J$ U: u
9 U  T) Q4 v8 ]方法2:定义TIM_HandleTypeDef TimHandle为全局变量。
/ D2 {" {' L  _; x6 d# g7 l: C5 J3 o' |# K- s
方法3:下面的方法
% ]) k8 @6 N! o, a
9 j; A' p8 X- x* b
  1. if(HAL_TIM_PWM_DeInit(&TimHandle) != HAL_OK)9 M& m' l; i- z; Y3 @$ g  [7 B4 s
  2. {
    ) S) ?6 f9 |- l5 I
  3.     Error_Handler();* |  u6 q7 q1 M2 U7 S% y2 q
  4. }  
    ; v0 D2 _# M4 p4 I% ?4 c! g& ~2 ~
  5. if(HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)
    0 H' O. u1 P. E7 n4 V$ `# F
  6. {0 z$ I) n4 x; Z1 p8 g
  7.     Error_Handler();
    & o+ e/ R) N3 a) k
  8. }
复制代码

- T" }0 ~! B8 t) R' C; S# w使用举例:
$ s  Z8 r, _( n$ [& M+ t9 i* N& w, Z0 L1 _% W0 C
  1. TIM_HandleTypeDef  TimHandle = {0};  C# {' v! b+ V$ e4 h
  2. 2 ]2 S; F3 J' s5 s: Z
  3. /*  PWM频率 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)*/
    . u/ s6 x* E- ~1 L# C8 ]3 e! u
  4. TimHandle.Instance = TIM1;
    ; `9 [: N6 g& ^, l' ~
  5. TimHandle.Init.Prescaler         = usPrescaler;: q" A) J5 s: S" r0 L% n
  6. TimHandle.Init.Period            = usPeriod;
    % @0 h/ |- l5 n+ H
  7. TimHandle.Init.ClockDivision     = 0;- q- U  J) D8 k  l  s  F: ^
  8. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;$ v. T0 F; [, F( ?
  9. TimHandle.Init.RepetitionCounter = 0;! I7 r3 m: j" O) `  k  ?
  10. TimHandle.Init.AutoReloadPreload = 0;7 U2 V; ?8 Z. ]0 J; M+ e6 E8 a) B- X
  11. if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK). }* M4 R% U- G' U$ H. e; b! T8 y
  12. {. O5 l$ F7 d/ C  y2 u$ c
  13.     Error_Handler(__FILE__, __LINE__);/ E0 R# d+ y4 L) R
  14. }
复制代码
( e7 o! m2 F: m# G" }  }
32.4.4 函数HAL_TIM_PWM_ConfigChannel
/ ~+ `/ b4 `: |5 u4 r函数原型:
# y. h: T0 d/ c& M$ i2 }9 J+ m+ ?1 o' u$ A* Z5 A* E% `4 |
  1. HAL_StatusTypeDef HAL_TIM_PWM_ConfigChannel(TIM_HandleTypeDef *htim,. ~1 _6 t1 U# c% A; A
  2.                                             TIM_OC_InitTypeDef* sConfig,
    5 V; s# C0 ~6 V# e5 d5 E
  3.                                             uint32_t Channel): [- a* `& f9 ~5 L# W  Z3 O
  4. {
    $ h' i! q/ s2 l2 l$ n8 M5 q
  5.    /* 省略 */. p+ G. k. ]( N) |

  6. ( g  [& t% Q2 p1 l! C
  7.   /* 开锁 */
    4 @9 z/ |  ?. C2 p* u' i8 g" p7 c( T
  8.   __HAL_LOCK(htim);1 J% N; a  G2 z" E
  9. 8 F5 |+ t7 J9 i0 }
  10.   htim->State = HAL_TIM_STATE_BUSY;5 N( l) [# w, j  w' W! {$ E1 w4 a; ]
  11. + u% }# s0 S- q/ F
  12.   switch (Channel)
    ' e! U3 R6 b7 Q0 E. V5 K
  13.   {
    , {6 L* T7 U6 {; o/ J% G
  14.     case TIM_CHANNEL_1:& N% \$ g4 O" D4 K8 n/ @/ K
  15.     {5 b: A3 x0 Q: |) i1 P* Y5 U6 E% Q
  16.       /* 检查参数 */
    7 o" F. Z# z3 @; q2 L& u
  17.       assert_param(IS_TIM_CC1_INSTANCE(htim->Instance));$ k! J: U( h6 ^5 r1 A+ |
  18. " L& a! }) K2 f1 U) w7 s
  19.       /* 配置通道1的PWM模式 */& O$ M' Z& n- \1 u
  20.       TIM_OC1_SetConfig(htim->Instance, sConfig);  R" t2 f' Q! f4 B, ?. c: g0 z
  21.   f/ P- n6 ?, T4 d3 f
  22.       /*预装载使能,更新事件产生时写入有效 */, N# Y9 e. Y' e. ?# J4 ?
  23.       htim->Instance->CCMR1 |= TIM_CCMR1_OC1PE;
    + _4 ?6 T4 O/ a9 _: Y  F
  24. ) V  C: D9 `9 F. R$ o" {6 b; Y
  25.       /* 配置是快速输出模式 */
    * t; i; T- Q! p2 _
  26.       htim->Instance->CCMR1 &= ~TIM_CCMR1_OC1FE;
    1 F* m  R& X0 \  y" I
  27.       htim->Instance->CCMR1 |= sConfig->OCFastMode;- u0 h& }# w5 _
  28.     }
    8 Q4 i; L* [7 m5 s
  29.     break;1 [2 Z& K/ p: I1 Y. u, _+ J
  30. ! f9 ]8 y  ?+ I2 f! `# J% r
  31.     case TIM_CHANNEL_2:8 [% P5 g9 Z: m5 N; l% w, Q) t( u& L
  32.     {
    2 B, X0 ^; E9 Q& L3 D5 x) k
  33.        /* 省略 */1 z8 m0 I2 _1 p
  34.     }
    , m/ |) ]8 D& W: q
  35.     break;
    % w" F7 n* A) ]$ f: V

  36. : E6 v! |( r% l; q! V
  37.     case TIM_CHANNEL_3:
    9 ?, O. F2 j2 N# i7 X9 C* _
  38.     {
    8 S( R9 G5 P6 ?' A
  39.        /* 省略 */& |" e3 T2 ?' o% F
  40.     }9 j- I1 P, ~( `! x# L
  41.     break;! l2 |9 y5 ?* f! a' W
  42. 6 A- O2 H8 K% \# a
  43.     case TIM_CHANNEL_4:1 ?( @, E8 u1 k# P2 J- a
  44.     {
    7 K. `$ v% u, H6 B' h7 f
  45.       /* 省略 */: |0 C7 o% E: }9 M
  46.     }
    % S( i/ F$ ]- _$ {2 c2 p
  47.     break;
    ' L/ p5 b! j9 i0 Y4 d

  48. * _- @3 A1 ]4 v  R" g9 [
  49.     case TIM_CHANNEL_5:2 ?4 ?" t/ k) X- I! I; @
  50.     {
    9 t  ^( \1 [* z+ U- j% [0 ?
  51.        /* 省略 */. R, p* T" a8 O! m- G
  52.     }
      ^1 W, @9 w4 M- K, p( D
  53.     break;
    ( ?0 I- Y& t0 x
  54. ; t. }. O( ~1 J4 X
  55.     case TIM_CHANNEL_6:
    0 Y8 Q0 E, E7 b* C. c1 A& z) j" ]
  56.     {
    + F# V( u/ f* B8 H' ~
  57.         /* 省略 */! X& _. v5 ~. I3 P3 I2 Z
  58.     }2 I0 b4 q! B) J, G$ h& j
  59.     break;
    + r4 I0 f( V1 u& W9 ~8 s& E
  60.   b: m% T# e1 ]% A8 M9 q
  61.     default:
    & k, @" h: D+ R) x
  62.     break;
    + \: }$ @- d1 Y% v# {9 l5 ]+ M5 f
  63.   }
    3 |$ ?% z  @: g
  64. ' v8 b& |0 \$ r% c+ _9 Y4 t# _" u
  65.   htim->State = HAL_TIM_STATE_READY;8 R# J0 C8 p7 ^$ r& M" w  }

  66. $ @" y/ D1 M8 D) e% @, u0 a/ u' C
  67.   /* 关锁 */: p2 h; @' l, ]& h2 |1 @
  68.   __HAL_UNLOCK(htim);
    + C; b4 V9 M+ ~6 T
  69. 1 o0 o9 u( K: x5 M  c5 R! y  U
  70.   return HAL_OK;
    6 S9 g& b/ S$ U6 q' c; o  V$ R* u
  71. }
复制代码

2 X0 J/ c& G% y' q函数描述:
3 e( w9 E+ n! u: q. [6 O4 Z  Y
+ ~) V& O3 x7 H2 S9 R5 b此函数用于配置定时器的PWM通道。+ T) k* f: E% |, z6 J& c
# x$ T/ N$ k" c$ y+ ^' N9 H
函数参数:, \' L) D% \: ^$ E  p* V5 O

: g2 l( G) ]. q0 E1 i( B  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于定时器基本参数配置。
- f' S. B; Y: Z8 u  第2个参数是TIM_OC_InitTypeDef类型结构体指定变量,用于定时器输出比较参数配置。
! P/ W1 t$ \7 p" A) }- n6 J  第3个参数是通道设置,支持以下参数:
$ J% {% |1 c3 U% m# J* bTIM_CHANNEL_1: I9 |/ L( U6 M* S& J

8 J% D* ^% s* O1 [% P6 ~1 zTIM_CHANNEL_21 g8 a7 Y5 [% w9 S. d* b

6 c5 [) @! i: V0 I4 BTIM_CHANNEL_3' a) k% `& M2 @: r3 \# Z) N  J  h

5 d. J. W+ }6 j% c( Z$ sTIM_CHANNEL_4
, v4 Q- B2 ?! k1 A+ k9 n8 U/ Y3 ?
TIM_CHANNEL_5
2 l& g; X1 Y" i0 f8 y$ K% ~$ \
" a" {- t* v9 D: t& T' zTIM_CHANNEL_6% }. g1 E/ |# W: L
2 _* O" v1 W: {* e' k4 O
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。9 M# W0 y) Q) {* g% e
使用举例:
. F8 V% V5 E7 g8 w: v
0 J* J: i" l$ C
  1. TIM_HandleTypeDef  TimHandle = {0};
    - Y7 K% s0 ?* F/ H9 n
  2. - x- H' O5 L( w! h8 @% d
  3. /*  PWM频率 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)*/
    0 \3 ~8 D. K. I" d' c
  4. TimHandle.Instance = TIM1;
    2 Y6 D( F4 w" p& r, N
  5. TimHandle.Init.Prescaler         = usPrescaler;
    " U4 A0 B) C" f& j" T( a/ d' \
  6. TimHandle.Init.Period            = usPeriod;9 X: v2 L6 V6 h& c* v- u, B4 ~# j
  7. TimHandle.Init.ClockDivision     = 0;
    1 ^+ u) P. R; ?/ ~' b
  8. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;
    1 G2 u; ?9 ^/ }) L
  9. TimHandle.Init.RepetitionCounter = 0;
    / H4 D) g# ]! }& i3 H! U
  10. TimHandle.Init.AutoReloadPreload = 0;' M1 i, [' a9 b
  11. if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)
    ' z( Z7 L6 t8 k3 W# S
  12. {
    " C" A) h* }& a& J7 a. U+ J
  13.     Error_Handler(__FILE__, __LINE__);
    5 t: f& Y. x9 F8 G" D4 j) a9 A
  14. }
    8 M; g# O* r1 I2 D, Y/ j+ }
  15. 7 j( X! E4 P- T$ ^, B% [5 E
  16. /* 配置定时器PWM输出通道 */' _6 ^, J, {% E# W2 @( p# y
  17. sConfig.OCMode       = TIM_OCMODE_PWM1;* C* ^2 p: u5 F) R: \* N
  18. sConfig.OCPolarity   = TIM_OCPOLARITY_HIGH;
    ! x; Z) b4 y& g" \  a* p  G& G
  19. sConfig.OCFastMode   = TIM_OCFAST_DISABLE;
    : o9 j- B. U/ N) x
  20. sConfig.OCNPolarity  = TIM_OCNPOLARITY_HIGH;) p! B; w- Y6 T% H6 B  l
  21. sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;
    8 w4 S3 N' U+ K2 D
  22. sConfig.OCIdleState  = TIM_OCIDLESTATE_RESET;
      t( s" L2 r5 z2 j# R

  23. ' s+ J  Y) D6 N% m+ p0 C7 M
  24. /* 占空比 */
    . a( y* q( S9 i8 v6 @2 A
  25. sConfig.Pulse = pulse;
    + G- d+ [: w! w0 a1 e1 U- R8 @4 E
  26. if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &sConfig, TimChannel[_ucChannel]) != HAL_OK)0 U, _& ^  e: |0 P3 m  C2 C% G
  27. {' }& s% o$ m4 l
  28.     Error_Handler(__FILE__, __LINE__);
    1 `$ {8 F! Y; J+ R
  29. }
复制代码
) }" T7 x% S1 s3 g& r, W
32.4.5 函数HAL_TIM_PWM_Start/ U: w- H% I. {7 r) u/ S* x4 L
函数原型:0 A, M: J/ d* e3 `! N

4 A4 B1 H- h+ w2 w  }
  1. HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel)6 Z. l; ^; M7 X; J0 e
  2. {
    ' S1 q1 \# X4 s& V1 t8 f
  3.   /* 检测参数 */) J- w# U# J7 `! P, r2 Z4 U
  4.   assert_param(IS_TIM_CCX_INSTANCE(htim->Instance, Channel));
    0 ~5 }8 c" q& a# i; L2 S, d7 W

  5. ( \4 L2 o4 ^" v
  6.   /* 使能捕获比较通道 */
    ( C1 Q, b9 t. \0 o. ~4 c! q9 J
  7.   TIM_CCxChannelCmd(htim->Instance, Channel, TIM_CCx_ENABLE);
    : ?- Z% P6 f! ]8 E2 w

  8. : w( d- r2 d, H
  9.   if(IS_TIM_BREAK_INSTANCE(htim->Instance) != RESET)  9 ]& j+ B9 O3 M3 v# l
  10.   {
    * c+ w* Q& z4 o5 @
  11.     /* 使能主输出 */) w3 {0 C; Y0 n) k" O6 O) ]
  12.     __HAL_TIM_MOE_ENABLE(htim);
    , Z; y5 I% B' ~- w
  13.   }7 r7 g- _/ I3 `0 u  d* H3 k
  14. 6 Y# i7 b6 S4 _, m% I* v
  15.   /* 使能定时器 */
    - `4 f2 b( ]. [) Q
  16.   __HAL_TIM_ENABLE(htim);; h. p. ^' `( \- z/ w; [

  17.   S$ K& m% d5 q. Q- [
  18.   /* 返回状态*/& [% N# Y4 P9 I' l+ K
  19.   return HAL_OK;* m- v' H4 p5 B; A/ m: @  D3 n
  20. }
复制代码
8 b, p) G: j1 B9 M' C# b  z! b
函数描述:0 K1 G* ^- g- j! K3 I: U
% R  Y. a% @9 `, W8 r( x0 C# a
此函数用于启动PWM。! S" y  I/ N$ C2 |

. e4 s1 i$ ?. F- ~. G2 ^5 M- a函数参数:; W# {' c4 G+ S% N" r( E
1 d: G6 j# d; \# ?3 H
  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。
2 g8 i' j/ u$ L& m; V  第2个参数是通道设置,支持以下参数:" q9 I0 z, S0 T+ j( E% q
TIM_CHANNEL_1, r' F' ~6 A7 x3 R! ?
& }' x* J% }3 h* k
TIM_CHANNEL_2
* e  T$ V7 M2 H$ f8 C/ u, k% q2 F: y0 p9 c8 B2 V( N
TIM_CHANNEL_3
3 d1 e1 z3 i; T, D' T6 k! g9 K2 L3 x; J( H6 s' R- t! o! l
TIM_CHANNEL_4
+ |. u* ~+ ], s; x. F5 n% q$ {
0 }! e' `( j" H0 o# \; Q  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。. n0 F# R: s* G+ n/ h
使用举例:1 _1 ^: F9 X" H) O5 E% m
. U; B$ E/ i3 E$ _8 A
  1. TIM_HandleTypeDef  TimHandle = {0};
    # a8 t2 e! z) J8 s" a0 z/ R
  2. ' P+ T" ~$ o/ X
  3. /*  PWM频率 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)*/
    4 {! N  T, k; w* J
  4. TimHandle.Instance = TIM1;9 [6 o: G, c$ Y* r4 C$ J" @
  5. TimHandle.Init.Prescaler         = usPrescaler;2 L, ]* U; O/ U/ J4 J( o0 |6 P* {
  6. TimHandle.Init.Period            = usPeriod;( N) M! j3 E* w4 U4 I8 S% y2 n. K
  7. TimHandle.Init.ClockDivision     = 0;4 D) e+ Z" G/ F' w6 \: @8 A9 U
  8. TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;- H+ Z7 b- o) I, p  W" r- c
  9. TimHandle.Init.RepetitionCounter = 0;0 l! v7 d& v% O' Z0 y2 r% M
  10. TimHandle.Init.AutoReloadPreload = 0;
    - I" x4 _5 ~) o. j% |
  11. if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)% x; T; Y, i/ R/ r; a  Q
  12. {
    6 d- `" ]  M8 M9 s5 e
  13.     Error_Handler(__FILE__, __LINE__);9 _! b9 h8 X% t6 x5 L
  14. }6 G$ D' G" Y8 ?

  15. 7 Y/ p3 x% S4 V$ R: F
  16. /* 配置定时器PWM输出通道 */
    , n$ C& X+ ?; Q8 Q4 X4 @# u
  17. sConfig.OCMode       = TIM_OCMODE_PWM1;
    ) m; g$ E3 z0 b, T
  18. sConfig.OCPolarity   = TIM_OCPOLARITY_HIGH;
    : I( s! q9 F* W6 G( `0 o; p3 o& ], i$ E
  19. sConfig.OCFastMode   = TIM_OCFAST_DISABLE;
    7 o# S; i. Z! Y+ h
  20. sConfig.OCNPolarity  = TIM_OCNPOLARITY_HIGH;) I  f' Y! p, l
  21. sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;
    9 Y' m! ^$ g0 N( _9 s" m* p( d
  22. sConfig.OCIdleState  = TIM_OCIDLESTATE_RESET;0 S" L  m0 e' K( ~# K6 @/ N3 `5 q
  23. + m  r' E6 w, |. m% v
  24. /* 占空比 */5 V5 v# f8 [6 V) a3 }$ z/ s% ^4 ?
  25. sConfig.Pulse = pulse;
    6 y2 E. N2 L$ o* ]; R2 `! z* J7 t
  26. if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &sConfig, TimChannel[_ucChannel]) != HAL_OK)% I% Q# |: F$ f! n& z
  27. {3 K$ l' w4 e' v# D1 G
  28.     Error_Handler(__FILE__, __LINE__);* U8 h1 ~5 [- E9 |
  29. }
    ' P& R1 `- j# c) N, w' a
  30. 4 ~- `; K4 ~0 Z7 f1 J8 G6 k
  31. /* 启动PWM输出 */7 |) p: l$ s0 k% y1 q% U- ]
  32. if (HAL_TIM_PWM_Start(&TimHandle, TimChannel[_ucChannel]) != HAL_OK)
    3 [# X+ n8 x7 J7 q/ b0 ?
  33. {1 \; S1 u) q' A0 _
  34.         Error_Handler(__FILE__, __LINE__);
    # s) B: R4 O: l/ K& T' t# ?6 K
  35. }
复制代码
) i0 ~7 K0 E) u" j6 C3 n5 v1 L
32.4.6 函数HAL_TIM_IC_Init5 U5 H8 ]. s& u8 j( _' w
函数原型:) g. |4 T) X2 L; F

. c: ^+ O" t/ }5 w  c+ e3 }
  1. HAL_StatusTypeDef HAL_TIM_IC_Init(TIM_HandleTypeDef *htim)
    . p9 u5 l5 _0 c
  2. {
    4 p$ o( _" Q" Y- V7 r/ S  c
  3.   /* 检测形参是否有效 */$ N' B& R5 z: J1 d( q/ d
  4.   if(htim == NULL)/ `/ K$ v  }# S3 z: n* Y
  5.   {$ m- W* X( h# _4 d* l* q
  6.     return HAL_ERROR;- f) @4 j" r! e" V6 X% {
  7.   }
    + ?- U6 O8 M8 ?

  8. 2 [3 x- L- X# g# f! ~
  9.   /* 检测参数 */; A* H+ N/ E- j7 C6 u
  10.   assert_param(IS_TIM_INSTANCE(htim->Instance));! R4 K5 [$ U2 x* w3 L8 r0 M5 {0 I
  11.   assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode));3 K( q6 t% i8 Y( H" l! K6 l, e0 r
  12.   assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision)); - y/ v1 B' n+ @6 W8 P+ @
  13. ) y* Z$ s' z1 R- P
  14.   if(htim->State == HAL_TIM_STATE_RESET)
    ( H5 R: q5 q7 c- u; k
  15.   {
    % F; x7 x' D6 T$ L1 ?
  16. /* 默认取消锁 */
    7 H9 X. t* {* [
  17.     htim->Lock = HAL_UNLOCKED;( B$ M7 E5 `% e; U

  18. - |$ U7 `  m4 h2 `) j9 j. h  E
  19.      /* 初始底层 : GPIO, CLOCK, NVIC 和 DMA */3 P* d/ V5 H/ x8 M, m% ~2 i* ~- ?4 W6 }
  20.     HAL_TIM_IC_MspInit(htim);
    1 Y9 c4 x+ H$ k" @+ M5 g( h
  21.   }
    0 _9 k) W/ O. h2 F3 o
  22. 1 O6 T2 {0 L3 R5 o9 `1 I' s
  23.   /* 设置定时器状态 */
      L, N: t0 C1 p- I) i
  24.   htim->State= HAL_TIM_STATE_BUSY;
    9 x. }: b& M5 M$ |( g4 d+ y
  25. 7 N" F" I3 @! e
  26.   /* 配置定时器为输入捕获模式 */  ) N# Z( x% w3 q
  27.   TIM_Base_SetConfig(htim->Instance, &htim->Init);
    , |8 E0 b# q  X' }$ [( `
  28. " i' ?/ r( x: O9 D3 p# ?: c3 y
  29.   /* 设置定时器状态 */
    : m1 \# |9 `: |! ?5 Q! p9 c
  30.   htim->State= HAL_TIM_STATE_READY;: ?8 U  k0 ]7 d+ A1 d: N
  31. 6 \) V; h3 l; d& K9 e: t8 b
  32.   return HAL_OK;. S) x! l- H+ H: ~& g5 N. c
  33. }
复制代码
. T, O  e5 a$ w
函数描述:
6 u. P6 l  X$ n* \2 g6 W
1 x1 q+ }8 f- {此函数用于定时器输入捕获初始化。9 M* j6 q; D6 W9 U/ r8 A- O
& L1 H9 O, Y( Q( M( s  {
函数参数:
6 U$ @0 K* @# S$ ?7 C6 ?' U" Q$ b4 {* J0 B$ |
  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。7 w* o" N; |2 B% S7 K/ a. e3 l( {: p
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。0 p$ h& i" X: o5 ]% N. w
注意事项:
$ X$ R' W5 t* v4 t6 V& F/ B$ W9 s. S3 |+ ~7 S- g
函数HAL_TIM_IC_MspInit用于初始化定时器的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能,由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
9 i9 y; T5 D- p8 o如果形参htim的结构体成员gState没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量TIM_HandleTypeDef TimHandle。: j) o: ]; Y2 o' M# O3 w
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个HAL_TIM_STATE_RESET  = 0x00U。" `; H: C0 }. F+ p5 W5 ?& x8 F

% L) r; C3 U9 C6 ]& |解决办法有三:$ Z2 Z5 m+ V5 j5 {; g# |2 T
) {. @, [; ]6 u0 r4 V- ]
方法1:用户自己初始定时器和涉及到的GPIO等。
0 J- L7 @5 }  D8 u: S. ^4 M( E! W/ T" @# D& }; w
方法2:定义TIM_HandleTypeDef TimHandle为全局变量。) \; u. |0 h" K6 ~
2 B( g1 H" L- ^7 ]) A* p: x
方法3;下面的方法
  m1 m/ |, F7 c% Y: |7 w8 l# Z4 H+ u1 J0 I5 b
  1. if(HAL_TIM_IC_DeInit(&UartHandle) != HAL_OK)
    9 B9 ~# ~) O5 ]' R
  2. {
    ' u  t/ D; ~, H/ B( h0 y( @3 p
  3.     Error_Handler();
    0 T; N  J6 b7 u* f- q/ q+ b5 J
  4. }  
    ( _  U9 W, P2 Z) z7 ]7 y, z$ `* q
  5. if(HAL_TIM_IC_Init(&UartHandle) != HAL_OK)9 ?; O/ Q) g& O" x: m7 ^. {8 ~
  6. {
    9 N0 R4 ~! R. R* Q3 p
  7.     Error_Handler();% p" e% F- U7 l8 j+ q. V5 ~* [
  8. }
复制代码

' T+ ?1 [6 v4 q32.4.7 函数HAL_TIM_IC_ConfigChannel; W/ K9 `1 q) s9 P: F  x( n3 V
函数原型:
8 o  ?$ l" H& e9 t# U* T- B
0 |) c3 n( \" R, H" u) O  V( b
  1. HAL_StatusTypeDef HAL_TIM_IC_ConfigChannel(TIM_HandleTypeDef *htim, TIM_IC_InitTypeDef* sConfig, uint32_t Channel)
    # d& w/ y! m! ?
  2. {
    8 C9 j+ R/ y6 n$ U- `
  3.   /* 检查参数 */
    ; T6 I/ i8 {4 |! J0 c- @
  4.   assert_param(IS_TIM_CC1_INSTANCE(htim->Instance));
    ' Z  Z" ~9 }, o( }
  5.   assert_param(IS_TIM_IC_POLARITY(sConfig->ICPolarity));
    2 H5 D& b+ `+ ~7 Q: L' X* I
  6.   assert_param(IS_TIM_IC_SELECTION(sConfig->ICSelection));
    ! v) g! i5 q1 `
  7.   assert_param(IS_TIM_IC_PRESCALER(sConfig->ICPrescaler));' Q+ m! P$ c2 i. U0 [$ p' u
  8.   assert_param(IS_TIM_IC_FILTER(sConfig->ICFilter));' |* ?& z/ }% f
  9. $ T! Q% @! ]# C% e
  10.   /* 开锁 */  
    2 r: |6 o3 n5 `/ h
  11.   __HAL_LOCK(htim);+ U6 F2 a( V2 w9 Z  c. E5 c3 A; `
  12. # t' y7 |: T% U- @2 D
  13.   htim->State = HAL_TIM_STATE_BUSY;5 ?( A' x9 {6 }, m& M

  14. 2 g- K9 T5 \4 x$ z
  15.   if (Channel == TIM_CHANNEL_1)# w, y& k1 t; |4 B, a6 y8 d1 k
  16.   {4 `2 z3 ^- t9 A/ B6 Y
  17.     /* 配置输入通道1 */
    + S+ Z# i1 Z& `8 H, }/ M
  18.     TIM_TI1_SetConfig(htim->Instance,
    : h3 I7 E. p* C
  19.                sConfig->ICPolarity,
    * K; J: f5 ^/ K  x1 @, |/ f
  20.                sConfig->ICSelection," m- A! L0 b$ F1 ]
  21.                sConfig->ICFilter);
    3 K" v7 H4 w9 `9 a" \4 @* R/ D

  22. # r: K, p4 `: o7 t% s# G
  23.     /* 清零IC1PSC位 */
    & R# p5 E  }, q# ]2 U% }7 f6 X
  24.     htim->Instance->CCMR1 &= ~TIM_CCMR1_IC1PSC;
    $ J( A" V6 Z. T: \* l

  25. 8 ?2 A" M- I8 X9 G, Q  s9 d% ]
  26.     /* 根据用户配置,设置分频 */# B  ^9 P) \5 D$ z9 ~) T1 A
  27.     htim->Instance->CCMR1 |= sConfig->ICPrescaler;
    9 u# c3 q5 J: G& [6 v7 z' l  W
  28.   }# B: u/ f/ p; E4 d% ?8 z* p" o
  29.   else if (Channel == TIM_CHANNEL_2)' o# G* Y  ^8 k0 ~* _
  30.   {
    ) A0 V" W$ G% w  H) T1 Z0 l
  31. /* 省略 */
    6 `$ J9 z2 x  w! L4 ~) u
  32.   }
    % C/ C0 @, h! u2 V# Q
  33.   else if (Channel == TIM_CHANNEL_3)0 h  `5 C) S$ ?4 A  `; Z9 {" }! |$ \
  34.   {
    $ K$ N' ^, [! e. y- d& L: ?
  35.      /* 省略 */
    ( n; B4 ?& |' C. d
  36.   }
    1 P0 |8 A  j5 N  ]* ?# F
  37.   else
    0 h& r) ^) q) N5 U9 y
  38.   {
    5 L* Z- v! F! h8 x; V" [* c& W3 {
  39.      /* 省略 */
    6 g% L, b) j3 I1 ?' F
  40.   }6 e2 r' S" @, q/ {5 e( y
  41. ( Z- h* t2 i/ S4 @$ W2 ]; J
  42.   htim->State = HAL_TIM_STATE_READY;
    : A; h4 ], {9 G& M
  43. 6 e  o2 I* A( t
  44.   __HAL_UNLOCK(htim);
    ! |' q* u7 K1 `; |+ q2 N/ p

  45. : U2 e& B+ _! X1 ^) ]! h5 v9 q, Y7 z
  46.   return HAL_OK; ! T8 J8 g, I; g2 r
  47. }
复制代码
, _; }( M; `: B$ y6 n
函数描述:' q7 G- E$ p5 }

3 m; I+ [) z/ g# M) E; j# m2 Y6 u此函数用于配置定时器的输入捕获通道。
: C' `0 }0 e! R  L( ]6 [3 y" H4 F/ v  U. l( l; b. C
函数参数:
+ H: [& ^( j8 t9 X2 d
4 L1 Z& r* _  m0 p6 x1 J  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于定时器基本参数配置
& p6 o7 V& u/ P: [8 `, x  第2个参数是TIM_IC_InitTypeDef类型结构体指定变量,用于定时器输出比较参数配置。! y9 f5 U0 Y% x# z3 \( {. Q7 _
  第3个参数是通道设置,支持以下参数:
4 c) D3 ?. X. t# STIM_CHANNEL_1
3 ]3 `9 y6 A" f( i$ v7 D6 F) @$ g& a. H' H4 z7 R
TIM_CHANNEL_2
% ]( r: X) Z/ Z! O' J1 m
! C3 Y* X+ ~: z: r: y1 a7 @5 v/ NTIM_CHANNEL_3
( O9 W6 g# q+ Y( ]( b/ w9 A" o! K$ N! [
TIM_CHANNEL_4* G# e' A% |8 o5 u: q: q) S

+ O6 G& ~0 W$ |& S9 I0 r, J  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
- C" o. j6 K/ v8 Q- `8 ~  G/ ?7 H1 H/ h% c
32.4.8 函数HAL_TIM_IC_Start_IT
% j+ b8 l6 U8 P5 E: t: `/ {. }函数原型:
+ C: g& A3 }0 }. O% n* E  X
. c5 L2 ^* R& C. _
  1. HAL_StatusTypeDef HAL_TIM_IC_Start_IT (TIM_HandleTypeDef *htim, uint32_t Channel)* {; ~* ^! P+ C) W+ ?; G
  2. {
    1 f! K3 r( t: U: p/ L3 P- E& a8 X
  3.   /* 检查参数 */
    ( c5 S% f, Z: W# M8 _
  4.   assert_param(IS_TIM_CCX_INSTANCE(htim->Instance, Channel));. _# @: @! P% u5 W' A; d7 e7 @1 Y. B
  5. # \* A$ ~* Z. g
  6.   switch (Channel)
    6 Y, ?2 `! s  V! p. M
  7.   {$ k8 Q1 Q1 Z. ^) W
  8.     case TIM_CHANNEL_1:7 u" v+ m# E7 i6 e1 N, U+ T
  9.     {       ! U% x) k2 w7 ^/ J, V
  10.       /* 使能CC1(Capture/Compare 1)中断 */# M. O0 ~, i, E: I
  11.       __HAL_TIM_ENABLE_IT(htim, TIM_IT_CC1);2 e! d( F5 Y- Y' A& d7 i
  12.     }  ~' B) I0 x' Z. r  R
  13.     break;. v( C1 s4 a  J7 I

  14. ) F1 Q2 V+ T. h" ~) d- l4 |" O
  15.     case TIM_CHANNEL_2:
    ) y, t" f8 @3 L4 d1 P, t
  16.     {" P2 c. X0 J; G: b% N
  17.    /* 省略 */
    - D  H, c5 D0 K- Q: M0 U/ B$ \
  18.     }
    - z3 ]' ^. M! L/ z4 a) N' x
  19.     break;* t% O: S- G: ?, U# ]

  20. ) w1 @" G9 m$ |  i" H/ o, g
  21.     case TIM_CHANNEL_3:' v6 z1 E% _2 W: x! T3 C7 e
  22.     {2 Q, K9 D& W4 |' U
  23.   /* 省略 */7 Z, [" @+ ^, B* e9 V& E; l
  24.     }6 }- o" \+ x# L1 t9 K9 Z3 ~6 j
  25.     break;
    ) _: q" C3 t, [3 {; M

  26. $ L7 Q- n  [8 p( f
  27.     case TIM_CHANNEL_4:
    1 [( f! Y3 k9 r, J* ]7 Z' ]! J
  28.     {7 ?4 x& g. B/ i( N
  29.   /* 省略 */
    5 u0 [' o3 w. J1 e0 G: u1 g
  30.     }8 y1 }" p* O, K4 G8 D4 ]
  31.     break;! ^" s1 @5 N' R0 ^0 y" j* e
  32. 1 N8 ?& g( @. K
  33.     default:9 }$ R2 T# B% h) N
  34.     break;
    0 _8 O  k- N' _; H9 s- C" X
  35.   }  
    ! F. ?1 k- n+ q( Q, ]8 @9 O8 f7 E% N
  36.   /* 使能输入捕获通道 */3 o  Y" ?+ a2 b! L, Y, |9 ?. F- J
  37.   TIM_CCxChannelCmd(htim->Instance, Channel, TIM_CCx_ENABLE);7 N2 `: z. p7 `) L$ t- n* e" w
  38. $ J0 {' Y5 W; a2 s2 M; P* f/ r3 A
  39.   /* 使能定时器 */% Y5 \9 L" r$ z1 ^9 Y9 }
  40.   __HAL_TIM_ENABLE(htim);  8 [( Y) K+ ^2 j* l5 g( y
  41. 2 U( Q6 k1 x) z6 {, `# a
  42.   /* 返回状态 */
    : r) q& w0 m+ _& p1 b) x1 b5 o
  43.   return HAL_OK;  , }' E! l( d3 M# z+ O
  44. }
复制代码
! l# V- O" a+ a" [
函数描述:
# D4 M2 Y" Y5 c, r. l
& ]0 [& }* `2 U+ A/ G: E此函数用于启动定时器输入捕获模式,采用定时器方式。
( f1 K4 Q, r" o$ s1 x' o9 Y* h; y
7 ?7 g( B# O9 o$ R5 _函数参数:4 N( {% ~2 N/ C: S

- \7 p6 O! {9 r  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。: v6 ]3 V. |* {  z: u
  第2个参数是通道设置,支持以下参数:
0 r5 j( v3 H  q* \8 e7 L2 ETIM_CHANNEL_1
7 ^/ i6 A: }* L& i1 b! P% m- s
; P  T4 \; B/ H" T$ I$ h5 dTIM_CHANNEL_2- ]% v3 S: D  z8 O8 x( q: c" S) J

- m+ `2 K8 a- I( X7 bTIM_CHANNEL_3
; y+ z# b7 C, S+ p6 M" V* ~6 v, d2 Y4 `  }7 c$ O: I+ s# Z# B
TIM_CHANNEL_4# Q* T4 h) [) h; L' S0 @4 T
+ L6 p, z$ P7 x" h) `
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
' \# g, v/ ?5 _8 z9 }
1 Z- r# L2 @# d5 N32.4.9 函数HAL_TIM_OC_Init
$ z" S/ C& B" |函数原型:
$ _  y( V1 z  H0 j" |
& Y6 h' D( {" ~' o( k1 \  Z, }
  1. HAL_StatusTypeDef HAL_TIM_OC_Init(TIM_HandleTypeDef* htim)
    ( b4 h8 o# b' Y% |
  2. {: y8 N) k* G; \6 U, w2 t
  3.   /* 检测形参是否有效 Check */1 v$ L! {$ Y2 _* p0 z7 X
  4.   if(htim == NULL)
    " B* z' W0 M, K; y+ B; I  y6 {
  5.   {/ e2 I' e7 p. R- }, F4 U0 u. J
  6.     return HAL_ERROR;, F/ u, L4 W+ `' T7 A6 ^
  7.   }: w$ Q3 g9 H9 f
  8. # D0 c, a& M+ s! S9 `# N$ G4 p2 g8 z
  9.   /* 检查参数 */1 M$ K$ e* D, o
  10.   assert_param(IS_TIM_INSTANCE(htim->Instance));
    ' I3 V* I9 \0 K
  11.   assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode));- d* [" E% {  d# B0 i0 H8 [0 i0 D2 o
  12.   assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision));
    7 A( Q: F- `9 A" D# M8 j6 B- a
  13. $ b; U' ^2 A! n( n
  14.   if(htim->State == HAL_TIM_STATE_RESET)! ~9 f* x2 U; m
  15.   {
    : `% P4 k' X. U! \
  16. /* 默认取消锁 */1 Y; G: i6 z  E, f$ Z
  17.     htim->Lock = HAL_UNLOCKED;
    3 B8 X% H% u  O) o- J0 v2 [- E
  18. 8 R8 ?9 _, Q' e6 J$ f, _
  19. /* 初始底层 : GPIO, CLOCK, NVIC 和 DMA */# X/ _, `; E8 y- f( R5 _: X) ?
  20.     HAL_TIM_OC_MspInit(htim);
    2 j, w$ z: N, T& @! P
  21.   }
    + R/ d( P6 h* S7 {( c
  22. # C% M0 D/ w5 ~
  23.   /* 设置定时器状态Set the TIM state */* R6 h2 U/ q0 k# v
  24.   htim->State= HAL_TIM_STATE_BUSY;4 E0 v4 W* X- s6 y2 K

  25. + v2 t5 ^: Z6 u' S/ _2 N3 \/ R
  26.   /* 配置定时器为输出比较模式Init the base time for the Output Compare */  4 `2 C! N& k! G* }# \2 N
  27.   TIM_Base_SetConfig(htim->Instance,  &htim->Init);
    - h2 T1 Z4 |% D( O
  28. + ]) ^8 h, `5 P
  29.   /* 设置定时器状态 */: G' C1 r1 V* ?( J+ U
  30.   htim->State= HAL_TIM_STATE_READY;! `3 z( a9 I0 P2 k+ K
  31. / s! p$ d2 k" Y
  32.   return HAL_OK;
    8 e" v3 a1 h, \  n4 N+ m' U& Y# F
  33. }
复制代码

2 f8 z! n- l7 J- u8 O$ y函数描述:
8 S( X" e& D: }/ r2 s- Q( P: e; ^: {: \4 j! {% a# L
此函数用于定时器输出比较初始化。7 I- x$ v7 G  p' Q6 ~7 L1 m
0 i/ ~0 ]: a1 B/ n
函数参数:
& i0 g' i3 I: e- C+ V' D, F. |. K9 L/ ?
  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。
0 t* ]$ n: l' N# L  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
& \. u4 l4 Y2 G/ D2 c注意事项:4 P" {0 @$ X# b; D1 @
1 {  L/ @+ v) Y: T' |8 k0 R
函数HAL_TIM_OC_MspInit用于初始化定时器的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能,由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。/ Z$ N. A' G$ p( R+ e, M9 R
如果形参htim的结构体成员gState没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量TIM_HandleTypeDef TimHandle。
7 K+ K) L0 I  x: ~2 Q; C  J( u& O1 G对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个HAL_TIM_STATE_RESET  = 0x00U。
$ _! O1 N  g3 m) d/ A, m+ V' R# I( [! p  Q
解决办法有三:
" D( X% R4 F; H0 {& N
4 y# P8 q) m5 G1 ~' B# g& M方法1:用户自己初始定时器和涉及到的GPIO等。3 Z, B8 X7 z* g# B

( T# g1 o3 o  u! d1 o9 y) D方法2:定义TIM_HandleTypeDef TimHandle为全局变量。
. n! w% V5 G$ |! e+ V' {
3 Z0 H' k: e& |3 J( m0 _方法3;下面的方法4 Y2 F: q  j' v) X
- |+ s" P9 [' s8 h. q
  1. if(HAL_TIM_OC_DeInit(&UartHandle) != HAL_OK)& P1 i$ |8 R! ^/ H& K& d: s
  2. {2 `+ b. u6 w, ~  {* ^' M
  3.     Error_Handler();
    1 M: o/ y6 @( g, i0 C
  4. }  
    . }! o+ _0 [4 y
  5. if(HAL_TIM_OC_Init(&UartHandle) != HAL_OK)' Q5 a9 ^) h1 P' l; |1 F, i0 h
  6. {
    - ?8 C" p* k, \6 r  F
  7.     Error_Handler();" p3 ]! x5 C0 a: l. y3 i7 [
  8. }
复制代码

  K  B' J) Q/ L9 o7 {" c32.4.10   函数HAL_TIM_OC_ConfigChannel
, [& S( E, i8 M+ Q函数原型:( V( F2 Z4 f7 S% _: r3 ]
, \7 z, l: S" t
  1. HAL_StatusTypeDef HAL_TIM_OC_ConfigChannel(TIM_HandleTypeDef *htim,
    , ~% w" V8 K: X6 o! ?7 l
  2.                                            TIM_OC_InitTypeDef* sConfig,
    / z) d" p; x5 N0 e0 z5 H
  3.                                            uint32_t Channel)2 C, ?' ~1 ^- K8 K2 p. F
  4. {  7 }1 Y% S6 A4 y3 A
  5.   /* Check the parameters */# Q1 A- Y2 ]$ |  O
  6.   assert_param(IS_TIM_CHANNELS(Channel)); - E& c6 O3 a9 k0 H" v7 I
  7.   assert_param(IS_TIM_OC_MODE(sConfig->OCMode));
    : W5 l2 h5 M& g: s; ^% Q4 D: M
  8.   assert_param(IS_TIM_OC_POLARITY(sConfig->OCPolarity));
    - W! h/ g! |. ^. T; G. m

  9. ( q! k. ]9 Q; j0 X4 `: p3 d/ n
  10.   /* Process Locked */
    9 i4 G5 S$ r. {9 d# d
  11.   __HAL_LOCK(htim);   B. ^) E* ~" c9 a
  12. : p- c. y/ K  w
  13.   htim->State = HAL_TIM_STATE_BUSY;
    ' ~' ?5 ?# t1 k% |! M/ j5 o

  14. % _/ s) R& H. A: c1 }
  15.   switch (Channel)
    # Y3 ]0 [! d2 E# O
  16.   {
    4 b7 ^0 k" e9 C" Y4 K
  17.     case TIM_CHANNEL_1:
    * w9 }: g4 K5 _* U% S! U
  18.     {
    - e; K3 G% n  j5 N6 I
  19.       /* 检测参数Check the parameters */
    5 v& M2 `' Q% p1 E7 ?, S- U
  20.       assert_param(IS_TIM_CC1_INSTANCE(htim->Instance));
    % b2 a2 p, f$ d, H
  21. 5 I; [6 y5 T6 s' e- n
  22.      /* 配置定时器输出比较通道1 */
    / n3 G7 a+ \( [! Q
  23.       TIM_OC1_SetConfig(htim->Instance, sConfig);
    , s% {% Y' N* u
  24.     }# S& f# z; }9 c' ~2 K
  25.     break;- h# @# y4 K0 P3 V
  26. " J; y( z* N7 x  X
  27.     case TIM_CHANNEL_2:3 h  L! W, D4 I. e6 K& {
  28.     {; z6 D3 ?, [' l6 f7 l
  29.       /* 省略 */
    ( O, E; P1 `5 l/ `3 V% o& n
  30.     }
    0 u( B- j$ p0 D1 B
  31.     break;8 G) g7 P5 J- u; E
  32. 0 p( ^/ S/ F0 X7 v/ ~  ?
  33.     case TIM_CHANNEL_3:8 U4 U5 m9 N" r0 G9 F3 U, L
  34.     {
    ! M* E4 N6 K. x6 ?
  35.       /* 省略 */
    # ~% W5 R  H) b
  36.     }8 ~/ t( ?& e( z
  37.     break;
    ! S% U$ v% r5 M1 D" ]( r/ R
  38. - }/ [- Q. u7 U, W
  39.     case TIM_CHANNEL_4:
    ! s! l9 s+ a0 g* V. G) W0 X
  40.     {
    + C7 a  S% W9 s' R- G8 V. Y
  41.       /* 省略 */6 U. g3 p3 I% n1 O: ?
  42.     }
    0 G9 v: r. D9 Q
  43.     break;% C: ~. h. _! a  A) I; n1 b' k0 w
  44. 7 u% @: `( E+ [4 P$ n
  45.     case TIM_CHANNEL_5:
    . E$ {8 H' M  M* m
  46.     {* }- M+ ~$ W3 C% X0 H
  47.       /* 省略 */* k9 K  }: J! p$ C2 s
  48.     }0 t5 S; O0 [9 }3 }! s/ m0 R5 m
  49.     break;
    " n) }4 C/ t+ R/ y' s) o& z

  50.   h& a$ f: s4 C  @
  51.     case TIM_CHANNEL_6:
    & a( k2 F) W: u
  52.     {
    - c) X/ @2 T2 O1 D/ r* I* N( n$ O6 t
  53.       /* 省略 */5 l4 s+ G  z. @; A/ U
  54.     }. H  x, E( u0 n! x7 @$ N
  55.     break;' O1 h1 `  U  r! v, V

  56. ) y: I% I: c* |% v* p; u
  57.     default:
    3 S7 w- v% Z( |' @8 {+ _
  58.     break;   
    9 ]( v: w, X2 I7 w
  59.   }
    1 O) a3 C8 X! F# N# P1 Y4 I

  60. - B) M. h1 a% O, [3 ^8 c
  61.   htim->State = HAL_TIM_STATE_READY;8 i, w" C+ @) {, y
  62. : F2 A% e& O$ Z) F
  63.   __HAL_UNLOCK(htim); ) o0 O6 _8 N: F) H1 U# m8 o

  64.   e, ~  ?' p* J) K9 T
  65.   return HAL_OK;7 [  V9 f: a! N9 m
  66. }
复制代码
. x  I( `/ O9 g3 X
函数描述:2 ]: Y0 R4 o$ l0 _; V
4 R  Z' p; N7 O6 ^( D/ M4 v- b
此函数用于初始化串口的基础特性和高级特性。
) e* j9 w0 Z  V: h( a+ j+ G4 g2 g) x1 V: M: I( }, w
函数参数:
% L) ~, l9 K# k5 W. [' r8 L. F" c+ E0 D+ E- V
  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于定时器基本参数配置。' X% J4 X1 n  K
  第2个参数是TIM_OC_InitTypeDef类型结构体指定变量,用于定时器输出比较参数配置。
( Y, U( j6 D3 g9 V& ~  第3个参数是通道设置,支持以下参数:
+ f8 J7 e( J& K6 iTIM_CHANNEL_1
7 s0 t8 Z# _# Z* Q2 x* m; @. m9 J& u* Y% s
TIM_CHANNEL_2$ x& }  d! G( @5 c

0 U/ q& b$ C3 Z/ c! D6 S2 XTIM_CHANNEL_3# t2 y* J( D4 g$ K

- G! ~, E/ q# }8 v3 ?4 sTIM_CHANNEL_4, j' U! Q4 [$ |$ D! C

( z3 S, D0 k6 ~/ A; {4 I3 y6 XTIM_CHANNEL_5
2 ~! G2 w- p9 X8 V0 q0 I7 f
' d3 n; H8 A" T5 G7 h* XTIM_CHANNEL_6
2 w0 K5 n2 A( m9 b( n  ?7 J/ Q
& f. K( l! I/ f1 R$ [  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。9 b; O, r) O2 m/ |
7 R$ i2 p3 N' y9 \! Z
32.4.11   函数HAL_TIM_OC_Start
  d5 P6 @% a/ l4 ?" S. L函数原型:9 C) q" }' M4 m+ g) O
8 v. Y* K: k1 Q& D! `0 r
  1. HAL_StatusTypeDef HAL_TIM_OC_Start(TIM_HandleTypeDef *htim, uint32_t Channel), a5 j4 B$ E- u1 l* p; X7 M  S- N
  2. {
    3 W9 {  O% {0 E  [0 C& y% c
  3.   /* 检查参数 */
    5 B1 m, ~: q1 q) x8 B
  4.   assert_param(IS_TIM_CCX_INSTANCE(htim->Instance, Channel));
    7 s5 F* h/ V9 S5 G) J. C$ z

  5. 3 |7 h  b, Z1 A9 r3 Q1 a- C
  6.   /* 使能输出比较通道 */3 z7 }  g% s4 O- r
  7.   TIM_CCxChannelCmd(htim->Instance, Channel, TIM_CCx_ENABLE);
    9 y$ ~" O" f' g# _) ^8 N7 f, F" M" {

  8. 2 E4 ?0 g5 P( x) _; w5 Z2 C
  9.   if(IS_TIM_BREAK_INSTANCE(htim->Instance) != RESET)    S5 W) U9 O$ w! Y7 W* ^
  10.   {
    ' l3 n% g! z2 R7 H5 X* F
  11.     /* 使能主输出 */! ]7 @0 E& _# Y2 i6 H5 F! _& `( C
  12.     __HAL_TIM_MOE_ENABLE(htim);( S( d) f$ x& i' `
  13.   }+ J9 @, w+ B- ?; y0 I/ p$ E
  14. 4 q7 p9 c8 c$ W1 j, b; i) Y
  15.   /* 使能定时器 */
    ( N4 s6 V0 N. e1 T6 N* y) X
  16.   __HAL_TIM_ENABLE(htim); 8 {+ Z8 S0 u8 z) O; D
  17. ( A' `, e8 T. H0 q" a* ]  E" t8 `
  18.   /* 返回状态 */
    5 t- d/ V  R% {* f
  19.   return HAL_OK;
    9 y0 a9 L+ u, O% M  h
  20. }
复制代码

( h5 \. O0 F+ S; M8 X" }- s4 \函数描述:
+ Q* g6 N& G: T2 ~+ e3 o
8 p  w  P  |/ |9 M5 A/ O! V( k此函数用于启动定时器输出比较模式。
0 a, v8 I  Z' V& g+ ~4 U2 q+ u* @) `. ^4 n
函数参数:6 a. @7 f) p: B- Q8 R
  Q% E6 C$ v1 ^3 `8 G
  第1个参数是TIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。
; Y  [$ x+ B1 {+ s  第2个参数是通道设置,支持以下参数:
* C* ?- C( X8 q( J( _TIM_CHANNEL_1
. D" W& D/ M0 X: a2 ~& G7 {5 x: p( W9 ^1 p  h0 ^! }5 s4 K- y
TIM_CHANNEL_2
) V8 ^  x) S* B% \! m( Z0 ^  w) I  L/ p# H  z5 d
TIM_CHANNEL_3/ E9 c9 ?) V  n1 l

8 {4 \, C% D+ v' h3 P" a5 Z; K$ \( ]TIM_CHANNEL_4
% |) w0 r- y$ N1 F
8 E% F% ?$ H  @6 V4 a  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
" r  D! V. B3 o5 O# _* p/ n8 p
. L+ J3 f9 {$ Y" Y32.5 总结; d6 i4 @5 Y2 l* z! r+ y
本章节就为大家讲解这么多,建议大家将GPIO的驱动源码结合参考手册中的寄存器通读一遍,对于我们后面章节的学习大有裨益。: T7 Z- J! \0 {3 Q* |7 Q6 g. J

* f: _, _, z& }3 y0 ]3 k
$ h& p$ N& ]8 e  O/ e; e2 G/ G, v2 X+ S4 P
收藏 评论0 发布时间:2021-12-21 23:00

举报

0个回答

所属标签

相似分享

官网相关资源

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