这是我参与更文挑战的第18天,活动详情查看: 更文挑战
STM32F103单片机定时器自带互补PWM波形输出功能,利用定时器输出比较模式,不仅可以输出互补的 PWM波,还可以设置输出方波的起始相位和死区时间。
下面就总结一下如何实现PWM互补输出。
void TIM1_PWM_DeadtimeInit( u16 arr, u16 psc, u16 ccr1, u16 ccr2, u16 deadtime )
{
GPIO_InitTypeDef GPIO_InitSturcture;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE );
RCC_APB2PeriphClockCmd( RCC_APB2Periph_TIM1, ENABLE );
//TIM1 互补PWM CH1->PA8 CH2->PA9 CH1N->PB13 CH2N->PB14
GPIO_InitSturcture.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitSturcture.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitSturcture.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init( GPIOA, &GPIO_InitSturcture );
GPIO_InitSturcture.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14;
GPIO_InitSturcture.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitSturcture.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init( GPIOB, &GPIO_InitSturcture );
//定时器设置
TIM_TimeBaseInitStructure.TIM_Period = arr;
TIM_TimeBaseInitStructure.TIM_Prescaler = psc;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_ClockDivision = 0x00;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0x00;
TIM_TimeBaseInit( TIM1, &TIM_TimeBaseInitStructure );
//通道1 捕获比较模式设置
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle; //翻转,当 TIMx_CCR1=TIMx_CNT时,翻转OC1REF的电平
TIM_OCInitStructure.TIM_Pulse = ccr1; //100
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //CCER的CC1P,输入/捕获输出极性
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //CER的CC1N,输入/捕获输出使能
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;//OIS1位
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset; //CR2的OIS1N位,当MOE位0时,输出空闲状态位OIS1N.
TIM_OC1Init( TIM1, &TIM_OCInitStructure );
//通道2 设置
TIM_OCInitStructure.TIM_Pulse = ccr2; //316
TIM_OC2Init( TIM1, &TIM_OCInitStructure );
//刹车和死区设置
TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; //OSSR:运行模式下“关闭状态”选择
TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; //OSSI:空闲模式下“关闭状态”选择
TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1; //锁定设 置,级别为1
TIM_BDTRInitStructure.TIM_DeadTime = deadtime; //死区延时时间
TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable; //禁止刹车输 入
TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_Low; //刹车输入极性
TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable; //自动输出使能
TIM_BDTRConfig( TIM1, &TIM_BDTRInitStructure );
TIM_CtrlPWMOutputs( TIM1, ENABLE );
TIM_OC1PreloadConfig( TIM1, TIM_OCPreload_Enable );
TIM_OC2PreloadConfig( TIM1, TIM_OCPreload_Enable );
TIM_ARRPreloadConfig( TIM1, ENABLE );
TIM_Cmd( TIM1, ENABLE );
}
复制代码
首先初始化IO口,这里使用的是定时器1的通道1和通道2。
PA8为定时器1通道1输出口,PB13为定时器1通道1互补输出口。
PA9为定时器1通道2输出口, PB14为定时器1通道2互补输出口。
下来初始化定时器,参数arr设置输出PWM波频率,psc设置定时器时钟分频系数。定时器初始化之后,设置定时器工作模式为输出比较模式,其中参数 ccr1 设置通道1的输出方波起始相位,参数cc2设置通道2输出方波起始相位。参数 deadtime 设置互补PWM波形的死区时间。初始化结束后启动定时器。
关于输出比较模式的详细说明参考STM32输出比较模式和PWM模式 比较这篇文章。
下面看主函数设置
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "pwm_ch_chn.h"
// LED0 PA8 LED1 PD2
int main(void)
{
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
LED_Init();
LED0 = 1;
LED1 = 1;
delay_ms(500);
LED0 = 0;
LED1 = 0;
// Tout=(719+1)*(0+1)/72M=10us 72M/720=0.1M=100K
TIM1_PWM_DeadtimeInit(719,0,0,0,72);//50KHz
while(1)
{
}
}
复制代码
主函数中设置自动装载值为 720,分频系数为0,那么输出方波频率为 72MHz / 720 = 0.1MHz,也就是输出波形频率为100K,由于此处用的是定时器的输出比较模式,所以输出频率为计算值的一半,所以实际输出方波频率为50KHz。ccr1值设置为0,也就是定时器1通道1的输出波形起始相位为0,ccr2的值为0,所以起始相位也为0。死区时间设置为72,为周期数的1/10,也就是2us。
下面看一下输出波形
黄色为 TIM1_CH1波形,绿色为TIM1_CH1N波形,这两个波形是通道1互补波形。
蓝色为 TIM1_CH2波形,粉色为TIM1_CH2N波形,这两个波形是通道2互补波形。
黄色和蓝色波形起始相位相同。
原波形和互补波形死区时间为1us,刚才计算的死区时间是2us,这里为什么是1us?因为死区时间是上升沿时间差+下降沿时间差,是两个对称的区间。这里只测了一个区间,所以为总时间的一半。
下来同时改变ccr1和ccr2的初始值,看看输出波形相位有没有发生变化。
TIM1_PWM_DeadtimeInit(719,0,72,144,72);//50KHz
复制代码
输出波形为
蓝色波形下降沿比黄色波形下降沿滞后了一点,说明起始相位已经发生了改变。
放大波形后可以看到,下降沿滞后的时间为1us,和死区时间相同。