STM32 互补输出和死区插入
扫描二维码
随时随地手机看文章
搞过全桥电机驱动的都知道控制死区时间的重要性,一般解决方案是搭建电路控制死区时间或直接使用全桥驱动芯片。
而STM32拥有两个高级定时器,可以直接输出具有调节死区时间的PWM。
现以TIM1通道1输出占空比为50%,死区时间为5us来做个例子。
首先TIM1通道1的PWM输出端口为PA8,互补输出通道为PB13,所以需要开启相应模块的时钟:
RCC->APB2ENR|=1<<11; //TIM1时钟使能
RCC->APB2ENR|=1<<2; //GPIOA时钟使能
RCC->APB2ENR|=1<<3; //GPIOB时钟使能
将需要使用的PA8,PB13口设置为复用式推挽输出并上拉:
GPIOA->CRH&=0XFFFFFFF0; //清PA8状态
GPIOA->CRH|=0X0000000B; //复用功能输出 推挽式
GPIOA->ODR|=3<<8; //PA8上拉
GPIOB->CRH&=0XFF0FFFFF; //清PB13状态
GPIOB->CRH|=0X00B00000; //复用功能输出 推挽式
GPIOB->ODR|=3<<13; //PB13上拉
接着需要设置的是TIM1->ARR和TIM1->PSC 这两个寄存器。
预分频器寄存器TIM1->PSC 对系统频率进行分频,得到定时器计数频率:
fCK_CNT=fck_PSC/(PSC[15:0]+1)
计数器自动重装寄存器TIM1->ARR对定时器计数频率进行分频,得到PWM频率:
fPWM=fCK_CNT/(ARR[15:0]+1)
stm32参考手册里的高级控制定时器框图表达的很明确了:
接下来就开始设置有关互补输出和死区控制的寄存器了。
1、刹车和死区寄存器TIM1->BDTR
DTG[7:0] 决定了插入的死区持续时间,假设DT表示其持续时间则:
DTG[7:5]=0xx => DT=DTG[7:0] × Tdtg,Tdtg = TDTS;
DTG[7:5]=10x => DT=(64+DTG[5:0]) × Tdtg,Tdtg = 2 × TDTS;
DTG[7:5]=110 => DT=(32+DTG[4:0]) × Tdtg,Tdtg = 8 × TDTS;
DTG[7:5]=111 => DT=(32+DTG[4:0])× Tdtg,Tdtg = 16 × TDTS;
TDTS为系统时钟周期时长,Tdtg为系统时钟周期时长乘以倍数后的时长。
这样当我需要5us的死区持续时间时,则可这么计算:
死区时间=1/72*1000X(32+DTG)X8=5us (72Mhz)
TIM1->BDTR|=0xCD; //72Mhz,死区时间=13.89nsX(32+DTG)X8=5us
MOE位为主输出使能,将在后面置位。
其他位的具体设置可参考《STm32参考手册》P244页,以下设置寄存器都不做详细介绍。
2、捕获/比较使能寄存器TIM1_CCER 这里要设置的只是使能通道x的互补输出,或输出极性:
TIM1->CCER|=1<<2; //CH1互补输出使能
剩下的还需要设置:
捕获/比较模式寄存器 TIMx_CCMR1 设置输出PWM的模式和开启预装载功能:
TIM1->CCMR1|=6<<4; //CH1 PWM模式1
TIM1->CCMR1|=1<<3; //CH1预装载使能
控制寄存器1 TIM1->CR1
TIM1->CR1|=1<<7; //使能ARR自动重装入缓冲器
最后,惯例,写个初始化函数:
////////////////////////////////////////////////////////////////////////////////// //初始化TIM1 PWM部分 PWM1模式//PWM互补输出//arr:自动重装值 决定PWM输出频率//psc:时钟预分频数 决定计数器频率 //修改日期:2011/10/11 占空比=(VAL/arr)*100%//修改人://////////////////////////////////////////////////////////////////////////////////
void TIM1_PWM_Init(u16 arr,u16 psc)
{
RCC->APB2ENR|=1<<11; //TIM1时钟使能
RCC->APB2ENR|=1<<2; //GPIOA时钟使能
RCC->APB2ENR|=1<<3; //GPIOB时钟使能
GPIOA->CRH&=0XFFFFFF00; //PA8,PA9输出
GPIOA->CRH|=0X000000BB; //复用功能输出 推挽式
GPIOA->ODR|=3<<8; //PA8,PA9上拉
GPIOB->CRH&=0XF00FFFFF; //PB13,PB14输出
GPIOB->CRH|=0X0BB00000; //复用功能输出 推挽式 GPIOB->ODR|=3<<13; //PB13,PB14上拉
TIM1->ARR=arr; //设定计数器自动重装值 fPWM=fCK_CNT/(ARR[15:0]+1) TIM1->PSC=psc; //预分频器设置 fCK_CNT=fck_PSC/(PSC[15:0]+1)
TIM1->BDTR|=0xCD; //72Mhz算,死区时间=13.89nsX(32+DTG)X8=5us
TIM1->CCER|=1<<2; //CH1互补输出使能
TIM1->CCMR1|=6<<4; //CH1 PWM1模式
TIM1->CCMR1|=1<<3; //CH1预装载使能
TIM1->CR1|=1<<7; //使能ARR自动重装入缓冲器
TIM1->BDTR|=1<<15; //主输出使能TIM1->CR1|=0x01; //使能定时器1
}
主函数调用
int main(void){
TIM1_PWM_Init(399,8); //预分频9,PWM频率=72000000/9/400=20khz
TIM1->CCR1=200;
TIM1->CCER|=0x01; //CH1 OC1信号输出使能
}
最后接上示波器查看波形: