学习笔记——STM32定时器程序应用(一)

PWM互补输出带死区时间和刹车控制代码讲解

时隔11天,我又回来了

之间写了STM32的三种定时器的一些基本概念,今天我来讲解一下相关的程序应用。

我们直接从野火的固件库例程中拷贝一个串口的例程:USART接发。

由于我们这个例程是关于互补输出,因此需要两个GPIO;死区时间用软件配置,而刹车控制也需要使用一个GPIO。所以我们在正通道中选择PA8,在互补通道中选择PB13,刹车控制选用PB12。

首先,在目标文件下的User文件夹下新建AdvanceTim文件夹,在其目录下创建bsp_AdvanceTim.c和bsp_AdvanceTim…h两个文件。

然后先在.h文件中添加条件编译语句:

#ifndef __BSP_ADVANCETIME_H
#define __BSP_ADVANCETIME_H

#include "stm32f10x.h"

#endif /* __BSP_ADVANCETIME_H */

在编写主体程序时,我们先来看看其原理:
我们先假设占空比为50%,需要配置CNT,CCR,ARR,当CNT从0向上计数时,初始设的有效电平为高电平,当CNT<CCR,则CNT一直为高电平,当CNT到达CCR时,电平就会发生跳变,从高变低,当到达ARR时,CNT清零,电平翻转,如此反复。

我们在刚刚创建的.c文件中配置GPIO为复用输出模式:

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引脚默认先输出低电平
}

然后,由于我们使用的是TIM1的三个引脚,因此我们需要在一开始新建的.h文件中写宏定义:

//当使用不同的定时器的时候,对应的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

紧接着,我们在.c函数中初始化我们需要用到的结构体:

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);
 //主输出使能,当我们使用的是通用定时器时,这句不需要
}

然后,在我们初始化完结构体之后,我们还需要对高级定时器写一个初始化函数:

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

最后,我们还需要一个主函数:

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

在开发板上测试程序的时候,使用示波器,一个连PA8,一个连PB12,一个连PB13,一个连GND。在观看波形是,PA8的波形从1到0,而PB13的波形应从0到1,但是没有立即变化,这是为了让MOS管完全导通,当互补通道从1变0时,PA8并没有立即开启,同样也是为了让PB13驱动的MOS管完全关闭。

在最后的最后,我留一个小问题:我们在大一大二学习C语言的时候,我们在定义任意结构体时,都是在第一个大括号之后全部定义,而我在刚刚初始化结构体的时候,则是在语句之后进行定义的,这是为什么呢?下期开始我会公布答案,有想法的童鞋们可以留言回复,在这里咱就提前祝大家国庆快乐。

猜你喜欢

转载自blog.csdn.net/weixin_41679822/article/details/101084155