STM32CubeMX Series|Input Capture

Input capture

1. Introduction to Input Capture

Input capture mode can be used to measure pulse width or frequency. The following figure uses pulse width measurement as an example to illustrate the principle of input capture

Insert picture description here
Assuming that the timer works in up-counting mode, the time t1-t2 in the figure is the low-level time we need to measure. The measurement method is: first set the timer channel x to capture on the falling edge, and the current CNT value will be captured at t1, then immediately clear the CNT, and set channel x to capture on the rising edge, and the capture event will be sent at t2 , Get the CNT value at this time (denoted as CCRx2). N times of timer overflow may occur between t1-t2, so it is necessary to deal with the timer overflow to prevent the low level from being too long to cause inaccurate data.
The number of counts between t1-t2 is: N * ARR + CCRx2, and then multiply by the CNT count period to get the low-level duration

Insert picture description here

2. Hardware design

This experiment captures the high-level duration of the KEY_UP button through the channel 1 input capture function of TIM5, and prints the captured high-level time through the printf function, and uses the D1 indicator to indicate the normal operation of the system

  • D1 indicator
  • K_UP button
  • USART1 serial port
  • TIM5

Insert picture description here

3. Software design

3.1 STM32CubeMX settings
  • RCC set external HSE, clock is set to 72M
  • PC0 is set to GPIO push-pull output mode, pull-up, high-speed, and the default output level is high
  • USART1 is selected as the asynchronous communication mode, the baud rate is set to 115200Bits/s, the transmission data length is 8Bit, no parity, 1 stop bit
  • Select TIM5, set the timer clock source to the internal clock source, set channel 1 to input capture mode (PA0 is automatically selected), activate the timer interrupt in the NVIC setting, and pull down PA0 in the GPIO setting to ensure the level when no signal is input stable

Insert picture description here
Insert picture description here

  • Set the prescaler coefficient to 72-1, count up, and set the auto-reload value to 0xFFFF, then the timer clock frequency is 1MHz, the timer period is 1us, and the timer overflow period is 65535 * 1 = 65535us

Insert picture description here

  • Enter the project name, select the project path (no Chinese), select MDK-ARM V5; check Generated periphera initialization as a pair of'.c/.h' files per IP; click GENERATE CODE to generate the project code
3.2 MDK-ARM programming
  • Write the timer update interrupt processing callback function in the tim.c file
/* TIM5CH1_CAP_STA 各数据位说明
** bit7   捕获完成标志
** bit6	  捕获到高电平标志
** bit5~0 捕获高电平后定时器溢出的次数*/
uint8_t TIM5CH1_CAP_STA = 0;
uint16_t TIM5CH1_CAP_VAL;

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
    
    
	if((TIM5CH1_CAP_STA & 0X80) == 0){
    
    	//还未成功捕获
		if(TIM5CH1_CAP_STA & 0X40){
    
    		//已经捕获到高电平
			if((TIM5CH1_CAP_STA & 0X3F) == 0X3F){
    
    	//高电平时间太长了
				TIM5CH1_CAP_STA |= 0X80;			//标记为完成一次捕获
				TIM5CH1_CAP_VAL = 0XFFFF;			//计数器值
			}
			else
				TIM5CH1_CAP_STA++;		//溢出次数加1			
		}	
	}
}
  • Write input capture interrupt processing callback function in tim.c file
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){
    
    
	if((TIM5CH1_CAP_STA & 0X80) == 0){
    
    	//还未成功捕获
		if(TIM5CH1_CAP_STA & 0X40){
    
    		//捕获到上升沿后条件为真
			TIM5CH1_CAP_STA |= 0X80;	//标记为完成一次高电平捕获
			TIM5CH1_CAP_VAL = HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_1);	//获取当前的计数器值
			TIM_RESET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1);	//清除原来的设置		
			TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING);	//设置上升沿捕获
		}
		else{
    
    
			TIM5CH1_CAP_STA = 0;
			TIM5CH1_CAP_VAL = 0;
			TIM5CH1_CAP_STA |= 0X40;	//标记捕获到上升沿
			__HAL_TIM_DISABLE(&htim5);	//关闭定时器
			__HAL_TIM_SET_COUNTER(&htim5,0);	//计数器值清零
			TIM_RESET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1);	//清除原来的设置				
			TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING);	//设置下降沿捕获
			__HAL_TIM_ENABLE(&htim5);	//使能定时器		
		}	
	}
}	

There is a HAL library function error in the TIM_RESET_CAPTUREPOLARITY() function here, which will cause an error when compiling the function. The solution is to find the definition of the function in the stm32f1xx_hal_tim.h file and delete the extra bracket')'

stm32f1xx_hal_tim.h
//修改前
#define TIM_RESET_CAPTUREPOLARITY(__HANDLE__, __CHANNEL__) \
  (((__CHANNEL__) == TIM_CHANNEL_1) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC1P | TIM_CCER_CC1NP))) :\
   ((__CHANNEL__) == TIM_CHANNEL_2) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC2P | TIM_CCER_CC2NP)) :\
   ((__CHANNEL__) == TIM_CHANNEL_3) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC3P)) :\
   ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC4P)))
//修改后
#define TIM_RESET_CAPTUREPOLARITY(__HANDLE__, __CHANNEL__) \
  (((__CHANNEL__) == TIM_CHANNEL_1) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC1P | TIM_CCER_CC1NP)) :\
   ((__CHANNEL__) == TIM_CHANNEL_2) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC2P | TIM_CCER_CC2NP)) :\
   ((__CHANNEL__) == TIM_CHANNEL_3) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC3P)) :\
   ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC4P)))
  • Write the high-level duration processing code in the main.c file
int main(void){
    
    
  long long temp = 0;
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_TIM5_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  HAL_TIM_IC_Start_IT(&htim5,TIM_CHANNEL_1);	//一定要开启TIM5通道1的捕获中断
  __HAL_TIM_ENABLE_IT(&htim5,TIM_IT_UPDATE);	//一定要开启TIM5的更新中断
  printf("This is TIM_CAP test...\n");
  /* USER CODE END 2 */
  while (1){
    
    
    HAL_Delay(500);
	if(TIM5CH1_CAP_STA & 0X80){
    
    		//完成一次高电平捕获
		temp = TIM5CH1_CAP_STA & 0X3F;
		temp *= 65536;				//溢出总时间
		temp += TIM5CH1_CAP_VAL;	//总的高电平时间
		printf("High level duration:%lld us\r\n",temp);
		TIM5CH1_CAP_STA = 0;		//准备下一次捕获
	}
	HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);
  }
}

4. Download verification

After the compilation is correct, download it to the development board, you can see that the D1 indicator flashes once every 500ms, after pressing KEY_UP, the serial port will print the corresponding high level duration

Insert picture description here

Guess you like

Origin blog.csdn.net/Chuangke_Andy/article/details/108590177