实例讲解之STM32的高级捕获模式
5 }9 L( |3 R9 j
简单介绍一下stm32的输入捕获模式 V2 p. X8 R; a- z7 w8 k8 l
STM32的通用定时器具备基本的输入捕捉功能。所谓输入捕捉功能,是指通用定时器可以通过检测输入信号的跳变沿,检测到跳变沿的同时将计数器的当前值写入相应的寄存器。我们可以利用定制器的输入捕捉模式可以测量输入信号的高电平时间、占空比和频率。
" n1 y: ?! N- G8 \
这是定时器的内部框图
7 F/ x# S4 [% g- ?
0 W9 v, |" |8 | 我们STM32的定时器有两种捕获模式普通输入模式和高级捕获模式(PWM输入模式) 需要注意的问题:定时器的时基频率不能太高,如果定时器工作于36M,采集50Hz的信号就会出现偏差(实测),所以程序中将定时器的时基频率配置为了1M;如果存在两个以上中断,需要设置中断优先级,否则容易出问题。 1 w& [, Z) c8 K: {8 {% l) l
一、PWM输入模式的基本原理 PWM输入模式是输入捕捉模式的高级应用,对于测量频率较高的输入信号的频率特别精确,当然,为了实现这个模式,也得做出一点牺牲。相比于基本输入捕捉功能的实现来说,PWM输入模式中,一路输入信号同时映射到两个引脚,而且只有第一和第二通道可以配置为这种模式,换句话说,每个通用定时器只能测量一路输入信号。 / K7 V, }' ]8 a6 T) E# `( c
PWM模式捕获方法:利用TIM2_CH1作PWM输出,TIM3_CH2捕获上述PWM信号,并测出频率和占空比。设置PWM频率为1KHz,占空比50%。 5 Z0 Z- L# P8 C- D1 i
具体步骤: 1. 为了实现PWM输入捕获,TIM3占用了2个通道。第2通道的电平变化会被第一通道和第二通道引脚检测到,其中第一通道被设置为从机模式(如何快速判别主从机模式,规则如下:如果设置的是第二通道作为PWM输入捕获,则剩余的第一通道都为从机,反之亦然)。 2. 假设输入的PWM从低电平开始跳变,在第一个上升沿到来时,1,2通道同时检测到上升沿。而从机设置为复位模式,所以将TIM3的计数值复位至0,此时不会产生一个中断请求。 3. 下一个到来的电平是下降沿,此时通道1发生捕获事件,将计数值存入通道1的CCR1里。 4. 然后是第二个上升沿到来后,此时通道2发生捕获事件,将此时的计数值存入通道2的CCR2里。复位模式此时又将TIM3计数值复位至0,等待第二个下降沿到来。 5. 一次捕获过程完成,则PWM的频率f=72M/CCR2;占空比:duty=(CCR1/CCR2) X100% # c2 P0 p/ g w% l% U. m
二、具体看看怎么配置
: V5 Y F$ n Z( t
单片机是stm32f103,如上述所示用TIM3的CH2通道捕获PWM波,注释非常详细,可以直接调用 - void tim3_pwmin_cfg(void)8 b& d+ d, b" D$ r8 K/ @1 r- i1 ?
- {4 D: h, f* {! X- C% Y; x/ {
- TIM_ICInitTypeDef TIM_ICInitStructure;
2 K) A- b3 Y6 m% }! S - TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;4 `6 N L. ?9 \1 {: I6 u4 [7 Y
- TIM_DeInit(TIM3);
' a* v3 D1 T" H9 e - /* 定时器基本参数设置 */4 f) J6 Q( \; H/ w- a% i) w5 T
-
. l# N: |- z8 z! o - /* 定时周期: TIM_Period+1 */
. B3 Q/ ?* [! }+ @% u: q - TIM_TimeBaseStructure.TIM_Period = 0xffff;
, w# D! s# W2 c+ r, }6 i' c0 j9 @9 u - /* 设置预分频TIM_Prescaler,输出脉冲频率:72MHz/(TIM_Prescaler+1)/(TIM_Period+1) */2 l/ m7 r: j2 O ^: l
- TIM_TimeBaseStructure.TIM_Prescaler = 7200;! G* i! h l/ E4 |3 D+ C
- /* 向上计数模式 */; b2 ~% k/ \! m0 z! I/ b# ?+ h
- TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
7 J7 \3 x: v/ | - /* 设置时钟分频系数:不分频(这里用不到) */
- {( i0 f( l6 _( |8 } - TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; 2 p3 u% y2 O/ X& O# W5 l6 m% ^
- /*设置重复溢出次数,就是多少次溢出后进入中断,一般为0,只有高级定时器才有用*/9 {1 c0 s4 K7 L
- // TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
P/ ^, c. d2 E; W" M - TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
a- r- f) Y4 p -
6 a9 x9 j7 U$ t$ U, l; J7 {' _
# q! n, k' I1 X- /* TIM3通道2*/
- A; z0 H9 o8 u% s' r9 j( R2 h - TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;, H& g! p% ~/ o d+ H
- /* 上升沿捕获*/' p* p( C. V1 a$ n1 b, n( Z- z- ?2 n
- TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
/ Y' K. A* q" v; Q - /* 映射到 TI1 上*/
. q) M3 m' c2 }; M% [- R! T - TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;0 \( W, ~0 u3 O. ^
- /* 预分频系数,不分频*/
: m5 E2 G C z. c - TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;2 f2 K4 |. s; E4 ~4 X5 ^
- TIM_ICInitStructure.TIM_ICFilter = 0x0;3 V' [+ h6 I+ E- W' {2 I
-
* s( h1 U2 u- | - /* PWM输入捕获模式是输入捕获模式的特例,初始化TIM3输入捕获参数 */6 M; K# E- i' O& t3 T
- TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);# Z- B& R- g5 r8 N! |6 c
- /*选择IC2为时钟触发源*/
( z3 \ a1 {! \6 p3 N! q - TIM_SelectInputTrigger(TIM3, TIM_TS_TI2FP2);
( G+ z. i7 w- g! h1 R1 B - /*启动定时器的被动触发*/" u4 E4 m3 S, T: v% B! ]1 ^
- TIM_SelectMasterSlaveMode(TIM3, TIM_MasterSlaveMode_Enable);5 q; t% t% t% n: g
- /*从模式控制器被设置为复位模式-选中的触发信号上升沿重新初始化计数器并产生一个更新信号) _5 _# L1 j: A% V' m7 N; K
- (上升沿一到,TIM4->CNT被清零,每次上升沿来到,CNT都会被清零)*/
8 s8 f$ c" |" X1 c C/ \5 T - TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
; \, }$ k5 A( C1 r& ] - # @. {8 I* Z' u% a. D8 C `
- /*捕获中断打开*/
/ P+ n- o8 Y' a! J. u) G2 j - TIM_ITConfig(TIM3, TIM_IT_CC2, ENABLE);
- T& d9 y+ ~( X* Y - /*使能定时器*/. S* {! G/ ^9 {1 I( E4 T2 U; I
- TIM_Cmd(TIM3, ENABLE);) J! g/ g) O- K+ X' Z
- * }$ g, @. K0 K: H* p- r, {9 B
- /*捕获中断清除标志位*/
: W2 Y" W9 q3 K, Q0 Q; Y - TIM_ClearFlag(TIM3,TIM_IT_CC2);
& G( x9 Z- l, |; N
& b6 A, m1 @ U. L( G-
/ c% C) {7 ~9 M ?& L" W- } - }
复制代码
, M$ y0 `3 _% m& U 中断配置,中断分组 - voidnvic_TIM3_cfg(void)
) [$ h$ o. j+ ]. o, A - {
0 z) \$ n( {* u8 N4 p - NVIC_InitTypeDef NVIC_InitStructure;
0 f5 M( Y, e, x `8 J( \/ m4 U - ! }) U0 j8 `1 I5 z
- /* 使用优先级组0,0位抢占,4位响应 */3 J% u3 p' H0 P: r/ U* K( d
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);$ p6 g x. ]8 [6 w9 ?; l+ L
- NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
. i" ]3 z2 l5 \! L- X - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = ST_NVIC_TIM3GL_P;* o) v4 B8 Z' e: b& x5 H
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = ST_NVIC_TIM3GL_S;
& [( U3 w* ]0 I+ l7 E0 | - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- Q% m, X0 L7 ` w0 p! s, N/ B- j - NVIC_Init(&NVIC_InitStructure);
9 u* n$ d) X" ]) F" \2 o - }
复制代码3 }/ }% M$ P, @: v' Z3 Y5 j
中断服务函数 - void st_tim3_irq_service(void)
b+ A' W( x; O& t* s: { - {
5 G! y* d8 ~- ]7 w
# E" I4 z' U2 C; `9 z- if(TIM3->SR & TIM_IT_Update) //if ( TIM_GetITStatus(TIM3 , TIM_IT_Update) != RESET ), c5 Y9 ~+ G5 d
- {
+ V; B0 ?1 o( X5 b9 N" R - TIM3->SR = ~TIM_FLAG_Update; //TIM_ClearITPendingBit(TIM3 , TIM_FLAG_Update); //清除中断标志
$ x4 \9 k/ V4 o- `% k
3 @4 ^, [, A0 X. f9 {) t- float IC2Value=0;. L) b6 P$ p6 x$ O1 n
- float DutyCycle=0;
; h% w; A B' u3 v: P
* I3 o- H2 c( o1 p6 |- float Frequency=0;
9 E8 o/ j# e/ | - float pulse=0;
/ l, K* |) W p4 B% h: @2 v7 H - . N' p$ f1 d% v8 D
- IC2Value=TIM_GetCapture2(TIM3);//读取IC2捕获寄存器的值,即为PWM周期的计数值
5 a9 l$ L. E) i- o" V; t; ?8 ^8 u - pulse=TIM_GetCapture1(TIM3);//获得占空比的值' h: R, ~; _" t, o. } g
- // DutyCycle=pulse/IC2Value;3 c! X2 Q" i' A3 N3 z
- // Frequency=72000000/IC2Value;2 G, T/ ]$ p* F- S; J
- // duty=(u32)(DutyCycle*100);
4 G7 W" C4 o) I4 f5 ] - // freq=(Frequency/1000);
/ \- V1 J* X3 G& W - , b! n) H) B! m: v6 G5 A
- // flag=1;; N* a. {/ d, ~% ^/ V
-
) j; ]- n; V! p. d- e - ; K) v# ? U0 X. d, k
& v1 F9 V8 r+ v, F' _- }. O1 A7 u, g3 A0 I1 n) U9 i
- }
复制代码
- j& c* q" S9 Z- y$ {; j 看到中断服务函数里有两个函数TIM_GetCapture1(TIM3)和TIM_GetCapture2(TIM3),原理非常方便的就把高电平时间和pwm周期的捕捉到了,原理上面讲的非常详细,并且在高速的PWM波捕捉时非常实用。 3 G$ V6 q9 U# R, v# J4 L
但是注意了。对于高级定时器和通过定时器只有通道1和1才可以使用PWM输入模式 / x4 ~6 _. Z- E% k0 H
; z: r g3 g8 y( _+ r* s
文章来源: 星球号
# B0 @- |8 U; U2 w/ C, K7 u* v |