"Embedded Blue Bridge Cup" timer TIM3 PWM output and TIM2 input capture measurement frequency record

Author's Blog Home Page
Author: Eterlove
, one stroke at a time, recording my study life! Standing on Shoulders of Giants!
This article is original, please indicate the source and author for reprinting

Disclaimer: This time is busy, and I will take time to make up for the analysis and explanation of relevant knowledge points.

1. Learning records

    Use the timer TIM3 to generate a PWM waveform [adjustable frequency, adjustable duty cycle -> relatively adjustable], and then use the input capture function of TIM2 to measure the frequency of the waveform .

PA1---->TIM2_CH2
PA2---->TIM2_CH3
PA6---->TIM3_CH1
PA7---->TIM3_CH2

2. Generate PWM waveform TIM3_CH1_PA6

/*  PA6----TIM3_CH1
    PA7----TIM3_CH2  */
#include "stm32f10x.h"
#include "TIM3.h"

// The TIM3 is running at 1 KHz: TIM3 Frequency = TIM3 counter clock/(ARR + 1)
//                        1 KHz                 = 1MHZ  /1000                                        

//ARR = (TIM3 counter clock /Frequency)-1

//PWM 信号频率可调,占空比可调  PA6	
void TIM3_PWM_Output(float Duty , uint32_t Frequency)
{
    
    
	
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  TIM_OCInitTypeDef  TIM_OCInitStructure;
  NVIC_InitTypeDef  NVIC_InitStructure;
  GPIO_InitTypeDef  GPIO_InitStructure;

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

  /* GPIOA  clock enable */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO ,ENABLE);

  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 ;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
	
	 /* Time base configuration */ 
  TIM_TimeBaseStructure.TIM_Period = (1000000/Frequency)-1;  //ARR = (TIM3 counter clock /Frequency)-1
  TIM_TimeBaseStructure.TIM_Prescaler = 71;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
	
	
  /* PWM1 Mode configuration: Channel1 */
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = ((1000000/Frequency)-1)*Duty;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

  TIM_OC1Init(TIM3, &TIM_OCInitStructure);

  TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
	
	
  TIM_ARRPreloadConfig(TIM3, ENABLE);

  /* TIM3 enable counter */
  TIM_Cmd(TIM3, ENABLE);
	
}

Why is the frequency and duty cycle relatively adjustable?
TIM_TimeBaseStructure.TIM_Prescaler = 71;
here I fixed the count clock frequency 72MHZ/72 =1MHZ
TIM_TimeBaseStructure.TIM_Period = (1000000/Frequency)-1; //ARR = (TIM3 counter clock /Frequency)-1
Frequency if the variable value is very high "Wonderful", then TIM_Period can only be divided by the whole, which will cause a little error. The same goes for the duty cycle. So I wrote this just to facilitate the direct input parameter call in the main function, the specific problem is analyzed in detail, please reconfigure some values ​​that are not easy to handle, and "round up"
TIM_OCInitStructure.TIM_Pulse = ((1000000/Frequency)-1 )*Duty;

3. The input capture measurement frequency of TIM2 TIM2_CH2_PA1

//Input_Capture.C文件
#include "Input_Capture.h"
//PA1---->TIM2_CH2
//PA2---->TIM2_CH3

__IO uint16_t IC2ReadValue1 = 0, IC2ReadValue2 = 0;
__IO uint16_t CaptureNumber = 0;
__IO uint32_t Capture = 0;
__IO uint32_t TIM2Freq = 0;

void Input_Capture_Init()
{
    
    
	GPIO_InitTypeDef GPIO_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  TIM_ICInitTypeDef  TIM_ICInitStructure;
	
	//留下一个问题,这里为什么不使能AFIO??
	/* 参考手册P121   对寄存器AFIO_EVCR,AFIO_MAPR和AFIO_EXTICRX进行读写操作前,应当首先打开AFIO
   的时钟。参考第6.3.7节APB2外设时钟使能寄存器(RCC_APB2ENR)。 */
	
	 /* TIM2 clock enable */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

  /* GPIOA and GPIOB clock enable */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

	
	
	 /* TIM2 channel 2,3 pin (PA.01,PA.02) configuration */
  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_1 | GPIO_Pin_2;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	 /* Enable the TIM2 global Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
	
		 /* Time base configuration */
  TIM_TimeBaseStructure.TIM_Period = 65535 ;
  TIM_TimeBaseStructure.TIM_Prescaler = 71;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
	
	//输入捕获配置  TIM2_CH2
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; 
  TIM_ICInitStructure.TIM_ICFilter = 0x0;   //滤波器
  TIM_ICInit(TIM2, &TIM_ICInitStructure);                                                                                                        
	//输入捕获配置  TIM2_CH3
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_3;
	TIM_ICInit(TIM2, &TIM_ICInitStructure);
	
	  /* TIM enable counter */
  TIM_Cmd(TIM2, ENABLE);
  /* Enable the CC2 Interrupt Request */
  TIM_ITConfig(TIM2, TIM_IT_CC2|TIM_IT_CC3, ENABLE);
	
}


