使用STM32CubeMx配置STM32输入捕获功能

时间:2024-03-14 15:35:50
  1. 输入捕获原理

    在输入捕获模式下,当检测到ICx信号上相应的边沿后,计数器的当前值被锁存到捕获/比较寄存
    器(TIMx_CCRx)中。当发生捕获事件时,相应的CCxIF标志(TIMx_SR寄存器)被置1,如果开放
    了中断或者DMA操作,则将产生中断或者DMA请求。如果发生捕获事件时CCxIF标志已经为
    高,那么重复捕获标志CCxOF(TIMx_SR寄存器)被置1。写CCxIF=0可清除CCxIF,或读取存储
    在TIMx_CCRx寄存器中的捕获数据也可清除CCxIF。写CCxOF=0可清除CCxOF。
    摘自《STM32参考手册中文》

  2. 简单解释:定时器一直在计数,如果检测到设置的极性边沿,会把当前的计数值存下来,并触发中断;

  3. 比如,定时器设置为TIM2,预分频719,计数周期0xFFFF,则TIM2 10us计数一次,计数到0xFFFF,重装载到0;现在设置的输入捕获极性为上升沿捕获,则当某通道捕获到一次上升沿后,触发中断,并将当前的计数值存在对应通道的CCR值;

  4. 所以无论是设置为上升沿捕获还是下降沿捕获,都只能得到整个脉冲的周期时间;如果是想获得高电平占整个周期的百分比呢?

  5. 那么我就需要在最开始设置为上升沿捕获,当捕获到一个上升沿后,把极性设置为下降沿捕获,依次类推,这样我们就可以得到高电平时间和周期时间了;注意要设置好标志位

  6. 这里的话会出现一个问题,比如我的上升沿时间点在上一个周期,下降沿时间点在下一个周期,那么在下降沿-上升沿之前还要再加上一个定时器周期

  7. 以下是我的STM32CubeMx配置

使用STM32CubeMx配置STM32输入捕获功能
使用STM32CubeMx配置STM32输入捕获功能使用STM32CubeMx配置STM32输入捕获功能
8. 以下是比较重要的代码

