STM32定时器pwm模式输入捕获##
, y- D, ~8 r0 J, I5 b' uSTM32中的定时器,除了TIM6和TIM7,其他定时器都有输入捕获功能。这种模式通常用在对输入信号频率frequency、占空比duty、高低脉宽的计算中,具有很广泛的用途。* Q' ]% V6 r- f5 Q
# P; d1 A* Z( n" o. D
7 b' K1 p/ h* o* ?3 LSTM32的输入捕获,简单的说就是通过检测TIMx_CHx上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存(TIMx_CCRx)里面,完成一次捕获。同时还可以配置捕获时是否触发中断/DMA 等。
" w9 ^3 G* B' ]
$ P, u) P2 ]0 C2 d
# c9 Q# @0 ?% D) g5 V; g0 JPWM模式捕获方法:利用TIM3_CH1作PWM输出,TIM2_CH2捕获上述PWM信号,并测出频率和占空比。设置PWM频率为1KHz,占空比50%。
( ~0 s1 V$ U+ f3 W+ _8 R具体步骤:3 ?9 N5 ^% P3 O) {, w& E
% s, c$ k$ x: b4 Z K3 U5 d: o% s G. k7 \7 F" ^6 d
1、为了实现PWM输入捕获,TIM2占用了2个通道。第2通道的电平变化会被第一通道和第二通道引脚检测到,其中第一通道被设置为从机模式(如何快速判别主从机模式,规则如下:如果设置的是第二通道作为PWM输入捕获,则剩余的第一通道都为从机,反之亦然)。
4 Q% O* \$ u0 r2 r1 K1 k2、假设输入的PWM从低电平开始跳变,在第一个上升沿到来时,1,2通道同时检测到上升沿。而从机设置为复位模式,所以将TIM2的计数值复位至0,此时不会产生一个中断请求。$ ]3 O; B/ U4 A- e. ]( H r# R
3、下一个到来的电平是下降沿,此时通道1发生捕获事件,将计数值存入通道1的CCR1里。
. y2 J3 W4 _- k G' E4 b然后是第二个上升沿到来后,此时通道2发生捕获事件,将此时的计数值存入通道2的CCR2里。复位模式此时又将TIM2计数值复位至0,等待第二个下降沿到来。/ |- {9 S, b* p* }6 e
4、一次捕获过程完成,则PWM的频率f=72M/CCR2;占空比:duty=(CCR1/CCR2) X100%9 W. r( d' v1 R* y% H$ b* N3 _
注:; G4 o5 K% a( d4 i3 |$ ~
PWM输入模式时,用到两个通道(一般用TIMx_CH1或TIMx_CH2),只给其中一个通道分配gpio时钟即可,另一个在内部使用。给一个通道分配gpio时钟后,需要设置另一个为从机且复位模式。(例如使用ch2,ch1就得设置成从机模式)。当一个输入信号(TI1或TI2)来临时,主通道捕获上升沿,从机捕获下降沿。
! K1 ^: ^* e% F7 r在CH2通道中:
1 O5 h! G8 {: tTI2FP1和TI2FP2都来自同一信号TI2 的边沿检测,信号相同,同一个TIx输入映射了两个ICx信号。& j- ?4 u F3 o& U
TI2FP1和TI2FP2可以分别由连接到的ICx (IC1或是IC2)相对应的控制寄存器设为上升沿或是下降沿触发,这两个ICx信号分别在相反的极性边沿有效。如果TI2FP2设置为上升沿触发,则TI2FP1设置为下降沿触发,二者极性相反。3 p4 z& ?1 R2 F1 e7 j8 d4 w
CH1,3,4相同。
* J' x6 O1 y+ V6 _% P% H* v" W# g) d, ~8 c/ w z, }4 n
! C d( d& ~5 O' i% ?5 Q
具体程序:" h) N0 b3 D& A
- include “pbdata.h”
' Z5 P5 Y* g" H( s" a) h - $ a# Q+ m5 _+ X0 \, H
- void RCC_Configuration(void);7 j' h* X6 E- E5 }: z9 K, W! O m7 }/ X
- void GPIO_Configuration(void);' s5 K7 B4 l4 l0 X3 l0 n& k9 z
- void NVIC_Configuration(void);
; d/ q8 J! n& X2 R - void TIM2_Configuration(void);
: ^) ?+ K; P2 s0 T - void TIM3_Configuration(void); N+ N2 i1 ~ S+ h3 S8 g ^* ^" e+ F! E
- void USART_Configuration(void);
8 Z& @" r% N% ] - W" z- ~; A3 A: |" V" D
- int fputc(int ch,FILE *f)" M% j; P- ?7 l; @" _
- {; X0 X2 X1 x7 N) N1 B
- USART_SendData(USART1,(u8)ch);
' B N5 L( s. G. Y8 | - while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);! B: y+ J1 [5 S3 ^# i" X( x
- return ch;
& G9 [0 g8 J; S) C' F - }
" G8 U/ O9 U6 R+ m7 H9 L - 4 f. T) i. d4 K' X
- int main(void)9 Y a3 q( c I' z. C
- {: o5 G% @5 ?: L6 e/ v
- RCC_Configuration(); //配置时钟
4 g5 ^0 s' r. {! {: x5 y - GPIO_Configuration();//IO口配置0 o8 a8 S6 \1 s+ [
- TIM3_Configuration();8 p" I1 z, z1 B1 ~
- TIM2_Configuration(); v. f8 o. y( x$ W! P% |0 K6 m, K
- NVIC_Configuration();
8 ^" l* U% f8 o1 G( [! u1 ^+ @ - USART_Configuration();
, X& e0 F: a$ l0 Z
% |( N1 B) z2 S6 b/ }1 z7 c' M2 b- while(1)
. k: k+ }, C, f6 W8 c5 e - {
4 c( ?1 e" d9 ~$ Z: } F - if(flag==1)) M: X0 H0 _+ |$ w" t/ F- R* K
- {6 q& M/ z7 ?5 n. b% O1 v0 v
- flag=0;4 ]' \% {& u. I8 K7 d0 q$ U1 u
- printf(“the duty is %d/r/n”,duty);
# i0 a! {9 o' X! ` - printf(“the frequency is %.2fKHz /r/n”,freq);3 t6 @3 C7 y4 x3 B% S
- }
: z9 ^2 E4 P9 S' i. K& c% @ - }
4 a$ O* D4 o" f/ N9 s - }1 F; p0 `- i" p0 u2 ^" s$ F; ^
* v1 R) y4 [) B% X/ l. a- void RCC_Configuration(void); k, c! ^8 A0 Q* X) d% |
- {! F$ r8 u+ |9 t
- SystemInit();, y' n1 r5 |$ B+ J3 S# O* R( P1 z
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);
) L1 L: i3 S) g" p2 @+ c - RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2|RCC_APB1Periph_TIM3,ENABLE);1 Y$ g0 }& G( T2 _7 a* I% }2 k5 ?
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
2 {: |6 S4 B& X6 U' k - }
5 n3 H/ J" ^' O" s7 Z3 y4 Q - * a$ `4 j3 L6 f# R9 o
- void GPIO_Configuration(void)1 a+ N' O9 N; j+ i
- {% b- |2 r# R% R8 a* \
- GPIO_InitTypeDef GPIO_InitStructure;
' `" `* Q9 F* L5 \9 G - //LED
7 F3 V! n+ \. w# M - GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//TX. W" u% p5 ~4 N9 E1 I9 v7 Y/ Z
- GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
. N- j! L+ D( c" t ~9 m - GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;& i" O& @3 R) R. h1 A0 g
- GPIO_Init(GPIOA,&GPIO_InitStructure);
3 z4 ~7 Y) F7 s! c( z8 N3 e& P - 0 W7 n4 U1 M: ?1 A
- GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//RX4 j* F$ j) \, J/ y
- GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;9 M1 f7 g8 C' w) D$ P/ I
- GPIO_Init(GPIOA,&GPIO_InitStructure);
1 }$ H O( ?, a% u" P# _( P - 0 h0 s% _6 G' f9 \8 V3 R
- GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;//PWM,TIM3_CH1 P: @5 B b, b0 ]" i7 U& {
- GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
1 s# P) h" B* l0 W C8 Z" Z - GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;0 A( a) k' K3 v8 t) j
- GPIO_Init(GPIOA,&GPIO_InitStructure);
5 f, @& v, W D7 K! j' E8 c( Y
, T' d/ g' `' F( q; c- GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;//TIM2_CH2* [3 x, q1 r+ z9 h* I3 Y+ t* ]
- GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
0 w: w/ D% b9 l* ?/ i: k - GPIO_Init(GPIOA,&GPIO_InitStructure);) L* M8 I: |7 Q6 K) u, q
- }3 k8 K* F5 W. }. J/ m
& G$ M1 w* Z0 v4 l8 K+ H8 I- void TIM2_Configuration(void)
* ]9 X( ? ?9 R* G- | @; ^9 ~/ I - {
( s0 S% X8 t4 P$ y* u - TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
. n- L- t. }2 f - TIM_ICInitTypeDef TIM_ICInitStructure;
# _1 @: e1 e- G L: ?
; p4 f& D2 G8 S9 m( e' p- TIM_ICInitStructure.TIM_Channel=TIM_Channel_2;//选择TIM2_CH2,选择输入端 IC2映射到TI2上2 g- U, [8 @/ b( U) ]5 C& h
- TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//上升沿捕获' Y6 f* v* W+ ~! {3 v0 J
- TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//映射到TI2上' V9 h& w+ v* Z+ A- b; Q5 W, S
- TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;//在捕获输入上每探测到一个边沿执行一次捕获* o# r# ^% Z& ~# l# w# J0 V
- TIM_ICInitStructure.TIM_ICFilter=0;//滤波设置,经历几个周期跳变认定波形稳定。(采样高电平,只有连续采集到N个电平是高电平时才认为是有效的,否则低于N个时认为是无效的,N取0x0-0xF), F' x9 h8 ?0 M/ T2 [
- TIM_PWMIConfig(TIM2,&TIM_ICInitStructure);//以上是输入捕获配置4 u& {0 y5 A+ t
- TIM_SelectInputTrigger(TIM2,TIM_TS_TI2FP2);//选择滤波后的TI2FP2输入作为触发源,触发下面程序的复位% x! ~8 U5 n" y
- TIM_SelectSlaveMode(TIM2,TIM_SlaveMode_Reset);//从模式控制器被设置为复位模式-选中的触发信号上升沿重新初始化计数器并产生一个更新信号(上升沿一到,TIM2->CNT被清零,每次上升沿来到,CNT都会被清零)
! d* W5 f* h" q3 G1 Q. Q6 d - TIM_SelectMasterSlaveMode(TIM2,TIM_MasterSlaveMode_Enable);//启动定时器的被动触发( z! u% B: z5 E& g
- TIM_ITConfig(TIM2,TIM_IT_CC2,ENABLE);//捕获中断打开9 e1 q8 O) i+ ?) `! ]6 r
- TIM_ClearFlag(TIM2,TIM_IT_CC2);//清除标志位
& }) y. n3 m- d% h, B0 | - TIM_Cmd(TIM2,ENABLE);//使能定时器2
]$ U2 q9 c2 B; g$ ` - }
. f- K: A3 c# I3 ^# {7 W
' W; w* m# @* v% x/ o- {, \' e- void TIM3_Configuration(void)
7 ?- Z- [+ O9 j1 Q1 L; e - {
0 C% o! k7 [7 z. s - TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;8 P8 `* E; q* j5 Z" K, P
- TIM_OCInitTypeDef TIM_OCInitStructure;
2 Y2 p9 O9 i3 ~: `1 I8 C8 q, o, i - TIM_TimeBaseStruct.TIM_Period=72000;//计数初值8 J" E0 i/ b- T7 A" o" a1 b0 A
- TIM_TimeBaseStruct.TIM_Prescaler=0;//分频系数
: U' P5 O4 o3 P4 F$ V! i - TIM_TimeBaseStruct.TIM_ClockDivision=0;//时钟分割
, L% V4 t& m" @ K" `; P+ a1 Z+ {0 W" h - TIM_TimeBaseStruct.TIM_CounterMode=TIM_CounterMode_Up;//向上计数模式
4 f9 k$ z3 \* B$ m# i1 a4 } - + z8 {9 e! ]: w; M% N
- TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStruct);) ?' k& r8 s1 ?- E& M9 l
+ K& ~+ P2 S6 j: r- //TIM3_CH1作为pwm输出
: \" e& k$ m. C) W+ X - TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
" D2 M$ H7 v, D& I0 P1 M - TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;7 d; L' y! T; a1 {
- TIM_OCInitStructure.TIM_Pulse=36000;9 S( W9 t( c X$ k2 a
- TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;& Q2 X% j9 c7 [4 j+ n f; f
- 9 ^5 A. K% B3 x8 {
- TIM_OC1Init(TIM3,&TIM_OCInitStructure);
+ E4 I' x" `# C+ U1 Y3 `1 v - 4 p9 T# E; c3 w; N, X5 V+ G
- TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Enable);! ~4 H2 n3 N: r8 i% ^+ \& I
- TIM_ARRPreloadConfig(TIM3,ENABLE);
" ?* y& O, T! V* |: A- q7 v' _ - TIM_Cmd(TIM3,ENABLE);+ m( K' H; o/ u8 m
- & O4 Y) U6 ]8 w8 o* a% [
- }
3 p/ `' C _4 ], f - 1 k* n- P! ?8 p" K1 r O
- void NVIC_Configuration(void)3 r: r" Y/ d1 \& g
- {) Q4 `3 F: R3 G8 X3 o
- NVIC_InitTypeDef NVIC_InitStructure;. R# O. F- R9 g, o% p% j
: P' ]$ `6 P+ D" }4 {" r8 P- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);4 D% q, p% x: @: }# e
: Z! P+ M1 [8 ]) r& {9 C0 [- NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
5 v; F8 M. x( ?: m$ H - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
; o# I* d# o$ H7 S - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
! N' i% m% J, T, O - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;+ d) E1 e$ k. V9 g/ ]) X1 I
- NVIC_Init(&NVIC_InitStructure);6 `. Y }: y) i! O; j% H+ m3 ^
- 4 I9 h* C& p$ `# M9 b4 {$ o
- }
3 r8 J( B) I/ p6 k4 a - 8 w5 M3 n* K! R2 x( M# r4 y/ N1 S
- void USART_Configuration(void)2 Q! x" c: O4 j
- {- B0 z# i! z: s6 P0 }; Z* H, M
- USART_InitTypeDef USART_InitStructure;
" N+ C7 r7 N. H% R; ]( [) P7 C# _ - / y0 k8 T! P; c# a" | r, q
- USART_InitStructure.USART_BaudRate=115200;
. [. B1 {4 m- I. T2 n2 t5 ] - USART_InitStructure.USART_WordLength=USART_WordLength_8b;
) S: q3 ]. H. e6 i- G - USART_InitStructure.USART_StopBits=USART_StopBits_1;# ]; p& V! E- K l7 c v% B0 d) w' W
- USART_InitStructure.USART_Parity=USART_Parity_No;
6 \5 Q/ Q% P3 Q* U2 f9 m+ A - USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
. p d4 {" ^2 d: c" P% z ^8 x - USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
0 l5 v; r6 a7 z" Q; V - ) X, y* t' H! q& B* h1 j7 \
- USART_Init(USART1,&USART_InitStructure);* e! B0 b, k2 [9 P- l/ C
- USART_Cmd(USART1,ENABLE);) ~. v. j7 }2 S* @7 d
- USART_ClearFlag(USART1,USART_FLAG_TC);7 K; L3 m: Q3 [- o! k
- }
- [8 Q+ g" L6 q
) l' D4 M1 [& J8 ]2 w3 {! o- //中断程序
) f6 g! Z0 ^4 @6 h* [8 K5 k6 G2 D - void TIM2_IRQHandler(void)
7 q& n: j4 J/ ?; K2 o - {2 z Y$ j7 p8 q9 i
- if(TIM_GetITStatus(TIM2,TIM_IT_CC2)==Bit_SET)9 D1 O* c( v0 n& \9 r
- {$ j7 T; t& N' Y! |
- float IC2Value=0;
# V9 f( L# v& ?$ L - float DutyCycle=0;( e- I8 a g: F% X* e
% g* K) g6 }& @2 ^- float Frequency=0;8 q( x8 u3 k( m- J4 T8 E) g/ H# d
- float pulse=0;
- z# R5 t) J4 p5 S% v
( v/ U& [3 }* n' n, d* c( q0 Z- IC2Value=TIM_GetCapture2(TIM2);//获得CCR2的值1 A5 p$ F( p2 g4 i. I2 y' W8 h2 W) w
- pulse=TIM_GetCapture1(TIM2);//获得CCR1的值# `4 ~5 O3 {7 Z" A1 N
- DutyCycle=pulse/IC2Value;# x5 L {) q j V& E& Q. u
- Frequency=72000000/IC2Value;& _% K0 l. |, V4 H
- duty=(u32)(DutyCycle*100);
. w1 ^; R( i3 x, l& X$ G) T; A - freq=(Frequency/1000);7 {5 a% r n3 H3 C; O
7 W5 x, ?3 N# u- flag=1;
. A+ d2 F9 b& d( ~ - , r6 U+ V7 t0 W, g
- TIM_ClearITPendingBit(TIM2,TIM_IT_CC2);
+ N* E) O1 j ` p7 b - }1 q- M- }# `" ^3 [
- }# R$ c5 R$ B" v6 R
+ ]9 S/ l* u, c" f( }+ n1 W- duty和freq是定义的全局变量, d3 p9 ?" j+ s/ y) u! R
- extern u32 duty;- R# j: x5 L. Y% \/ M# y
- extern u16 freq;3 W! S. y0 J; {, M
- $ }3 ]7 q7 ?# B/ C( M
- u32 duty=0;
; S3 r! N$ o8 \ - u16 freq=0;
复制代码 经调试程序可用。频率和占空比都对。频率的设置不要太高,因为printf函数发数所需时间较多,两次捕获的时间间隔短的话可能使printf不能及时地送出数据,造成数据被刷新。更改方法,使用:USART_SendData();函数发数。
9 E1 S8 R: M8 \
; n! G- n* C, T. P5 @+ B% l( [2 C7 \, }% W5 B% j
其他应用:; g5 o( T7 t! b8 ?" C1 B$ p' O
1.测量高电平时间:a,上文中的CCR1就是高电平时间;b,当使用一个通道CH1时,先将触发沿选为为上升沿,产生捕获中断,读取CCR1中的内容,再改变触发沿为下降沿,下降沿到来时捕获,再次读出CCR1的内容,两次相减为高电平时间。% c2 Q& T( n9 @% N- w
2.测量脉冲个数:a,开启定时器1的捕获中断,捕获信号边沿(上升沿或下降沿)进中断,count++计数,再开启定时器2的更新中断,定时一定时间进更新中断,读取count值,此为脉冲个数。b,开启外部中断,配置沿触发中断,count++计数,再开启定时器x的更新中断,定时一定时间进更新中断,读取count值,此为脉冲个数。. ~" M9 m3 r0 c5 N$ J8 v
3.计算一路信号的频率,可以选择定时器的CH1或CH2(不可同时计算两路频率,否则计算出的频率是后初始化的那个通道代表的信号频率。当然,要同时也可以,每次得到频率后切换通道,将数据通过DMA取走即可),使用PWM输入捕获模式,使用上升沿触发。而CH3和CH4通道则不行,如图2所示,只有红线所指的4个信号连在了从模式控制器上。所以,对于3和4通道,计数器的值不可能在接受到信号上升沿时候,有复位这个动作。
( n4 p/ d2 @1 F B; K) r
6 n: C( z9 W% b4 }( |& D, x( G# x# G; R7 E/ ?- s2 G3 o
|