Study notes-STM32 timer program application (two)

PWM input capture code explanation
Hello everyone, I finally appeared, because I have to prepare for the review of the postgraduate entrance examination, and I have learned the camera after 32 years of study, I have been pigeoning for a few days.

Well, not much to say, let's go directly to the topic.

This experiment is actually used to measure PWM signals. The same timer cannot use input capture and output comparison at the same time, so in this experiment we use general-purpose timers to generate signals, and advanced timers to capture signals.

As in the previous experiment, add bsp_AdvanceTim.c and bsp_AdvanceTim.h files under the User folder in the example. Note here that you must put the advance and general folders. This is because when different timers are used, the corresponding GPIOs are different.

We first initialize 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);
}

Note here that GPIO should be set to IN_FLOATING floating input to capture square waves.

Then transplant the .h file in the routine:

#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

After configuring GPIO in the .c file, we need to initialize it:

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); 
}

Here is an important point to pay special attention to: when we are configuring, the values ​​of Period and PSC cannot be configured at will. We assume that the generated square wave is 100K, and the period is 1/100=10us. If the counting period is <10us, then the period cannot be captured, and if it is <1khz, or >10ki, then it cannot be captured. The driving frequency of a common motor is between 10K and 25K.

Note that we need to set the interrupt priority and initialize the input capture structure:

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);
  //使能高级控制定时器,计数器开始计数

The interrupt priority is:

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); 
}

Finally, we put the three functions written in .h into the timer initialization function:

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

We need to write an interrupt service function in it.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;

Finally, we can sort out 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)
  {
    
    
  }
}

Okay, so all the related timers are finished, the next update is the chapter of the camera. If you still don’t understand the timer, you can leave a comment below or enter the URL to view the full video: https://www.bilibili.com/video/av28951854?from=search&seid=13956434192947447162

Guess you like

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