|
STM32通用定时器使用详解 #1.通用定时器基本介绍 & i$ s3 i* S" K4 r" H. d W* [! S6 @
. y0 _7 ]3 i3 H4 k& h7 s- p1 ?- E" P" a※ 通用定时器包括TIM2、TIM3、TIM4和TIM5 ※ STM32通用定时器是一个通过可编程预分频器驱动的16位自动装载计数器构成。 ※ 每个定时器都是完全独立的,没有互相共享任何资源。它们可以一起同步操作。 ※ 定时器可以进行定时器基本定时,输出4路PWM,输入捕获 ※ 本文详细介绍这三个功能并且利用定时器3并且示例代码使用 6 `1 d# x1 G7 x B! q# I
#2.开发环境
" Y7 U+ O# Q# B* o' A) b% p& F 9 [& Q5 y- C: s, d0 Z. U/ a4 y5 |) V
开发平台:keil5 单片机:STM32F103ZET6 9 n& r0 D- c1 A! X
#3.基本定时功能 ! X+ c. q. S/ t8 X; s- U
- f0 j: d) ]; Y4 Y
## 3.1定时器时钟来源分析 STM32部分时钟树: 1 s8 ]1 E7 ^" _, U" p
3.1.1 首先我们我们的系统时钟(SYSCLK 72MHz) 经过AHB分频器给APB1外设,但是APB1外设最大的只能到36Mhz,所以必须要系统时钟的二分频。下面又规定了如果APB1预分频系数为1则频率不变,否则频率X2至定时器27,所以定时器27的时钟频率为还是72MHz
9 k- ^3 b. J# N m
" X: z) h; C5 a2 J: p 3.1.2 分配给我们定时器的时钟是72MHz,我们可以根据自己的需求再设置定时器的分频,设置它的定时值 - /*
o d4 M3 j8 Q: p6 O0 j$ k - * 初始化定时器的时候指定我们分频系数psc,这里是将我们的系统时钟(72MHz)进行分频4 _9 f8 Q, N* T
- * 然后指定重装载值arr,这个重装载值的意思就是当 我们的定时器的计数值 达到这个arr时,定时器就会重新装载其他值.
0 u4 a2 S( ~+ i+ j/ ] - 例如当我们设置定时器为向上计数时,定时器计数的值等于arr之后就会被清0重新计数+ m1 E) K' G: {0 y* I0 u
- * 定时器计数的值被重装载一次被就是一个更新(Update)
8 M3 v5 o" z( ]& Y% B4 q4 M' z - * 计算Update时间公式
+ A/ Q" B" Q( @1 ? - Tout = ((arr+1)*(psc+1))/Tclk1 [' X4 `# W% J! l8 B
- 公式推导详解:
3 S) r: J4 [6 t; d$ B3 Z( v - Tclk是定时器时钟源,在这里就是72Mhz : Y" m! J6 j8 d2 C v
- 我们将分配的时钟进行分频,指定分频值为psc,就将我们的Tclk分了psc+1,我们定时器的最终频率就是Tclk/(psc+1) MHz) d. d$ o. G! v% X, T% X. h
- 这里的频率的意思就是1s中记 Tclk/(psc+1)M个数 (1M=10的6次方) ,每记一个数的时间为(psc+1)/Tclk ,很好理解频率的倒数是周期,这里每一个数的周期就是(psc+1)/Tclk 秒
2 @& O; ?2 ~' T0 L( P) Q' B6 N - 然后我们从0记到arr 就是 (arr+1)*(psc+1)/Tclk
/ }$ F, G. f2 y4 Q% O9 {. s - 举例:比如我们设置arr=7199,psc=9999
9 M& j4 a- Z; T, u, ` - 我们将72MHz (1M等于10的6次方) 分成了(9999+1)等于 7200Hz
& }+ _# e& s8 z - 就是一秒钟记录9000数,每记录一个数就是1/7200秒
( T7 B' d. ?9 S( R) r1 X, l6 S - 我们这里记录9000个数进入定时器更新(7199+1)*(1/7200)=1s,也就是1s进入一次更新Update
& i0 `3 @' N, z6 |4 ] - */
2 T3 H) u* X" d4 H7 ]" ~# U% j0 t - //简单进行定时器初始化,设置 预装载值 和 分频系数
" \+ C' R4 ^7 j4 T - void MY_TIM3_Init(u16 arr,u16 psc){$ i) b$ _ m6 M5 |' c
- 4 ~" ^0 I! X Y O$ m( O
- //初始化结构体
, G! v+ G2 T7 l: r0 w# M - TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;- I ]0 ~) v, ~; [# |& p
-
9 R, z! i/ |3 ~* c - //1.分配时钟
: V1 N! ^9 r# a9 _" R - RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
6 K R* w9 D5 N/ ? -
% ?' u# J& p/ g/ Y0 x - //2.初始化定时器相关配置
4 v/ c2 b2 H( J, X - TIM_TimeBaseStructure.TIM_Period = arr;
" T* [7 E7 M$ D& z - TIM_TimeBaseStructure.TIM_Prescaler = psc; k) ^ w1 G9 s+ v1 {% J7 e
- ; d# t7 c# T! W/ I0 l
- /*在这里说一下这个TIM_ClockDivision 是设置与进行输入捕获相关的分频+ P: ]/ V. e% |( F4 N, b) x
- 设置的这个值不会影响定时器的时钟频率,我们一般设置为TIM_CKD_DIV1,也就是不分频*/
0 b! G5 Q! P+ W - TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
. p7 X1 h3 r: |4 U3 q8 \9 M - TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
. P2 y6 C! m+ _/ q! M - TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);
6 ]. X: G( M' O( l$ p- z -
! r8 ~/ z7 o- X6 d9 @* b- C6 O+ Z) O - //3.打开定时器6 o7 C4 k* x$ K/ ?$ e8 A
- TIM_Cmd(TIM3,ENABLE);
% X% A$ h9 t* e4 K - }2 J: ?& [6 C- A8 [1 G* K0 s0 M
" b( p9 ]" ~: }9 v( y- /****************** 主函数 ********************/; ^' x7 J7 k& V6 [9 G
- //在主函数中我们可以调用初始化/ Z6 V6 T* ~/ k: {" |3 V
- int main(){
" z% [! M# h! a; ~! C. m; w) d - //定时器初始化
Q2 j4 R r( m4 c H0 L - MY_TIM3_Init(7199,9999);) y8 T' x+ F2 ?5 c( Z
- while(1){1 A$ S4 [ D% a4 z( ]) w
- 5 r0 G; r0 e) W8 R' ^8 h0 L
- //检测更新标志位
7 ?. q( |3 u5 f3 X, R - if(TIM_GetFlagStatus(TIM3,TIM_IT_Update)){6 U7 x' F& K% i {: Z! S7 `. I
- //清除标志位
) Q) F5 O* m7 {1 D3 `5 n - TIM_ClearFlag(TIM3,TIM_IT_Update);
7 ~( x3 ?0 E3 C# | - //....(每隔一秒执行任务)* j% Q! z! L$ ^' H- I
- }. J, p8 L4 T( x8 ]
- / D) N# M( T; U4 u+ M8 ?
- }/ t' A3 \+ Q9 N- Y# X
- }
复制代码
/ ^7 O6 `: X6 \4 h1 ?& V#4.定时器输出PWM
+ q1 x- x" R7 f/ t
## 4.1基本介绍 / U, z1 [" _; w
4.1.1PWM是脉冲宽度调制,我们是通过改变脉冲的宽度来达到改变输出电压的效果,本质上就是调节占空比实现的,STM32除了基本定时器(TIM6,TIM7)不能输出PWM以外,其它的定时器都具有输出PWM,其中高级定时器(TIM1和TIM8)还能输出7路PWM,基本定时器(TIM2,TIM3,TIM4,TIM5)也可以输出4路PWM > 输出PWM是很有用的,比如我们可以通过控制电机来玩小车,或者通过输出PWM改变LED的亮度,制造呼吸灯等等
8 A6 j/ @! g; T+ H, A9 ] 4.1.2 我们通用定时器能输出PWM的IO口是固定的,虽然我们可以通过重映射可以改变引脚,具体是哪一些IO口我们要通过查阅STM32的参考手册
0 N. F2 F* {- n5 B' x这里涉及到一个重映射的概念,重映射就是管脚的外设功能映射到另一个管脚,但是不是可以随便映射的,具体对应关系参考手册上的管脚说明。这样优点是可以优化电路设计;扩展功能,减少外设芯片资源
e, r7 J$ `2 W0 I+ s$ I+ h) F1 e6 v- 时器3,可产生四路的PWM输出,四个通道分别对应的引脚情况如下( F* s. c7 z% U
- TIM3_CH1,TIM3_CH2,TIM3_CH3,TIM3_CH4' k, e; v. j. |1 p1 @& f* F
- 没有重映像的对应情况:' v4 b8 u/ f, h: O
- PA6,PA7,PB0,PB1
( h( X$ x1 p# c' q: Y# q" y - 部分重映像:
# Q8 M2 Q+ o6 ]2 I+ d/ e7 q - PB4,PB5,PB0,PB10 h& Q8 U. W M" @# U$ U5 C
- 完全重映像:
3 P* j6 L6 p& R4 d+ }8 J; D2 @ - PC6,PC7,PC8,PC9 5 X3 _' `+ R/ P4 q n6 Y, Q1 s0 m. G
- ( x& Y2 ~7 W* l6 p1 v* h
- 当我们的IO口不仅仅是做普通的输入输出使用的时候,作为别的外设(AD,串口,定时器等)的特定功能引脚,就需要开启外设.! ?+ z0 {* S0 o# U
- 这里我们还需要开启APB2外设上的复用时钟AFIO,同时IO口采用的是复用输出!# A, I; [! D! T$ t6 O2 V0 T- H! v( K
* V0 Y4 A Z8 C* `- 我们这里是没有使用重映射功能.! v7 t4 B( z# Q" n& l3 U$ j: T! t
- */
/ O1 ]( _3 j o. R5 F; b2 q+ }' N - // 宏定义
, p7 ?5 R. k: n* ~$ x# J4 l* A+ ^ - //判断当前是处于哪一种模式,以便于我们初始化IO口
9 p: h7 q& C* w' }8 z4 p4 k( y - #define NO_REAMP 06 C' S+ b7 q9 F" V
- #define PART_REAMP 1+ G- H6 t; `4 q; `! ^/ g( G
- #define FULL_REAMP 2
7 B: O" d( \8 z2 w3 C$ f5 ~
( ] D$ D- q9 d4 ^- // ---> 这里是需要制定的参数
) T0 \1 ^% h/ B# S" w" K - " [7 U A; O& I
- //指定这里的 当前的模式,我们给她默认指定是 没有重映射
& p% Z Y4 Z0 r4 l9 \; L - #define CURRENT_MODE NO_REAMP 6 S9 b: v2 D. l, W/ ~' \ b
2 X# V" N9 Q9 I; K1 O- //*************根据当前模式初始化IO口 函数
7 n' S1 @# \7 R% ? - void MY_TIM3_GPIO_Init(void){" p" x& Y' s* M) C6 Q. h, B a+ Q
-
( D* i2 R( r6 y7 o% w( G - GPIO_InitTypeDef GPIO_InitStructure;! A$ e7 n3 t G% |4 {9 q1 n
-
& k8 E6 b. @+ V5 S6 C - //1.开启AFIO时钟' ~# l8 O7 ?* o
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
/ Q* z0 o& n+ ]. F -
8 o9 C3 P3 I3 Y/ h! S - //2. 根据当前的重映像的模式 配置时钟 和 初始化相关引脚
4 G- D: i4 ?0 R3 h - switch(CURRENT_MODE){
# s n/ t/ ?; W6 T# \" j - $ f9 Z; ~; `) T$ M* k4 s
- //2.1 如果没有重映射! m3 k/ d5 K/ y S) {$ W+ n# l0 L
- case NO_REAMP:{4 j) z2 s( W. H5 }; }/ r/ ~% x( v- u& [
- ( ?, x( @" ?8 u+ L
- // 时钟分配- q/ V2 G: Y2 L6 c- A9 R; R
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,ENABLE);) n" f) j+ q$ }; u- T2 e
- // 初始化IO口
* p5 M) P$ Z4 f - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
P+ ~5 ~$ x/ s1 p6 Z: I - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/ x4 N1 r9 _4 y7 v( d5 h$ B - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; x/ i) G; E1 v% O( d% q2 l2 a! ^
- GPIO_Init(GPIOA,&GPIO_InitStructure);
- S) [& N" ]+ g$ V& ^0 n - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;
3 D& @, {4 {/ N4 A! p3 v1 q# F! F - GPIO_Init(GPIOB,&GPIO_InitStructure);
- h3 B. J- y7 ~* x: B3 D- S - 7 R5 ]# s% I$ B! D
- break;5 K* P, w. r* f' H6 K, K
- }8 l. ~0 P6 k- a% \5 j
- //2.2 部分重映射
, X* S @ a7 g5 C( m+ O - case PART_REAMP:{
' M2 q7 F" Z z1 I" m -
/ B. _! W0 J2 w3 H% t - // 时钟分配- D% P6 V! ^3 ?1 f! d/ q
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);. Z6 R9 ~+ X% X }: c( k
- // 初始化IO口+ Y5 [3 L Y. [+ K/ w
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;4 n* E+ Z5 f6 w
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
% `! `+ l. D1 ^6 o) \' k - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_4|GPIO_Pin_5;; ?1 g, O$ u3 k% o
- GPIO_Init(GPIOB,&GPIO_InitStructure);9 g' s) e! J- j/ o4 d4 H& v
- : h8 @) }& C m8 K
- break;; C0 ], G2 n. }# g# {! J# d. k& f
- }
1 V: h. ?' X% n% a. `, ~ - //2.3 全映射3 I* O7 V; ]& t5 U0 }0 x
- case FULL_REAMP:{
0 x( n; v0 K1 I" y: T -
8 Z+ s- m% I8 R - // 时钟分配
0 E" w# B( R+ G - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);8 v4 a" }2 s! [, {4 x3 P/ T8 u
- // 初始化IO口% W" K6 `1 q* r3 i
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
5 p/ V0 \9 y3 Z3 k* p8 t - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
6 I: [+ d, g# p. m - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9;6 b* p$ L5 l# L6 [/ r/ P
- GPIO_Init(GPIOB,&GPIO_InitStructure);
, {5 M1 m; K' d- Z6 p. _$ t - u" Z/ H- h) y# {; W: Z
- break;
& @ ~; P1 i' X6 _- N3 A1 g/ G - }
& s$ o4 ^& `' k! e1 z& { - default:break; Y" D7 {! i6 w
- }
- ` |5 X" w* f8 E- @1 j - }6 T- Y( ^6 a7 }' F0 v$ v
3 j6 T3 f) b) R6 L. Q- S* w& z- //***************** 定时器PWM输出初始化函数3 d. p; |( W$ p- W" Q! R8 p
- void MY_TIM3_PWM_Init(u16 arr,u16 psc){
8 U9 \5 U% j9 y1 Q - ) u2 [) c: h# }+ x- y
- //初始化结构体8 v9 V4 Q/ T" M, x$ M" F9 S
- TIM_OCInitTypeDef TIM_OCInitstrcuture;
; Y2 |( ^- C% A -
9 d4 O2 S# W' B# x9 L! j# x9 L4 N4 t - //1.初始化定时器 和 相关的IO口! `. C% p5 M% j' @& L
- MY_TIM3_Init(arr,psc);
: U" I. L1 P2 c/ u - MY_TIM3_GPIO_Init();
) S, @# T' S/ r0 ^) R2 R -
) ^" ~+ M1 i- \, U$ X/ w3 I; _ - //2.初始化PWM的模式
4 f3 L) m5 [2 z& } - + c- K6 k1 a& n& H) g3 O
- /*** z5 j( ~ S4 z- S: p
- 选择PWM模式:
9 n I- b* `% V7 y- d# j - PWM1模式:5 E* Z& r7 v3 J" H; m( D8 i B1 f" e
- 向上计数时,当我们 当前的 计数值 小于我们的设置阈值为有效电平,否则为无效电平,向下计数时与向上计数时相反
( U2 z% S/ }2 P3 z - PWM2模式:5 J0 D J7 h; ?# W8 q9 I
- 与PWM1模式向上向下计数时完全相反
' {2 q; {2 v n1 H# G3 u+ b6 L - */$ s6 L- g# H; Z4 u- @
- TIM_OCInitstrcuture.TIM_OCMode = TIM_OCMode_PWM1;: N1 C9 l! {) B1 R) Y4 \- ?) q
- TIM_OCInitstrcuture.TIM_OutputState = TIM_OutputState_Enable;
% @# N8 s8 r' V- y - TIM_OCInitstrcuture.TIM_OCPolarity = TIM_OCPolarity_High; //输出电平为高,也就是有效电平为高
6 N) f% N4 ?$ R6 {3 ~& E; P8 G - TIM_OC1Init(TIM3,&TIM_OCInitstrcuture); //这里是设置利用通道1输出: }2 r5 a+ U) d5 f( z
- V4 V' x5 r8 ^# ?. h
- //这里只初始化通道1,我们可以根据自己需求初始化其它通道
9 H z$ l2 q' Y6 P$ z - - C2 o; l8 O* f: |- z9 Y2 |& k
- // TIM_OC2Init(TIM3,&TIM_OCInitstrcuture);! G7 a: B8 @7 B, G) E
- // TIM_OC3Init(TIM3,&TIM_OCInitstrcuture);+ A" |- _! Q+ V$ J" v) T2 U
- // TIM_OC4Init(TIM3,&TIM_OCInitstrcuture);
# {8 }/ v# n9 V' w" z8 q
9 `" T0 ^" N X. O7 J' z+ o$ Z+ z) Q$ I1 i- TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能预装载寄存器
) S' v& k, C3 a9 p6 O - }
! U6 O" J) {6 G' k$ ?: E4 u' K! z
+ w9 c5 s% p! l& p: Y6 U- //*********************主函数调用4 H8 N2 o, S5 x4 u. E* U* r2 X5 c
- int main(){$ o2 m* q0 [8 V( a! ?6 u2 i
- 8 b6 p4 e9 e* o! i
- //因为我们单片机引脚输出电压3.3V左右,我们设置预装载值为330
* k2 L! r b* ~% g/ K - MY_TIM3_PWM_Init(330,0);# \- A: B' F: j$ i
- 8 j, o' F/ o( \6 {, _+ c
- //我们初始化的时候选择的是PWM1模式,当计数值小于我们的设定值100时为有效电平,这里是高电平
( y( P S6 |* q/ g4 f9 N" c - //所以对于的1通道(PA6)电压是大概就是 3.3 * (100/330) = 1V 左右,我们可以用万用表测量
/ |9 t" B7 o7 J! h0 ^. Y - TIM_SetCompare1(TIM3,100);' a$ V% p& D* N
- 4 a2 M" Y2 v/ y2 `* j
- while(1);
复制代码 1 C3 |1 U9 S o( Z8 v% f. w
#5.定时器输入捕获
' w' d: l9 \2 z0 D L
## 5.1基本介绍
, B7 K9 I; y {6 P# u※ 上面介绍了定时器的四路通道可以输出PWM,同样的我们也可以捕获该定时器这四路通道上的边沿状态(上升沿,下降沿)
; e4 }, ^7 K9 _9 s6 k" h) i" X※ 由此可见基本定时器也不能进行输入捕获,没有思路通道
) y) T# X% n/ V. ?我们可以通过输入捕获的来测量高电平脉宽时间,首先捕获到高电平,记录下改时间,然后切换为捕获低电平,得到时间 1 M4 q2 R5 J( V2 \
## 5.2开发步骤 ### 输入捕获 (捕获边沿信号,上升沿和下降沿) 首先我们需要以一定的频率检测电平的跳变,然后对部分跳变(也就是部分输入的波形)进行过滤------ 这就是定时器里面的滤波器的任务 * z! D5 [1 u( V0 B3 T
1. 指定输入滤波器时钟频率,首先是系统时钟分给定时器72Mhz,我们首先初始化定时器的时候指定了TIM_TimeBaseStructure.TIM_ClockDivision= TIM_CKD_DIV1; 没有分频,输入给滤波器的时钟频率还是72MHz,TIM_ClockDivision也可以指定为2分频或者4分频
l5 N3 w& }: [/ h; ~' Q' f2. 波形过滤(TIM_ICFilter),这里有一个指定过滤器的参数(参考芯片手册),例如我们设置参数为0101(二进制),采样频率(fsampling)为 滤波器频率/2 = 36Mhz,N=8.当检测到一个上升沿的时候,再以fsampling频率连续8次检测到高电平才确认是一个有效的上升沿,这样可以滤除那些高电平脉宽低于8个采样周期的脉冲信号,从而达到滤高频波的效果。
0 ~1 t X8 I* J) m1 i; X( U: N B- h) v
3. 配置输入分频(TIM_ICPrescaler),如果我们设置不分频,一个边沿(上升沿或者下降沿)就触发一次捕获,二分频就是两次边沿触发捕获,这里这个分频可以为1,2,4,8
5 ]1 V0 ^( |: I4 g2 T0 t- //定时器输入捕获初始化
, v+ o* [2 h: s+ d Z* d4 i - void MY_TIM3_Cap_Init(u16 arr,u16 psc){& X+ V! R; r0 _. l- j
+ n3 g4 E/ ] Z: f4 h- //初始化结构体
J2 a5 q+ l$ O4 }/ C - TIM_ICInitTypeDef TIM_ICInitStructure;
3 N W$ y! E* I. v; d -
V5 C. j% Q6 B& ~9 L) n7 x: g7 T! B. E5 | - //1.初始化定时器 和 相关的IO口
# T, j/ l' k; A( X - MY_TIM3_Init(arr,psc); 4 N- M6 x7 n2 C9 M3 P+ P
- 9 `' ~5 i# j; K; W; n
- //这里的IO口根据自己需求改成输入,我这改成下拉输入,具体代码就不展现了
n- D. F. R) R' O - MY_TIM3_GPIO_Init();; [! Q" R7 t8 L a: }9 \3 X
-
. |5 C/ S6 z! E4 A, Q - //2.初始化定时器输入捕获 K: Z; x# F8 j
- TIM_ICInitStructure.TIM_Channel = TIM_Channel_1 ; // 设置输入捕获的通道
% S' q& p/ A$ p- m* K+ `7 D" Q -
0 @# F( T) c, u - //不使用过滤器,假设我们想使用,例如上述举例使用01016 Y: y3 C9 y1 O
- //我们就给TIM_ICFilter = 0x05 ,(0000 0101),根据上表可以知道这个值范围(0x00~0x0F)
5 H5 Q, l5 G0 I6 a! V+ [5 E3 O - TIM_ICInitStructure.TIM_ICFilter = 0x00;
, E$ v0 h" E @7 t3 b7 c. } - 9 A9 |/ F5 x0 \/ W. F' c0 V
- TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获; A# I5 x% P3 \+ h
- TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,这里不分频,1次检测到边沿信号就发生捕获
: d4 M5 }4 \. E$ j/ i
/ t% W) }, u F/ f8 K' F- \1 T/ d' ?- /*$ r2 |0 N1 j1 n
- 这里说一下定时器通道可以进行交叉捕获,通道1捕获通道2引脚上的边沿信号,通道2捕获通道1引脚,通道3可以捕获通道4对应引脚,... ) p1 B7 L$ @" d9 z
- 但是只能相邻一对可以相互捕获,例如通道2不能捕获通道3引脚边沿信号 g3 l. v/ N, Q, @3 h0 ]! s
- TIM_ICSelection_DirectTI 表示直接捕获,通道1对应通道1引脚,通道2对应通道2引脚
; s1 E4 P H- F - TIM_ICSelection_IndirectTI 表示进行交叉捕获
' Y9 _8 K5 i, r. `. Z( ~4 X* R - */
, _/ ~( W% O$ t% { - TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射捕获对应通道的引脚8 T; {$ i% h0 M& l
- TIM_ICInit(TIM3,&TIM_ICInitStructure); $ Z5 U0 m* R0 S5 X! }4 s
-
$ z- z R8 U% s! e3 ?" N - }+ B8 [9 `! t/ e0 W6 H
- //****************主函数9 |$ `( { s* {
- int main(){9 @: Z6 K T7 t$ M7 n
- //初始化输入捕获9 [0 y _- \4 U% O
- MY_TIM3_Cap_Init(1000,0);( S9 c) [8 n! R6 ]+ n( Z
- ! z! L5 c/ @# y% S
- while(1){+ a. X- I' e: S: \
- //检测是否捕获到上升沿
6 j' A& Z- _2 r) E) ~( y - if(TIM_GetFlagStatus(TIM3,TIM_IT_CC1)){
l! P, o4 L2 m2 `; k5 T - TIM_ClearFlag(TIM3,TIM_IT_CC1); Z6 w# u% d. n$ }8 \' ~3 c
- //捕获到上升沿之后的任务...9 r/ l7 l( H# q u( J; i- n7 ?
- //一般测量高电平脉宽,我们可以先捕获上升沿再捕获下降沿
6 o5 l* `+ Q: c3 d* x- ? - //TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); 修改为下降沿捕获9 y! j2 \" A! D
- }
+ x4 B# U% I: Q5 w+ Y - $ z, f0 [) I' u! ?, | J
- }
6 E3 _, M# q- ~2 P7 o3 x$ [1 w& X1 d - }
复制代码
4 W7 `$ ~6 w8 s8 u, s6 z4 ^0 N) a6 z+ t7 j; d# J
#6.定时器中断 ) G: {1 o9 ^9 ]% q/ F* @, g
1.谈及到中断,我们就必须涉及到NVIC,具体关于NVIC请参考我的另外一篇,这里是直接使用,我们使能定时器3中断并且配置完抢占优先级和响应优先级之后,再在主函数中使能其更新中断和输入捕获中断 0 a" ]0 P+ E6 m$ q
- //使能更新中断和输入捕获通道1的中断: }3 V& p* R1 k
- TIM_ITConfig(TIM3,TIM_IT_Update|TIM_IT_CC1,ENABLE);
复制代码 - Y$ {" J, Z* p/ E9 K6 A
0 b# X+ ?' w+ Y% X% |
2.我们使用中断的一个主要目的就是能够及时处理信息,不用在主函数的while循环里面等待 : L, `: k, ]: O- N
- //定时器3的中断处理函数* R0 s* w9 _$ u" d
- void TIM3_IRQHandler(void){6 U q% E+ N+ j, d
- 9 @3 M2 y$ x" _
- //1.判断是什么中断+ B& B( ]( B$ u' U) f
- 0 j4 Y1 ]3 ]8 I+ {
- // 1.1定时器更新中断
( z) I6 J. q. k0 s. X( `% G - if(TIM_GetITStatus(TIM3,TIM_IT_Update)){
+ R( P& k- w6 Y7 H+ _- U5 ? - //...处理定时器更新之后任务7 m: R( R/ v% {# c- H) W/ _1 A3 e# L
- }) W j' M1 c0 g7 ~
- // 1.2如果是定时器 通道1的捕获中断
0 m$ S1 ~5 m+ @7 e& a K - else if( TIM_GetITStatus(TIM3,TIM_IT_CC1) ){" M- Z) z: o. [. e# m! s
- //处理输入捕获之后的任务
2 y$ }' [3 d5 W$ [! N& p - //TIM_OC1PolarityConfig(TIM3,TIM_ICPolarity_Falling);更改为下降沿捕获
$ A# e7 W) H8 ` W4 j8 r1 _3 x3 k - }
% e8 y% W6 q9 P8 @# N3 s% l -
+ J# v0 b6 W* X" v9 d, p; l' S# ?! i - //2.最后将中断标志位都清理掉* H( m# j! @/ F- @1 f/ W3 o4 G
- TIM_ClearITPendingBit(TIM3,TIM_IT_Update|TIM_IT_CC1);2 Z" g& q7 {2 l% ]
- }
复制代码 , z1 U: M' J1 F6 {) a6 g2 H; B7 b) H
$ {: Q' T4 |, u" f文章出处: 智能车杂谈
: }& O- o& }# T' ^1 ~2 e |