STM32-单个定时器捕获多个通道方波的频率和占空比的实现

STM32-单个定时器捕获多个通道方波的频率和占空比的实现

关于如何捕获方波的频率和占空比在我之前写的博客中已经做出了详细的梳理,不清楚的可以看一看https://blog.csdn.net/qq_43715171/article/details/113372999,强烈建议先将这篇博客看一看,本次的实验都是建立在上一篇的基础上。

现在的问题主要是如何使用单个定时器捕获多个通道的方波?
看了网上的一些例子是通过分时来实现的,即一段时间是通道1捕获,下一段时间是通道2进行捕获,其实这样是不必要的,定时器的各个通道实际上是可以同时进行捕获,基本不会造成干扰。只是我们在写程序的时候,应该注意一些细节的问题。

实际上,单个通道的输入捕获的姿势正确了的话,多个通道其实直接加就完事了,前面提到的上一篇博客中的输入捕获的姿势实际上还不太准确,下面会来一个比较准确的例子,不过开始之前,先说说为什么之前的例子不太准确。

我们知道,捕获得到的时间就是通过计数值CNT换算而来的,而在之前的程序中为了方便,在每一次捕获的第一个上升沿的时候,通过TIM_SetCounter(TIM3, 0);将当前的计数清零了,这样的好处当然是计算更加方便,这个只有捕获单个通道的时候比较使用,假设我们要同时捕获两个通道的话,那么在其中任何一个通道中,将计数清除了,影响的是整个定时器,进而影响了这个定时器下的所有的通道。那么要想各个通道之间不用互相干扰的话,我们就不能改变计数的值。

这里就介绍另一种实现的方法,这种实现方法不会改变计数值。

定时器捕获单个通道

这个例子与上一篇博客中的区别是这里使用的是TIM_GetCapture2(TIM2)来得到当前的计数值,需要特别注意的是,我们必须开启定时器的溢出中断TIM_IT_Update。

  1. 在第一次捕获到上升沿的时候,记录下当前的计数值TIM2_IC2_ReadValue1,然后将触发变为下降沿触发。
  2. 紧接着捕获到了下降沿的时候,此刻的时间和上一次的时间之差应该为TIM2_IC2_ReadValue2 = TIM2_IC2_OverCnt * 65535 + TIM_GetCapture2(TIM2) - TIM2_IC2_ReadValue1(TIM2_IC2_OverCnt 就是溢出的次数,TIM2_IC2_ReadValue1是在第一次捕获到上升沿的时刻的计数值)。这一段时间就是一个周期中高电平所占的时间。然后将触发的方式又更换为上降沿。
  3. 此时,第二次捕获到上升沿,就是已经是一个完整的周期了,然后我们就可以得到一个周期的时间是TIM2_IC2_ReadValue1 = TIM2_IC2_OverCnt * 65535 + TIM_GetCapture2(TIM2) - TIM2_IC2_ReadValue1;
    到此,一个周期中高电平所占的时间和一个周期的所有时间都知道了,那么方波的频率和占空比也就出来了。
    并且可以注意到,在这个程序中,我们没有对计数值进行改变,那么每个通道直接读取当前捕获到的计数值即可,所以就不会产生通道之间的相互干扰的问题了。

uint32_t TIM2_IC2_ReadValue1 = 0, TIM2_IC2_ReadValue2 = 0;
uint32_t TIM2_IC2_CaptureNumber = 0;
uint32_t TIM2_IC2_Freq = 0;
float 	 TIM2_IC2_Duty = 0;
uint32_t TIM2_IC2_OverCnt = 0;

/**
  * @brief  Configures the different system clocks.
  * @param  None
  * @retval None
  */
