Notas de estudo - aplicação do programa temporizador STM32 (1)

Saída complementar PWM com tempo morto e explicação do código de controle de freio

Depois de 11 dias, estou de volta

Eu escrevi alguns conceitos básicos dos três temporizadores do STM32. Hoje irei explicar os aplicativos do programa relacionados.

Copiamos diretamente uma rotina de porta serial da rotina de biblioteca de firmware do Wildfire: envio e recebimento USART.

Como nosso exemplo é sobre saída complementar, dois GPIOs são necessários; o tempo morto é configurado pelo software e o controle de freio também precisa usar um GPIO. Portanto, escolhemos PA8 no canal positivo, PB13 no canal complementar e PB12 no controle de freio.

Primeiro, crie uma nova pasta AdvanceTim na pasta Usuário no arquivo de destino e crie dois arquivos bsp_AdvanceTim.c e bsp_AdvanceTim ... h em seu diretório.

Em seguida, primeiro adicione instruções de compilação condicional no arquivo .h:

#ifndef __BSP_ADVANCETIME_H
#define __BSP_ADVANCETIME_H

#include "stm32f10x.h"

#endif /* __BSP_ADVANCETIME_H */

Ao escrever o programa principal, vamos dar uma olhada no princípio:
vamos primeiro assumir que o ciclo de trabalho é de 50% e CNT, CCR e ARR precisam ser configurados. Quando o CNT conta a partir de 0, o nível efetivo inicial é definido como alto. , Quando CNT <CCR, CNT está sempre alto. Quando CNT atinge CCR, o nível vai de alto para baixo. Quando atinge ARR, CNT é limpo e o nível é revertido, e assim por diante.

Configuramos o GPIO para o modo de saída multiplex no arquivo .c que acabamos de criar:

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

Então, como estamos usando os três pinos do TIM1, precisamos escrever a definição da macro no arquivo .h recém-criado no início:

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

Em seguida, inicializamos a estrutura que precisamos usar na função .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);
 //主输出使能,当我们使用的是通用定时器时,这句不需要
}

Então, depois de inicializarmos a estrutura, também precisamos escrever uma função de inicialização para o temporizador avançado:

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

Finalmente, também precisamos de uma função principal:

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

Ao testar programas na placa de desenvolvimento, use um osciloscópio, um conectado ao PA8, um conectado ao PB12, um conectado ao PB13 e um conectado ao GND. Ao olhar para a forma de onda, a forma de onda de PA8 é de 1 a 0, e a forma de onda de PB13 deve ser de 0 a 1, mas não há alteração imediata. Isso fará com que o tubo MOS esteja completamente ligado. Quando o canal complementar muda de 1 para 0, PA8 não Ligar também desliga completamente o tubo MOS acionado por PB13.

No final do último, deixo uma pequena pergunta: quando estávamos aprendendo a linguagem C em nosso primeiro e segundo ano, quando definimos qualquer estrutura, definimos todas as estruturas após a primeira chave e eu apenas inicializei a estrutura Quando, é definido após a declaração. Por quê? Anunciarei a resposta na próxima edição. As crianças que tiverem ideias podem deixar uma mensagem para responder. Aqui, desejamos a todos um feliz Dia Nacional com antecedência.

Acho que você gosta

Origin blog.csdn.net/weixin_41679822/article/details/101084155
Recomendado
Clasificación