1. 程式人生 > >STM32F103高階定時器死區時間的計算

STM32F103高階定時器死區時間的計算

看了一些網上講死區時間計算的教程,覺得講述的不是很清楚,所以在此用我自己理解的方式講述一遍,如有錯誤,請讀者賜教。
  死區時間的設定:由暫存器“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);
}