/* Private variables ---------------------------------------------------------*/
uint16_t 	Channel1HighTime, Channel2HighTime, Channel3HighTime, Channel4HighTime;
uint16_t 	Channel1Period, Channel2Period, Channel3Period, Channel4Period;
uint8_t  	Channel1Edge = 0, Channel2Edge = 0, Channel3Edge = 0, Channel4Edge = 0;
uint16_t 	Channel1Percent, Channel2Percent, Channel3Percent, Channel4Percent;
uint16_t	Channel1PercentTemp[3] = {0, 0, 0};
uint8_t 	Channel1TempCount = 0;
uint16_t 	Channel1RisingTimeLast=0, Channel1RisingTimeNow, Channel1FallingTime;
uint16_t 	Channel2RisingTimeLast=0, Channel2RisingTimeNow, Channel2FallingTime;
uint16_t 	Channel3RisingTimeLast=0, Channel3RisingTimeNow, Channel3FallingTime;
uint16_t 	Channel4RisingTimeLast=0, Channel4RisingTimeNow, Channel4FallingTime;
/* USER CODE END PV */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration----------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_TIM2_Init();
  /* USER CODE BEGIN 2 */
	HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
	HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);
	HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_3);
	HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_4);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
		HAL_Delay(500);
  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */

  }
  /* USER CODE END 3 */

}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(htim);
  /* NOTE : This function Should not be modified, when the callback is needed,
            the __HAL_TIM_IC_CaptureCallback could be implemented in the user file
   */
	if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
	{
		if(Channel1Edge == 0)
		{
			Channel1RisingTimeNow = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_1);//获取上升沿时间点
			__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_FALLING);//切换捕获极性
			HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
			Channel1Edge = 1;
			if(Channel1RisingTimeLast == 0)
			{
				Channel1Period = 0;
			}
			else
			{
				if(Channel1RisingTimeNow > Channel1RisingTimeLast)
				{
					Channel1Period = Channel1RisingTimeNow - Channel1RisingTimeLast;
				}
				else
				{
					Channel1Period = Channel1RisingTimeNow + 0xffff - Channel1RisingTimeLast + 1;
				}
			}
			Channel1RisingTimeLast = Channel1RisingTimeNow;
		}
		else if(Channel1Edge == 1)
		{
			Channel1FallingTime = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_1);	
			__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING);
			HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
			
			if(Channel1FallingTime < Channel1RisingTimeNow)
			{
				Channel1HighTime = Channel1FallingTime + 0xffff - Channel1RisingTimeNow + 1;
			}
			else
			{
				Channel1HighTime = Channel1FallingTime - Channel1RisingTimeNow;
			}
			if(Channel1Period != 0)
			{
				Channel1Percent = (uint8_t)(((float)Channel1HighTime / Channel1Period) * 1000);
				printf("Channel1 = %d	", Channel1Percent);
			}
			Channel1Edge = 0;
		}
	}
	else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
	{
		if(Channel2Edge == 0)
		{
			Channel2RisingTimeNow = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_2);
			__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_FALLING);
			HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);
			Channel2Edge = 1;
			if(Channel2RisingTimeLast == 0)
			{
				Channel2Period = 0;
			}
			else
			{
				if(Channel2RisingTimeNow > Channel2RisingTimeLast)
				{
					Channel2Period = Channel2RisingTimeNow - Channel2RisingTimeLast;
				}
				else
				{
					Channel2Period = Channel2RisingTimeNow + 0xffff - Channel2RisingTimeLast + 1;
				}
			}
			Channel2RisingTimeLast = Channel2RisingTimeNow;
		}
		else if(Channel2Edge == 1)
		{
			Channel2FallingTime = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_2);	
			__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_RISING);
			HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);
			
			if(Channel2FallingTime < Channel2RisingTimeNow)
			{
				Channel2HighTime = Channel2FallingTime + 0xffff - Channel2RisingTimeNow + 1;
			}
			else
			{
				Channel2HighTime = Channel2FallingTime - Channel2RisingTimeNow;
			}
			if(Channel2Period != 0)
			{
				Channel2Percent = (uint8_t)(((float)Channel2HighTime / Channel2Period) * 1000);
				printf("Channel2 = %d	", Channel2Percent);
			}
			Channel2Edge = 0;
		}
	}
	else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_3)
	{
		if(Channel3Edge == 0)
		{
			Channel3RisingTimeNow = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_3);
			__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_3, TIM_INPUTCHANNELPOLARITY_FALLING);
			HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_3);
			Channel3Edge = 1;
			if(Channel3RisingTimeLast == 0)
			{
				Channel3Period = 0;
			}
			else
			{
				if(Channel3RisingTimeNow > Channel3RisingTimeLast)
				{
					Channel3Period = Channel3RisingTimeNow - Channel3RisingTimeLast;
				}
				else
				{
					Channel3Period = Channel3RisingTimeNow + 0xffff - Channel3RisingTimeLast + 1;
				}
			}
			Channel3RisingTimeLast = Channel3RisingTimeNow;
		}
		else if(Channel3Edge == 1)
		{
			Channel3FallingTime = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_3);	
			__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_3, TIM_INPUTCHANNELPOLARITY_RISING);
			HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_3);
			
			if(Channel3FallingTime < Channel3RisingTimeNow)
			{
				Channel3HighTime = Channel3FallingTime + 0xffff - Channel3RisingTimeNow + 1;
			}
			else
			{
				Channel3HighTime = Channel3FallingTime - Channel3RisingTimeNow;
			}
			if(Channel3Period != 0)
			{
				Channel3Percent = (uint8_t)(((float)Channel3HighTime / Channel3Period) * 1000);
				printf("Channel3 = %d	", Channel3Percent);
			}
			Channel3Edge = 0;
		}
	}
	else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_4)
	{
		if(Channel4Edge == 0)
		{
			Channel4RisingTimeNow = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_4);
			__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_4, TIM_INPUTCHANNELPOLARITY_FALLING);
			HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_4);
			Channel4Edge = 1;
			if(Channel4RisingTimeLast == 0)
			{
				Channel4Period = 0;
			}
			else
			{
				if(Channel4RisingTimeNow > Channel4RisingTimeLast)
				{
					Channel4Period = Channel4RisingTimeNow - Channel4RisingTimeLast;
				}
				else
				{
					Channel4Period = Channel4RisingTimeNow + 0xffff - Channel4RisingTimeLast + 1;
				}
			}
			Channel4RisingTimeLast = Channel4RisingTimeNow;
		}
		else if(Channel4Edge == 1)
		{
			Channel4FallingTime = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_4);	
			__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_4, TIM_INPUTCHANNELPOLARITY_RISING);
			HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_4);
			
			if(Channel4FallingTime < Channel4RisingTimeNow)
			{
				Channel4HighTime = Channel4FallingTime + 0xffff - Channel4RisingTimeNow + 1;
			}
			else
			{
				Channel4HighTime = Channel4FallingTime - Channel4RisingTimeNow;
			}
			if(Channel4Period != 0)
			{
				Channel4Percent = (uint8_t)(((float)Channel4HighTime / Channel4Period) * 1000);
				printf("Channel4 = %d\n", Channel4Percent);
			}
			Channel4Edge = 0;
		}
	}
}