STM32F103高级定时器死区时间的计算

本文详细解析了STM32中死区时间的计算方法,以72MHz晶振为例,介绍了如何通过TIMX_BDTR寄存器设置死区时间,并给出了具体的计算步骤与实例。同时,分享了一种利用STM32高级定时器TIM1输出嵌入死区的互补PWM的初始化函数。

看了一些网上讲死区时间计算的教程,觉得讲述的不是很清楚,所以在此用我自己理解的方式讲述一遍,如有错误,请读者赐教。
  死区时间的设置:由寄存器“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]
步长值(二进制)110110111
步长是周期几倍12816
乘数位置DTG[6:0]DTG[5:0]DTG[4:0]DTG[4:0]
乘数最大值12764+6363+3132+31
乘数范围0~12764~12732~6334~63
等价几倍周期0~127128~254256~504512~1008
周期125ns时,死区范围ns0~1587516000~3175032000~6300064000~126000
周期13.89ns时,死区范围ns0~17641778~35283556~70007112~14001

接下来举例说明表格怎么用。
  例如72MHz的晶振,需要14us的死区时间,那么属于情况4,DTG[7:5] = 0b111,DTG[4:0]=31=0b11111,所以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 标准库的高级定时器(TIM1 和 TIM8)死区功能的配置步骤: 1. 使能定时器时钟,并初始化定时器。 ``` RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); // 使能 TIM1 时钟 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_TimeBaseStructure.TIM_Period = 999; // 自动重装值 TIM_TimeBaseStructure.TIM_Prescaler = 71; // 时钟预分频 TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); // 初始化 TIM1 TIM_Cmd(TIM1, ENABLE); // 启动 TIM1 ``` 2. 配置死区时间,并使能死区时间。 ``` TIM_BDTRInitTypeDef TIM_BDTRInitStructure; TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Disable; // 关闭内部触发信号 TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Disable; // 关闭内部触发信号 TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF; // 关闭锁定功能 TIM_BDTRInitStructure.TIM_DeadTime = 50; // 死区时间,单位为 TIM 时钟周期 TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure); // 初始化 TIM1 的 BDTR ``` 3. 配置输出比较通道,并使能预装载功能。 ``` TIM_OCInitTypeDef TIM_OCInitStructure; TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // PWM 模式1 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 使能输出 TIM_OCInitStructure.TIM_Pulse = 499; // 比较值 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 高电平极性 TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset; // 空闲状态为低电平 TIM_OC1Init(TIM1, &TIM_OCInitStructure); // 初始化 TIM1 的通道1 TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable); // 使能通道1的预装载功能 ``` 4. 配置 DMA 传输的突发长度,并使能 DMA 传输。 ``` DMA_InitTypeDef DMA_InitStructure; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &TIM1->DMAR; // DMA 传输目标地址 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) &ADCValue; // DMA 传输源地址 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; // 传输方向:从存储器到外设 DMA_InitStructure.DMA_BufferSize = 2; // DMA 传输数据量 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 禁止目标地址自增 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 允许源地址自增 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 目标数据长度为半字 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; // 源数据长度为半字 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // 循环传输 DMA_InitStructure.DMA_Priority = DMA_Priority_High; // DMA 优先级 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // 禁用内存到内存传输 DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE); // 允许 DMA 传输完成中断 DMA_Init(DMA2_Stream0, &DMA_InitStructure); // 初始化 DMA DMA_Cmd(DMA2_Stream0, ENABLE); // 启动 DMA ``` 通过上述步骤,就可以实现 STM32 高级定时器死区功能配置。需要注意的是,具体的配置参数需要根据具体应用来确定,以上仅为参考。
评论 19
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值