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部分时钟树: , 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,我们可以根据自己的需求再设置定时器的分频,设置它的定时值 - /*
$ X/ p8 i1 [, h! f) S3 ^ - * 初始化定时器的时候指定我们分频系数psc,这里是将我们的系统时钟(72MHz)进行分频
" N; X7 ^4 k- U3 ]& u8 m - * 然后指定重装载值arr,这个重装载值的意思就是当 我们的定时器的计数值 达到这个arr时,定时器就会重新装载其他值.
: @! }+ L( G, E1 H1 w - 例如当我们设置定时器为向上计数时,定时器计数的值等于arr之后就会被清0重新计数
7 u# g8 J& A5 r3 ^8 F$ w. K3 j1 p - * 定时器计数的值被重装载一次被就是一个更新(Update)- g1 r$ b0 y6 ]! n
- * 计算Update时间公式
+ K& u: B' j9 B1 B - Tout = ((arr+1)*(psc+1))/Tclk
7 }' h* B( i1 _9 O2 A - 公式推导详解:$ ]2 K/ ]- e( L) F
- Tclk是定时器时钟源,在这里就是72Mhz
/ p, \8 ]+ P6 M9 P2 u: f9 J - 我们将分配的时钟进行分频,指定分频值为psc,就将我们的Tclk分了psc+1,我们定时器的最终频率就是Tclk/(psc+1) MHz
- f, w! d g' x2 b5 ~ - 这里的频率的意思就是1s中记 Tclk/(psc+1)M个数 (1M=10的6次方) ,每记一个数的时间为(psc+1)/Tclk ,很好理解频率的倒数是周期,这里每一个数的周期就是(psc+1)/Tclk 秒. e& r/ ^7 x4 C- _- {1 u! N
- 然后我们从0记到arr 就是 (arr+1)*(psc+1)/Tclk5 Z, x$ X* L7 d& u7 h
- 举例:比如我们设置arr=7199,psc=9999, H8 t8 Z1 s' g+ e4 o$ W% x
- 我们将72MHz (1M等于10的6次方) 分成了(9999+1)等于 7200Hz
2 @: Q% s$ C# O2 h0 H! m - 就是一秒钟记录9000数,每记录一个数就是1/7200秒
( q) g5 l" o7 H - 我们这里记录9000个数进入定时器更新(7199+1)*(1/7200)=1s,也就是1s进入一次更新Update3 T+ e; s/ G( C" i
- */2 s6 P8 L. F q) q' Y* _7 c
- //简单进行定时器初始化,设置 预装载值 和 分频系数
* T5 v. f9 J8 ^! [4 W - void MY_TIM3_Init(u16 arr,u16 psc){
" q5 B! m+ v# g# B0 O$ w -
! I- c `% f: Y7 X" j) k1 Y* l; o - //初始化结构体
& s! p! w6 u0 n1 Y9 Q - TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
2 p$ t+ n8 o0 E -
/ Y, o$ h% w. ~2 P% t7 e3 S - //1.分配时钟) y7 Z7 I0 L8 e6 p, P
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);) T P; M5 i4 ] |* Y
- - T: ]( f3 Z1 D4 T
- //2.初始化定时器相关配置
2 T3 ?, k; G, O% Z9 K - TIM_TimeBaseStructure.TIM_Period = arr;4 Z; k& n; r8 h0 @
- TIM_TimeBaseStructure.TIM_Prescaler = psc;
# A* Q6 N5 ^8 M4 o7 K" f -
& o5 y5 ~- t# p, X. g8 U0 x - /*在这里说一下这个TIM_ClockDivision 是设置与进行输入捕获相关的分频
1 {9 E3 G0 k) A - 设置的这个值不会影响定时器的时钟频率,我们一般设置为TIM_CKD_DIV1,也就是不分频*/1 s4 e+ B# F, X0 ?
- TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;: q' ^$ ~% n7 M+ A) T+ m
- TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数( u, o" l1 w0 Q: Q3 U, _
- TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);
& m2 P9 X8 C8 H0 y - & q0 p) a, v0 Y& } U' t6 o( S
- //3.打开定时器4 j- S* r5 r( a. V6 t9 y* G; U
- TIM_Cmd(TIM3,ENABLE);4 s4 T1 F$ }7 n, p T! u/ _
- }
- g4 R2 l8 S: `6 r! b - / |$ u. F3 p6 z9 D
- /****************** 主函数 ********************/0 y8 U3 @( N# Y) f. d0 Q6 x T+ g; q
- //在主函数中我们可以调用初始化# H6 j: Q: c. t9 a$ e
- int main(){
5 L! _$ ?6 c+ ?+ T3 z. q$ N - //定时器初始化& K, N$ Q8 Q) y4 l; N
- MY_TIM3_Init(7199,9999);% X; ? G1 I {; K0 O
- while(1){- M& J* I7 m. ]4 J- m$ t
-
" J5 |8 f. y0 d# F2 g - //检测更新标志位( D# B/ y- ]+ F, T- m, Y; T
- if(TIM_GetFlagStatus(TIM3,TIM_IT_Update)){: I4 P L7 W: k* A
- //清除标志位, D. |- N }3 a. k( ~
- TIM_ClearFlag(TIM3,TIM_IT_Update);
0 h5 e) o! Y8 v$ ~' J$ y% k - //....(每隔一秒执行任务)
4 a) d( x7 Q% d - }
3 k! m8 c. e9 J' t$ ?0 U -
2 I4 g* O$ i* p. y& a. e, d - }
# t6 k4 K6 w8 _) y: P- v Z - }
复制代码 . 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
- 时器3,可产生四路的PWM输出,四个通道分别对应的引脚情况如下
! @, A5 q" R3 H% ?, n, y0 t- y" b - TIM3_CH1,TIM3_CH2,TIM3_CH3,TIM3_CH4
1 V- a$ _6 `. V3 ~5 s/ y( |" j - 没有重映像的对应情况:
) n2 K* u$ v3 Q* d - PA6,PA7,PB0,PB1/ r w# x3 ] C. G
- 部分重映像:9 y3 _* J: H) ~, n$ a8 o
- PB4,PB5,PB0,PB1
; @; J M- G0 x3 P5 d. c% r1 J - 完全重映像:: c! g, |/ `2 I7 J% M# y
- PC6,PC7,PC8,PC9 7 e: e/ k+ d- |
- 0 ^# q0 N% o& b
- 当我们的IO口不仅仅是做普通的输入输出使用的时候,作为别的外设(AD,串口,定时器等)的特定功能引脚,就需要开启外设.' `* A7 q/ F8 A6 y! U: m7 E# [7 _. n
- 这里我们还需要开启APB2外设上的复用时钟AFIO,同时IO口采用的是复用输出!9 X9 m9 L1 Y8 X% o& D; ?$ q) o8 V
4 z7 q. Y7 N$ {7 c* f- 我们这里是没有使用重映射功能.
% \: H' R+ G) ^. h* F - */8 i: H/ Y& z& h+ P7 B5 w
- // 宏定义
1 C3 z8 w* T) y9 ]6 M6 d* ?( R - //判断当前是处于哪一种模式,以便于我们初始化IO口9 f; l9 J/ i! h
- #define NO_REAMP 04 k1 i+ g3 O7 s2 e6 N: j
- #define PART_REAMP 1* E2 X! a3 C0 t0 _# f* s9 C$ _- `- M
- #define FULL_REAMP 2
% `8 y% }8 l; R& ^ - 0 o; ], `3 J0 q0 p
- // ---> 这里是需要制定的参数" z+ D: e: Y: p6 G' U9 F
3 D4 i8 c& u0 e7 o+ @# w- //指定这里的 当前的模式,我们给她默认指定是 没有重映射' A& G1 T5 G! S
- #define CURRENT_MODE NO_REAMP
) f% d7 d5 k( {5 s
( a% A* I; G2 x: r- //*************根据当前模式初始化IO口 函数
! Z% C: e$ G2 x) l2 f - void MY_TIM3_GPIO_Init(void){! |( _' l- X9 z4 T6 O
-
# j( G8 r! Z. ?" X! b5 `# { - GPIO_InitTypeDef GPIO_InitStructure;1 y8 S' u6 `* N3 {
- % g' M, L# {$ U+ K, w0 ]
- //1.开启AFIO时钟
& C# Z( @5 O5 ^+ R$ n& P - RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
' w% ?% V; {* [ -
' N8 a+ i! Q7 }0 s - //2. 根据当前的重映像的模式 配置时钟 和 初始化相关引脚
0 W0 W6 g1 q" }' K9 f5 ~ - switch(CURRENT_MODE){
* r. t3 C1 s) T - $ U7 y# c% h8 _+ [
- //2.1 如果没有重映射
3 E3 z! {3 N& z" f+ U - case NO_REAMP:{
2 ^$ w. x, k/ l w; c - : S% z+ ^( t! }/ R% ]
- // 时钟分配
5 L8 K! V5 r( W) ?; J- {0 G - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,ENABLE);
1 B' l% B6 E# s- D3 z2 p - // 初始化IO口
- Y, T# T9 c2 Y1 m - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
9 c% ^, ]- \% L - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;2 J" W A' x+ U" l1 x
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
0 I6 k: n! ^% b2 _) `) w/ ~1 P - GPIO_Init(GPIOA,&GPIO_InitStructure);: k7 y. _* c) ?+ D" O/ l# q
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;
+ j) m2 @% j* y. z% J* j' K - GPIO_Init(GPIOB,&GPIO_InitStructure);* h! V# F0 r5 s0 e; ~, j s$ A( D
-
8 Q* U z) N) `. J# ? - break;' {8 C" X6 _( @# Y" _, a
- }
, L) \' o8 O5 U( q& q$ Q - //2.2 部分重映射7 r2 G+ [7 n" v* W
- case PART_REAMP:{) z. E, R! @' j, @1 b6 V) S
- 9 V% { ^6 F D+ p% E$ Q9 v$ m
- // 时钟分配
5 t1 k. _5 W$ l) a8 ]' X0 O - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
7 d2 h# w( e3 }8 O, ^0 @ - // 初始化IO口+ g9 ?- R; B9 T! S1 t# O6 J
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;. ~0 z* ]+ i& {9 y2 H
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;+ C) { S/ h+ Y1 q
- 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
- GPIO_Init(GPIOB,&GPIO_InitStructure);# m4 p! f5 f$ a. q
-
1 { }! u% r& q! Y& f5 a - break;
; q' }- }& }/ d! K4 ]0 o$ T8 _, Q - }
0 O9 c% T( w- p - //2.3 全映射- F( {& }# ~1 k/ }
- case FULL_REAMP:{
' A! P" `* N! _0 W) ^7 l% U5 \ -
" d/ n' P: g! Q! D6 n; R - // 时钟分配7 i [. G6 w5 ^
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);& d2 K+ x2 t2 R/ i
- // 初始化IO口7 v" y. O1 n* C, Z! `
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;) m8 v9 s+ ~4 o9 U
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;$ V8 F8 ? s' }& G) N- z
- 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& ]
- GPIO_Init(GPIOB,&GPIO_InitStructure);/ e0 k4 ^& B0 s1 R" c k( a P9 P
- ! P1 o; Y. y4 T" V1 |
- break;
' a, `) g5 v- l! u - }1 y" U" x+ n2 j6 p- V3 I
- default:break;
! c# w, ]1 a$ G* t V& P - }
* h2 t6 D/ p. O; |9 ?1 a3 F* [* b - }2 y8 L- _5 @, M0 h. Z e
- 0 |# x5 w' c! T# c, j o; D9 j
- //***************** 定时器PWM输出初始化函数0 \8 v5 I& M! N, U
- void MY_TIM3_PWM_Init(u16 arr,u16 psc){
5 k) l' S/ b6 u* ?, j& i - / G. g4 g$ E8 p7 f
- //初始化结构体
; B: p) D2 R1 Q- q - TIM_OCInitTypeDef TIM_OCInitstrcuture;
$ ?7 y5 w+ w+ Y% r! q2 `. a - / E- R) h% c# }) [- M! G
- //1.初始化定时器 和 相关的IO口
( I& _- a9 N# Z - MY_TIM3_Init(arr,psc);
0 F% Z* u u: b, k X - MY_TIM3_GPIO_Init();/ I9 z n" t! d
-
5 d3 Z" B* T+ A1 h - //2.初始化PWM的模式
% c' w* v+ X/ ~- r, {4 b - 2 o' l# u' N8 q
- /**0 \! ^1 d! O: f) R
- 选择PWM模式:& F, U' T+ O4 h
- PWM1模式:
6 p4 L4 i5 p9 Z# }8 o - 向上计数时,当我们 当前的 计数值 小于我们的设置阈值为有效电平,否则为无效电平,向下计数时与向上计数时相反
7 o5 m( R0 q; W9 N% ^4 W4 t - PWM2模式:9 \" ^3 C: U# i- s2 O+ X
- 与PWM1模式向上向下计数时完全相反 [! O7 R: O0 v- I
- *// l, q4 f$ R2 o% e9 c ~, x
- TIM_OCInitstrcuture.TIM_OCMode = TIM_OCMode_PWM1;
& D, H' |& S0 a# p - TIM_OCInitstrcuture.TIM_OutputState = TIM_OutputState_Enable;
' V9 V3 t9 ?2 m# ~0 Q" p - TIM_OCInitstrcuture.TIM_OCPolarity = TIM_OCPolarity_High; //输出电平为高,也就是有效电平为高
. i( c. m; ?/ n: p" T( ? - TIM_OC1Init(TIM3,&TIM_OCInitstrcuture); //这里是设置利用通道1输出* {' ~+ b$ U# `6 r
- # @9 x' D J4 |* C
- //这里只初始化通道1,我们可以根据自己需求初始化其它通道
- o5 ?1 V% n! O. f+ { - : s- q0 K- x* j9 J3 L
- // TIM_OC2Init(TIM3,&TIM_OCInitstrcuture);+ k, \0 T$ `1 ^6 E% V) z5 @5 S
- // TIM_OC3Init(TIM3,&TIM_OCInitstrcuture);# V' l, c6 h, R0 K3 O2 \) L
- // TIM_OC4Init(TIM3,&TIM_OCInitstrcuture);
. Z7 u3 Y; S9 _) ~ _ - 3 e( ~! O2 y4 E" z9 [
- TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能预装载寄存器
E* R/ E* `9 K8 X( q R! u# ` - }
/ J3 P/ d9 ] ?( Q# E5 K4 j - ! S. z" }& Z: `: A: W4 ~1 @" g( B; K
- //*********************主函数调用
" W$ R8 N& _6 ^# b# s( r& ~) p+ A. Q - int main(){
; ?7 ?% v1 c& F. F6 j7 M -
. G6 g3 Z) X. _, {0 F& e0 d - //因为我们单片机引脚输出电压3.3V左右,我们设置预装载值为330/ e. P0 g9 q+ y0 q( {; O4 y
- MY_TIM3_PWM_Init(330,0);8 ?+ S+ M* c& y- y# t
- : F( L, _. U5 _9 ?& `
- //我们初始化的时候选择的是PWM1模式,当计数值小于我们的设定值100时为有效电平,这里是高电平
# j$ |! d: z- K/ @! i - //所以对于的1通道(PA6)电压是大概就是 3.3 * (100/330) = 1V 左右,我们可以用万用表测量5 g" d9 t0 h* `# u- N( U' {
- TIM_SetCompare1(TIM3,100);9 W$ }7 g& S* {! m
- 7 R- }6 x* J! E6 b
- 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 N2. 波形过滤(TIM_ICFilter),这里有一个指定过滤器的参数(参考芯片手册),例如我们设置参数为0101(二进制),采样频率(fsampling)为 滤波器频率/2 = 36Mhz,N=8.当检测到一个上升沿的时候,再以fsampling频率连续8次检测到高电平才确认是一个有效的上升沿,这样可以滤除那些高电平脉宽低于8个采样周期的脉冲信号,从而达到滤高频波的效果。 , l" a3 t8 f# }
3 A/ C- f0 r9 X# ], p3 X7 D3. 配置输入分频(TIM_ICPrescaler),如果我们设置不分频,一个边沿(上升沿或者下降沿)就触发一次捕获,二分频就是两次边沿触发捕获,这里这个分频可以为1,2,4,8
7 b7 C6 g; o7 I) S! d8 h" q- //定时器输入捕获初始化! R; v( m7 U( A6 Q( P0 K7 o8 Q$ @3 g
- void MY_TIM3_Cap_Init(u16 arr,u16 psc){
% T$ Y5 y6 ~* I7 X/ P& O, a
7 L% d( T) Q& Z) `& |. c- //初始化结构体4 }. S1 S. }9 s& g$ ^
- TIM_ICInitTypeDef TIM_ICInitStructure;
. ?4 M- E8 m1 [- U( w, ~8 I -
) Y" U9 @( h- b4 d9 S - //1.初始化定时器 和 相关的IO口
% d" ^8 L. h+ D2 S7 P - MY_TIM3_Init(arr,psc);
! t9 I9 |. N- a* d/ Q7 C
" ?7 r3 Z" i6 w- //这里的IO口根据自己需求改成输入,我这改成下拉输入,具体代码就不展现了
. m5 x; `% b3 S/ q9 Y ` - MY_TIM3_GPIO_Init();
: k1 C( e, u! A' t b2 [2 N - / ?, F2 c# |( T" M! d3 y
- //2.初始化定时器输入捕获& }; G2 W5 ~2 ?
- TIM_ICInitStructure.TIM_Channel = TIM_Channel_1 ; // 设置输入捕获的通道
* Q3 @: x% c, s - , r$ l3 t" |4 Q% b r& M
- //不使用过滤器,假设我们想使用,例如上述举例使用0101
! p3 R' w7 V% d' m7 f. m - //我们就给TIM_ICFilter = 0x05 ,(0000 0101),根据上表可以知道这个值范围(0x00~0x0F)/ F( a* m* {/ H2 B6 t t1 e+ l* e
- TIM_ICInitStructure.TIM_ICFilter = 0x00;, P+ C, v g5 Y1 n
- ( l6 Q3 F6 a ^' f+ p8 V
- TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获 N* e* ?% A/ y1 { h: {2 [
- TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,这里不分频,1次检测到边沿信号就发生捕获
1 f* \1 X8 q3 ]& P# ]3 a0 F+ j
9 o' \* ~# h I6 \) r, S$ F- /*
7 U5 v, r! v$ O) N - 这里说一下定时器通道可以进行交叉捕获,通道1捕获通道2引脚上的边沿信号,通道2捕获通道1引脚,通道3可以捕获通道4对应引脚,...
& T! ^6 p* X/ y2 Z. {0 ? - 但是只能相邻一对可以相互捕获,例如通道2不能捕获通道3引脚边沿信号! y5 W# ]* z1 u: w% B' K
- TIM_ICSelection_DirectTI 表示直接捕获,通道1对应通道1引脚,通道2对应通道2引脚
E& E& S2 Y) J( R$ R3 ~, J5 `$ k1 P - TIM_ICSelection_IndirectTI 表示进行交叉捕获
$ ~2 ^2 U. z( t# k - */4 d D1 P* m' M: Q/ y& z1 v: s6 O h
- TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射捕获对应通道的引脚
7 I5 m) D# N+ {* p" k8 j8 J& G. N - TIM_ICInit(TIM3,&TIM_ICInitStructure); , t% q5 e; L- _1 Q9 i8 ~
- " W4 G) j, J& ^. N6 K
- }
3 r* k7 {/ D7 f5 U# y* e. p5 x - //****************主函数 e5 j Y) y% j3 B; l W
- int main(){/ H! T Q' G' b" m: K' n) R9 `
- //初始化输入捕获$ u7 y$ k( Z/ @
- MY_TIM3_Cap_Init(1000,0);4 d, n& z% d9 l: j$ ~
-
7 S7 Q( \ l5 \: C - while(1){; u2 z- p. b' f! @0 D9 Q! T% |, ~0 _0 ?
- //检测是否捕获到上升沿3 I/ r& m6 J, Z; v6 `$ v
- if(TIM_GetFlagStatus(TIM3,TIM_IT_CC1)){# |: R$ @# X% ^- R
- TIM_ClearFlag(TIM3,TIM_IT_CC1);. A; ~$ z; a1 S m3 n$ p
- //捕获到上升沿之后的任务...# l7 }, q \5 Z6 c0 c. m( b
- //一般测量高电平脉宽,我们可以先捕获上升沿再捕获下降沿" S" ~" @* F& {
- //TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); 修改为下降沿捕获
# e% X0 z! P1 ?& m1 `" e - }
' ~# S( ?7 G Y" [4 j2 @ - " R& }' G5 X8 ?. X* w
- }4 j9 j; H: i& p1 _6 H. v4 I4 h- k/ l
- }
复制代码 + 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的中断5 l4 C _- Z; g' Z% ]+ t& Z, Y
- 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- //定时器3的中断处理函数
+ I2 R% u% @9 f8 L/ n8 h! G, C - void TIM3_IRQHandler(void){
* ` a! I7 B c- L( M1 r - 2 J- S2 N; b: ]9 l) u+ X
- //1.判断是什么中断% p2 k/ c% t' B/ p
- ; n% R; r; p3 C
- // 1.1定时器更新中断
+ u! B J5 C( R% t* ` - if(TIM_GetITStatus(TIM3,TIM_IT_Update)){
X) E5 z- ]0 E) M9 t, ^ - //...处理定时器更新之后任务$ O6 ]: X' z# C' n) O
- }+ C' E% l& c, u
- // 1.2如果是定时器 通道1的捕获中断
Q, O \( y: ]) U) S2 d* ?3 t7 K - else if( TIM_GetITStatus(TIM3,TIM_IT_CC1) ){
f$ i6 m% }6 C7 q: C3 c# J - //处理输入捕获之后的任务" G! c7 `" {" h0 \9 X4 z0 F9 a
- //TIM_OC1PolarityConfig(TIM3,TIM_ICPolarity_Falling);更改为下降沿捕获5 `+ d, D3 s0 d) o+ f5 C+ n
- }
* _ J7 D' L U) R" e$ d - 8 C" H2 \( T' A' t
- //2.最后将中断标志位都清理掉; |& X Z+ ^# N+ o6 H7 C' S
- TIM_ClearITPendingBit(TIM3,TIM_IT_Update|TIM_IT_CC1);! _8 W8 @9 r5 z4 h* t( N
- }
复制代码
5 [6 Q9 h! N5 e4 \; `
6 w6 e1 T7 R1 ?% y. S: c文章出处: 智能车杂谈
- A9 z$ l5 K# @; {" |5 x( x& t |