STM32定时器pwm模式输入捕获##( t' c: `# N5 Y# P1 X
STM32中的定时器,除了TIM6和TIM7,其他定时器都有输入捕获功能。这种模式通常用在对输入信号频率frequency、占空比duty、高低脉宽的计算中,具有很广泛的用途。
' C, L. U$ Y5 Q4 s w
! R7 e/ N0 i$ c: f% g6 k; a2 e& d! [& K* P$ ~( h) y! E" f I" I
STM32的输入捕获,简单的说就是通过检测TIMx_CHx上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存(TIMx_CCRx)里面,完成一次捕获。同时还可以配置捕获时是否触发中断/DMA 等。$ E& A( M, W/ C! Q
' B5 e. ^0 T' E! y/ P0 ~
* A7 S- S# i% q1 }PWM模式捕获方法:利用TIM3_CH1作PWM输出,TIM2_CH2捕获上述PWM信号,并测出频率和占空比。设置PWM频率为1KHz,占空比50%。* T7 V3 y. ^6 G ]5 X& r
具体步骤:
9 ]0 y$ t J# i9 y9 \# f# q# U2 \. R7 x; {
2 z8 W+ g+ k2 U' S" M1 u2 J- }
1、为了实现PWM输入捕获,TIM2占用了2个通道。第2通道的电平变化会被第一通道和第二通道引脚检测到,其中第一通道被设置为从机模式(如何快速判别主从机模式,规则如下:如果设置的是第二通道作为PWM输入捕获,则剩余的第一通道都为从机,反之亦然)。+ e. J/ C# W$ }% H; |0 `7 j
2、假设输入的PWM从低电平开始跳变,在第一个上升沿到来时,1,2通道同时检测到上升沿。而从机设置为复位模式,所以将TIM2的计数值复位至0,此时不会产生一个中断请求。+ s7 ^, q- Z/ b- O* j
3、下一个到来的电平是下降沿,此时通道1发生捕获事件,将计数值存入通道1的CCR1里。
5 R- D7 D( X1 {4 ^' U# b然后是第二个上升沿到来后,此时通道2发生捕获事件,将此时的计数值存入通道2的CCR2里。复位模式此时又将TIM2计数值复位至0,等待第二个下降沿到来。
2 ^1 N, N! S; p7 L4、一次捕获过程完成,则PWM的频率f=72M/CCR2;占空比:duty=(CCR1/CCR2) X100%; i9 O/ e$ h7 Q4 q- U
注:) w4 m, {8 ~. x9 r+ M& H+ h
PWM输入模式时,用到两个通道(一般用TIMx_CH1或TIMx_CH2),只给其中一个通道分配gpio时钟即可,另一个在内部使用。给一个通道分配gpio时钟后,需要设置另一个为从机且复位模式。(例如使用ch2,ch1就得设置成从机模式)。当一个输入信号(TI1或TI2)来临时,主通道捕获上升沿,从机捕获下降沿。
* }6 D* y- \5 ^8 a在CH2通道中:5 k% B- |2 K/ u, @
TI2FP1和TI2FP2都来自同一信号TI2 的边沿检测,信号相同,同一个TIx输入映射了两个ICx信号。
D# R( J* K% W9 O: LTI2FP1和TI2FP2可以分别由连接到的ICx (IC1或是IC2)相对应的控制寄存器设为上升沿或是下降沿触发,这两个ICx信号分别在相反的极性边沿有效。如果TI2FP2设置为上升沿触发,则TI2FP1设置为下降沿触发,二者极性相反。
0 {8 [3 m+ z; Q* z6 W. [CH1,3,4相同。/ T: H0 l" r* A+ K1 a* H$ O
1 \1 }; W3 R/ u2 L8 W$ X; E7 w/ A1 U, v# L0 k% F' S
具体程序:: \( E5 Z2 b4 w) t# l
- include “pbdata.h”2 L! k- ]. @: {: }+ l$ L4 U
1 X w g" D, m3 ]. B' g5 {- void RCC_Configuration(void);9 L) @( @' A! K
- void GPIO_Configuration(void);5 a% l6 m/ m; J; c8 k! y7 P
- void NVIC_Configuration(void);
2 \6 x1 h5 Y" K2 u4 M) n0 B- I - void TIM2_Configuration(void);2 ?% N& W* V" ^( p" t0 A6 _ n# C% r" \
- void TIM3_Configuration(void);
, r2 q. z/ `" @; e* @4 r - void USART_Configuration(void);2 m1 }/ \! l" Q% m u) N# c3 x! M
- # M1 q8 |- s& m3 ]+ M# p8 S4 O
- int fputc(int ch,FILE *f)' \/ ~) S) O8 x7 ?) N
- {" w ]5 _6 P( {- H
- USART_SendData(USART1,(u8)ch);
- H* N' K5 d& B2 z. Z4 O! ^2 F# Z! e - while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);0 W3 X2 d% H0 v4 w' j2 r
- return ch;
! _0 u. z [6 Y. Z - }
* E# ]7 D; S9 a' \7 h7 x
" D! |9 ~% a5 z# ~. ?- int main(void)' }( g* h1 f8 W) q# Y
- {
4 [3 W8 @9 w& v/ Z7 Z( J) O+ X - RCC_Configuration(); //配置时钟- V$ d0 w# N1 Y% H7 \4 A# {# E# ~3 N+ p
- GPIO_Configuration();//IO口配置
+ d2 d1 q0 B8 C% b! p - TIM3_Configuration();
2 H. w5 Y q$ L3 s7 H2 S - TIM2_Configuration();5 X5 k8 h% V4 }' x" V$ A( d! T
- NVIC_Configuration();" Z2 k; R. H- X% Q) ]' p
- USART_Configuration();9 n& ^! m4 H% z5 G
! y7 H0 |& Z9 q2 J$ [. @- while(1)
0 J7 d0 r3 n& H6 @1 P( J" G - {! c- d- B* N j5 f! z+ ]
- if(flag==1)
" Q' U/ C0 ]' H( u! H$ M6 s: X5 S - {1 {5 `4 u4 h9 H% U: _& j1 z
- flag=0;3 w4 X+ p) R5 ?$ Q$ W
- printf(“the duty is %d/r/n”,duty);
$ r8 x6 [ A1 W - printf(“the frequency is %.2fKHz /r/n”,freq);, u! l# J# p) @4 v4 x+ E' Q. U
- }' b' k/ [# m/ H% K6 e
- } M% o1 z' |% x* c6 O3 t2 C
- }. q& _) f. P8 w# d! T2 q" q4 s
- & _! B+ l6 B% l) m% G9 {
- void RCC_Configuration(void)
c! h Q- p" N9 T5 Y7 l$ O; q - {1 o' i( [7 w/ w$ x4 {
- SystemInit();) j0 C: `3 j) @* C
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);) K* X8 n3 a( a; F6 c" s! X- ^
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2|RCC_APB1Periph_TIM3,ENABLE);
+ ~9 z* j" @1 r' I - RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
# k# I1 I3 B' N- E - }- z' t, n' ^( g# V ]) S) p7 W
, I5 ?$ H! b2 Z0 p& K- void GPIO_Configuration(void). N0 ]8 x; U' g! [
- {8 R& A/ g2 t h
- GPIO_InitTypeDef GPIO_InitStructure;% @3 b) ~( }7 E8 S
- //LED
2 H) r c6 _. i7 x5 @9 d) g1 d: e - GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//TX
( b6 O3 d- O5 D, G - GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;: w7 a I9 B: z! i9 |
- GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;/ c( L# A3 {) \0 I! l
- GPIO_Init(GPIOA,&GPIO_InitStructure);
8 [. {( r( D7 v- d6 Z: Y
! i) b Y; B8 Q- M) Q- GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//RX m' [9 P$ I: |" Q) @. E8 G h
- GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;0 o- |) h7 o/ q5 S. d+ {
- GPIO_Init(GPIOA,&GPIO_InitStructure);
& Z7 M+ O7 z1 ~& J - ; {* M! v+ D6 M1 r/ J1 B3 f3 x
- GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;//PWM,TIM3_CH1
; q/ B" W9 X( ` - GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;& F: F* \1 G# P. Q: \
- GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
' v0 t2 y2 Z0 O! m; c( Q. i' C/ ` - GPIO_Init(GPIOA,&GPIO_InitStructure);- T7 B3 p& h9 M" @! T. s
- . ~ O$ H1 G% J9 T7 J" q
- GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;//TIM2_CH2% V% y o4 X. Z1 [, ~
- GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
6 l( Y( |0 u; \/ Y; \. h - GPIO_Init(GPIOA,&GPIO_InitStructure);# {' s3 q# G4 h3 w) H
- }
7 e$ F) z5 l9 J2 q; M' O - ; O1 Z6 Q2 l: n, [+ @
- void TIM2_Configuration(void)9 m4 e- j7 \. M
- {( Y" h4 N Q* |2 F) D/ h! J1 @' Q( Y
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;$ ^: b) E7 ]2 A- S
- TIM_ICInitTypeDef TIM_ICInitStructure;& _ A% K! u/ P; j! Y ~ Z/ f$ J8 u+ |
; n' r& I) {. O2 ?, o7 c- TIM_ICInitStructure.TIM_Channel=TIM_Channel_2;//选择TIM2_CH2,选择输入端 IC2映射到TI2上* C9 Y* `3 \- ~, ~. H+ u
- TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//上升沿捕获
' X) T* U* s1 G; p& Q* |% U - TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//映射到TI2上/ M/ s7 J0 e+ u$ K! d: ^ s
- TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;//在捕获输入上每探测到一个边沿执行一次捕获3 D4 A' e8 G4 t/ I( W* ?; {5 K
- TIM_ICInitStructure.TIM_ICFilter=0;//滤波设置,经历几个周期跳变认定波形稳定。(采样高电平,只有连续采集到N个电平是高电平时才认为是有效的,否则低于N个时认为是无效的,N取0x0-0xF)" t. \" y; ]! k* @
- TIM_PWMIConfig(TIM2,&TIM_ICInitStructure);//以上是输入捕获配置: A* D) c' A' R" _! F E- E- A
- TIM_SelectInputTrigger(TIM2,TIM_TS_TI2FP2);//选择滤波后的TI2FP2输入作为触发源,触发下面程序的复位
' L% w) p$ T+ ^: d4 V - TIM_SelectSlaveMode(TIM2,TIM_SlaveMode_Reset);//从模式控制器被设置为复位模式-选中的触发信号上升沿重新初始化计数器并产生一个更新信号(上升沿一到,TIM2->CNT被清零,每次上升沿来到,CNT都会被清零)
9 R9 r+ N: D+ B7 _4 t: o - TIM_SelectMasterSlaveMode(TIM2,TIM_MasterSlaveMode_Enable);//启动定时器的被动触发; F/ P. w/ c! Q' m
- TIM_ITConfig(TIM2,TIM_IT_CC2,ENABLE);//捕获中断打开- w3 Y/ }' F2 d3 p- p3 ?+ V
- TIM_ClearFlag(TIM2,TIM_IT_CC2);//清除标志位: V! G' f1 Z; R5 w, T- ?
- TIM_Cmd(TIM2,ENABLE);//使能定时器2
% f7 h5 |7 o$ G( j, h3 n - }
! T* Y7 n+ P b- h - 1 v0 d7 C5 Z, a9 E2 |
- void TIM3_Configuration(void)! ?7 O* B3 c# a2 v2 V" h4 o% x
- {
; b% g, x1 `' q& Y: z - TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
1 P' n! w/ Z7 E/ ?. M* z! Q7 F. {$ z - TIM_OCInitTypeDef TIM_OCInitStructure;; W0 H2 Z: n* \
- TIM_TimeBaseStruct.TIM_Period=72000;//计数初值
~9 t7 ~* `3 R" R& O# h$ X V) [2 ? - TIM_TimeBaseStruct.TIM_Prescaler=0;//分频系数
0 J |4 V1 X5 p) P" l1 x9 K - TIM_TimeBaseStruct.TIM_ClockDivision=0;//时钟分割
: |; k" r5 C/ O - TIM_TimeBaseStruct.TIM_CounterMode=TIM_CounterMode_Up;//向上计数模式' C0 Z% a- _3 z/ P
. ] l+ P9 }+ J$ Z7 b; _- TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStruct);* v) }5 v; T$ W& t* G* Z9 P
- % C) V5 O1 o" }( u$ Y
- //TIM3_CH1作为pwm输出4 e7 s/ F" G) ^, K( j6 g' i
- TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;" [1 q2 X1 E- K5 c( x# k$ y B
- TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;& N+ q) z1 V% D+ u/ ?
- TIM_OCInitStructure.TIM_Pulse=36000;
/ C; l' B. R5 ` - TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;& H* T6 v- v* {/ ]# N
- ! F& k3 p/ C" p2 f
- TIM_OC1Init(TIM3,&TIM_OCInitStructure);
! M u4 Y# r1 d9 m) D. ?- x' s
- {: h) t! E/ s: O- TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Enable);
5 J$ e v9 \5 A9 `6 E( | - TIM_ARRPreloadConfig(TIM3,ENABLE);
5 |. Q e6 N$ w; | I+ g - TIM_Cmd(TIM3,ENABLE);+ s. y, A+ Q$ m6 Y
- / \9 p' Z- y' d
- }: z7 R2 J8 Y: `/ a0 g$ g
- 8 H4 r" l, d( _7 K+ J
- void NVIC_Configuration(void)
3 I) z- c/ o) T+ v! k5 Y+ d: `# ~ - {: y" y% Y5 Q) `0 q# f1 ^2 C. R
- NVIC_InitTypeDef NVIC_InitStructure;8 J( ]( c S; t3 P. F4 `
5 \/ E7 C9 ~1 @, T/ A# ?' p- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
3 O/ w! l. |$ z1 a- g - 9 b) V1 J b& Y% ?* H: y
- NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;9 R8 Y8 Q- N1 K9 M7 c4 w
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
; N. s8 d) C: ^0 l+ q3 ~6 j - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;5 M2 y' e# ^( i9 i
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;, m7 H" l+ o! [) Y, y6 U8 d* s
- NVIC_Init(&NVIC_InitStructure);
9 p4 w1 ]% B. Z t) \
/ F" a5 O. J+ {" w7 r& e- }
6 i/ F7 ^! {5 b$ W7 n5 m
* X# {* M0 N2 J6 r+ Y: j1 Q* S- void USART_Configuration(void)
3 N7 q; U% C! ^4 o9 A& c' o' V2 ] - {
5 L# m- J4 V0 n5 r1 n - USART_InitTypeDef USART_InitStructure;
6 I+ |7 I7 _5 D
, q u5 g+ L" }! ]! v6 j: v( ?. K. P- USART_InitStructure.USART_BaudRate=115200;; _' c( w5 d- H/ v8 y
- USART_InitStructure.USART_WordLength=USART_WordLength_8b;+ }+ {3 Y9 {4 c9 L. p. h4 v
- USART_InitStructure.USART_StopBits=USART_StopBits_1;' t6 j% r" s- e0 C$ N& A% m4 z
- USART_InitStructure.USART_Parity=USART_Parity_No;
) O% G+ H" H: A - USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
/ _5 k' r# j3 A/ C) X - USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
: I0 h& K+ W0 B3 l6 @; [% _
1 u2 ]: t' W1 f- USART_Init(USART1,&USART_InitStructure);& [9 p2 V' ^. c L4 }
- USART_Cmd(USART1,ENABLE);
+ C0 | Q0 S: E7 b0 W+ ] - USART_ClearFlag(USART1,USART_FLAG_TC);. P: x4 U! V) m4 r$ y0 P2 T
- }
0 ?/ X1 b+ V$ s! `) j- k
U% R8 D% k& h$ a5 A4 X- //中断程序
2 L, q' A e1 S1 W6 u( X3 S - void TIM2_IRQHandler(void)4 w4 L5 Y+ U' L
- {
$ R& k4 G$ f/ z1 ^# g, e - if(TIM_GetITStatus(TIM2,TIM_IT_CC2)==Bit_SET): @* H, a9 R* c) E* T# {2 D+ _
- {5 r# f4 _0 D1 c# {& i |
- float IC2Value=0;4 C0 X7 ?; P( r4 T' b/ ? r4 ~- Z
- float DutyCycle=0;
, ~- a6 O8 u4 ^ T7 S! V - " ^' X8 ?0 W6 P) T
- float Frequency=0;* J0 @: D- k0 m5 d+ s n! D; c' a. I
- float pulse=0;
# j8 T9 G* A4 {3 |7 ` - ( Z. B( P2 i6 x* B* r: P
- IC2Value=TIM_GetCapture2(TIM2);//获得CCR2的值( k: [+ ^( ?& j
- pulse=TIM_GetCapture1(TIM2);//获得CCR1的值
" Y7 Q$ e, p( E5 \* Q3 d+ ^/ ` - DutyCycle=pulse/IC2Value;4 M8 v R L1 u+ U( ?
- Frequency=72000000/IC2Value;+ {. z- T( Q) Y0 G
- duty=(u32)(DutyCycle*100);
+ F- H' f6 Q R/ h0 ~7 ] - freq=(Frequency/1000);9 [; S1 ~7 ~1 {! C4 S+ N' ~
- , |0 S) z8 \5 J5 }6 x P
- flag=1;) Q( q# Y' p1 ]8 Z) V" {
- . x7 F4 L# B6 H9 m1 g. r
- TIM_ClearITPendingBit(TIM2,TIM_IT_CC2);% e- K% @1 M7 L; a' x0 ?$ t' R
- }
2 }+ l- ~8 e& D& D+ c% A, S/ U. I - }; }# `: {! j9 V! y$ s
- 9 w7 t3 D2 c8 e' a- r4 Z
- duty和freq是定义的全局变量
: c5 k, X( [7 ]# X" @9 e; K - extern u32 duty;
0 R7 j! F! G, j# D - extern u16 freq;: U) ] G, O3 v! u
- , H7 d3 ]6 }! A5 l% M
- u32 duty=0;
7 K2 o: I6 F, P7 J S0 G: t - u16 freq=0;
复制代码 经调试程序可用。频率和占空比都对。频率的设置不要太高,因为printf函数发数所需时间较多,两次捕获的时间间隔短的话可能使printf不能及时地送出数据,造成数据被刷新。更改方法,使用:USART_SendData();函数发数。8 q# ^4 c( \9 Q. K$ k! \& P
, n7 A, a/ _- \+ m
1 z2 P" ^: w W s6 w, Y其他应用:
. c/ h1 W) v; d. f# g+ e, k7 S3 C1.测量高电平时间:a,上文中的CCR1就是高电平时间;b,当使用一个通道CH1时,先将触发沿选为为上升沿,产生捕获中断,读取CCR1中的内容,再改变触发沿为下降沿,下降沿到来时捕获,再次读出CCR1的内容,两次相减为高电平时间。0 `: \ q) K6 n! K9 t
2.测量脉冲个数:a,开启定时器1的捕获中断,捕获信号边沿(上升沿或下降沿)进中断,count++计数,再开启定时器2的更新中断,定时一定时间进更新中断,读取count值,此为脉冲个数。b,开启外部中断,配置沿触发中断,count++计数,再开启定时器x的更新中断,定时一定时间进更新中断,读取count值,此为脉冲个数。# C7 y( H6 s1 u# R8 D' Q) ?
3.计算一路信号的频率,可以选择定时器的CH1或CH2(不可同时计算两路频率,否则计算出的频率是后初始化的那个通道代表的信号频率。当然,要同时也可以,每次得到频率后切换通道,将数据通过DMA取走即可),使用PWM输入捕获模式,使用上升沿触发。而CH3和CH4通道则不行,如图2所示,只有红线所指的4个信号连在了从模式控制器上。所以,对于3和4通道,计数器的值不可能在接受到信号上升沿时候,有复位这个动作。9 A6 q% T" o2 e' ~
6 I# h, ?; m z1 l6 R4 X2 L6 B2 s1 h$ v, z1 l
|