STM32F103单片机的定时器不仅能输出PWM波,而且还能捕获输入的PWM波。可以通过定时器的捕获功能测量输入PWM波的周期和占空比。其中定时器的输入捕获功能如下:% j, Q M: F* Y4 W! G- `/ x; A5 ]) {9 P
9 I0 ^* i! c5 J; k& B 在输入捕获模式下,当检测到ICx信号上相应的边沿后,计数器的当前值被锁存到捕获/比较寄存器(TIMx_CCRx)中。当发生捕获事件时,相应的CCxIF标志(TIMx_SR寄存器)被置1,如果开放了中断或者DMA操作,则将产生中断或者DMA请求。如果发生捕获事件时CCxIF标志已经为高,那么重复捕获标志CCxOF(TIMx_SR寄存器)被置1。写CCxIF=0可清除CCxIF,或读取存储在TIMx_CCRx寄存器中的捕获数据也可清除CCxIF。写CCxOF=0可清除CCxOF。
/ s, e1 y+ x8 U$ v7 Z$ J# W1 j' c+ J8 z0 Q% b/ M: s
这里就使用捕获模式测量PWM波形的高电平时长,具体实现原理简单的来说就是,当第一个上升沿到来之后,清空计数器,当第一个下降沿到来之后,此时计数器的值就是高电平的值。1 e9 q. I+ _0 @2 H \ v/ w4 C
设置代码如下:/ k$ ~, U0 n( {4 c: N% ?$ _- H+ U: a
+ z' N& i5 g4 C# x5 A1 J# }- void TIM5_Cap_Init(u16 arr, u16 psc)
\% l8 n6 S5 S& E - {' L3 a4 K/ F! k8 o/ _
- GPIO_InitTypeDef GPIO_InitStructure;
- G) B$ n( Z1 Y- y5 w - TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
7 D* U- A) S' t' e - TIM_ICInitTypeDef TIM_ICInitStructure;, r; a2 U( \+ A8 B
- NVIC_InitTypeDef NVIC_InitStructure;
; p# i. \- N" m9 ?1 W( G
1 E6 B$ S* A9 j! F7 U- //时钟初始化
' c& D; ~$ ^0 `& E. ] - RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
' x4 ^6 ?7 v- A1 g3 c - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
! c& a1 q3 B& s* V, {; g - //IO口初始化+ r. ~, V; r9 b" Y# h' l2 M
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;' f8 V8 {3 r* U, i1 t# @6 E/ H' a
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;7 o3 z) w/ G2 R% Y) I, B; R" _& P
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
7 P/ q/ X" X a) s9 v! c - GPIO_Init(GPIOA, &GPIO_InitStructure);1 `; v* i8 a) U3 n
- //TIM5初始化
0 f" o5 R1 N( S; m - TIM_TimeBaseStructure.TIM_Period = arr;. q4 C6 @1 m8 _( b/ C
- TIM_TimeBaseStructure.TIM_Prescaler = psc;
: x4 h0 }/ A- e/ s( ]* d( l - TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;0 {* t" j0 \" r2 r. Q- d% h- |
- TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; O) k: g7 i+ a& H% S
- TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);) p! u* b) q; i4 O* S$ B. D% V9 E) |
- //TIM5输入捕获参数
P- v5 y, e' T5 Z$ l" ~4 n - TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 选择输入端 IC1映射到TI1上
1 }5 _) d/ O# j - TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
- Q$ y- Z+ p7 F - TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
1 J: j d- [ b) w$ ~) _ I5 }# ? - TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
* ?7 R0 J( J, U, J - TIM_ICInitStructure.TIM_ICFilter = 0x00; //IC1F=0000 配置输入滤波器 不滤波) J% t: L, ^ V" `" l" k6 z) y
- TIM_ICInit(TIM5, &TIM_ICInitStructure);
+ v$ q- X* c3 }# h - //中断分组初始化
# I. b; ~9 o; t: e; I6 g# L - NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;9 w' Q& M l2 _5 F9 `" F% @
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;/ `# V: q/ b4 u
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;
" z8 H2 N: [) e" K, M4 ~' y - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
7 e1 t) H8 M; L: C1 ] q% o$ z - NVIC_Init(&NVIC_InitStructure);
. H6 a6 C( e% Y5 H/ ` - . ? i( t) T2 W
- TIM_ITConfig(TIM5, TIM_IT_Update | TIM_IT_CC1, ENABLE);
7 i, `7 s3 [* ]. p+ k( L - TIM_Cmd(TIM5, ENABLE);' V% K. `3 y4 K9 F
- }
( I/ y" j" m1 I* z( R, @ X5 P - % O ]! I" s7 Z6 g! b
" i: G0 v; d& V- u8 TIM5CH1_CAP_STA = 0; //输入捕获状态 V3 c, {' l5 @; [- F4 N8 D; ]
- u16 TIM5CH1_CAP_VAL; //输入捕获值6 X! u$ {9 P2 l# T
- void TIM5_IRQHandler(void)
9 c5 r9 z$ _2 ~& j - {( k5 y1 L) [$ k; P1 C/ N o
- if((TIM5CH1_CAP_STA & 0x80) == 0)
7 H- \2 r+ d' U# i c0 ]9 ]1 _* O5 s - {1 i' T- x6 y8 R3 F- N
- if(TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET) //溢出中断
( ?% d/ R5 A; C - {5 H) G. a: S ` D
- if(TIM5CH1_CAP_STA & 0x40) //已经捕获到高电平了8 m1 w& M5 O. c$ U; p1 D- k
- {
( F& G. c9 C3 y& F" L. D - if((TIM5CH1_CAP_STA & 0x3F) == 0x3F) //高电平太长了# V2 h4 i0 M! k: v Y' ~- G
- {- E0 D3 i$ H$ Z+ l
- TIM5CH1_CAP_STA |= 0x80; //标记成功捕获了一次
' L/ a7 O* c, Q7 n - TIM5CH1_CAP_VAL = 0xFFFF;
* c( \! a; l C& T) i - }
" G( R5 E& [$ i$ ?: x, k - else( d8 v" y. r; C
- TIM5CH1_CAP_STA++;
- z1 x3 T( r, i8 o" z3 G - }' g' N3 h3 S7 V _" k3 U7 n! K
- }" e6 `& A3 M3 r# T
- if(TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET) //捕获中断$ H( H b, _2 B! W
- {
+ P6 s! k& [( ^5 m7 Y* C - if(TIM5CH1_CAP_STA & 0x40) //下降沿捕获2 t8 r! c a; F3 g
- {
0 P9 m. b1 a( U3 G$ p' D6 K6 H9 [, u: s4 X - TIM5CH1_CAP_STA |= 0x80; //标记成功捕获一次高电平脉宽
8 J0 i( Q& \2 Z8 x' A$ K - TIM5CH1_CAP_VAL = TIM_GetCapture1(TIM5);
/ h+ v1 H( O$ y$ w! M9 y3 x/ V - TIM_OC1PolarityConfig(TIM5, TIM_ICPolarity_Rising); //设置上升沿捕获
1 F( ]4 U2 g# B% q: N+ K - }
& B1 X* H7 ^+ D$ b& k# x0 E! o - else //上升沿捕获* M' T: O2 E3 t0 a- L E" M5 V
- {
* ~ I I+ S$ s1 h3 P5 O - TIM5CH1_CAP_STA = 0; //清空' L0 C+ M) G9 v0 d
- TIM5CH1_CAP_VAL = 0;, N7 T+ Z0 N K
- TIM_SetCounter(TIM5, 0);
2 C; }/ U) y; Y! t: e; q - TIM5CH1_CAP_STA |= 0x40; //标记捕获到了高电平
: y- ~8 {! D/ U" j& @: |% m) d E - TIM_OC1PolarityConfig(TIM5, TIM_ICPolarity_Falling); //设置下降沿捕获
! D, `3 p3 i& u/ F5 n9 J7 { - }0 t: {. g. ^ M- S% K
- }
9 o) h& z1 C% s - }- @$ u8 Q# Y R; U2 N" e# {
- TIM_ClearITPendingBit(TIM5, TIM_IT_Update | TIM_IT_CC1);
6 n) k& s$ m) S3 }3 [8 R6 P4 ~# G - }
复制代码 - w2 P: ~; Y @ Z+ U/ ?
这里使用定时器5的通道1来进行捕获,首先设置通道1为上升沿捕获,当上升沿触发中断之后,清空计数器的值,然后将中断设置为下降沿中断。当下一次下降沿中断触发后,此时的时间就是PWM波的高电平时间,接着再将中断设置为上升沿中断,等待下一次高电平的触发。
( Q. X/ H( v# b# V6 `- M2 d: i
1 X+ y/ V; B/ E0 E 每次捕获成功时,在主函数中将高电平时长打印出来。+ _! X7 X7 a# n6 G: k
7 t: _. w/ {, q, }5 C- extern u8 TIM5CH1_CAP_STA; //输入捕获状态
+ m4 U" e! W: F+ P. r; E& c - extern u16 TIM5CH1_CAP_VAL; //输入捕获值
' ~$ U1 X: q9 s - int main(void)5 F. _8 j# C9 w& e6 n. t
- {
2 i6 U- }; l6 t* b5 w+ l& c - u32 temp = 0;
" Q [/ \6 c4 b# t( ? - delay_init(); //延时函数初始化( A2 y G1 W# F! G4 }, ^" L/ v3 Z
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);! _6 Y+ Y2 I5 @1 g+ Z7 `
- uart_init(115200);2 X6 I+ b B( U
- LED_Init();
* ^5 y7 Y" n9 H, U9 A
, e3 R2 C, s, l$ g7 a8 f3 h- q/ N- LED0 = 1;. e3 K/ k: L* Q9 P" i! p x
- LED1 = 1;. M: @/ K9 X) W3 B& l: o6 }: L" h
- delay_ms(500);
4 @$ ~0 ]4 g+ l. ? - LED0 = 0;" d: b4 r( y& M
- LED1 = 0;
. J+ x, O; I! H - - S5 u6 \- C3 m
- TIM3_PWM_Init(3600-1,0); //不分频。PWM频率=72000000/3600=20Khz PB5输出PWM
: I) Y' m3 s4 Q1 _ -
$ c, @; W6 b+ S1 m" p - TIM5_Cap_Init(0xffff, 72 - 1); //以1Mhz的频率计数 PA0
) z( f& v3 F0 a# y/ F% H0 S
) O+ Z* M' ~6 g( a1 Z6 {% S- printf("Input Capture test!!!\r\n");8 a0 B4 {7 Z2 e$ i) m5 b, J$ ]. ]3 U
- while(1). W; p- f8 c0 J$ o: x
- {3 |$ O, V, A7 y' Y
- delay_ms(10);
; f/ k! @3 _! P4 O - TIM_SetCompare2(TIM3,TIM_GetCapture2(TIM3)+1);% ?' s f- r6 E. o6 D+ J1 y: t
, P" j8 ?: H1 i& y, R0 Y/ H- if(TIM_GetCapture2(TIM3)==3600)+ d' Q9 v! R: o3 o
- TIM_SetCompare2(TIM3,0); ( h C. | ` V8 X( W
- 7 V/ F" L2 {$ |& J9 F; w4 u6 k
- if(TIM5CH1_CAP_STA & 0X80) //成功捕获到了一次上升沿8 J# F4 n y: Z; v# C! U9 |
- {3 B% x8 G* r @) Q! D& b" q+ E
- temp = TIM5CH1_CAP_STA & 0X3F;! V; c3 q @# V. Q, w$ [6 [
- temp *= 65536; //溢出时间总和; ]% p; O( X- F9 ]5 T
- temp += TIM5CH1_CAP_VAL; //得到总的高电平时间" X8 s$ `/ h s
- printf("HIGH:%d us %d ms %d s\r\n", temp,temp/1000,temp/1000000); //打印总的高点平时间7 v; l% p- w/ j- G' S2 f- K$ }
- TIM5CH1_CAP_STA = 0; //开启下一次捕获9 p4 o4 I* F% x+ f
- }
8 o1 o2 j% Z2 U2 U, Q3 Y - }8 I5 d' [3 W, Q8 ~
- }
复制代码
# z2 p9 t$ z, h6 B4 k7 M0 N1 {
5 f* G; v) C( z4 K; b7 Z8 F# p定时器3用来产生一个PWM波,然后通过定时器5的捕获功能来测量PWM波的高电平时间。
; U9 k8 ]. n* Q O1 a+ q S
7 s/ Q; M6 h6 D: x; _7 |: L1 ~1 s0 c& Z+ o
|