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

Explicação do código de captura de entrada PWM
Olá a todos, finalmente apareci, porque tenho que me preparar para a revisão do exame de admissão de pós-graduação, e aprendi a câmera depois de 32 anos de estudo, tenho pego por alguns dias.

Bem, não há muito a dizer, vamos direto ao assunto.

Este experimento é realmente usado para medir sinais PWM. O mesmo temporizador não pode usar captura de entrada e comparação de saída ao mesmo tempo, portanto, neste experimento usamos temporizadores de uso geral para gerar sinais e temporizadores avançados para capturar sinais.

Como no experimento anterior, adicione os arquivos bsp_AdvanceTim.c e bsp_AdvanceTim.h na pasta Usuário no exemplo. Observe aqui que você deve colocar as pastas de avanço e geral. Isso ocorre porque quando diferentes temporizadores são usados, os GPIOs correspondentes são diferentes.

Primeiro inicializamos o PIO:

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_IN_FLOATING;  
  GPIO_Init(ADVANCE_TIM_CH1_PORT, &GPIO_InitStructure);
}

Observe aqui que GPIO deve ser definido como IN_FLOATING entrada flutuante para capturar ondas quadradas.

Em seguida, transplante o arquivo .h na rotina:

#ifndef __BSP_ADVANCETIME_H
#define __BSP_ADVANCETIME_H

#include "stm32f10x.h"

#define            ADVANCE_TIM                   TIM1
#define            ADVANCE_TIM_APBxClock_FUN     RCC_APB2PeriphClockCmd
#define            ADVANCE_TIM_CLK               RCC_APB2Periph_TIM1

//输入捕获能捕获到的最小频率为72M/{(ARR+1)*(PSC+1)}
#define            ADVANCE_TIM_PERIOD            (1000-1)
#define            ADVANCE_TIM_PSC               (72-1)

//中断相关宏定义
#define            ADVANCE_TIM_IRQ               TIM1_CC_IRQn
#define            ADVANCE_TIM_IRQHandler        TIM1_CC_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

#define            ADVANCE_TIM_IC1PWM_CHANNEL    TIM_Channel_1

void ADVANCE_TIM_Init(void);

#endif

Depois de configurar o GPIO no arquivo .c, precisamos inicializá-lo:

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_IN_FLOATING;  
  GPIO_Init(ADVANCE_TIM_CH1_PORT, &GPIO_InitStructure); 
}

Aqui está um ponto importante para prestar atenção especial: quando estamos configurando, os valores de Period e PSC não podem ser configurados à vontade. Assumimos que a onda quadrada gerada é 100K e o período é 1/100 = 10us. Se o período de contagem for <10us, o período não pode ser capturado, e se for <1khz ou> 10ki, então não pode ser capturado. A frequência de acionamento de um motor comum está entre 10K e 25K.

Observe que precisamos definir a prioridade de interrupção e inicializar a estrutura de captura de entrada:

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; 
 //自动重装载寄存器的值,累计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; 
  //重复计数器的值
  TIM_TimeBaseInit(ADVANCE_TIM, &TIM_TimeBaseStructure);
  //初始化定时器

  TIM_ICInitTypeDef  TIM_ICInitStructure;

  TIM_ICInitStructure.TIM_Channel = ADVANCE_TIM_IC1PWM_CHANNEL;
  //捕获通道IC1配置
  //选择捕获通道
  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
  //设置捕获的边沿
  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
  //设置捕获通道的信号来自于哪个输入通道,由直连和非直连两种
  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
  //1分频,即捕获信号的每个有效边沿都捕获
  TIM_ICInitStructure.TIM_ICFilter = 0x0;
  //不滤波
  TIM_PWMIConfig(ADVANCE_TIM, &TIM_ICInitStructure);
  //初始化PWM输入模式
  

  TIM_SelectInputTrigger(ADVANCE_TIM, TIM_TS_TI1FP1); 
  //选择输入捕获的触发信号
  TIM_SelectSlaveMode(ADVANCE_TIM, TIM_SlaveMode_Reset);
  TIM_SelectMasterSlaveMode(ADVANCE_TIM,TIM_MasterSlaveMode_Enable);
  //选择从模式:复位模式
  //PWM输入模式时,从模式必须工作在复位模式,当捕获开始时,计数器CNT会被复位
  TIM_ITConfig(ADVANCE_TIM, TIM_IT_CC1, ENABLE);
  //使能捕获中断,这个中断针对的是主捕获通道
  TIM_ClearITPendingBit(ADVANCE_TIM, TIM_IT_CC1);
  //清除中断标志位
  TIM_Cmd(ADVANCE_TIM, ENABLE);
  //使能高级控制定时器,计数器开始计数

A prioridade de interrupção é:

static void ADVANCE_TIM_NVIC_Config(void)
{
    
    
 NVIC_InitTypeDef NVIC_InitStructure;
 
 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
 //设置中断组为0
 NVIC_InitStructure.NVIC_IRQChannel = ADVANCE_TIM_IRQ; 
 //设置中断来源
 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
 //设置抢占优先级
 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
 //设置子优先级
 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
 NVIC_Init(&NVIC_InitStructure); 
}

Por fim, colocamos as três funções escritas em .h na função de inicialização do temporizador:

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

Precisamos escrever uma função de serviço de interrupção nele. C:

void ADVANCE_TIM_IRQHandler(void)
{
    
    
  TIM_ClearITPendingBit(ADVANCE_TIM, TIM_IT_CC1);
  //清除中断标志位
  IC1Value = TIM_GetCapture1(ADVANCE_TIM);
  IC2Value = TIM_GetCapture2(ADVANCE_TIM);
  //获取输入捕获值
  if (IC1Value != 0)
  //注意:捕获寄存器CCR1和CCR2的值在计算占空比和频率的时候必须+1
  {
    
    
    DutyCycle = (float)((IC2Value+1) * 100) / (IC1Value+1);
    //占空比计算
    Frequency = (72000000/(ADVANCE_TIM_PSC+1))/(float)(IC1Value+1);
    //频率计算
    printf("Õ¼¿Õ±È£º%0.2f%%   ƵÂÊ£º%0.2fHz\n",DutyCycle,Frequency);
  }
  else
  {
    
    
    DutyCycle = 0;
    Frequency = 0;
  }
}
``如果是第一个上升沿中断,计数器会被复位,锁存到CCR1的值为0,CCR2的值也是0.无法计算频率与占空比; 当第二次上升沿到来的时候,CCR1和CCR2捕获到的值为有效的值,其中CCR1对应的是周期,CCR2对应的是占空比。

好的,到这里程序基本上就编写完成了,但是如果现在别写程序的时候就会出现:DutyCycle、Frequency未定义的情况出现,因此我们还需要加最后一步。就是在中断服务函数掐面加上定义:

```c
__IO uint16_t IC2Value = 0;
__IO uint16_t IC1Value = 0;
__IO float DutyCycle = 0;
__IO float Frequency = 0;

Finalmente, podemos classificar main.c:

#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_GeneralTim.h"  
#include "bsp_AdvanceTim.h" 
#include "bsp_usart.h"

int main(void)
{
    
     
  USART_Config();
  GENERAL_TIM_Init();
  ADVANCE_TIM_Init();

  while(1)
  {
    
    
  }
}

Ok, então todos os temporizadores relacionados terminaram, a próxima atualização é o capítulo da câmera. Se você ainda não entendeu o cronômetro, pode deixar um comentário abaixo ou inserir o URL para ver o vídeo completo: https://www.bilibili.com/video/av28951854?from=search&seid=13956434192947447162

Acho que você gosta

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