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);
}