void Tim2_Input_Capture_RCC_Configuration(void)
{
    
    
  /* TIM2 clock enable */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

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

/**
  * @brief  Configure the GPIOD Pins.
  * @param  None
  * @retval None
  */
void Tim2_Input_Capture_GPIO_Configuration(void)
{
    
    
  GPIO_InitTypeDef GPIO_InitStructure;

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

/**
  * @brief  Configure the nested vectored interrupt controller.
  * @param  None
  * @retval None
  */
void Tim2_Input_Capture_NVIC_Configuration(void)
{
    
    
  NVIC_InitTypeDef NVIC_InitStructure;

  /* Enable the TIM2 global Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

void Tim2_Input_Capture_Init(void)
{
    
    
	TIM_ICInitTypeDef  TIM_ICInitStructure;
	/* System Clocks Configuration */
  Tim2_Input_Capture_RCC_Configuration();

  /* NVIC configuration */
  Tim2_Input_Capture_NVIC_Configuration();

  /* Configure the GPIO ports */
  Tim2_Input_Capture_GPIO_Configuration();

  /* TIM2 configuration: Input Capture mode ---------------------
     The external signal is connected to TIM2 CH2 pin (PA.01)  
     The Rising edge is used as active edge,
     The TIM2 CCR2 is used to compute the frequency value 
  ------------------------------------------------------------ */

  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);
  
  /* TIM enable counter */
  TIM_Cmd(TIM2, ENABLE);

  /* Enable the CC2 Interrupt Request */
  TIM_ITConfig(TIM2, TIM_IT_CC3 | TIM_IT_Update, ENABLE);
}

/**
  * @brief  This function handles TIM2 global interrupt request.
  * @param  None
  * @retval None
  */
void TIM2_IRQHandler(void)
{
    
     
	if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
    
    
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
		TIM2_IC2_OverCnt++;
	}
	
  if(TIM_GetITStatus(TIM2, TIM_IT_CC2) == SET) 
  {
    
    
    /* Clear TIM2 Capture compare interrupt pending bit */
    TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);
    if(TIM2_IC2_CaptureNumber == 0)
    {
    
    
      /* Get the Input Capture value */
      TIM2_IC2_ReadValue1 = TIM_GetCapture2(TIM2);
			TIM_OC2PolarityConfig(TIM2,TIM_ICPolarity_Falling);
      TIM2_IC2_CaptureNumber = 1;
			TIM2_IC2_OverCnt = 0;
    }
    else if(TIM2_IC2_CaptureNumber == 1)
    {
    
    
      /* Get the Input Capture value */
      TIM2_IC2_ReadValue2 = TIM2_IC2_OverCnt * 65535 + TIM_GetCapture2(TIM2) - TIM2_IC2_ReadValue1; 
      TIM_OC2PolarityConfig(TIM2,TIM_ICPolarity_Rising);
			TIM2_IC2_CaptureNumber = 2;
    }
		else if(TIM2_IC2_CaptureNumber == 2)
		{
    
    
			/* Get the Input Capture value */
      TIM2_IC2_ReadValue1 = TIM2_IC2_OverCnt * 65535 + TIM_GetCapture2(TIM2) - TIM2_IC2_ReadValue1; 
      TIM_OC2PolarityConfig(TIM2,TIM_ICPolarity_Rising);
			TIM2_IC2_Freq = (uint32_t) (SystemCoreClock * 1.0 / TIM2_IC2_ReadValue1 + 0.5);
			TIM2_IC2_Duty = (float)TIM2_IC2_ReadValue2 * 1.0 / TIM2_IC2_ReadValue1;
			TIM2_IC2_CaptureNumber = 0;
		}
  }
}

定时器捕获多个通道

有了上面的例子,捕获多个通道那就简直太简单了,直接把其他通道的初始化加进去就行了,就很easy,因为上面的例子已经消除了前面提到的通道间计数值的干扰的问题。


uint32_t TIM2_IC2_ReadValue1 = 0, TIM2_IC2_ReadValue2 = 0;
uint32_t TIM2_IC2_CaptureNumber = 0;
uint32_t TIM2_IC2_Freq = 0;
float 	 TIM2_IC2_Duty = 0;
uint32_t TIM2_IC2_OverCnt = 0;

uint32_t TIM2_IC3_ReadValue1 = 0, TIM2_IC3_ReadValue2 = 0;
uint32_t TIM2_IC3_CaptureNumber = 0;
uint32_t TIM2_IC3_Freq = 0;
float 	 TIM2_IC3_Duty = 0;
uint32_t TIM2_IC3_OverCnt = 0;

/**
  * @brief  Configures the different system clocks.
  * @param  None
  * @retval None
  */
void Tim2_Input_Capture_RCC_Configuration(void)
{
    
    
  /* TIM2 clock enable */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

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

/**
  * @brief  Configure the GPIOD Pins.
  * @param  None
  * @retval None
  */
void Tim2_Input_Capture_GPIO_Configuration(void)
{
    
    
  GPIO_InitTypeDef GPIO_InitStructure;

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

/**
  * @brief  Configure the nested vectored interrupt controller.
  * @param  None
  * @retval None
  */
void Tim2_Input_Capture_NVIC_Configuration(void)
{
    
    
  NVIC_InitTypeDef NVIC_InitStructure;

  /* Enable the TIM2 global Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

void Tim2_Input_Capture_Init(void)
{
    
    
	TIM_ICInitTypeDef  TIM_ICInitStructure;
	/* System Clocks Configuration */
  Tim2_Input_Capture_RCC_Configuration();

  /* NVIC configuration */
  Tim2_Input_Capture_NVIC_Configuration();

  /* Configure the GPIO ports */
  Tim2_Input_Capture_GPIO_Configuration();

  /* TIM2 configuration: Input Capture mode ---------------------
     The external signal is connected to TIM2 CH2 pin (PA.07)  
     The Rising edge is used as active edge,
     The TIM2 CCR2 is used to compute the frequency value 
  ------------------------------------------------------------ */

  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);
	
	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 | TIM_IT_Update, ENABLE);
}

