STM32 advanced timer TIM1 generates two-way complementary PWM wave (with dead zone), stm32tim1
Test environment: Keil 5.2.160.0 STM32F103RBT6 Firmware Library version: STM32F10x_StdPeriph_Lib_V3.5.0 (2011)
In this paper, TIM1 Channel 1 and Channel 2 are used to generate two complementary PWM waves with 1 khz and 1 us dead zone.
IO port used: We use pin PA9, PA10, complementary Output Using PB14, PB15
Some code is as follows:
/* Configure the I/O used when TIM1 multiplexes the output PWM */
Static void TIM1_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* TIM1 clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
/* GPIOA and GPIOB clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
Initialize IO
Initialize IO
Initialize the timer function configuration
U16 CCR2_Val = 500;
U16 CCR3_Val = 500; / / duty cycle, period is 1000
/*Configure the mode of the PWM signal output by TIM1, such as period, polarity, duty cycle */
Void TIM1_Mode_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_BDTRInitTypeDef TIM1_BDTRInitStruct;
TIM_OCInitTypeDef TIM_OCInitStructure;
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 1000-1; //Count cycle, count up to this number, count value is cleared
TIM_TimeBaseStructure.TIM_Prescaler = 72-1; / / timer division factor, Ftimer = 72M / (TIM_Prescaler + 1) = 1ms
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; / / related to the dead time division
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; / / up counting mode
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
/****** Configure BDTR register to configure dead time****************/
/*
Timer clock 72M TIM_ClockDivision = TIM_CKD_DIV1, Tdts = 13.89ns
0 - 1.764us using algorithm one
1.778us - 3.505us with algorithm two
3.556us - 7.000us with algorithm three
7.1117us - 14us with algorithm four
Take longer to use TIM_ClockDivision crossover
*/
TIM1_BDTRInitStruct.TIM_OSSRState = TIM_OSSRState_Disable;
TIM1_BDTRInitStruct.TIM_OSSIState = TIM_OSSIState_Disable;
TIM1_BDTRInitStruct.TIM_LOCKLevel = TIM_LOCKLevel_OFF;
TIM1_BDTRInitStruct.TIM_DeadTime = 205; // Dead time 72:1us 172:3us 205:5us
TIM_BDTRConfig(TIM1,&TIM1_BDTRInitStruct);
// TIM1->BDTR |= 72; //Set dead zone Note: The above method is also available, this is fast and simple
/* PWM1 Mode configuration: Channel2 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; // PWM2 mode
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //Compare output enable
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;//Compare complementary output enable
TIM_OCInitStructure.TIM_Pulse = CCR2_Val; //Compare value, ie duty cycle
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //output polarity
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; / / complementary output polarity
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;//Specifies the pin state of the TIM output compare in idle state.
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;//Specifies the pin state of the TIM complementary output compare in idle state.
TIM_OC2Init(TIM1, &TIM_OCInitStructure); //Initialize channel 2 comparison output
TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable); //Configure channel two, auto-reload enable
/* PWM1 Mode configuration: Channel3 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR3_Val;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
TIM_OC3Init(TIM1, &TIM_OCInitStructure);
TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM1, ENABLE);//Overloaded load value ENABLE takes effect immediately, DISABLE next comparison cycle takes effect
/* TIM1 enable counter */
TIM_Cmd(TIM1, ENABLE);//Enable Timer 1
TIM_CtrlPWMOutputs(TIM1, ENABLE);//Enable PWM peripheral output
}
int main(void)
{
TIM1_GPIO_Config();
TIM1_Mode_Config();
while(1)
{
TIM1->CCR2 = CCR2_Val;
TIM1->CCR3 = CCR3_Val;
CCR2_Val+=5;
CCR3_Val+=10;
if(CCR2_Val>900) CCR2_Val = 100;
if(CCR3_Val>900) CCR3_Val = 100;
Delay_mS(200);
}
}
main函数
Main Function
Calculation of Dead Time:
First, paste a few screenshots of the TIM clock:
The first figure shows the time division factor of the dead zone. (For the code, see the initialization timer function configuration code section 14th)
Figure 2: dead-time calculation
The timer 1 clock is mounted on the APB2 bus and the clock is 72 M. When TIM_ClockDivision = TIM_CKD_DIV1, Tdts = 1/72 M = 13.89ns
0-1.764us algorithm 1
1.778us-3.505us algorithm 2
3.556us-7.000us algorithm 3
7.1117us-14us algorithm 4
It takes a longer time. After TIM_ClockDivision is used, the dead zone time can be set.
Test data:
Experimental phenomenon: a complementary PWM signal with a dead-time of 1 US is generated. The signal frequency is 1 kHz, the duty cycle is constantly changing between 10% and 90%, and the channel 3 is faster than Channel 2.
Dead Zone Time (take Channel 2 as an example): (Yellow: PA10 Green: PB15)
Channel Two capture waveform (Yellow: PA10 Green: PB15)
Channel trigger waveform (Yellow: PA9 Green: PB14)
Channel 2 and Channel 3 (Yellow: PA9 Green: PA10)