Study notes-STM32 timer program application (1)

PWM complementary output with dead time and brake control code explanation

After 11 days, I am back

I wrote some basic concepts of the three timers of STM32. Today I will explain the related program applications.

We directly copy a serial port routine from Wildfire's firmware library routine: USART send and receive.

Since our example is about complementary output, we need two GPIOs; the dead time is configured by software, and the brake control also needs to use one GPIO. So we choose PA8 in the positive channel, PB13 in the complementary channel, and PB12 in the brake control.

First, create a new AdvanceTim folder under the User folder under the target file, and create two files bsp_AdvanceTim.c and bsp_AdvanceTim...h in its directory.

Then first add conditional compilation statements in the .h file:

#ifndef __BSP_ADVANCETIME_H
#define __BSP_ADVANCETIME_H

#include "stm32f10x.h"

#endif /* __BSP_ADVANCETIME_H */

When writing the main program, let's take a look at the principle:
let's first assume that the duty cycle is 50%, and CNT, CCR, and ARR need to be configured. When CNT counts up from 0, the initial effective level is set to high. , When CNT<CCR, CNT is always high. When CNT reaches CCR, the level will jump from high to low. When it reaches ARR, CNT is cleared and the level is reversed, and so on.

We configure GPIO to multiplex output mode in the .c file we just created:

static void ADVANCE_TIM_GPIO_Config(void) 
{
    
    
  GPIO_InitTypeDef GPIO_InitStructure;
  
  /*输出比较通道初始化*/
  RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1_GPIO_CLK, ENABLE);
  GPIO_InitStructure.GPIO_Pin =  ADVANCE_TIM_CH1_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(ADVANCE_TIM_CH1_PORT, &GPIO_InitStructure);

  /*输出比较通道互补通道GPIO初始化*/
  RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1N_GPIO_CLK, ENABLE);
  GPIO_InitStructure.GPIO_Pin =  ADVANCE_TIM_CH1N_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(ADVANCE_TIM_CH1N_PORT, &GPIO_InitStructure);

  /*输出比较刹车通道GPIO初始化*/
  RCC_APB2PeriphClockCmd(ADVANCE_TIM_BKIN_GPIO_CLK, ENABLE);
  GPIO_InitStructure.GPIO_Pin =  ADVANCE_TIM_BKIN_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(ADVANCE_TIM_BKIN_PORT, &GPIO_InitStructure);

  GPIO_ResetBits(ADVANCE_TIM_BKIN_PORT,ADVANCE_TIM_BKIN_PIN); //BKIN引脚默认先输出低电平
}

Then, since we are using the three pins of TIM1, we need to write the macro definition in the newly created .h file at the beginning:

//当使用不同的定时器的时候,对应的GPIO是不一样的,这里我们使用的是TIM1
#define            ADVANCE_TIM                   TIM1
#define            ADVANCE_TIM_APBxClock_FUN     RCC_APB2PeriphClockCmd
#define            ADVANCE_TIM_CLK               RCC_APB2Periph_TIM1

//PWM信号的频率 F=TIM_CLK/{(ARR+1)*(PSC+1)}
#define            ADVANCE_TIM_PERIOD            (8-1)
#define            ADVANCE_TIM_PSC               (9-1)
#define            ADVANCE_TIM_PULSE             4

#define            ADVANCE_TIM_IRQ               TIM1_UP_IRQn
#define            ADVANCE_TIM_IRQHandler        TIM1_UP_IRQHandler

//TIM1输出比较通道
#define            ADVANCE_TIM_CH1_GPIO_CLK      RCC_APB2Periph_GPIOA
#define            ADVANCE_TIM_CH1_PORT          GPIOA
#define            ADVANCE_TIM_CH1_PIN           GPIO_Pin_8

//TIM1输出比较通道的互补通道
#define            ADVANCE_TIM_CH1N_GPIO_CLK      RCC_APB2Periph_GPIOB
#define            ADVANCE_TIM_CH1N_PORT          GPIOB
#define            ADVANCE_TIM_CH1N_PIN           GPIO_Pin_13