/**
  * @brief  This function handles TIM2 global interrupt request.
  * @param  None
  * @retval None
  */
void TIM2_IRQHandler(void)
{
    
     
	if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
    
    
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
		TIM2_IC2_OverCnt++;
		TIM2_IC3_OverCnt++;
	}
	
  if(TIM_GetITStatus(TIM2, TIM_IT_CC2) == SET) 
  {
    
    
    /* Clear TIM2 Capture compare interrupt pending bit */
    TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);
    if(TIM2_IC2_CaptureNumber == 0)
    {
    
    
      /* Get the Input Capture value */
      TIM2_IC2_ReadValue1 = TIM_GetCapture2(TIM2);
			TIM_OC2PolarityConfig(TIM2,TIM_ICPolarity_Falling);
      TIM2_IC2_CaptureNumber = 1;
			TIM2_IC2_OverCnt = 0;
    }
    else if(TIM2_IC2_CaptureNumber == 1)
    {
    
    
      /* Get the Input Capture value */
      TIM2_IC2_ReadValue2 = TIM2_IC2_OverCnt * 65535 + TIM_GetCapture2(TIM2) - TIM2_IC2_ReadValue1; 
      TIM_OC2PolarityConfig(TIM2,TIM_ICPolarity_Rising);
			TIM2_IC2_CaptureNumber = 2;
    }
		else if(TIM2_IC2_CaptureNumber == 2)
		{
    
    
			/* Get the Input Capture value */
      TIM2_IC2_ReadValue1 = TIM2_IC2_OverCnt * 65535 + TIM_GetCapture2(TIM2) - TIM2_IC2_ReadValue1; 
      TIM_OC2PolarityConfig(TIM2,TIM_ICPolarity_Rising);
			TIM2_IC2_Freq = (uint32_t) (SystemCoreClock * 1.0 / TIM2_IC2_ReadValue1 + 0.5);
			TIM2_IC2_Duty = (float)TIM2_IC2_ReadValue2 * 1.0 / TIM2_IC2_ReadValue1;
			TIM2_IC2_CaptureNumber = 0;
		}
  }
	else if(TIM_GetITStatus(TIM2, TIM_IT_CC3) == SET) 
  {
    
    
    /* Clear TIM2 Capture compare interrupt pending bit */
    TIM_ClearITPendingBit(TIM2, TIM_IT_CC3);
    if(TIM2_IC3_CaptureNumber == 0)
    {
    
    
      /* Get the Input Capture value */
      TIM2_IC3_ReadValue1 = TIM_GetCapture3(TIM2);
			TIM_OC3PolarityConfig(TIM2,TIM_ICPolarity_Falling);
      TIM2_IC3_CaptureNumber = 1;
			TIM2_IC3_OverCnt = 0;
    }
    else if(TIM2_IC3_CaptureNumber == 1)
    {
    
    
      /* Get the Input Capture value */
      TIM2_IC3_ReadValue2 = TIM2_IC3_OverCnt * 65535 + TIM_GetCapture3(TIM2) - TIM2_IC3_ReadValue1; 
      TIM_OC3PolarityConfig(TIM2,TIM_ICPolarity_Rising);
			TIM2_IC3_CaptureNumber = 2;
    }
		else if(TIM2_IC3_CaptureNumber == 2)
		{
    
    
			/* Get the Input Capture value */
      TIM2_IC3_ReadValue1 = TIM2_IC3_OverCnt * 65535 + TIM_GetCapture3(TIM2) - TIM2_IC3_ReadValue1; 
      TIM_OC3PolarityConfig(TIM2,TIM_ICPolarity_Rising);
			TIM2_IC3_Freq = (uint32_t) (SystemCoreClock * 1.0 / TIM2_IC3_ReadValue1 + 0.5);
			TIM2_IC3_Duty = (float)TIM2_IC3_ReadValue2 * 1.0 / TIM2_IC3_ReadValue1;
			TIM2_IC3_CaptureNumber = 0;
		}
  }
}

猜你喜欢

转载自blog.csdn.net/qq_43715171/article/details/113854043