STM32定时器pwm模式输入捕获##
' o2 U6 L; c& a x9 y, Z# WSTM32中的定时器,除了TIM6和TIM7,其他定时器都有输入捕获功能。这种模式通常用在对输入信号频率frequency、占空比duty、高低脉宽的计算中,具有很广泛的用途。6 a; r, n6 e& B3 u0 a( C: l; U
; M! B7 b( u; w* u! y! L; m: F. y
7 w1 x1 |. l7 _( _, ySTM32的输入捕获,简单的说就是通过检测TIMx_CHx上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存(TIMx_CCRx)里面,完成一次捕获。同时还可以配置捕获时是否触发中断/DMA 等。' I2 F D5 Z" d$ x) l: ~
M( K ^! `' x# u" r! D. V
% h. z# c/ U1 }
PWM模式捕获方法:利用TIM3_CH1作PWM输出,TIM2_CH2捕获上述PWM信号,并测出频率和占空比。设置PWM频率为1KHz,占空比50%。( O# }5 R% W# g+ h+ e( p
具体步骤:8 V! r" a. n4 u# Q& b0 a
+ X3 U4 [0 ~, z0 `5 I; r' t
+ F% w; S8 C- S1、为了实现PWM输入捕获,TIM2占用了2个通道。第2通道的电平变化会被第一通道和第二通道引脚检测到,其中第一通道被设置为从机模式(如何快速判别主从机模式,规则如下:如果设置的是第二通道作为PWM输入捕获,则剩余的第一通道都为从机,反之亦然)。' P, ~2 b% R/ r$ w5 p
2、假设输入的PWM从低电平开始跳变,在第一个上升沿到来时,1,2通道同时检测到上升沿。而从机设置为复位模式,所以将TIM2的计数值复位至0,此时不会产生一个中断请求。
* C# c, x* }9 E* @' z( p3、下一个到来的电平是下降沿,此时通道1发生捕获事件,将计数值存入通道1的CCR1里。
5 L* \2 `& Y( {% }然后是第二个上升沿到来后,此时通道2发生捕获事件,将此时的计数值存入通道2的CCR2里。复位模式此时又将TIM2计数值复位至0,等待第二个下降沿到来。3 ]5 n' l8 h5 R( o
4、一次捕获过程完成,则PWM的频率f=72M/CCR2;占空比:duty=(CCR1/CCR2) X100%
9 _! ~+ p, w q5 ~. q; x% q注:
) O+ A6 {9 b1 D( f$ k, WPWM输入模式时,用到两个通道(一般用TIMx_CH1或TIMx_CH2),只给其中一个通道分配gpio时钟即可,另一个在内部使用。给一个通道分配gpio时钟后,需要设置另一个为从机且复位模式。(例如使用ch2,ch1就得设置成从机模式)。当一个输入信号(TI1或TI2)来临时,主通道捕获上升沿,从机捕获下降沿。2 p8 l8 n* g3 F$ W
在CH2通道中:
: E D$ o2 O; L& m# w2 J% hTI2FP1和TI2FP2都来自同一信号TI2 的边沿检测,信号相同,同一个TIx输入映射了两个ICx信号。( p* { M6 J/ K0 V8 ^
TI2FP1和TI2FP2可以分别由连接到的ICx (IC1或是IC2)相对应的控制寄存器设为上升沿或是下降沿触发,这两个ICx信号分别在相反的极性边沿有效。如果TI2FP2设置为上升沿触发,则TI2FP1设置为下降沿触发,二者极性相反。
/ H5 }" x6 o4 ZCH1,3,4相同。) G, ^! H3 y @8 m) G+ ~
1 ?4 D1 K# V, Y
0 ~- G, h. W; h8 s具体程序: Y3 f& R, M- f$ n
- include “pbdata.h”
4 v! K) o8 H1 N( n+ l/ Y4 R7 ~
b+ F5 I' E3 X+ e" L4 @- void RCC_Configuration(void);
& i/ p& t5 d, u# i - void GPIO_Configuration(void);' G' f" _6 Y3 F5 Y8 t& z3 E
- void NVIC_Configuration(void);& b. U0 `/ \( C' ~
- void TIM2_Configuration(void);
; n! b! r* U; V v - void TIM3_Configuration(void);8 f: h; ]& S4 f; ~$ e- Y B( V# ]
- void USART_Configuration(void);5 Y( Y, h$ m% x; `
7 W& v5 F- B# ^7 i- int fputc(int ch,FILE *f)
8 G8 F. u1 d) @2 L/ K% d h - {! r- l3 ^8 S/ E6 ^6 g& f$ t
- USART_SendData(USART1,(u8)ch);
- M2 @ c9 \' x q - while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
- C' t2 f& b: r/ I5 ~& J - return ch;: ~6 k3 N9 c/ c
- }
/ m) M* W0 K1 B( D5 g- f - 1 X5 x0 c/ k1 C& P3 i' U) i# s
- int main(void); ?0 `) g2 V* h! W3 w: n
- {* |& g6 f" K* J. Q! i* |
- RCC_Configuration(); //配置时钟
E6 z3 z; p, g3 w1 a$ @/ }$ Y - GPIO_Configuration();//IO口配置/ D" ~# m% F( l. M' b) k
- TIM3_Configuration();
3 I+ x4 w' G3 n4 \ - TIM2_Configuration();! }+ n/ |, v w$ F- R
- NVIC_Configuration();
& u/ d! b' u& s% v, C6 ~- D - USART_Configuration();
4 u1 N+ L$ R; H
% w+ r* u& E# Z6 s4 H- while(1)
' |' p* b7 O! M" v X1 ~+ A9 R - {$ Y' H1 k5 ]/ e2 @
- if(flag==1)" |( { G2 j+ G1 _$ n' R! A* M) y
- {
1 d' |7 t& D0 G9 [6 R3 z - flag=0;
2 {6 Z* h. p' |1 R* ~ - printf(“the duty is %d/r/n”,duty);
2 o5 l* Y/ Q2 V0 x/ t' i1 Z - printf(“the frequency is %.2fKHz /r/n”,freq);
0 u0 S/ o5 M" N" S - }. }7 n1 w/ u' k. {3 r
- }
5 E; N8 d+ Y d - }# k3 w& I' n2 s9 R( R
+ f$ b+ b" _4 r! ?6 }. E- void RCC_Configuration(void)" h+ j5 X) ]! p( U6 I* A" z
- {
+ p! k; R! o6 ?/ h9 u% x/ G - SystemInit();2 u$ R$ k' ~7 d8 [
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);
( M5 Z0 ?4 p7 s" [/ ? - RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2|RCC_APB1Periph_TIM3,ENABLE);
) ^! p9 W9 z: i3 `# o4 `4 ~ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
: ~: S# w0 z9 L: K: g) G* X O: y2 s; _ - }
# Y5 x$ J N0 m" _. n
$ J. P8 m6 }: R. r* K6 |+ P) H- void GPIO_Configuration(void)
: W$ w0 e+ E* X. [3 }, s - {
% ?% W, N: g# G3 @ c - GPIO_InitTypeDef GPIO_InitStructure;" z* S9 N9 V$ @1 Q
- //LED
& V- o- d* l) U( M - GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//TX
2 @: L8 `! O4 ^ y/ k5 K9 i/ U+ x: X - GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
. f) r' y5 U& |- q - GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
: o6 }% M) r/ n - GPIO_Init(GPIOA,&GPIO_InitStructure);3 S# C6 Q y6 N8 b0 H7 M
- $ @) l* u5 S- a8 l$ ?) ?* v
- GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//RX
) X. M7 p6 W1 M R2 b2 N. j3 W" B5 g - GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
* ]4 W& L- }8 u - GPIO_Init(GPIOA,&GPIO_InitStructure);
; Y1 ?; z9 E# F/ V& I* j( t - : B! j3 ?: e' r8 l
- GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;//PWM,TIM3_CH1$ s2 \% I* x2 H, O' ?7 K' v( M
- GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;' j/ ]$ j) X% I& d2 @4 F: F0 \. [
- GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;0 H2 Q; Y* W. P8 L2 Z$ `
- GPIO_Init(GPIOA,&GPIO_InitStructure);
7 Y) |* ^' S1 b. U
' C% }: P! p, q$ \/ k& N- GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;//TIM2_CH2/ j: `) A$ t B% v. P
- GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
4 [* Z; z/ X$ |$ S0 C - GPIO_Init(GPIOA,&GPIO_InitStructure);
7 h9 w8 H6 N+ M# ]- T# ^& k - }% r) D5 P5 A- k$ [: T; h0 ?( k
9 H# h( U5 j' z' f- u9 `- void TIM2_Configuration(void)
/ X& v0 k" c# T - {2 h5 ~2 I; i& K0 |) `: X7 y
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;0 N6 Z, a `0 W1 i+ t0 w0 }
- TIM_ICInitTypeDef TIM_ICInitStructure;
1 W9 U2 d$ A& L2 m3 C6 t - 8 X5 z4 w" C+ g$ z
- TIM_ICInitStructure.TIM_Channel=TIM_Channel_2;//选择TIM2_CH2,选择输入端 IC2映射到TI2上5 D( F& S- T; h+ z7 o) D$ q( a; V
- TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//上升沿捕获3 z# Z9 l% x8 d9 [
- TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//映射到TI2上 T) n7 Y1 n. G; x, o4 L) t- {' f
- TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;//在捕获输入上每探测到一个边沿执行一次捕获
- N; F& a$ Z& a" S - TIM_ICInitStructure.TIM_ICFilter=0;//滤波设置,经历几个周期跳变认定波形稳定。(采样高电平,只有连续采集到N个电平是高电平时才认为是有效的,否则低于N个时认为是无效的,N取0x0-0xF)
; M& w% `1 C3 p! o/ q - TIM_PWMIConfig(TIM2,&TIM_ICInitStructure);//以上是输入捕获配置
; [" \3 O4 K7 s - TIM_SelectInputTrigger(TIM2,TIM_TS_TI2FP2);//选择滤波后的TI2FP2输入作为触发源,触发下面程序的复位
( I* g4 c1 e' b6 }3 s - TIM_SelectSlaveMode(TIM2,TIM_SlaveMode_Reset);//从模式控制器被设置为复位模式-选中的触发信号上升沿重新初始化计数器并产生一个更新信号(上升沿一到,TIM2->CNT被清零,每次上升沿来到,CNT都会被清零)
: B/ i4 C" A1 G' i* U4 f4 Z+ z) B - TIM_SelectMasterSlaveMode(TIM2,TIM_MasterSlaveMode_Enable);//启动定时器的被动触发# ?! [+ A+ t% S+ a5 ^0 Z( p
- TIM_ITConfig(TIM2,TIM_IT_CC2,ENABLE);//捕获中断打开
% @) Y0 i( P4 c% P+ s: [) }8 H" q - TIM_ClearFlag(TIM2,TIM_IT_CC2);//清除标志位
: _$ b8 E4 g6 K6 ` - TIM_Cmd(TIM2,ENABLE);//使能定时器2
6 X5 E9 F# \ C: m - }+ C' q8 m+ g2 w Q- B
. k* x o, f' T. O. z+ l# J9 k- void TIM3_Configuration(void)
& @- S5 k5 q) J3 M5 O - {9 j! M2 a& \( {8 w# i
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
4 u1 s" x2 P4 Z0 d4 q$ F0 A - TIM_OCInitTypeDef TIM_OCInitStructure;
, l# `4 t' U% b1 p6 U( l - TIM_TimeBaseStruct.TIM_Period=72000;//计数初值
+ ~2 p( a8 h" h+ m* D - TIM_TimeBaseStruct.TIM_Prescaler=0;//分频系数
& F% a1 I- E; Z, q* e. {7 T( F7 s - TIM_TimeBaseStruct.TIM_ClockDivision=0;//时钟分割
; g' j+ j3 C% d/ V9 v( l2 G - TIM_TimeBaseStruct.TIM_CounterMode=TIM_CounterMode_Up;//向上计数模式
; e3 e" Y, G$ q+ v# ~& u. ~4 ~ - ' N: j% A% a% L! u1 A) @4 t$ u
- TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStruct);
# `; m) W Y ]* L
9 e* F+ ]; _: f. \, \. |$ c1 g) L- //TIM3_CH1作为pwm输出9 k- R8 o. f k) d
- TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;3 U: a9 _. Z- M
- TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;" | m! h( y1 O4 i1 B
- TIM_OCInitStructure.TIM_Pulse=36000;% F+ _* \( k0 y
- TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
; A/ R- L# q ^9 j! R% r; I
) P; @- \4 @0 ~! v- TIM_OC1Init(TIM3,&TIM_OCInitStructure);7 b: Q! }. d$ o5 Q! i2 Q
" t M; z" L9 V* B5 w. H3 g- TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Enable);
$ U4 c4 H/ ? S- [/ c7 A- P' {9 C - TIM_ARRPreloadConfig(TIM3,ENABLE);
* e) l0 R5 [/ r ?1 @# ^! R - TIM_Cmd(TIM3,ENABLE);
5 U! A& @/ A) F5 u% K x Z - 6 g8 |0 V! I! M; J7 Z4 k
- }
4 s3 |- ?5 s6 G6 V - 8 O- }) N, G) j. ]
- void NVIC_Configuration(void)
9 J/ {/ R& E/ C) Q% i1 y: n - {4 j1 e1 H$ _4 P6 i- \ F
- NVIC_InitTypeDef NVIC_InitStructure;
) H% B9 s) R: }
; f" e" c+ }; c( U( b# g- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);# ~% H: @/ T* d# }/ j
" I% N9 J' ?2 V( [- NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;( q$ K; i0 {* {1 X6 t9 D
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
- _/ Q: |9 m/ r% ^2 F - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
4 o# W8 M) \/ b5 c B, T - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
6 A4 t) N1 A3 I7 C5 C' Q7 k - NVIC_Init(&NVIC_InitStructure);
+ m! ~* C! F- Y3 _! D6 l ]
+ o/ O5 \) a0 U/ q+ g. T7 L- }
# _. Q2 ]4 I& W# c7 }+ T3 H - 8 G ~* \( @" C4 w
- void USART_Configuration(void)3 n" _3 B- Y. D1 G
- {
i f$ F1 ]- B% N Y0 h: `# F - USART_InitTypeDef USART_InitStructure;
- k4 H7 i& S/ k$ S9 v" _1 X
- ?0 P5 e) c9 z' c3 S0 K- USART_InitStructure.USART_BaudRate=115200;( z3 [$ X) L; ?2 z, k" m4 ?8 v
- USART_InitStructure.USART_WordLength=USART_WordLength_8b;6 g( ` P0 i! d
- USART_InitStructure.USART_StopBits=USART_StopBits_1;, Z0 }2 y& L% j2 Z, Z- K
- USART_InitStructure.USART_Parity=USART_Parity_No;5 d6 C! J$ u( D( O9 D5 }7 W
- USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;& j/ o' C* a( p- v
- USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
, q5 M! J: O# H7 `1 [
! ^4 a* T: S) z, t6 D u8 n- USART_Init(USART1,&USART_InitStructure);5 Z v: _' i$ S8 }) P
- USART_Cmd(USART1,ENABLE);/ V' i/ R4 p. {! s$ h0 F r
- USART_ClearFlag(USART1,USART_FLAG_TC);
0 n# v$ [8 f/ O2 T& T - }+ d' c4 n0 f4 G6 W1 B O) s( h
1 V! ~8 W3 P- I$ y2 W6 u) ]2 C- //中断程序
7 x @( o8 C& x4 V/ u) x9 b9 N - void TIM2_IRQHandler(void)
1 U( }. i9 ^; t, r- s - {
r) f0 u5 P, T. i2 a% Z - if(TIM_GetITStatus(TIM2,TIM_IT_CC2)==Bit_SET)
4 c+ L+ t) _- O2 Q+ f2 y - {
w( F* E+ T% V! V q - float IC2Value=0;+ \8 t+ R# V7 S1 d5 `$ K/ S
- float DutyCycle=0;
; t. l9 ~5 a! m/ t& e- k+ D" s+ I" [
7 B# {) k$ `/ ]6 N( O- float Frequency=0;
. D! a; ^+ {" d6 _5 i% o4 m - float pulse=0;' U1 z* m. I- t+ ]) t
' F8 k: f* ^6 e+ k6 F3 Q5 l# _- IC2Value=TIM_GetCapture2(TIM2);//获得CCR2的值6 j4 _; |; J3 P" e: m8 @/ R4 R
- pulse=TIM_GetCapture1(TIM2);//获得CCR1的值
! P8 i; ~$ g6 @' [2 t; W' y/ g7 r - DutyCycle=pulse/IC2Value;
. h+ g5 U1 E2 p0 d# Y - Frequency=72000000/IC2Value;8 D" \8 J9 B: B/ k# x
- duty=(u32)(DutyCycle*100);7 v0 N/ q% H- r
- freq=(Frequency/1000);
; C! m: y K& E" `1 M
3 G2 r2 `# w7 v9 J9 N" D4 O- flag=1;; ^* u# q7 Q; Y$ Z! l$ i
- % m; X b5 s ^* [) Q, y% }% i
- TIM_ClearITPendingBit(TIM2,TIM_IT_CC2);
- @! Y- o+ Y3 z$ ^" B$ Y- t# _ - }- i$ {! l% z+ H7 c
- }3 j8 H& B. p/ r; K
9 D L# h( c: T1 i- duty和freq是定义的全局变量
6 j' \, ]* l$ X- @, G - extern u32 duty;8 `9 C" V* d! P! m" z, J
- extern u16 freq;+ t v* U9 b4 p6 E* z* _* u
2 K& O4 e* m( k- u32 duty=0;" H+ O: s. D O0 E/ l1 E
- u16 freq=0;
复制代码 经调试程序可用。频率和占空比都对。频率的设置不要太高,因为printf函数发数所需时间较多,两次捕获的时间间隔短的话可能使printf不能及时地送出数据,造成数据被刷新。更改方法,使用:USART_SendData();函数发数。. C2 }) c' n$ L+ q& Y# h
" {' \6 J. j& A- g2 l6 U; ^, I5 `( v
其他应用:
1 t4 G' { d; k' l, y& M1.测量高电平时间:a,上文中的CCR1就是高电平时间;b,当使用一个通道CH1时,先将触发沿选为为上升沿,产生捕获中断,读取CCR1中的内容,再改变触发沿为下降沿,下降沿到来时捕获,再次读出CCR1的内容,两次相减为高电平时间。
; ?8 L; p, o+ e0 n$ b2.测量脉冲个数:a,开启定时器1的捕获中断,捕获信号边沿(上升沿或下降沿)进中断,count++计数,再开启定时器2的更新中断,定时一定时间进更新中断,读取count值,此为脉冲个数。b,开启外部中断,配置沿触发中断,count++计数,再开启定时器x的更新中断,定时一定时间进更新中断,读取count值,此为脉冲个数。2 E5 K- |: y4 t) w1 n. G# Z
3.计算一路信号的频率,可以选择定时器的CH1或CH2(不可同时计算两路频率,否则计算出的频率是后初始化的那个通道代表的信号频率。当然,要同时也可以,每次得到频率后切换通道,将数据通过DMA取走即可),使用PWM输入捕获模式,使用上升沿触发。而CH3和CH4通道则不行,如图2所示,只有红线所指的4个信号连在了从模式控制器上。所以,对于3和4通道,计数器的值不可能在接受到信号上升沿时候,有复位这个动作。
3 o; d' l1 H# g. p# B. U& ]3 y5 c& U n- A0 P2 T4 `; Q+ P
! {' A& \6 ]) U6 K& {" g, D5 ~
|