//TIM1输出比较通道的刹车通道
#define            ADVANCE_TIM_BKIN_GPIO_CLK      RCC_APB2Periph_GPIOB
#define            ADVANCE_TIM_BKIN_PORT          GPIOB
#define            ADVANCE_TIM_BKIN_PIN           GPIO_Pin_12

Next, we initialize the structure we need to use in the .c function:

static void ADVANCE_TIM_Mode_Config(void)
{
    
    
  ADVANCE_TIM_APBxClock_FUN(ADVANCE_TIM_CLK,ENABLE);

  /*时基结构体初始化*/
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
 
 TIM_TimeBaseStructure.TIM_Period=ADVANCE_TIM_PERIOD; 
 //ARR的值,累计TIM_Period+1个频率后产生一个更新或中断
 TIM_TimeBaseStructure.TIM_Prescaler= ADVANCE_TIM_PSC; 
 //驱动CNT时钟
 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;  
 //时钟分频因子,配置死区时间要用
 TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;  
 //计数模式,向上计数
 TIM_TimeBaseStructure.TIM_RepetitionCounter=0; 
 //重复CNT的值,没用到可以不管
 TIM_TimeBaseInit(ADVANCE_TIM, &TIM_TimeBaseStructure);
 //初始化定时器

 /*输出比较结构体初始化*/
 TIM_OCInitTypeDef  TIM_OCInitStructure;
 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
 // 配置为PWM模式1
 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
 //输出使能
 TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
 //互补输出使能
 TIM_OCInitStructure.TIM_Pulse = ADVANCE_TIM_PULSE;
 //设置占空比大小
 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
 //输出通道电平极性配置
 TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
 //互补输出通道电平极性配置
 TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
 //输出通道空闲电平极性配置
 TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
 //互补输出通道空闲电平极性配置
 TIM_OC1Init(ADVANCE_TIM, &TIM_OCInitStructure);
 TIM_OC1PreloadConfig(ADVANCE_TIM, TIM_OCPreload_Enable);

 /*刹车和死区结构体初始化*/
 TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
 TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;
 TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
 TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;
 //有关刹车和死区结构体的承运啊具体可参考BDTR寄存器的描述
 
 TIM_BDTRInitStructure.TIM_DeadTime = 11;
 TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;
 //输出比较信号死区时间配置

 TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;
 TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
 TIM_BDTRConfig(ADVANCE_TIM, &TIM_BDTRInitStructure);
 //当BKIN引脚检测到高电平的时候,输出比较信号被禁止,就好像刹车一样

 TIM_Cmd(ADVANCE_TIM, ENABLE); 
 //使能计数器
 TIM_CtrlPWMOutputs(ADVANCE_TIM, ENABLE);
 //主输出使能,当我们使用的是通用定时器时,这句不需要
}

Then, after we initialize the structure, we also need to write an initialization function for the advanced timer:

void ADVANCE_TIM_Init(void)
{
    
    
 ADVANCE_TIM_GPIO_Config();
 ADVANCE_TIM_Mode_Config();  
}

Finally, we also need a main function:

#include "stm32f10x.h"
#include "bsp_usart.h"
#include "bsp_AdvanceTim.h"  
int main(void)
{
    
     
 USART_Config();
 ADVANCE_TIM_Init();
 while(1)
 {
    
          
 }
}

When testing programs on the development board, use an oscilloscope, one connected to PA8, one connected to PB12, one connected to PB13, and one connected to GND. When looking at the waveform, the waveform of PA8 is from 1 to 0, and the waveform of PB13 should be from 0 to 1, but there is no immediate change. This is to make the MOS tube completely turned on. When the complementary channel changes from 1 to 0, PA8 does not immediately Turning on is also to completely turn off the MOS tube driven by PB13.

At the end of the last, I leave a small question: when we were learning C language in our freshman year and sophomore year, when we defined any structure, we defined all structures after the first curly brace, and I just initialized the structure When, it is defined after the statement. Why? I will announce the answer in the next issue. Children who have ideas can leave a message to reply. Here we wish everyone a happy National Day in advance.

Guess you like

Origin blog.csdn.net/weixin_41679822/article/details/101084155