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

STM32通用定时器使用详解

[复制链接]
STMCU小助手 发布时间:2021-2-23 09:37
STM32通用定时器使用详解
#1.通用定时器基本介绍

% P' y* ]# D- [& w; U

/ c4 r" ^( q" |# M
※       通用定时器包括TIM2、TIM3、TIM4和TIM5
※       STM32通用定时器是一个通过可编程预分频器驱动的16位自动装载计数器构成。
※       每个定时器都是完全独立的,没有互相共享任何资源。它们可以一起同步操作。
※       定时器可以进行定时器基本定时,输出4路PWM,输入捕获
※       本文详细介绍这三个功能并且利用定时器3并且示例代码使用

6 I, p8 ?1 |( X
#2.开发环境

; i8 A. A% I) T- ^# u& g

5 ~% y$ ~  |  w+ R' \
开发平台:keil5
单片机:STM32F103ZET6
+ }4 t* ~/ A4 f, o: ]6 \
#3.基本定时功能
4 u( Y+ p0 p/ Z. B9 Z! A& T3 J: H
  G% D; ?* G# Y! X( R
## 3.1定时器时钟来源分析
     STM32部分时钟树:
1.1.png
, O# y; v) n' N3 d4 [( y: o! {' L  k
3.1.1 首先我们我们的系统时钟(SYSCLK 72MHz) 经过AHB分频器给APB1外设,但是APB1外设最大的只能到36Mhz,所以必须要系统时钟的二分频。下面又规定了如果APB1预分频系数为1则频率不变,否则频率X2至定时器27,所以定时器27的时钟频率为还是72MHz
1 j, E( ?( a& l( E7 \

. g1 G: O" t& @; \  N" t
3.1.2 分配给我们定时器的时钟是72MHz,我们可以根据自己的需求再设置定时器的分频,设置它的定时值
  1. /*
    $ X/ p8 i1 [, h! f) S3 ^
  2.   * 初始化定时器的时候指定我们分频系数psc,这里是将我们的系统时钟(72MHz)进行分频
    " N; X7 ^4 k- U3 ]& u8 m
  3.   * 然后指定重装载值arr,这个重装载值的意思就是当 我们的定时器的计数值 达到这个arr时,定时器就会重新装载其他值.
    : @! }+ L( G, E1 H1 w
  4.     例如当我们设置定时器为向上计数时,定时器计数的值等于arr之后就会被清0重新计数
    7 u# g8 J& A5 r3 ^8 F$ w. K3 j1 p
  5.   * 定时器计数的值被重装载一次被就是一个更新(Update)- g1 r$ b0 y6 ]! n
  6.   * 计算Update时间公式
    + K& u: B' j9 B1 B
  7.   Tout = ((arr+1)*(psc+1))/Tclk
    7 }' h* B( i1 _9 O2 A
  8.   公式推导详解:$ ]2 K/ ]- e( L) F
  9.     Tclk是定时器时钟源,在这里就是72Mhz
    / p, \8 ]+ P6 M9 P2 u: f9 J
  10.     我们将分配的时钟进行分频,指定分频值为psc,就将我们的Tclk分了psc+1,我们定时器的最终频率就是Tclk/(psc+1) MHz
    - f, w! d  g' x2 b5 ~
  11.     这里的频率的意思就是1s中记 Tclk/(psc+1)M个数 (1M=10的6次方) ,每记一个数的时间为(psc+1)/Tclk ,很好理解频率的倒数是周期,这里每一个数的周期就是(psc+1)/Tclk 秒. e& r/ ^7 x4 C- _- {1 u! N
  12.     然后我们从0记到arr 就是 (arr+1)*(psc+1)/Tclk5 Z, x$ X* L7 d& u7 h
  13.   举例:比如我们设置arr=7199,psc=9999, H8 t8 Z1 s' g+ e4 o$ W% x
  14.   我们将72MHz (1M等于10的6次方) 分成了(9999+1)等于 7200Hz
    2 @: Q% s$ C# O2 h0 H! m
  15.   就是一秒钟记录9000数,每记录一个数就是1/7200秒
    ( q) g5 l" o7 H
  16.   我们这里记录9000个数进入定时器更新(7199+1)*(1/7200)=1s,也就是1s进入一次更新Update3 T+ e; s/ G( C" i
  17. */2 s6 P8 L. F  q) q' Y* _7 c
  18. //简单进行定时器初始化,设置 预装载值 和 分频系数
    * T5 v. f9 J8 ^! [4 W
  19. void MY_TIM3_Init(u16 arr,u16 psc){
    " q5 B! m+ v# g# B0 O$ w
  20.   
    ! I- c  `% f: Y7 X" j) k1 Y* l; o
  21.   //初始化结构体
    & s! p! w6 u0 n1 Y9 Q
  22.   TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    2 p$ t+ n8 o0 E
  23.   
    / Y, o$ h% w. ~2 P% t7 e3 S
  24.   //1.分配时钟) y7 Z7 I0 L8 e6 p, P
  25.   RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);) T  P; M5 i4 ]  |* Y
  26.   - T: ]( f3 Z1 D4 T
  27.   //2.初始化定时器相关配置
    2 T3 ?, k; G, O% Z9 K
  28.   TIM_TimeBaseStructure.TIM_Period = arr;4 Z; k& n; r8 h0 @
  29.   TIM_TimeBaseStructure.TIM_Prescaler = psc;
    # A* Q6 N5 ^8 M4 o7 K" f
  30.   
    & o5 y5 ~- t# p, X. g8 U0 x
  31.   /*在这里说一下这个TIM_ClockDivision 是设置与进行输入捕获相关的分频
    1 {9 E3 G0 k) A
  32.     设置的这个值不会影响定时器的时钟频率,我们一般设置为TIM_CKD_DIV1,也就是不分频*/1 s4 e+ B# F, X0 ?
  33.   TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;: q' ^$ ~% n7 M+ A) T+ m
  34.   TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数( u, o" l1 w0 Q: Q3 U, _
  35.   TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);
    & m2 P9 X8 C8 H0 y
  36.   & q0 p) a, v0 Y& }  U' t6 o( S
  37.   //3.打开定时器4 j- S* r5 r( a. V6 t9 y* G; U
  38.   TIM_Cmd(TIM3,ENABLE);4 s4 T1 F$ }7 n, p  T! u/ _
  39. }
    - g4 R2 l8 S: `6 r! b
  40. / |$ u. F3 p6 z9 D
  41. /****************** 主函数 ********************/0 y8 U3 @( N# Y) f. d0 Q6 x  T+ g; q
  42. //在主函数中我们可以调用初始化# H6 j: Q: c. t9 a$ e
  43. int main(){
    5 L! _$ ?6 c+ ?+ T3 z. q$ N
  44.   //定时器初始化& K, N$ Q8 Q) y4 l; N
  45.   MY_TIM3_Init(7199,9999);% X; ?  G1 I  {; K0 O
  46.   while(1){- M& J* I7 m. ]4 J- m$ t
  47.    
    " J5 |8 f. y0 d# F2 g
  48.     //检测更新标志位( D# B/ y- ]+ F, T- m, Y; T
  49.     if(TIM_GetFlagStatus(TIM3,TIM_IT_Update)){: I4 P  L7 W: k* A
  50.       //清除标志位, D. |- N  }3 a. k( ~
  51.       TIM_ClearFlag(TIM3,TIM_IT_Update);
    0 h5 e) o! Y8 v$ ~' J$ y% k
  52.       //....(每隔一秒执行任务)
    4 a) d( x7 Q% d
  53.     }
    3 k! m8 c. e9 J' t$ ?0 U
  54.    
    2 I4 g* O$ i* p. y& a. e, d
  55.   }
    # t6 k4 K6 w8 _) y: P- v  Z
  56. }
复制代码
. l# ]4 v! f2 P4 L0 \
#4.定时器输出PWM
9 r; y, h; ^/ k& ?8 s
## 4.1基本介绍   
% S* q4 h5 g+ _% @# P: a7 m8 j
  4.1.1PWM是脉冲宽度调制,我们是通过改变脉冲的宽度来达到改变输出电压的效果,本质上就是调节占空比实现的,STM32除了基本定时器(TIM6,TIM7)不能输出PWM以外,其它的定时器都具有输出PWM,其中高级定时器(TIM1和TIM8)还能输出7路PWM,基本定时器(TIM2,TIM3,TIM4,TIM5)也可以输出4路PWM > 输出PWM是很有用的,比如我们可以通过控制电机来玩小车,或者通过输出PWM改变LED的亮度,制造呼吸灯等等

; R- V6 l2 L- n5 H0 t
4.1.2 我们通用定时器能输出PWM的IO口是固定的,虽然我们可以通过重映射可以改变引脚,具体是哪一些IO口我们要通过查阅STM32的参考手册
" l3 P9 a5 M) t8 y% W! h+ A% @
这里涉及到一个重映射的概念,重映射就是管脚的外设功能映射到另一个管脚,但是不是可以随便映射的,具体对应关系参考手册上的管脚说明。这样优点是可以优化电路设计;扩展功能,减少外设芯片资源
  v9 C" V# [) \' h
  1. 时器3,可产生四路的PWM输出,四个通道分别对应的引脚情况如下
    ! @, A5 q" R3 H% ?, n, y0 t- y" b
  2.   TIM3_CH1,TIM3_CH2,TIM3_CH3,TIM3_CH4
    1 V- a$ _6 `. V3 ~5 s/ y( |" j
  3.   没有重映像的对应情况:
    ) n2 K* u$ v3 Q* d
  4.   PA6,PA7,PB0,PB1/ r  w# x3 ]  C. G
  5.   部分重映像:9 y3 _* J: H) ~, n$ a8 o
  6.   PB4,PB5,PB0,PB1
    ; @; J  M- G0 x3 P5 d. c% r1 J
  7.   完全重映像:: c! g, |/ `2 I7 J% M# y
  8.   PC6,PC7,PC8,PC9  7 e: e/ k+ d- |
  9. 0 ^# q0 N% o& b
  10.   当我们的IO口不仅仅是做普通的输入输出使用的时候,作为别的外设(AD,串口,定时器等)的特定功能引脚,就需要开启外设.' `* A7 q/ F8 A6 y! U: m7 E# [7 _. n
  11.   这里我们还需要开启APB2外设上的复用时钟AFIO,同时IO口采用的是复用输出!9 X9 m9 L1 Y8 X% o& D; ?$ q) o8 V

  12. 4 z7 q. Y7 N$ {7 c* f
  13.   我们这里是没有使用重映射功能.
    % \: H' R+ G) ^. h* F
  14. */8 i: H/ Y& z& h+ P7 B5 w
  15. // 宏定义
    1 C3 z8 w* T) y9 ]6 M6 d* ?( R
  16. //判断当前是处于哪一种模式,以便于我们初始化IO口9 f; l9 J/ i! h
  17. #define NO_REAMP   04 k1 i+ g3 O7 s2 e6 N: j
  18. #define PART_REAMP 1* E2 X! a3 C0 t0 _# f* s9 C$ _- `- M
  19. #define FULL_REAMP 2
    % `8 y% }8 l; R& ^
  20. 0 o; ], `3 J0 q0 p
  21. // ---> 这里是需要制定的参数" z+ D: e: Y: p6 G' U9 F

  22. 3 D4 i8 c& u0 e7 o+ @# w
  23. //指定这里的 当前的模式,我们给她默认指定是 没有重映射' A& G1 T5 G! S
  24. #define CURRENT_MODE NO_REAMP
    ) f% d7 d5 k( {5 s

  25. ( a% A* I; G2 x: r
  26. //*************根据当前模式初始化IO口 函数
    ! Z% C: e$ G2 x) l2 f
  27. void MY_TIM3_GPIO_Init(void){! |( _' l- X9 z4 T6 O
  28.   
    # j( G8 r! Z. ?" X! b5 `# {
  29.   GPIO_InitTypeDef   GPIO_InitStructure;1 y8 S' u6 `* N3 {
  30.   % g' M, L# {$ U+ K, w0 ]
  31.   //1.开启AFIO时钟
    & C# Z( @5 O5 ^+ R$ n& P
  32.   RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
    ' w% ?% V; {* [
  33.   
    ' N8 a+ i! Q7 }0 s
  34.   //2. 根据当前的重映像的模式 配置时钟 和 初始化相关引脚
    0 W0 W6 g1 q" }' K9 f5 ~
  35.   switch(CURRENT_MODE){
    * r. t3 C1 s) T
  36.     $ U7 y# c% h8 _+ [
  37.     //2.1 如果没有重映射
    3 E3 z! {3 N& z" f+ U
  38.     case NO_REAMP:{
    2 ^$ w. x, k/ l  w; c
  39.       : S% z+ ^( t! }/ R% ]
  40.       // 时钟分配
    5 L8 K! V5 r( W) ?; J- {0 G
  41.       RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,ENABLE);
    1 B' l% B6 E# s- D3 z2 p
  42.       // 初始化IO口
    - Y, T# T9 c2 Y1 m
  43.       GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    9 c% ^, ]- \% L
  44.       GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;2 J" W  A' x+ U" l1 x
  45.       GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
    0 I6 k: n! ^% b2 _) `) w/ ~1 P
  46.       GPIO_Init(GPIOA,&GPIO_InitStructure);: k7 y. _* c) ?+ D" O/ l# q
  47.       GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;
    + j) m2 @% j* y. z% J* j' K
  48.       GPIO_Init(GPIOB,&GPIO_InitStructure);* h! V# F0 r5 s0 e; ~, j  s$ A( D
  49.       
    8 Q* U  z) N) `. J# ?
  50.       break;' {8 C" X6 _( @# Y" _, a
  51.     }
    , L) \' o8 O5 U( q& q$ Q
  52.     //2.2 部分重映射7 r2 G+ [7 n" v* W
  53.     case PART_REAMP:{) z. E, R! @' j, @1 b6 V) S
  54.       9 V% {  ^6 F  D+ p% E$ Q9 v$ m
  55.       // 时钟分配
    5 t1 k. _5 W$ l) a8 ]' X0 O
  56.       RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
    7 d2 h# w( e3 }8 O, ^0 @
  57.       // 初始化IO口+ g9 ?- R; B9 T! S1 t# O6 J
  58.       GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;. ~0 z* ]+ i& {9 y2 H
  59.       GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;+ C) {  S/ h+ Y1 q
  60.       GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_4|GPIO_Pin_5;! h9 ?0 r- Q# f- L% Q* P! G
  61.       GPIO_Init(GPIOB,&GPIO_InitStructure);# m4 p! f5 f$ a. q
  62.       
    1 {  }! u% r& q! Y& f5 a
  63.       break;
    ; q' }- }& }/ d! K4 ]0 o$ T8 _, Q
  64.     }
    0 O9 c% T( w- p
  65.     //2.3 全映射- F( {& }# ~1 k/ }
  66.     case FULL_REAMP:{
    ' A! P" `* N! _0 W) ^7 l% U5 \
  67.       
    " d/ n' P: g! Q! D6 n; R
  68.       // 时钟分配7 i  [. G6 w5 ^
  69.       RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);& d2 K+ x2 t2 R/ i
  70.       // 初始化IO口7 v" y. O1 n* C, Z! `
  71.       GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;) m8 v9 s+ ~4 o9 U
  72.       GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;$ V8 F8 ?  s' }& G) N- z
  73.       GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9;! K6 V8 o/ D/ N3 d& H+ X# N& ]
  74.       GPIO_Init(GPIOB,&GPIO_InitStructure);/ e0 k4 ^& B0 s1 R" c  k( a  P9 P
  75.       ! P1 o; Y. y4 T" V1 |
  76.       break;
    ' a, `) g5 v- l! u
  77.     }1 y" U" x+ n2 j6 p- V3 I
  78.     default:break;
    ! c# w, ]1 a$ G* t  V& P
  79.   }  
    * h2 t6 D/ p. O; |9 ?1 a3 F* [* b
  80. }2 y8 L- _5 @, M0 h. Z  e
  81. 0 |# x5 w' c! T# c, j  o; D9 j
  82. //***************** 定时器PWM输出初始化函数0 \8 v5 I& M! N, U
  83. void MY_TIM3_PWM_Init(u16 arr,u16 psc){
    5 k) l' S/ b6 u* ?, j& i
  84.   / G. g4 g$ E8 p7 f
  85.   //初始化结构体
    ; B: p) D2 R1 Q- q
  86.   TIM_OCInitTypeDef TIM_OCInitstrcuture;
    $ ?7 y5 w+ w+ Y% r! q2 `. a
  87.   / E- R) h% c# }) [- M! G
  88.   //1.初始化定时器 和 相关的IO口
    ( I& _- a9 N# Z
  89.   MY_TIM3_Init(arr,psc);
    0 F% Z* u  u: b, k  X
  90.   MY_TIM3_GPIO_Init();/ I9 z  n" t! d
  91.   
    5 d3 Z" B* T+ A1 h
  92.   //2.初始化PWM的模式
    % c' w* v+ X/ ~- r, {4 b
  93.   2 o' l# u' N8 q
  94.   /**0 \! ^1 d! O: f) R
  95.   选择PWM模式:& F, U' T+ O4 h
  96.     PWM1模式:
    6 p4 L4 i5 p9 Z# }8 o
  97.       向上计数时,当我们 当前的 计数值 小于我们的设置阈值为有效电平,否则为无效电平,向下计数时与向上计数时相反
    7 o5 m( R0 q; W9 N% ^4 W4 t
  98.     PWM2模式:9 \" ^3 C: U# i- s2 O+ X
  99.       与PWM1模式向上向下计数时完全相反  [! O7 R: O0 v- I
  100.   *// l, q4 f$ R2 o% e9 c  ~, x
  101.   TIM_OCInitstrcuture.TIM_OCMode = TIM_OCMode_PWM1;
    & D, H' |& S0 a# p
  102.   TIM_OCInitstrcuture.TIM_OutputState = TIM_OutputState_Enable;
    ' V9 V3 t9 ?2 m# ~0 Q" p
  103.   TIM_OCInitstrcuture.TIM_OCPolarity = TIM_OCPolarity_High;   //输出电平为高,也就是有效电平为高
    . i( c. m; ?/ n: p" T( ?
  104.   TIM_OC1Init(TIM3,&TIM_OCInitstrcuture);            //这里是设置利用通道1输出* {' ~+ b$ U# `6 r
  105.   # @9 x' D  J4 |* C
  106.   //这里只初始化通道1,我们可以根据自己需求初始化其它通道
    - o5 ?1 V% n! O. f+ {
  107.   : s- q0 K- x* j9 J3 L
  108. //  TIM_OC2Init(TIM3,&TIM_OCInitstrcuture);+ k, \0 T$ `1 ^6 E% V) z5 @5 S
  109. //  TIM_OC3Init(TIM3,&TIM_OCInitstrcuture);# V' l, c6 h, R0 K3 O2 \) L
  110. //  TIM_OC4Init(TIM3,&TIM_OCInitstrcuture);
    . Z7 u3 Y; S9 _) ~  _
  111. 3 e( ~! O2 y4 E" z9 [
  112.   TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能预装载寄存器
      E* R/ E* `9 K8 X( q  R! u# `
  113. }
    / J3 P/ d9 ]  ?( Q# E5 K4 j
  114. ! S. z" }& Z: `: A: W4 ~1 @" g( B; K
  115. //*********************主函数调用
    " W$ R8 N& _6 ^# b# s( r& ~) p+ A. Q
  116. int main(){
    ; ?7 ?% v1 c& F. F6 j7 M
  117.   
    . G6 g3 Z) X. _, {0 F& e0 d
  118.   //因为我们单片机引脚输出电压3.3V左右,我们设置预装载值为330/ e. P0 g9 q+ y0 q( {; O4 y
  119.   MY_TIM3_PWM_Init(330,0);8 ?+ S+ M* c& y- y# t
  120.   : F( L, _. U5 _9 ?& `
  121.   //我们初始化的时候选择的是PWM1模式,当计数值小于我们的设定值100时为有效电平,这里是高电平
    # j$ |! d: z- K/ @! i
  122.   //所以对于的1通道(PA6)电压是大概就是 3.3 * (100/330) = 1V 左右,我们可以用万用表测量5 g" d9 t0 h* `# u- N( U' {
  123.   TIM_SetCompare1(TIM3,100);9 W$ }7 g& S* {! m
  124.   7 R- }6 x* J! E6 b
  125.   while(1);
复制代码

, k/ ]1 {/ g; ~0 J! P  T7 y# h9 P
#5.定时器输入捕获
- j7 l' t; \5 k5 k) ^& Z9 ~
## 5.1基本介绍

/ B# ^% o+ `3 [3 W* N) a4 j3 W
※       上面介绍了定时器的四路通道可以输出PWM,同样的我们也可以捕获该定时器这四路通道上的边沿状态(上升沿,下降沿)

8 t3 d1 p: M% l+ _
※       由此可见基本定时器也不能进行输入捕获,没有思路通道

& R1 l7 }6 t& @3 V6 B
我们可以通过输入捕获的来测量高电平脉宽时间,首先捕获到高电平,记录下改时间,然后切换为捕获低电平,得到时间

, G5 v9 z2 i% H* C& V2 V' j
## 5.2开发步骤
###  输入捕获 (捕获边沿信号,上升沿和下降沿)
   首先我们需要以一定的频率检测电平的跳变,然后对部分跳变(也就是部分输入的波形)进行过滤------ 这就是定时器里面的滤波器的任务
7 T- i, g7 g5 W0 G# N, a% F. Y: _+ d- C
1.      指定输入滤波器时钟频率,首先是系统时钟分给定时器72Mhz,我们首先初始化定时器的时候指定了TIM_TimeBaseStructure.TIM_ClockDivision= TIM_CKD_DIV1; 没有分频,输入给滤波器的时钟频率还是72MHz,TIM_ClockDivision也可以指定为2分频或者4分频

( k, J. x' B7 q5 N
2.      波形过滤(TIM_ICFilter),这里有一个指定过滤器的参数(参考芯片手册),例如我们设置参数为0101(二进制),采样频率(fsampling)为 滤波器频率/2 = 36Mhz,N=8.当检测到一个上升沿的时候,再以fsampling频率连续8次检测到高电平才确认是一个有效的上升沿,这样可以滤除那些高电平脉宽低于8个采样周期的脉冲信号,从而达到滤高频波的效果。
, l" a3 t8 f# }
1.2.png

3 A/ C- f0 r9 X# ], p3 X7 D
3.      配置输入分频(TIM_ICPrescaler),如果我们设置不分频,一个边沿(上升沿或者下降沿)就触发一次捕获,二分频就是两次边沿触发捕获,这里这个分频可以为1,2,4,8

7 b7 C6 g; o7 I) S! d8 h" q
  1. //定时器输入捕获初始化! R; v( m7 U( A6 Q( P0 K7 o8 Q$ @3 g
  2. void MY_TIM3_Cap_Init(u16 arr,u16 psc){
    % T$ Y5 y6 ~* I7 X/ P& O, a

  3. 7 L% d( T) Q& Z) `& |. c
  4.   //初始化结构体4 }. S1 S. }9 s& g$ ^
  5.   TIM_ICInitTypeDef TIM_ICInitStructure;
    . ?4 M- E8 m1 [- U( w, ~8 I
  6.   
    ) Y" U9 @( h- b4 d9 S
  7.   //1.初始化定时器 和 相关的IO口
    % d" ^8 L. h+ D2 S7 P
  8.   MY_TIM3_Init(arr,psc);
    ! t9 I9 |. N- a* d/ Q7 C

  9. " ?7 r3 Z" i6 w
  10.   //这里的IO口根据自己需求改成输入,我这改成下拉输入,具体代码就不展现了
    . m5 x; `% b3 S/ q9 Y  `
  11.   MY_TIM3_GPIO_Init();
    : k1 C( e, u! A' t  b2 [2 N
  12.   / ?, F2 c# |( T" M! d3 y
  13.   //2.初始化定时器输入捕获& }; G2 W5 ~2 ?
  14.   TIM_ICInitStructure.TIM_Channel = TIM_Channel_1 ; // 设置输入捕获的通道
    * Q3 @: x% c, s
  15.   , r$ l3 t" |4 Q% b  r& M
  16.   //不使用过滤器,假设我们想使用,例如上述举例使用0101
    ! p3 R' w7 V% d' m7 f. m
  17.   //我们就给TIM_ICFilter  = 0x05 ,(0000 0101),根据上表可以知道这个值范围(0x00~0x0F)/ F( a* m* {/ H2 B6 t  t1 e+ l* e
  18.   TIM_ICInitStructure.TIM_ICFilter = 0x00;, P+ C, v  g5 Y1 n
  19.   ( l6 Q3 F6 a  ^' f+ p8 V
  20.   TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获  N* e* ?% A/ y1 {  h: {2 [
  21.   TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;    //配置输入分频,这里不分频,1次检测到边沿信号就发生捕获
    1 f* \1 X8 q3 ]& P# ]3 a0 F+ j

  22. 9 o' \* ~# h  I6 \) r, S$ F
  23.   /*
    7 U5 v, r! v$ O) N
  24.     这里说一下定时器通道可以进行交叉捕获,通道1捕获通道2引脚上的边沿信号,通道2捕获通道1引脚,通道3可以捕获通道4对应引脚,...
    & T! ^6 p* X/ y2 Z. {0 ?
  25.     但是只能相邻一对可以相互捕获,例如通道2不能捕获通道3引脚边沿信号! y5 W# ]* z1 u: w% B' K
  26.     TIM_ICSelection_DirectTI 表示直接捕获,通道1对应通道1引脚,通道2对应通道2引脚
      E& E& S2 Y) J( R$ R3 ~, J5 `$ k1 P
  27.     TIM_ICSelection_IndirectTI 表示进行交叉捕获
    $ ~2 ^2 U. z( t# k
  28.   */4 d  D1 P* m' M: Q/ y& z1 v: s6 O  h
  29.   TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射捕获对应通道的引脚
    7 I5 m) D# N+ {* p" k8 j8 J& G. N
  30.   TIM_ICInit(TIM3,&TIM_ICInitStructure);                          , t% q5 e; L- _1 Q9 i8 ~
  31.   " W4 G) j, J& ^. N6 K
  32. }
    3 r* k7 {/ D7 f5 U# y* e. p5 x
  33. //****************主函数  e5 j  Y) y% j3 B; l  W
  34. int main(){/ H! T  Q' G' b" m: K' n) R9 `
  35.   //初始化输入捕获$ u7 y$ k( Z/ @
  36.   MY_TIM3_Cap_Init(1000,0);4 d, n& z% d9 l: j$ ~
  37.   
    7 S7 Q( \  l5 \: C
  38.   while(1){; u2 z- p. b' f! @0 D9 Q! T% |, ~0 _0 ?
  39.     //检测是否捕获到上升沿3 I/ r& m6 J, Z; v6 `$ v
  40.     if(TIM_GetFlagStatus(TIM3,TIM_IT_CC1)){# |: R$ @# X% ^- R
  41.       TIM_ClearFlag(TIM3,TIM_IT_CC1);. A; ~$ z; a1 S  m3 n$ p
  42.       //捕获到上升沿之后的任务...# l7 }, q  \5 Z6 c0 c. m( b
  43.       //一般测量高电平脉宽,我们可以先捕获上升沿再捕获下降沿" S" ~" @* F& {
  44.       //TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); 修改为下降沿捕获
    # e% X0 z! P1 ?& m1 `" e
  45.     }
    ' ~# S( ?7 G  Y" [4 j2 @
  46.     " R& }' G5 X8 ?. X* w
  47.   }4 j9 j; H: i& p1 _6 H. v4 I4 h- k/ l
  48. }
复制代码
+ z# v- f' G% J
" b* `! C# X& U! n& [
#6.定时器中断

7 c3 c5 S" o3 a: N4 x' A& J& k, x
1.谈及到中断,我们就必须涉及到NVIC,具体关于NVIC请参考我的另外一篇,这里是直接使用,我们使能定时器3中断并且配置完抢占优先级和响应优先级之后,再在主函数中使能其更新中断和输入捕获中断
1 y3 e- w4 e( u
  1. //使能更新中断和输入捕获通道1的中断5 l4 C  _- Z; g' Z% ]+ t& Z, Y
  2. TIM_ITConfig(TIM3,TIM_IT_Update|TIM_IT_CC1,ENABLE);
复制代码
- r5 G* @/ s" P$ G! t4 l0 [) @

' A) L2 S; u! w9 L0 a
2.我们使用中断的一个主要目的就是能够及时处理信息,不用在主函数的while循环里面等待

9 D$ o: D' [3 K) w/ p( x. o% S$ P0 i
  1. //定时器3的中断处理函数
    + I2 R% u% @9 f8 L/ n8 h! G, C
  2. void TIM3_IRQHandler(void){
    * `  a! I7 B  c- L( M1 r
  3.   2 J- S2 N; b: ]9 l) u+ X
  4.   //1.判断是什么中断% p2 k/ c% t' B/ p
  5.   ; n% R; r; p3 C
  6.   // 1.1定时器更新中断
    + u! B  J5 C( R% t* `
  7.   if(TIM_GetITStatus(TIM3,TIM_IT_Update)){
      X) E5 z- ]0 E) M9 t, ^
  8.     //...处理定时器更新之后任务$ O6 ]: X' z# C' n) O
  9.   }+ C' E% l& c, u
  10.   // 1.2如果是定时器 通道1的捕获中断
      Q, O  \( y: ]) U) S2 d* ?3 t7 K
  11.   else if( TIM_GetITStatus(TIM3,TIM_IT_CC1) ){
      f$ i6 m% }6 C7 q: C3 c# J
  12.       //处理输入捕获之后的任务" G! c7 `" {" h0 \9 X4 z0 F9 a
  13.       //TIM_OC1PolarityConfig(TIM3,TIM_ICPolarity_Falling);更改为下降沿捕获5 `+ d, D3 s0 d) o+ f5 C+ n
  14.   }
    * _  J7 D' L  U) R" e$ d
  15.   8 C" H2 \( T' A' t
  16.   //2.最后将中断标志位都清理掉; |& X  Z+ ^# N+ o6 H7 C' S
  17.   TIM_ClearITPendingBit(TIM3,TIM_IT_Update|TIM_IT_CC1);! _8 W8 @9 r5 z4 h* t( N
  18. }
复制代码

5 [6 Q9 h! N5 e4 \; `
6 w6 e1 T7 R1 ?% y. S: c
文章出处: 智能车杂谈

- A9 z$ l5 K# @; {" |5 x( x& t
收藏 1 评论0 发布时间:2021-2-23 09:37

举报

0个回答

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版