void TIM2_IRQHandler(void)
{
    
     
  if(TIM_GetITStatus(TIM2, TIM_IT_CC2) == SET) 
  {
    
    
    /* Clear TIM2 Capture compare interrupt pending bit */
    TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);
    if(CaptureNumber == 0)
    {
    
    
      /* Get the Input Capture value */
      IC2ReadValue1 = TIM_GetCapture2(TIM2);
      CaptureNumber = 1;
    }
		
		
    else if(CaptureNumber == 1)
    {
    
    
      /* Get the Input Capture value */
      IC2ReadValue2 = TIM_GetCapture2(TIM2); 
      
      /* Capture computation */
      if (IC2ReadValue2 > IC2ReadValue1)
      {
    
    
        Capture = (IC2ReadValue2 - IC2ReadValue1); 
      }
      else
      {
    
    
        Capture = ((0xFFFF - IC2ReadValue1) + IC2ReadValue2); 
      }
      /* Frequency computation */ 
        //TIM2Freq = (uint32_t) SystemCoreClock/72/ Capture;
			  TIM2Freq = (uint32_t)1000000 / Capture;
      CaptureNumber = 0;
    }
  }
}

Input_Capture.C file, why do you want to divide TIM2 /72 to get a count frequency of 1MHZ?

Because our CCRx register is a 16-bit register, the count range is 0 to 0xFFFF, that is, 0~65535, but when the measured rectangular wave period is too long, the pulse width is too wide, and our counting is too fast, CCRx overflow is prone to occur. Therefore, when we measure low-frequency signals, we must divide the clock of the TIM , so that our counting will not be so fast and overflow will not occur.

		 /* Time base configuration */
  TIM_TimeBaseStructure.TIM_Period = 65535 ;
  TIM_TimeBaseStructure.TIM_Prescaler = 71;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

4. Experimental phenomenon

#include "stm32f10x.h"
#include "lcd.h"
#include "stdio.h"
#include "Key.h"
#include "TIM3.h"
#include "LED.h"
#include "string.h"
#include "Input_Capture.h"
	
u32 TimingDelay = 0;
void Delay_Ms(u32 nTime);

u8 TIM2FreqBuffer[20] = {
    
    0};
extern __IO uint32_t TIM2Freq;

//Main Body

int main(void)
{
    
    
	SysTick_Config(SystemCoreClock/1000);
	Delay_Ms(200);
	STM3210B_LCD_Init();
	LCD_Clear(Black);
	LCD_SetBackColor(Black);  
	LCD_SetTextColor(White);
	Led_Init();    //LED初始化
	Led_Control(LED_ALL , OFF); //LED全关
    Key_Init();  //按键初始化
    TIM3_PWM_Output(0.40 , 1000); //PWM 信号频率可调 ,占空比可调  PA6	
	Input_Capture_Init();  //定时器TIM2 捕获初始化
	
	while(1)
	{
    
    
	   //测得频率显示在LCD
		sprintf(TIM2FreqBuffer , "TIM2Freq:%d HZ"  ,TIM2Freq);
		LCD_DisplayStringLine(Line5 ,  TIM2FreqBuffer );	
	}
} 

//毫秒延时函数
void Delay_Ms(u32 nTime)
{
    
    
	TimingDelay = nTime;
	while(TimingDelay != 0);	
}

(1) For example, the output is duty: 40%, 1KHZ PWM waveform

    TIM3_PWM_Output(0.40 , 1000); //PWM 信号频率可调 ,占空比可调  PA6	

Verify with an oscilloscope and measure the frequency of the PWM output from the PA6 pin to prevent accidents
insert image description here
insert image description here

    Input_Capture_Init();  //定时器TIM2 捕获初始化

Connect PA6 and PA1
insert image description here

Increase the PWM waveform frequency to 55KHZ

  TIM3_PWM_Output(0.40 , 55000); //PWM 信号频率可调 ,占空比可调  PA6	
  Input_Capture_Init();  //定时器TIM2 捕获初始化

insert image description here
Thanks everyone for reading!

Guess you like

Origin blog.csdn.net/Eterlove/article/details/123957933