STM32通用定时器使用详解 #1.通用定时器基本介绍 ! L; O7 q! B4 ?
7 H2 F: {) q ?/ b: p4 R* }※ 通用定时器包括TIM2、TIM3、TIM4和TIM5 ※ STM32通用定时器是一个通过可编程预分频器驱动的16位自动装载计数器构成。 ※ 每个定时器都是完全独立的,没有互相共享任何资源。它们可以一起同步操作。 ※ 定时器可以进行定时器基本定时,输出4路PWM,输入捕获 ※ 本文详细介绍这三个功能并且利用定时器3并且示例代码使用
: N5 t) {2 l8 K% r( H#2.开发环境 L9 c7 U$ N) k _+ g/ ]1 A" T' [
9 w* G* F( m+ ^% u+ h2 ]) L开发平台:keil5 单片机:STM32F103ZET6
! z, O7 T5 ]. c* ~#3.基本定时功能
3 m' @ ?# @; F
! q' p5 q2 c9 k9 g7 @3 U. s## 3.1定时器时钟来源分析 STM32部分时钟树:
" Q2 |' B' n5 F. K& I0 B5 y7 Y& z 3.1.1 首先我们我们的系统时钟(SYSCLK 72MHz) 经过AHB分频器给APB1外设,但是APB1外设最大的只能到36Mhz,所以必须要系统时钟的二分频。下面又规定了如果APB1预分频系数为1则频率不变,否则频率X2至定时器27,所以定时器27的时钟频率为还是72MHz
* b3 n4 p" [1 P( r2 m' N
' Z# F! n2 Z9 g; U 3.1.2 分配给我们定时器的时钟是72MHz,我们可以根据自己的需求再设置定时器的分频,设置它的定时值 - /*
& J: i: z0 D* g* F) |3 J# L& l, b - * 初始化定时器的时候指定我们分频系数psc,这里是将我们的系统时钟(72MHz)进行分频- \7 q" ^, `6 S
- * 然后指定重装载值arr,这个重装载值的意思就是当 我们的定时器的计数值 达到这个arr时,定时器就会重新装载其他值.
! A* x4 t l1 y+ i - 例如当我们设置定时器为向上计数时,定时器计数的值等于arr之后就会被清0重新计数9 W% L" w# b, {2 y
- * 定时器计数的值被重装载一次被就是一个更新(Update)0 A) I, r' g: g5 g. L
- * 计算Update时间公式
$ a) n* ]+ s; N h! x1 ]# Y - Tout = ((arr+1)*(psc+1))/Tclk
, t, S+ N7 r3 V; C1 ~ - 公式推导详解:2 N8 T# A- ]. E- D3 P
- Tclk是定时器时钟源,在这里就是72Mhz + U. r" Y- ]4 D: K& m
- 我们将分配的时钟进行分频,指定分频值为psc,就将我们的Tclk分了psc+1,我们定时器的最终频率就是Tclk/(psc+1) MHz* S6 Y+ [% F1 f' G5 j+ w& c5 F6 m8 U
- 这里的频率的意思就是1s中记 Tclk/(psc+1)M个数 (1M=10的6次方) ,每记一个数的时间为(psc+1)/Tclk ,很好理解频率的倒数是周期,这里每一个数的周期就是(psc+1)/Tclk 秒
9 k) w# ^+ e* c4 B! J - 然后我们从0记到arr 就是 (arr+1)*(psc+1)/Tclk) a) d; p2 b! d! q
- 举例:比如我们设置arr=7199,psc=9999
8 a. w0 |/ {; ?/ N - 我们将72MHz (1M等于10的6次方) 分成了(9999+1)等于 7200Hz. @/ z+ b+ e) t3 G# e* C
- 就是一秒钟记录9000数,每记录一个数就是1/7200秒
2 a" L3 G; I- p" p0 N0 k - 我们这里记录9000个数进入定时器更新(7199+1)*(1/7200)=1s,也就是1s进入一次更新Update" G1 n- \% `6 e
- */
! b N$ f, v7 w6 n2 M( f0 z2 b; f - //简单进行定时器初始化,设置 预装载值 和 分频系数
5 ~( s+ K) V8 G0 m/ M1 U( } - void MY_TIM3_Init(u16 arr,u16 psc){+ G) ~. X- z) e6 G( T" c2 ]
-
1 l0 I: ^6 j1 i$ F, ]1 g - //初始化结构体
( c( ?3 I1 V$ e9 ?& h! F* N5 K& q - TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
$ `9 e. @9 a8 e$ y% f -
2 K" w! f( G" k) b/ m- K - //1.分配时钟7 G; x, A! W c- f$ }: S1 Q/ n
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);; q4 L/ ^% `' d6 n) W2 H) t9 c: X! Q
-
6 a5 `' _5 O( d$ R' D - //2.初始化定时器相关配置" }% `. F# K% W+ `0 \) |1 a R$ G. t: U* F
- TIM_TimeBaseStructure.TIM_Period = arr;
" W* @3 u' V; j - TIM_TimeBaseStructure.TIM_Prescaler = psc;
& S! v1 M+ ~+ d5 J/ Q3 { -
/ [) R% K7 T3 }% f0 w z c$ R - /*在这里说一下这个TIM_ClockDivision 是设置与进行输入捕获相关的分频" p- R$ |/ z$ X% i
- 设置的这个值不会影响定时器的时钟频率,我们一般设置为TIM_CKD_DIV1,也就是不分频*/
# E7 ]( G' r! ^ Z - TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
2 L, X: I6 G7 c m3 [ - TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数, d/ i" i8 ?" l( e q# e5 E
- TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);& L8 E1 R$ J6 S6 b$ g2 r1 J3 c
-
0 Q4 l( Q) y$ l5 n8 Q( W1 I$ ]" f - //3.打开定时器2 H0 b8 w1 Q" l1 X- |5 |, O$ n
- TIM_Cmd(TIM3,ENABLE);9 U: X+ @7 n) b7 r
- }& v* t& T; B, n* G
- / D$ X3 Y, {1 n9 M) r# I
- /****************** 主函数 ********************/
# [3 E$ F7 p" G0 q( u: X8 b* k - //在主函数中我们可以调用初始化6 v3 b6 ~) C# ?3 L1 z" {+ j! ]0 C
- int main(){" O: z& v2 k% b! u- x' C
- //定时器初始化" M9 W* g9 w7 q
- MY_TIM3_Init(7199,9999);# R+ |1 a/ d6 A& {6 V! w5 @6 n. ?
- while(1){
' @1 B8 _2 m5 V( c' d8 u" ^ -
. m0 c0 [0 C& p* z8 d& U* _8 g4 V - //检测更新标志位
2 V; c& M- e, v; X% P8 T8 m- b! l3 W - if(TIM_GetFlagStatus(TIM3,TIM_IT_Update)){4 Y1 f4 R, m' N( f% ~2 k
- //清除标志位
1 o$ Q. s$ @- N. ]6 T - TIM_ClearFlag(TIM3,TIM_IT_Update);
" p9 ~) F1 M- |4 H9 H3 m - //....(每隔一秒执行任务) E3 S& V- v& P# h( X8 k
- }
9 j) {2 H I7 O; t - / f% t* ~, u" a5 v7 m! W
- }: k) }' H' ?6 e* H [
- }
复制代码
% a1 ]0 N' l! E. ^: s* o#4.定时器输出PWM
5 Z! w" W; F8 }
## 4.1基本介绍 / @0 a, h1 c1 \
4.1.1PWM是脉冲宽度调制,我们是通过改变脉冲的宽度来达到改变输出电压的效果,本质上就是调节占空比实现的,STM32除了基本定时器(TIM6,TIM7)不能输出PWM以外,其它的定时器都具有输出PWM,其中高级定时器(TIM1和TIM8)还能输出7路PWM,基本定时器(TIM2,TIM3,TIM4,TIM5)也可以输出4路PWM > 输出PWM是很有用的,比如我们可以通过控制电机来玩小车,或者通过输出PWM改变LED的亮度,制造呼吸灯等等 ( u+ O7 C( H) x5 p% y( S
4.1.2 我们通用定时器能输出PWM的IO口是固定的,虽然我们可以通过重映射可以改变引脚,具体是哪一些IO口我们要通过查阅STM32的参考手册 3 K1 ~, P; E: L
这里涉及到一个重映射的概念,重映射就是管脚的外设功能映射到另一个管脚,但是不是可以随便映射的,具体对应关系参考手册上的管脚说明。这样优点是可以优化电路设计;扩展功能,减少外设芯片资源
: e7 o1 e1 J+ X+ P- 时器3,可产生四路的PWM输出,四个通道分别对应的引脚情况如下' N* W4 p# n: U
- TIM3_CH1,TIM3_CH2,TIM3_CH3,TIM3_CH4% D5 }* G' J" J# M6 p4 s
- 没有重映像的对应情况:
0 w; K% D' C0 Q5 Y& d - PA6,PA7,PB0,PB1
. T' M* v/ ^+ {) U, M4 g - 部分重映像:. |$ \: E" E7 q# x4 H
- PB4,PB5,PB0,PB1
3 t- m9 E4 g' U, _5 I( H - 完全重映像:
4 z0 z+ r k9 X. g - PC6,PC7,PC8,PC9
6 i; h" \- e! Z8 k6 n( d
' B4 k! H. U' i/ L3 n- 当我们的IO口不仅仅是做普通的输入输出使用的时候,作为别的外设(AD,串口,定时器等)的特定功能引脚,就需要开启外设.& |& T ?4 `3 R% p- n, Q3 k
- 这里我们还需要开启APB2外设上的复用时钟AFIO,同时IO口采用的是复用输出!
0 `/ J1 e+ P& ?( n3 z1 ?
4 @2 ~( U7 t* k; s+ `+ `( F- 我们这里是没有使用重映射功能.' Y0 v v# [: C5 }+ g
- */
% G# t) [& e) u( T8 y - // 宏定义
! n( w" g$ W9 T - //判断当前是处于哪一种模式,以便于我们初始化IO口
" @! {" L3 Y z. u - #define NO_REAMP 0* L# l) Y8 L2 g/ [+ ^# p- B9 ~, ?
- #define PART_REAMP 1; u/ ?' @. B4 {4 k% V
- #define FULL_REAMP 2
, z Y& r2 M _% \! l
7 q: ~5 |) o. ~8 I8 u+ U! |- // ---> 这里是需要制定的参数
' D' i4 t1 V- c/ j, B
I3 W; f( D* I. d+ @- //指定这里的 当前的模式,我们给她默认指定是 没有重映射2 z, P R$ {" w8 U" Y
- #define CURRENT_MODE NO_REAMP
! e9 ?0 `& |/ r3 [* u - * U; K2 `0 |+ a# J: j' C
- //*************根据当前模式初始化IO口 函数
) R) Z0 ~: Q4 }2 r - void MY_TIM3_GPIO_Init(void){6 L; K3 R7 M+ J/ r
- , W9 m# ?# e( ^7 y
- GPIO_InitTypeDef GPIO_InitStructure;
/ V' I }* Z4 V+ l! F# i) f -
3 u& a+ e6 [+ } - //1.开启AFIO时钟- C# B" a f4 N! k
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
9 b- d+ S" ?& t0 i9 V7 ? -
; w% P' T2 O0 G - //2. 根据当前的重映像的模式 配置时钟 和 初始化相关引脚* W# t; s9 m$ h+ k! D
- switch(CURRENT_MODE){! o5 F# {. I ?, w' u: o
- * e4 B1 W9 C2 [ v" ?' V
- //2.1 如果没有重映射
. Q& X. `5 K& i/ z: b - case NO_REAMP:{
. W* x7 r% B4 e+ o' V" ~ - 0 L9 Z8 J3 A% z0 q# U. k
- // 时钟分配0 ^5 d4 d' X* m0 ?& Y- L
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,ENABLE);9 o/ q3 d+ z( _2 l
- // 初始化IO口* P- t0 s. _0 l* o. r- F9 b p
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;3 M. g! H7 f3 h) K+ F7 R
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
: m$ r9 S& A" c# i - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
+ y, o U. c" A- k - GPIO_Init(GPIOA,&GPIO_InitStructure);
8 T- ?9 u! k9 D# k: A - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;! N) |; W% F0 u, J$ E+ R; l2 i3 y
- GPIO_Init(GPIOB,&GPIO_InitStructure);) u5 Q7 F" }" b( A+ B
- ! w/ c' `5 k9 B& y6 g6 g
- break;: s; ]) P2 M0 }: K ^ x% \; f6 P
- }2 q5 v! _9 I7 c
- //2.2 部分重映射
. T* ?+ f6 d8 T1 ^ - case PART_REAMP:{1 b7 }# {/ C t0 A, q
-
( x$ ]# o t# m: t% Z! t6 U3 h" W - // 时钟分配
0 @( o( v6 D* t7 c7 t8 j - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);: w# t! Z2 T5 \1 Q
- // 初始化IO口* ~2 ^3 L0 {- K; g8 d5 h8 F
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; u( L: V* |. ?/ p+ N
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;' b* v2 C5 \) k7 T6 M
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_4|GPIO_Pin_5;
3 L2 t: ^+ _6 Q* x% Z( v - GPIO_Init(GPIOB,&GPIO_InitStructure);% n Y' [: T, U4 e' L
-
- J1 E4 x5 {1 w3 f+ U2 J% k - break;6 F$ d; a: F: p
- }
9 Y0 G/ q5 U& z2 K5 w( a6 M, @ - //2.3 全映射- v8 A. T3 i+ F, X) D2 y; G' v
- case FULL_REAMP:{- b8 \( _6 M' z/ N" M) U$ u
- ( |$ ^+ @) Q; z, o$ k1 F0 x
- // 时钟分配
' v4 Z+ N8 F. f: ?9 e( y0 b - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);. H& a8 I2 d/ j1 Q
- // 初始化IO口# o n# d8 d F; G
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;7 r+ @# t% c8 H
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;- K7 E: h* I( N# p( \ d' v; ?
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9;6 B I, U0 u$ @! \: V
- GPIO_Init(GPIOB,&GPIO_InitStructure);4 t: a3 ~, ~! }8 [% [- O
-
6 B X! z8 D m9 Z' R1 f - break; R8 G3 C) u% g, ^: N& R9 H
- }' E6 }9 o7 ?4 {3 u
- default:break;
' S7 B0 R) d1 T* T4 a - }
; u( a6 d5 S: X - }" W' Q4 Z- R! U% n6 I/ E
! Q5 D5 c! @5 d i( e% b- //***************** 定时器PWM输出初始化函数6 q1 N( x3 t9 X* Z" o
- void MY_TIM3_PWM_Init(u16 arr,u16 psc){
- ?( T1 I7 l- v1 ?! ~0 ^ -
9 X1 b. m" f3 j3 J0 I - //初始化结构体' e) Y( c1 r; E; z+ C) \
- TIM_OCInitTypeDef TIM_OCInitstrcuture;" H- E, U6 T- ^5 W
- / X3 M- P( l Q z/ F$ n
- //1.初始化定时器 和 相关的IO口
9 e5 A. G7 O/ r7 s7 x# E, P4 E - MY_TIM3_Init(arr,psc);
: D' @* O+ Q) g% K - MY_TIM3_GPIO_Init();1 k5 k1 O; T/ `2 X. W4 m
- ! w* M% J w+ }' V0 v
- //2.初始化PWM的模式: N/ T8 t& O2 y, O- A& t
-
9 y6 D' Z; d7 f3 G! ?. [' R - /**
! o0 W0 n, m5 U5 a/ k: n: w3 ~ - 选择PWM模式:
! U4 o$ [1 H% h0 z - PWM1模式:
' e0 A- i' E4 |/ D - 向上计数时,当我们 当前的 计数值 小于我们的设置阈值为有效电平,否则为无效电平,向下计数时与向上计数时相反6 {* z& N8 x9 k' G$ [
- PWM2模式:& g1 y& ]2 R) W7 d" o7 P5 y$ `5 N
- 与PWM1模式向上向下计数时完全相反& B% c* X" f' X( k4 a% f0 _5 B
- */
) J/ u- T5 a* J9 { - TIM_OCInitstrcuture.TIM_OCMode = TIM_OCMode_PWM1;
9 x. l8 Y E C8 p" N- E5 M2 s - TIM_OCInitstrcuture.TIM_OutputState = TIM_OutputState_Enable;. m( f [ X0 @ ~& J% x
- TIM_OCInitstrcuture.TIM_OCPolarity = TIM_OCPolarity_High; //输出电平为高,也就是有效电平为高
8 ^# S0 c4 S- Q: h: Z$ j! { - TIM_OC1Init(TIM3,&TIM_OCInitstrcuture); //这里是设置利用通道1输出
' t O3 S' X$ }- j -
6 ?( |2 D9 o! G [& R9 E# F - //这里只初始化通道1,我们可以根据自己需求初始化其它通道
$ ~! z0 y* |1 d3 J+ S( E - " t- m& O& c% S6 [) L7 r; l
- // TIM_OC2Init(TIM3,&TIM_OCInitstrcuture);
, j( W7 ~- l2 q. A) _- ] - // TIM_OC3Init(TIM3,&TIM_OCInitstrcuture);
~& F4 x6 y7 j# g9 `0 p+ [2 \6 v - // TIM_OC4Init(TIM3,&TIM_OCInitstrcuture);' Q5 z& H3 P* X& I; U
- 0 v. n# |4 I5 k. a5 P8 o! b
- TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能预装载寄存器" C& h- s( D8 t" K; X
- }
+ H& J* A( W1 h) e
: c3 |+ d" H. S$ }2 S- //*********************主函数调用4 p7 C# ?( [1 X+ Z
- int main(){
* C& B4 D+ g2 ?5 {2 a4 Y! V - 6 v" i0 D% H3 @- E% a
- //因为我们单片机引脚输出电压3.3V左右,我们设置预装载值为330$ S$ p1 v! L1 F0 Y! g
- MY_TIM3_PWM_Init(330,0);% b. C) B' @3 d! ?. H
- ! a# @$ _3 l6 O4 M8 a: ^% g
- //我们初始化的时候选择的是PWM1模式,当计数值小于我们的设定值100时为有效电平,这里是高电平
( M- ~! X+ D8 n - //所以对于的1通道(PA6)电压是大概就是 3.3 * (100/330) = 1V 左右,我们可以用万用表测量5 X; T5 h' \1 f' P: H
- TIM_SetCompare1(TIM3,100);
% h) ^' U; a2 C& Y4 f - 0 r) y; S. @$ {" s
- while(1);
复制代码 0 D9 J, F1 F+ X& |2 G
#5.定时器输入捕获 2 f4 w6 M* Q/ \$ T5 ` b$ T5 u
## 5.1基本介绍
. I# a; s/ e6 ~: C! J# @& @※ 上面介绍了定时器的四路通道可以输出PWM,同样的我们也可以捕获该定时器这四路通道上的边沿状态(上升沿,下降沿) ( o! X6 E& R% |$ a
※ 由此可见基本定时器也不能进行输入捕获,没有思路通道 * i, p3 `# h4 Z L, x5 N
我们可以通过输入捕获的来测量高电平脉宽时间,首先捕获到高电平,记录下改时间,然后切换为捕获低电平,得到时间
( p# c, S" B* f) o7 D## 5.2开发步骤 ### 输入捕获 (捕获边沿信号,上升沿和下降沿) 首先我们需要以一定的频率检测电平的跳变,然后对部分跳变(也就是部分输入的波形)进行过滤------ 这就是定时器里面的滤波器的任务 ( W/ v3 O8 W7 @0 E
1. 指定输入滤波器时钟频率,首先是系统时钟分给定时器72Mhz,我们首先初始化定时器的时候指定了TIM_TimeBaseStructure.TIM_ClockDivision= TIM_CKD_DIV1; 没有分频,输入给滤波器的时钟频率还是72MHz,TIM_ClockDivision也可以指定为2分频或者4分频 ; G7 T& r! D* f1 Z
2. 波形过滤(TIM_ICFilter),这里有一个指定过滤器的参数(参考芯片手册),例如我们设置参数为0101(二进制),采样频率(fsampling)为 滤波器频率/2 = 36Mhz,N=8.当检测到一个上升沿的时候,再以fsampling频率连续8次检测到高电平才确认是一个有效的上升沿,这样可以滤除那些高电平脉宽低于8个采样周期的脉冲信号,从而达到滤高频波的效果。
" }" Y% d$ `* ?& A- b+ T5 f' z- c. m7 G; i, `4 d. W
3. 配置输入分频(TIM_ICPrescaler),如果我们设置不分频,一个边沿(上升沿或者下降沿)就触发一次捕获,二分频就是两次边沿触发捕获,这里这个分频可以为1,2,4,8 6 ^% y4 M; Y- N2 G
- //定时器输入捕获初始化0 d: @8 N2 u7 v6 q3 u2 W) S& i+ l
- void MY_TIM3_Cap_Init(u16 arr,u16 psc){
* P+ ]' u {' A0 e6 a6 J - & c% L. X" i9 q) ?6 Z* |/ S% h; ^- o
- //初始化结构体
; e& C N) a1 G& A+ O* O' S - TIM_ICInitTypeDef TIM_ICInitStructure;
" B1 h. }1 \- Q$ o0 m -
/ f5 B, k# `8 g* L0 r6 i& t - //1.初始化定时器 和 相关的IO口
. P9 U/ T" D% ~. ^) Z - MY_TIM3_Init(arr,psc); ; c1 s% ^; m3 E: }( a9 k+ d$ |# M
. n3 a# t3 Z9 R( {- //这里的IO口根据自己需求改成输入,我这改成下拉输入,具体代码就不展现了 K% S/ j/ u) v, M2 |0 O& p+ L
- MY_TIM3_GPIO_Init();7 e3 H) `4 f, T' J
-
0 R% G. @3 S( W% O9 K4 T - //2.初始化定时器输入捕获
( b- H ?$ R9 w o- T; y, z - TIM_ICInitStructure.TIM_Channel = TIM_Channel_1 ; // 设置输入捕获的通道/ l; P1 H) K0 p8 p
-
2 K2 L2 ^5 E; D: R. k; Q. O - //不使用过滤器,假设我们想使用,例如上述举例使用0101
" S% s0 C ?7 y+ u; z - //我们就给TIM_ICFilter = 0x05 ,(0000 0101),根据上表可以知道这个值范围(0x00~0x0F)
3 p7 O6 m5 T+ x I l - TIM_ICInitStructure.TIM_ICFilter = 0x00;7 I* t! L2 Z8 y& o0 Q! ~
-
; \& u3 B5 A5 `6 Z! C - TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
7 w" g: @! Y; f; k- u - TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,这里不分频,1次检测到边沿信号就发生捕获* C# d# B$ W; }& [# ^; A
- 1 V( A* t8 _( \8 [8 [
- /*2 d7 V6 V$ N+ ~+ x& T: g
- 这里说一下定时器通道可以进行交叉捕获,通道1捕获通道2引脚上的边沿信号,通道2捕获通道1引脚,通道3可以捕获通道4对应引脚,... 2 `" c7 ~6 Y/ ~! S/ S. t
- 但是只能相邻一对可以相互捕获,例如通道2不能捕获通道3引脚边沿信号
, D& _& o' A: ]3 ~ - TIM_ICSelection_DirectTI 表示直接捕获,通道1对应通道1引脚,通道2对应通道2引脚1 W* d+ i$ |& N) r5 b0 |
- TIM_ICSelection_IndirectTI 表示进行交叉捕获; c1 P$ _% h+ \* o2 w
- */
9 T6 J* P, C$ w& O J& g+ D - TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射捕获对应通道的引脚( n9 _4 V, H/ t6 o6 R! p
- TIM_ICInit(TIM3,&TIM_ICInitStructure); # Z; y( @0 a( k9 V& N2 K1 v# m
- - [1 I% g: \. S9 j, O
- }' \" d0 s4 L+ {( j) ^
- //****************主函数+ ]1 T8 P4 M( L; w
- int main(){
3 F- l& c: l: Y4 `$ [% P - //初始化输入捕获- o$ c% @) S% q$ q Y8 W
- MY_TIM3_Cap_Init(1000,0);3 @5 U/ B# S0 z0 X5 o
-
8 \8 w' _' I2 U* m/ S( @' _2 [ - while(1){' R7 Z' l: Q; {) Q4 [/ `! [0 d9 D
- //检测是否捕获到上升沿
3 n1 g+ Z9 y2 l# u; U - if(TIM_GetFlagStatus(TIM3,TIM_IT_CC1)){4 E9 g* q$ ^, h! ~* _" r0 a0 h* W
- TIM_ClearFlag(TIM3,TIM_IT_CC1);
& S+ L# X) R% m% P8 D - //捕获到上升沿之后的任务... B7 r, k% X) K
- //一般测量高电平脉宽,我们可以先捕获上升沿再捕获下降沿
+ _2 i, U# P7 C; V8 s - //TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); 修改为下降沿捕获
3 S/ R1 {* E- d - }
: E8 g- t7 E5 Y/ X -
' X' c9 g1 @3 x% Z - }4 L7 u8 d, A6 q9 I) @
- }
复制代码
: U" I* o' r' `/ S* ]+ L p: P
9 i; I o$ [. H0 V#6.定时器中断 # `0 w5 n( a% e5 d `+ U
1.谈及到中断,我们就必须涉及到NVIC,具体关于NVIC请参考我的另外一篇,这里是直接使用,我们使能定时器3中断并且配置完抢占优先级和响应优先级之后,再在主函数中使能其更新中断和输入捕获中断 p1 T! Y% H/ v5 f' a: S1 x
- //使能更新中断和输入捕获通道1的中断1 d/ k9 x( p F# z0 d4 X* c
- TIM_ITConfig(TIM3,TIM_IT_Update|TIM_IT_CC1,ENABLE);
复制代码
/ g; i, Z6 ], n2 H5 ]; E. A* I( O6 b. _5 A E
2.我们使用中断的一个主要目的就是能够及时处理信息,不用在主函数的while循环里面等待
; \: b- M( _. ^- //定时器3的中断处理函数
0 i0 t# i- r1 ~ - void TIM3_IRQHandler(void){
- x" O# j& d, j -
9 E6 K" X. r0 @ - //1.判断是什么中断4 V& N4 q+ |$ V( U
- # q+ R F, I7 u* c1 ?
- // 1.1定时器更新中断
. s0 N) I$ a `$ H: u/ ^4 t - if(TIM_GetITStatus(TIM3,TIM_IT_Update)){
! Z0 l7 \1 z0 P {/ Y9 w) ? - //...处理定时器更新之后任务) ?. S; M9 J2 [. e& R
- }
5 c& ?9 c4 @( d# Q% Q- V - // 1.2如果是定时器 通道1的捕获中断
' i1 Y/ k- H9 S" G" g1 i4 u - else if( TIM_GetITStatus(TIM3,TIM_IT_CC1) ){
2 E9 n+ c; z! b+ n1 ]7 _6 V5 S - //处理输入捕获之后的任务: b7 G) @% T( j+ L2 W! m
- //TIM_OC1PolarityConfig(TIM3,TIM_ICPolarity_Falling);更改为下降沿捕获
% g. i0 h' T0 Q. a, P - }
( P! d+ t) @% D* U2 C: q) k2 U - - U5 |: J# L/ S2 o3 z7 K4 D1 M' ~, s/ e
- //2.最后将中断标志位都清理掉, b. ~6 G( L: F, j) U
- TIM_ClearITPendingBit(TIM3,TIM_IT_Update|TIM_IT_CC1);
2 U3 a8 K% L% q" Q1 M - }
复制代码 # D9 v) J* @. n; {" w8 A, f/ @
$ @) ~, T/ b. P, ~( \- L8 P文章出处: 智能车杂谈 " }: G# l" t" m2 {- E X) a
|