硬件:Stm32f103c8t6最小系统。
开发平台:MDK-Arm。
目的:使用Stm32高级定时器TIM1。配置中心对齐模式输出三路互补PWM。
(1)Stm32的高级定时器:
Stm32f103c8t6有一个高级定时器TIM1。STM32的高级定时器比通用定时器增加了可编程死区互补输出,重复计数器,带刹车(短路)功能。这些功能为电机控制提供了便利。其中重复计数器下篇文章单独讲。
TIM1的IO分配:
(2)高级定时器框图分析:
图1
图1高级定时器框图,可分为6部分,①时钟源选择,②控制器,③时基单元,④输入捕获,⑤输出比较,⑥刹车断路。
①时钟选择:
时钟源有:内部时钟(CK_INT),外部时钟模式1,外部时钟模式2,内部触发输入(ITRx)。具体可以看TIMx_SMCR寄存器SMS位和ECE位这里我们使用内部时钟64MHz(没使用外部晶振,系统时钟是64MHz)。
②控制器
控制器部分包含触发控制器,从模式控制器,编码器接口。触发控制器可以为片内外设提供触发信号。
③⑤时基单元和输出比较
时基单元的计数模式选中心对齐模式和比较输出的比较模式选PWM模式来讲解。
首先时钟源通过预分频寄存器PSC分频得到CK_CNT,得到计数器CNT计数频率,计数器开始从0向上计数,每计一次,和CCR比较一次,当CRR>CNT, 输出高电平,反之输出低电平,计数器CNT继续计数,当计数器等于ARR值时,计数器向下计数,当计数器CNT>CCR时,输出低电平,反之输出高电平。计数器周而复始向上向下计数并不断的和CRR值比较,参考图2。
图2
实际此过程我们可以看成一个比较器,CRR作为参考电压,接到比较器同相输入端,CNT作为信号电压,接到比较器反相输入端,这样根据比较输出PWM。反之把CNT和CRR调换位置,会输出相反极性的PWM,参考图2.
计数器计数模式有:向上计数,向下计数,中心对齐计数。
比较输出比较模式:冻结,匹配时设置通道x为有效电平,匹配时设置通道x为无效电平,翻转,强制为无效电平,强制为有效电平,PWM1,PWM2。
死区发生器:
通过寄存器BDTR的位UTG[7:0]来配置死区时间,关于死区时间设置可以这篇文章:
⑥短路功能
断路功能用于电控的刹车功能,可以通过寄存器BDTR的BKE位使能断路功能,BKP位设置断路输入引脚的有效电平
④输入捕获
输入捕获可以对输入的信号的上升沿,下降沿或者双边沿进行捕获,常用的有测量输 入信号的脉宽和测量 PWM 输入信号的频率和占空比这两种。
输入捕获的大概的原理就是,当捕获到信号的跳变沿的时候,把计数器 CNT 的值锁存 到捕获寄存器 CCR 中,把前后两次捕获到的 CCR 寄存器中的值相减,就可以算出脉宽或者频率。如果捕获的脉宽的时间长度超过你的捕获定时器的周期,就会发生溢出,这个我 们需要做额外的处理。
(3)程序设计
程序使用ST官方固件库,编程步骤:
①GPIO初始化;
②时基结构体TIM_TimeBaseInitTypeDef 初始化;
③比较结构体 TIM_OCInitTypeDef 初始化;
④刹车和死区结构体 TIM_BDTRInitTypeDef 初始化。
程序分析:
①宏定义:
#define RCC_TIMGPIO_CLK RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB
#define TIM_CHxGPIO_Pinx GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11
#define TIM_CHxGPIOx GPIOA
#define TIM_CHxNGPIO_Pinx GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15
#define TIM_CHxNGPIOx GPIOB
#define TIM_BKINGPIO_Pinx GPIO_Pin_2
#define TIM_BKINGPIOx GPIOB
//TIM1 macro definition
/ PWM频率和死区时间计算 */
//电机控制载波频率一般配置在15-20KHz,频率配置低了电机噪声大,配置高了,对MOS
//管开关频率要求高,且开关损耗大,这里载波配置为20KHz。
//计数器频率计算CK_CNT = 64MHz/(PSC+1) = 64MHz/1=64MHz
//中心对齐PWM频率=CK_INT/2(ARR+1)=64M/2(1599+1)=20KHz。
//死区时间配置为2us
//64M/(CKD+1)/ UTG = 500KHz,换算成时间位2us
// TIMx_CR1寄存器CKD 位,TIMx_BDTR寄存器UTG位。
#define TIMx TIM1
#define RCC_TIM_CLK RCC_APB2Periph_TIM1
#define TIM_ARR 1599
#define TIM_CK_PSC 0
#define TIM_RCR 0
#define TIM_CCRx 799
#define PWM_DeadTime 128
②GPIO初始化:
static void GPIO_TIM_Config(void){
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_TIMGPIO_CLK, ENABLE);
//TIM1_PA8CH1 PA9CH2 PA10CH3 PA11CH4
GPIO_InitStructure.GPIO_Pin = TIM_CHxGPIO_Pinx;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//PB13CH1N PB14CH2N PB15CH3N PB12BKIN
GPIO_InitStructure.GPIO_Pin = TIM_CHxNGPIO_Pinx;
GPIO_Init(TIM_CHxNGPIOx, &GPIO_InitStructure);
//PB12BKIN
GPIO_InitStructure.GPIO_Pin = TIM_BKINGPIO_Pinx;
GPIO_Init(TIM_BKINGPIOx, &GPIO_InitStructure);
GPIO_ResetBits(TIM_BKINGPIOx,TIM_BKINGPIO_Pinx);//刹车
}
③定时器时基单元,输出比较,刹车死区初始化:
static void AdvanceTIM1_Config(void){
//开启定时器时钟,即内部时钟CK_INT=64MHz
RCC_APB2PeriphClockCmd(RCC_TIM_CLK,ENABLE);
/*--------------------时基结构体初始化-------------------------*/
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = TIM_ARR; //自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
TIM_TimeBaseStructure.TIM_Prescaler = TIM_CK_PSC; //驱动CNT计数器的时钟 = Fck_int/(psc+1)
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频因子 ,配置死区时间时需要用到
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_CenterAligned1; //中心对齐1
TIM_TimeBaseStructure.TIM_RepetitionCounter = TIM_RCR; //重复计数器的值,没用到不用管
TIM_TimeBaseInit(TIMx, &TIM_TimeBaseStructure); //初始化定时器
/*--------------------输出比较结构体初始化-------------------*/
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //PWM1模式
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //输出使能
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; //互补输出使能
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_OCNIdleState_Reset; //互补输出通道空闲电平极性配置
TIM_OCInitStructure.TIM_Pulse = TIM_CCRx; //设置占空比大小
TIM_OC1Init(TIMx, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIMx, TIM_OCPreload_Enable);
TIM_OC2Init(TIMx, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIMx, TIM_OCPreload_Enable);
TIM_OC3Init(TIMx, &TIM_OCInitStructure);
TIM_OC3PreloadConfig(TIMx, TIM_OCPreload_Enable);
/*-------------------刹车和死区结构体初始化-------------------*/
//有关刹车和死区结构体的成员具体可参考BDTR寄存器的描述
TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;
TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;
//输出比较信号死区时间配置,具体如何计算可参考 BDTR:UTG[7:0]的描述
//这里配置的死区时间为2uS
TIM_BDTRInitStructure.TIM_DeadTime = 128;
TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;
//当BKIN引脚检测到高电平的时候,输出比较信号被禁止,就好像是刹车一样
TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;
TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
TIM_BDTRConfig(TIMx, &TIM_BDTRInitStructure);
TIM_Cmd(TIMx, ENABLE);
//主输出使能,当使用的是通用定时器时,这句不需要
TIM_CtrlPWMOutputs(TIMx, ENABLE);
}
(4)程序烧录验证:图3是一对PWM互补输出波形。
图3