历史上的今天
今天是:2025年03月14日(星期五)
2019年03月14日 | STM32F103高级定时器死区时间的计算
2019-03-14 来源:eefocus
看了一些网上讲死区时间计算的教程,觉得讲述的不是很清楚,所以在此用我自己理解的方式讲述一遍,如有错误,请读者赐教。
死区时间的设置:由寄存器“TIM1和TIM8刹车和死区寄存器TIMX_BDTR”中,位DTG[7:0]控制(中文数据手册可能出现错误,应当是DTG)。



官方数据手册的说明不容易看懂,举的例子与我的应用场合也不一致,我使用的是72MHz的晶振,讲一讲我的死区时间是怎么算出来的。
DT死区时间;
TDTS为系统时钟周期时长;
TDTG为系统周期时长乘以倍数,这个值用于计算最终死区时间,也叫作步长。
在72M的定时器时钟下,TDTS = 1/72M = 13.89ns。
这个计算比较复杂,主要思想就是把DTG的八位,掰成两半用。一半决定步长,另一半是与步长相乘的乘数,乘数可以自行设定,步长*乘数=死区时间。至于步长与乘数从哪里分开,看下表
项目 情况1 情况2 情况3 情况4
步长位置 DTG[7] DTG[7:6] DTG[7:5] DTG[7:5]
步长值(二进制) 1 10 110 111
步长是周期几倍 1 2 8 16
乘数位置 DTG[6:0] DTG[5:0] DTG[4:0] DTG[4:0]
乘数最大值 127 64+63 63+31 32+31
乘数范围 0~127 64~127 32~63 34~63
等价几倍周期 0~127 128~254 256~504 512~1008
周期125ns时,死区范围ns 0~15875 16000~31750 32000~63000 64000~126000
周期13.89ns时,死区范围ns 0~1764 1778~3528 3556~7000 7112~14001
接下来举例说明表格怎么用。
例如72MHz的晶振,需要14us的死区时间,那么属于情况4,DTG[7:5] = 0b111,DTG[4:0]=31=0b1111,所以DTG = 0xff。72MH晶振的情况下,最大只能14us的死区。
还是72MHz的晶振,需要3us的死区时间,那么属于情况2,DTG[7:6] = 0b10,步长=27.78,需要的乘数 = 3000÷27.78-64=108-64=44=0b101100,DTG[7:0]=0b10101100=0xAC。
实际的系统中,死区的时间一般由硬件的响应速度决定。我的系统使用的驱动电路设计参考之前的博客
使用的电机型号是JGB37-3530B。经过测试,3us的死区时间可以使用。
下边是电机初始化的函数,主要的功能是用STM32的高级定时器TIM1,输出嵌入死区的互补PWM。
使用两个通道输出PWM,通道1 的引脚是PA8和PB13,通道2 的引脚是PA9和PB14。一个周期是1ms,频率是1KHz,3us的死区时间。默认通道1的占空比是50%,通道2的占空比是0%,让电机以49.7%(占空比减去死区)的速度正转。
void PWM_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_BaseInitStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//开启TIM和相应端口时钟
//启动GPIO
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB,ENABLE);
//启动AFIO
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
//启动TIM1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
//GPIO做相应设置,为AF输出 //PA8,PB13一组互补输出 A9,PB14一组互补输出
//PA.8/9口设置为TIM1的OC1输出口
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//PB.13/14口设置为TIM1_CH1N和TIM1_CH2N输出口
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOA, GPIO_Pin_8 | GPIO_Pin_9);
GPIO_SetBits(GPIOB, GPIO_Pin_13 | GPIO_Pin_14);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//TIM1基本计数器设置(设置PWM频率)1KHz
TIM_BaseInitStructure.TIM_Period = 1000-1; //1khz 好计算。按照1%的精确度,理论最大72000/100 = 720KHz
TIM_BaseInitStructure.TIM_Prescaler = 72-1;
TIM_BaseInitStructure.TIM_ClockDivision = 0;
TIM_BaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_BaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1, &TIM_BaseInitStructure);
//启用ARR的影子寄存器(直到产生更新事件才更改设置)
TIM_ARRPreloadConfig(TIM1, ENABLE);
//TIM1_OC1模块设置(设置1通道占空比)
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//TIM脉冲宽度调制模式1
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输出比较极性高
//TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
TIM_OCInitStructure.TIM_Pulse = 500;//待装入捕获比较寄存器的脉冲值
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
//启用CCR1寄存器的影子寄存器(直到产生更新事件才更改设置)
TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
//TIM1_OC2模块设置(设置2通道占空比)
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OC2Init(TIM1, &TIM_OCInitStructure);
//启用CCR2寄存器的影子寄存器(直到产生更新事件才更改设置)
TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);
//OCx输出信号与参考信号相同,只是它的上升沿相对参考信号的上升沿有一个延迟
//OCxN输出信号与参考信号相同,只是它的上升沿相对参考信号的下降沿有一个延迟
//死区设置
TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;
TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_2;
TIM_BDTRInitStructure.TIM_DeadTime = 0xAC; //这里调整死区大小为3us
TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable;
TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;
TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);
//TIM1_OC通道输出PWM
TIM_CtrlPWMOutputs(TIM1, ENABLE);
//TIM1开启
TIM_Cmd(TIM1, ENABLE);
}
下一篇:STM32定时器库函数讲解
史海拾趣
|
Analog Design/verifiction Engineer Analog Design/verifiction Engineer 美资公司 LSI 上海研发中心高薪诚聘存储通讯领域人才,薪水待遇优厚,部分人员有出国培训机会。(部门内部推荐) 有意者请将中英文简历发送至:asic_tapeout@hotmail.com Analog Design Engineer City :&nbs ...… 查看全部问答> |
|
最近再做数据库开发.看见ADOCE提供的接口 /* [id] */ HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetRows )( _Recordset __RPC_FAR * This, ...… 查看全部问答> |
|
在写ds18b20驱动程序时,由于读设备64位rom代码,因此想用下结构体。 自定义的结构体为: struct RomCode { uchar FamilyCode; uchar SerialCode[6]; uchar Crc; }; 测试主函数: void main() ...… 查看全部问答> |
|
楼主我是一名年近30的工程师,目前在一大城市的半导体日企工作。1直2在奔3路上,94不敢娶7买房。最近面试不少90后,公司也有两个90后新人,他们个个像个小人精,就是那个责任心和态度呀~~~~搞出的事情经常让你无言以对,偏偏他们嘴甜会卖萌, ~~~~~ ...… 查看全部问答> |
|
项目中需要检测机车发出的0到20mA的电流信号,这个电流信号是用来控制机车的加减速的。由于涉及到机车的安全运行,只能采用非接触式的检测方式,比如互感器、霍尔传感器。现在找了很多互感器及霍尔传感器都没有这个DC 0~20mA这个范围,实在是太小了 ...… 查看全部问答> |




