STM32F103单片机定时器自带互补PWM波形输出功能,利用定时器输出比较模式,不仅可以输出互补的 PWM波,还可以设置输出方波的起始相位和死区时间。
6 H+ E! L8 }9 O( i. z
& w4 |, t" S5 Q- \ 下面就总结一下如何实现PWM互补输出。3 O4 L' ]: k, x) `* M# A
2 [6 e% q0 T3 |) f" s7 ~- / s4 R. h+ W, R" I
- void TIM1_PWM_DeadtimeInit( u16 arr, u16 psc, u16 ccr1, u16 ccr2, u16 deadtime )
, p% Q2 i3 `! m9 x8 T: D z# m$ r - {
. [8 r2 w# B* y' P3 w R - GPIO_InitTypeDef GPIO_InitSturcture;) ?! z" u; I" c! {6 u7 m% T$ R: U0 |
- TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;1 k6 c& U# _; s0 m1 _. x# v
- TIM_OCInitTypeDef TIM_OCInitStructure;
0 @' K. J: Z2 I! i - TIM_BDTRInitTypeDef TIM_BDTRInitStructure;+ H3 P$ z* A) _/ R( e1 h
. b3 ^# K) L% m m; S- RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE );
' C# f7 ^2 {! P `; G& G% g - RCC_APB2PeriphClockCmd( RCC_APB2Periph_TIM1, ENABLE );
( [! y9 ?+ ^+ p* _( ^
, f4 R& x# y5 ^1 Q" u, N" S- //TIM1 互补PWM CH1->PA8 CH2->PA9 CH1N->PB13 CH2N->PB14" I" R& w7 J0 j
- GPIO_InitSturcture.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
! C$ s0 y' E: t( z& @0 r - GPIO_InitSturcture.GPIO_Mode = GPIO_Mode_AF_PP;
3 A9 {0 L1 y% X4 J2 Z! `! W% A; |" Y - GPIO_InitSturcture.GPIO_Speed = GPIO_Speed_50MHz;* v) O# n# {2 c+ P% l$ h
- GPIO_Init( GPIOA, &GPIO_InitSturcture );
9 _: c5 ]9 l* }- w* B - . q2 F' D6 b* ]/ S( _
- GPIO_InitSturcture.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14;
9 i( @. u3 Z0 x: r9 v7 H- b* h - GPIO_InitSturcture.GPIO_Mode = GPIO_Mode_AF_PP;8 p& G( x7 H. a0 W
- GPIO_InitSturcture.GPIO_Speed = GPIO_Speed_50MHz;
% k% V- y2 }9 Q8 y0 Q; { - GPIO_Init( GPIOB, &GPIO_InitSturcture );! m) i2 C/ C; x$ p; q9 C; H' H
- //定时器设置
/ `# R9 [' r* }) R* m# ~) J - TIM_TimeBaseInitStructure.TIM_Period = arr;
4 x7 |9 V' A5 _% ~, E - TIM_TimeBaseInitStructure.TIM_Prescaler = psc;2 ]2 o- B, m# |8 I# a }, i. o
- TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;4 \8 U; z+ }8 D% ~ S6 g. J ]
- TIM_TimeBaseInitStructure.TIM_ClockDivision = 0x00;
2 f" k a v# n4 w - TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0x00;% P" A" j& Q$ B4 c) E( B
- TIM_TimeBaseInit( TIM1, &TIM_TimeBaseInitStructure );, I/ X0 e) `0 v* O/ x" z
- //通道1 捕获比较模式设置
; x( D: c" f" d. ? F# x/ Z/ Q - TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle; //翻转,当 TIMx_CCR1=TIMx_CNT时,翻转OC1REF的电平
7 H( t! } Q, V9 W) g. ]: ?5 G - TIM_OCInitStructure.TIM_Pulse = ccr1; //100
# u5 w+ Y4 _( J& p5 B - TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //CCER的CC1P,输入/捕获输出极性
, ]8 \; \. _" n) ~$ j/ B& k - TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCPolarity_High;
) y1 f( B; Q4 I& q - TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //CER的CC1N,输入/捕获输出使能4 n# q' ^' I6 c) a
- TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;* @ K" Z0 W0 s+ n
- TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset; //OIS1位
- u i4 j! @- w% W3 G- S7 W - TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset; //CR2的OIS1N位,当MOE位0时,输出空闲状态位OIS1N./ b; i4 e, g: r1 o% k4 t
- TIM_OC1Init( TIM1, &TIM_OCInitStructure );9 Q7 S; R% P: g2 r/ d. b
- //通道2 设置
3 _1 w$ s# @' j; e$ \* K% Q! G& ?/ x1 ~2 c - TIM_OCInitStructure.TIM_Pulse = ccr2; //316
) ?0 {) I1 _/ \7 c( W - TIM_OC2Init( TIM1, &TIM_OCInitStructure );
0 c% p1 D1 q2 p I! v/ p - //刹车和死区设置
6 K. n3 T8 C! R- J9 f - TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; //OSSR:运行模式下“关闭状态”选择1 j" b$ r& y4 U+ L( W& d
- TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; //OSSI:空闲模式下“关闭状态”选择 ^8 b& x! s8 ~! J! g: e! w' S/ G
- TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1; //锁定设 置,级别为1' B4 g% [! u' F1 C4 x- D" _
- TIM_BDTRInitStructure.TIM_DeadTime = deadtime; //死区延时时间8 c! }8 a8 J- [4 |* Y/ K7 E
- TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable; //禁止刹车输 入2 T* x! y) ^0 _6 [+ I! t
- TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_Low; //刹车输入极性
- J4 [5 r" A2 T$ { - TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable; //自动输出使能
e p4 v, N6 L/ n7 c, C" { - TIM_BDTRConfig( TIM1, &TIM_BDTRInitStructure );
: |- \4 p# m* Y3 _* H8 n: r - 1 t+ O& T- ?1 D K2 { K
- TIM_CtrlPWMOutputs( TIM1, ENABLE );
& ?) Q& _0 B4 a; j1 Z% o; W( Y - TIM_OC1PreloadConfig( TIM1, TIM_OCPreload_Enable );
6 X6 [ Q4 [* x0 _- U$ ^3 B/ b - TIM_OC2PreloadConfig( TIM1, TIM_OCPreload_Enable );
: t5 ] v; M4 e5 V - TIM_ARRPreloadConfig( TIM1, ENABLE );
; ~/ s! c% `; m% w6 `5 U" q - TIM_Cmd( TIM1, ENABLE );
# X" `6 f" n0 t4 |* q- i - }
复制代码 . `0 L9 U0 {8 h
2 ~ d4 _2 v3 [首先初始化IO口,这里使用的是定时器1的通道1和通道2。 e* Z, H+ t! J7 |! n
# a I8 s! j3 @+ h0 ^
, i# R+ p* d7 H* p, S
: V/ b/ @2 C+ t$ [0 O. _; Z
PA8为定时器1通道1输出口,PB13为定时器1通道1互补输出口。
8 v, w2 }" x! @: p7 T4 B9 Z. P6 ?
( B3 }$ R( y9 p9 T0 H3 p% Q, v- `; {2 pPA9为定时器1通道2输出口, PB14为定时器1通道2互补输出口。
: [: ]9 b: |0 X; U: U% c# s
. b$ I' e3 }+ @5 q0 [下来初始化定时器,参数arr设置输出PWM波频率,psc设置定时器时钟分频系数。定时器初始化之后,设置定时器工作模式为输出比较模式,其中参数 ccr1 设置通道1的输出方波起始相位,参数cc2设置通道2输出方波起始相位。参数 deadtime 设置互补PWM波形的死区时间。初始化结束后启动定时器。, N5 p+ s9 K1 Y
- J/ @2 j, G+ O, b- P! t4 I2 {
关于输出比较模式的详细说明参考STM32输出比较模式和PWM模式 比较这篇文章。7 `8 x b# k% m4 @* r& A
6 f* [, v+ {7 L" |; W! ]/ h5 r
下面看主函数设置5 u I1 X4 r% ]9 x3 K
' U1 [8 ^" ]5 J2 K
- #include "sys.h"
2 n7 w$ s J; x1 r - #include "delay.h"6 |, i2 d+ ^; I# t9 S! x
- #include "usart.h"
0 p |- K6 J5 S" Z4 j - #include "led.h"
$ a8 N( E. V' H: K' s ^% H - #include "pwm_ch_chn.h"0 o- R$ S% ?' ~7 p( Q H& P
- // LED0 PA8 LED1 PD2
8 V! C6 A* [) J- @* I# d - int main(void)
$ J6 d( j0 z- N+ R1 d3 r0 H0 ~ - {: \/ m) R* Q/ `: d& T
- delay_init(); //延时函数初始化# j8 t0 S* a7 P6 k9 E% Y3 }$ `( i
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);" C) R8 f$ ?1 r; ^0 Y8 ^$ [
- LED_Init();
; ]# i9 o" z# ^( l) t M1 s - LED0 = 1;* ~' u" j" J3 U3 K4 ?
- LED1 = 1;# P* ] `/ c" i" R1 d
- delay_ms(500);, M( o i; d( n, E. m
- LED0 = 0;
; g3 _- }8 o# ~3 Q/ { - LED1 = 0;
. {; V& t& a) X$ b+ i - // Tout=(719+1)*(0+1)/72M=10us 72M/720=0.1M=100K
9 x% B' }& u; k6 m3 C+ Z - TIM1_PWM_DeadtimeInit(719,0,0,0,72);//50KHz
8 T5 X( C- Y* v" l4 w" B( ?, o - while(1)
/ h3 q8 \; S4 T: G; ] - {
9 G! W$ T& ?. D4 e- c+ d: `- l -
6 L. t; S) V3 Y! G1 i$ _6 F - }
2 }9 \9 Z' u) M* i: o3 q - }
复制代码 ( H4 R" Z* L5 [ ]& U- E9 T
# l! q6 Q4 o9 A
主函数中设置自动装载值为 720,分频系数为0,那么输出方波频率为 72MHz / 720 = 0.1MHz,也就是输出波形频率为100K,由于此处用的是定时器的输出比较模式,所以输出频率为计算值的一半,所以实际输出方波频率为50KHz。ccr1值设置为0,也就是定时器1通道1的输出波形起始相位为0,ccr2的值为0,所以起始相位也为0。死区时间设置为72,为周期数的1/10,也就是2us。
. {; C) J( `2 ?2 n5 l' a( [3 @& d( `& O J
2 X) c9 B3 q! B( j! Q0 i7 p下面看一下输出波形
2 B: v/ ?/ t+ o3 Z7 G: ^
6 U* X0 R0 V' ^
$ x, j0 @. d) n! Y( d2 J
1 z: @/ ^% p Y3 I" T黄色为 TIM1_CH1波形,绿色为TIM1_CH1N波形,这两个波形是通道1互补波形。
( s' ^4 u- h0 l+ P0 q& a
1 N7 N" F! C. p F- r9 h蓝色为 TIM1_CH2波形,粉色为TIM1_CH2N波形,这两个波形是通道2互补波形。& e5 m8 B4 f8 b& L
' _$ G; n0 v% F" s( k! c
黄色和蓝色波形起始相位相同。
6 c2 F3 j7 \& y2 C; [2 z, Z0 {0 l! c' M R6 b3 G3 V
% }8 t7 Q0 R9 \
$ h: Y1 y& ^& j% g G" K& S7 J原波形和互补波形死区时间为1us,刚才计算的死区时间是2us,这里为什么是1us?因为死区时间是上升沿时间差+下降沿时间差,是两个对称的区间。这里只测了一个区间,所以为总时间的一半。5 `$ ~4 z" q! |5 K" X: p
/ \' m, N$ d" A9 L下来同时改变ccr1和ccr2的初始值,看看输出波形相位有没有发生变化。
+ Z% \/ }2 G& b/ X9 \- TIM1_PWM_DeadtimeInit(719,0,72,144,72);//50KHz
复制代码
, }) h. z4 v8 m& b$ }% f输出波形为% i: F, t/ }# X, p( g9 O: r8 }2 a
! z. ?: K$ N+ \' Y5 @; T; S
- L1 D, ^) K: ?$ a6 _8 I# |' T& j" D* _# B3 W
蓝色波形下降沿比黄色波形下降沿滞后了一点,说明起始相位已经发生了改变。
% [( z% P b4 ~! ~0 |+ S! ]9 ?2 g$ N# K% P# E) ^6 K4 P& K
% J3 ]0 C! H1 C4 t& M
% w9 R8 z( D+ l5 g0 @/ E放大波形后可以看到,下降沿滞后的时间为1us,和死区时间相同。# f1 c. ?. o- ~& P4 L& A) W
( {2 y% R9 w5 c
8 J t9 C4 x$ N" N) D' W |