在上一章的输出多路PWM的基础上,本章主要讲述如何配置WB32上的高级定时器TIM1完成PWM互补输出。
对PWM互补输出的概括放到10.3节中,请大家先跟随10.1节了解PWM互补输出如何配置,再结合10.2节实验现象对10.3节PWM互补输出概述进行参照,相信大家对PWM互补输出会有一个更清晰的认知。
本章节我们需要使用到固件库例程中TIM_ComplementarySignals工程,来讲解如何配置TIM1来完成PWM互补输出,需要注意PWM互补输出只能使用高级定时器来配置。
本例程中我们使用到高级定时器TIM1,使用其中三个通道(TIM_CH1、TIM_CH2、TIM_CH3)和三个互补通道(TIM_CH1N、TIM_CH2N、TIM_CH3N),还有一个用来检测“刹车信号”的引脚(TIM1_BKIN)。
结合例程,根据WB32F103查表可知,使用到的引脚依次为PA8(TIM_CH1)、PA9(TIM_CH2)、PA10(TIM_CH3)、PB13(TIM_CH1N)、PB4(TIM_CH2N)、PB15(TIM_CH3N)和PA6(TIM1_BKIN)。
void RCC_Configuration(void)
{
/* 使能TIM1 GPIOA GPIOB AFIO 时钟 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BMX1 |
RCC_APB1Periph_TIM1 |
RCC_APB1Periph_GPIOA |
RCC_APB1Periph_GPIOB |
RCC_APB1Periph_AFIO ,
ENABLE);
}
void GPIO_Configuration(void)
{
/*GPIOA 初始化: TIM1_CH1, TIM1_CH2, TIM1_CH3 and TIM1_BKIN */
GPIO_Init(GPIOA, GPIO_Pin_6 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10, GPIO_MODE_AF | GPIO_AF1);
/*GPIOB 初始化: TIM1_CH1N, TIM1_CH2N, TIM1_CH3N*/
GPIO_Init(GPIOB, GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15, GPIO_MODE_AF | GPIO_AF1);
}
/* 初始化定时器参数 */
TIM_TimeBaseStructure.TIM_Prescaler = 0; //配置预分频器为0。
//驱动CNT计数器的时钟CK_CNT = CK_INT /(TIM_Prescaler+1)
//例:本例程中 CK_CNT = 72M/(0+1) = 72M
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //配置定时器计数模式为向上计数
TIM_TimeBaseStructure.TIM_Period = TimerPeriod; //配置定时器周期为0xFFFF,即65535,可设置范围为0x00000~oxFFFFF。
//自动重装载寄存器(ARR)的值累计TIM_Period个频率后产生一个更新或中断。
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //配置时钟分频因子为0。
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; //配置重复计数器为0
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //初始化定时器基本结构体
注意:
1)此处例程中结构体成员TIM_Period的值被赋值为TimerPeriod。关于TimerPeriod的值,在使用uint16_t TimerPeriod = 0;
将其初始化为0后,接着在主函数中通过TimerPeriod = 0xFFFF;
将其赋值为0xFFFF。
2)关于输出的PWM周期与频率计算公式与方法请查看上章内容,本章节不再赘述。
/* 配置Channel 1, 2 and 3 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //比较输出模式选择为PWM2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; //比较互补输出使能
TIM_OCInitStructure.TIM_Pulse = Channel1Pulse; //脉冲宽度设置为Channel1Pulse。此处决定着PWM的占空比。
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //配置比较输出极性为高电平有效。(亦可设置为低电平有效,
//使用示波器查看与配置为高电平输出有何不同)
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; //配置比较互补输出极性为高电平有效。(亦可设置为低电平有效,
//使用示波器查看与配置为高电平输出有何不同)
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set; //空闲状态下输出电平设置为高,即在空闲状态时,经过死区时间后
//定时器通道输出高电平或低电平。
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset; //空闲状态下互补输出电平设置为低,即在空闲状态时,经过死区时
//间后定时器互补通道输出高电平或低电平,设定值必须与
//TIM_OCIdleState相反。
TIM_OC1Init(TIM1, &TIM_OCInitStructure); //TIM通道1输出比较结构体初始化
TIM_OCInitStructure.TIM_Pulse = Channel2Pulse; //脉冲宽度设置为Channel2Pulse。此处决定着PWM的占空比。
TIM_OC2Init(TIM1, &TIM_OCInitStructure); //TIM通道2输出比较结构体初始化
TIM_OCInitStructure.TIM_Pulse = Channel3Pulse; //脉冲宽度设置为Channel3Pulse。此处决定着PWM的占空比。
TIM_OC3Init(TIM1, &TIM_OCInitStructure); //TIM通道3输出比较结构体初始化
注意
1)在配置输出比较结构体成员TIM_OCMode时,可以注意到与上一章中的配置不同,本章选择配置为PWM2模式,两种模式用法相近,具体区别见下表:
2)在配置输出比较结构体成员TIM_Pulse时,将其配置为Channel1Pulse,这个变量具体的值可以通过代码Channel1Pulse = (uint16_t) (((uint32_t) 5 * (TimerPeriod - 1)) / 10);
计算得来。
例:Channel1Pulse = 5*(65535-1)/10 = 32767 ,根据上一章的占空比计算可得TIM1通道1输出的PWM占空比为50%,另外,TIM1通道1输出的互补PWM的占空比亦是50%。
Channel2Pulse与Channel3Pulse的计算方法相同。
3)相较于上一章,本章完成PWM互补输出需要相关的结构体成员,配置方式在注释中。
需要注意结构体成员TIM_OCIdleState和TIM_OCNIdleState的配置,现在读不明白注释的请阅读完10.2节和10.3节后再思考。
/* 断路和死区结构体配置*/
TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; //使能运行模式下的关闭状态
TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; //使能空闲模式下的关闭状态
TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1; //配置锁定级别为1
TIM_BDTRInitStructure.TIM_DeadTime = 11; //定义死区持续时间为152ns。设置范围为 0x0 至 0xFF。
TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable; //使能断路输入功能。
TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High; //配置断路输入通道 BRK 极性为高。
TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable; //自动输出使能,可选使能或禁止
TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure); //初始化断路和死区结构体
注意:
1)关于此结构体配置,主要了解如何配置死区时间即可,其他结构体成员配置主要为开启TIM输出的断路(“刹车”)功能。
2)死区时间配置可参考WB32中文参考手册TIM1高级控制定时器的刹车和死区寄存器(TIMx_BDTR)部分。
关于此部分配置我们会单出一篇文章进行详解。
TIM_Cmd(TIM1, ENABLE); //使能TIM1计数器。
TIM_CtrlPWMOutputs(TIM1, ENABLE); //主输出使能。
本例仅观察TIM1通道1(TIM_CH1)与TIM1互补通道1(TIM_CH1N)的现象,其余两个通道请自行观察学习。
将示波器探头通道1接在PA8上,探头通道2接在PB13上,即可观察到如下波形:
大家可以观察到,PA8与PB13输出的波形是互补的,当PA8输出高电平时,PB13输出低电平,反之亦然。
但设置的死区时间在哪里?注意图片中用红框标注的地方,此时的200us代表示波器横坐标的1格的时间尺度。
我们在程序中设置的死区时间为153ns,所以在200us为时间单位的坐标中自然不能看清,接下来我们将时间尺度继续缩小:
可以看到,当示波器中1格的时间达到50.0ns时,即可在电平转换的边沿观察到死区时间,且PA8与PB13输出的PWM总是不同时为高电平。
另外,还有一项“断路(刹车)”功能,此时我们使用杜邦线将PA6与板载3.3V供电相连接,可以看到:
此时不再产生任何波形,就像对我们的WB32踩下“刹车”一样。
我们本节课的PWM互补输出配置讲解就到此为止,那么学会配置PWM互补输出到底是什么?用来干什么?请阅读10.3节。
注意:
1)当PA6断开与3.3V的连接后PWM会照常输出。
简单的讲,互补的意思就是当PWM1是高电平时,PWM2是低电平,如果PWM1是低电平时PWM2是高电平,总之PWM1和PWM2不会同时变高或变低,总是不一样的。
需要知道,PWM互补输出多用在驱动器和逆变器等方面。
一般这样的PWM输出用于控制由两个MOS管组成的在电源和地之间的桥,由于两个同时接通的话会导致桥臂短路电源和地引起烧毁,所以采用互补的波形来避免同时导通的情况出现。
但是,由于两个MOS管的参数不一定完全相同,关断速度也不一定相同,可能出现第一个MOS管还差几us或几ms关闭但第二个MOS管已经打开,造成了两个MOS都短暂导通,进而烧毁驱动电路的现象。
因此,本章引入“死区时间”概念:即在PWM1变为低电平时,等待一段时间后,PWM2再从低电平变为高电平;或PWM2从高电平变为低电平时,等待一段时间后,PWM1从低电平变到高电平。这段等待的时间就是“死区时间”。