23_Timer input capture experiment

/**
  ******************************************************************************
  * @file           : user_mian.h
  * @brief          : V1.00
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Include Include ------------------------------------------------- --------------*/
#include "stm32f10x.h"
#include <stdbool.h>
#include "user_gpio.h"
#include "user_delay.h"
#include "user_rcc_config.h"
#include "user_uart.h"
#include "user_timer.h"


/* Typedef type------------------------------------------------- ---------------*/
/* Define  definition------------------------------------------------- ---------------*/
/* Macro   macro ----------------------------------------------- -----------------*/
/* Variables variable------------------------------------------------- -------------*/
//Receive up to 200 bytes at a time
uint8_t USART_RX_BUF[200];
//receiving status
//bit15, receive completion flag
//bit14, received 0x0d
//bit13~0, the number of valid bytes received
uint16_t USART_RX_STA=0;       //receive status flag	
extern u8  TIM5CH1_CAPTURE_STA;		//input capture status		    				
extern u16	TIM5CH1_CAPTURE_VAL;	//Enter capture value	
/* Constants constant------------------------------------------------- -------------*/
/* Function  function------------------------------------------------- -------------*/


 int main(void)
 {	
	u32 temp=0;
	 
	/*Configure system interrupt grouping as 2-bit preemptive 2-bit response*/
	 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	 /*Delay function initialization*/
	 delay_init();
	/*RCC configuration*/
	 Rcc_config();
	/*GPIO initialization*/ 
	 Gpio_Init();
	/*USART1 initialization*/
	 Uart1_Init(9600);
	 /*Timer 5 initialization*/
	 Tim5_Input_Init(0xFFFF,72-1); //Counting at a frequency of 1Mhz, the counter overflows from 0 to FFFF, and one clock cycle is 1us
	/*Infinite loop*/ 
	 while(1){
			delay_ms(10);
		 /*successfully captured the completion*/
		if(TIM5CH1_CAPTURE_STA&0X80)
		{	/*How many times to take overflow*/
			temp=TIM5CH1_CAPTURE_STA&0X3F;
			/*Because every time the counter time is FFFF converted to decimal is 65535*/
			temp*=65536;//sum of overflow times
			temp+=TIM5CH1_CAPTURE_VAL;//The sum of the last capture + overflow time = get the total high time 
			printf("HIGH:%d ms\r\n",temp/1000);//Print the total high flat time
			TIM5CH1_CAPTURE_STA=0;//start next capture
		}

	 } 
		

}
 
 /************************************************************** END OF FILE ****/

STM32 input capture working process

STM32 input capture working process (channel 1 as an example)

 

Summarize the working process in one sentence: By detecting the edge signal on TIMx_CHx, when the edge signal jumps (such as rising edge/falling edge), store the current timer value (TIMx_CNT) in the corresponding capture/compare register (TIMx_CCRx inside), to complete a capture.

input capture filter

 

Input capture 1 filter ICIF[3:0], this is used to set the input sampling frequency and digital filter length. Among them, fck_INT is the input frequency of the timer (TIMxCLK), generally 72Mhz, and fDTS is determined according to the setting of CKD[1:0] of TIMx_CRI. If CKD[1:0] is set to 00, then fors= fck_INT. The N value is the filter length.

Set input capture polarity

 

Set the capture mapping channel

 

If CC1S is set to 00, channel 1 is set to output. 01 is CC1 channel is configured bit input and mapped to TI1.

In general, channel 1 is mapped to IC1, and channel 2 is mapped to IC2.

Set the input capture divider

 

Capturing a valid signal can enable the interrupt

Brief description: The input capture of STM32, simply put, is to detect the edge signal on TIMx_CHx, and when the edge signal jumps (such as rising edge/falling edge), the current timer value (TIMx_CNT) is stored in the corresponding In the capture/compare register (TIMx_CCRx) of the channel, a capture is completed. First set the input capture to rising edge detection, and record the value of TIMx_CNT when the rising edge occurs. Then configure the capture signal as falling edge capture. When the falling edge arrives, the capture occurs and the TIMx_CNT value at this time is recorded. In this way, the difference between the two TIMx_CNT before and after is the high-level pulse width. At the same time, we know the counting frequency of TIMx, so that the accurate time of the high-level pulse width can be calculated.

Frequency calculation:

Set the capture mode to falling edge/rising edge capture. When the rising edge/falling edge is captured for the first time, an interrupt will be triggered. In the interrupt, the current count value will be recorded as Value1; the rising edge will be captured for the second time. /falling edge, trigger an interrupt again, in which we record the current count value Value2. So the time between the second capture and the first is the period of the wave. Assuming the timer's clock is set to 72MHz, then the frequency of the resulting wave should be 72MHz/(Value2 - Value1).

Detailed input capture structure

typedef struct
{
uint16_t TIM_Channel; //Capture channels 1-4
uint16_t TIM_ICPolarity; //capture polarity
uint16_t TIM_ICSelection; //Mapping relations
uint16_t TIM_ICPrescaler; //Frequency division factor
uint16_t TIM_ICFilter; //filter
}TIM_ICInitTypeDef;

Input capture related functions

Input capture channel initialization function

void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);

Channel polarity setting independent function

void TIM_OCxPofarityConfig(TIM_TypeDef* TIMx, uint16_1 TIM_OCPolarity);

Get channel capture value

uint32_t  TIM GetCapture 1(TIM_ TypeDef* TIMx):

General configuration steps for input capture:

1. Initialize the timer and the clock corresponding to the IO of the channel.

2. Initialize the IO port, mode bit input:

GPIO_Init();

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; // Pull down input

3. Initialize the timer ARR,PSC

TIM_TimeBaselnit();

4. Initialize the input capture channel

TIM ICInit();

5. If you want to enable capture interrupt

TIM_ITConfig();

NVIC Init();

6. Enable the timer

TIM_Cmd();

7. Write interrupt service function

TIMx_IRQHandler();

Experiment code:

Detect the high level time of the GPIOA.0 pin

/**
  ******************************************************************************
  * @file           : user_rcc_config.c
  * @brief          : V1.00
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Include Include------------------------------------------------- --------------*/
#include "user_rcc_config.h"
/* Typedef type------------------------------------------------- ---------------*/
/* Define  definition------------------------------------------------- ---------------*/
/* Macro   macro ----------------------------------------------- -----------------*/
/* Variables variable------------------------------------------------- -------------*/
/* Constants constant------------------------------------------------- -------------*/
/* Function  function------------------------------------------------- -------------*/

/*!
	\brief		Timer initialization
	\param[in]	none
	\param[in]	none
	\retval 	none
*/
void Rcc_config(void)
{	
	/*Enable GPIOA clock*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	/*Enable UART1 clock*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	/*Enable Timer 5 clock*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);
	
	
}

/************************************************************** END OF FILE ****/
/**
  ******************************************************************************
  * @file           : user_gpio.c
  * @brief          : V1.00
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Include Include------------------------------------------------- --------------*/
#include "user_gpio.h"
/* Typedef type------------------------------------------------- ---------------*/
/* Define  definition------------------------------------------------- ---------------*/
/* Macro   macro ----------------------------------------------- -----------------*/
/* Variables variable------------------------------------------------- -------------*/
/* Constants constant------------------------------------------------- -------------*/
/* Function  function------------------------------------------------- -------------*/

/*!
	\brief		GPIO initialization function
	\param[in]	none
	\param[out]	none
	\retval 	none
*/
void Gpio_Init(void)
{	
	/*GPIO structure*/
	GPIO_InitTypeDef GPIO_InitTypeDefstruct;
	
	/*UART1 Send pin configuration*/
	GPIO_InitTypeDefstruct.GPIO_Mode  = GPIO_Mode_AF_PP;//Push-pull multiplexed output
	GPIO_InitTypeDefstruct.GPIO_Pin   = GPIO_Pin_9;
	GPIO_InitTypeDefstruct.GPIO_Speed =	GPIO_Speed_10MHz;
	/*Write structure to GPIOA*/
	GPIO_Init(GPIOA,&GPIO_InitTypeDefstruct);
	
	/*UART1 Receive pin configuration*/
	GPIO_InitTypeDefstruct.GPIO_Mode  = GPIO_Mode_IN_FLOATING;//floating input
	GPIO_InitTypeDefstruct.GPIO_Pin   = GPIO_Pin_10;
	GPIO_InitTypeDefstruct.GPIO_Speed =	GPIO_Speed_10MHz;
	/*Write structure to GPIOA*/	
	GPIO_Init(GPIOA,&GPIO_InitTypeDefstruct);
	
	/*Initialize PA0*/
	GPIO_InitTypeDefstruct.GPIO_Mode  = GPIO_Mode_IPD;//pull down input
	GPIO_InitTypeDefstruct.GPIO_Pin   = GPIO_Pin_0;	
	/*Write structure to GPIOA*/
	GPIO_Init(GPIOA,&GPIO_InitTypeDefstruct);
	
	/*Set as dropdown input*/
	GPIO_ResetBits(GPIOA,GPIO_Pin_0);
}

/************************************************************** END OF FILE ****/
/**
  ******************************************************************************
  * @file           : user_uart.c
  * @brief          : V1.00
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Include Include------------------------------------------------- --------------*/
#include "user_uart.h"
/* Typedef type------------------------------------------------- ---------------*/
/* Define  definition------------------------------------------------- ---------------*/
/* Macro   macro ----------------------------------------------- -----------------*/
/* Variables variable------------------------------------------------- -------------*/

extern uint16_t USART_RX_STA;
extern uint8_t USART_RX_BUF[200];


/* Constants constant------------------------------------------------- -------------*/
/* Function  function------------------------------------------------- -------------*/


#if 1
#pragma import(__use_no_semihosting)  
/*Implement Printf code*/
struct __FILE 
{ 
	int handle; 

}; 
FILE __stdout;       

void _sys_exit(int x) 
{ 
	x = x; 
} 
//Redefine the fputc function 
int fputc(int ch, FILE *f)
{      
	while((USART1->SR&0X40)==0);//Send in a loop until the send is complete   
    USART1->DR = (u8) ch;      
	return ch;
}
#endif 





/*!
	\brief		UART1 initialization
	\param[in]	none
	\param[out]	none
	\retval 	none
*/

void Uart1_Init(u32 bound)
{
	/*UART structure*/
	USART_InitTypeDef USART_InitTypeDefstruct;
	
	/*UART Structure configuration*/
	USART_InitTypeDefstruct.USART_BaudRate = bound; //baud rate
	USART_InitTypeDefstruct.USART_HardwareFlowControl =USART_HardwareFlowControl_None; //no hardware streaming
	USART_InitTypeDefstruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//Send and receive enable
	USART_InitTypeDefstruct.USART_Parity = USART_Parity_No; //Do not use parity
	USART_InitTypeDefstruct.USART_StopBits = USART_StopBits_1; //1 stop bit
	USART_InitTypeDefstruct.USART_WordLength = USART_WordLength_8b; //8 data bits
	/*write to USART1*/
	USART_Init(USART1,&USART_InitTypeDefstruct);
	
	/*Enable serial port 1*/
	USART_Cmd(USART1,ENABLE);

}


/*!
	\brief		UART1 interrupt service function
	\param[in]	none
	\param[out]	none
	\retval 	none
*/

void USART1_IRQHandler(void)
{

}
	

/************************************************************** END OF FILE ****/
 
/**
  ******************************************************************************
  * @file           : user_timer.c
  * @brief          : V1.00
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Include Include------------------------------------------------- --------------*/
#include "user_timer.h"
/* Typedef type------------------------------------------------- ---------------*/
/* Define  definition------------------------------------------------- ---------------*/
/* Macro   macro ----------------------------------------------- -----------------*/
/* Variables variable------------------------------------------------- -------------*/
/*
Because the captured high level does not know how long
 Is it possible that the timer has been exceeded or
 High level so get a byte to record
 Capture complete, capture to high level, and timer overflow times
 This works out how much time we captured
TIM5CH1_CAPTURE_STA
bit7   capture complete flag 
bit6   capture high flag
bit5~0 Capture the number of high-level timer overflows
*/
u8  TIM5CH1_CAPTURE_STA=0;	//input capture status		    				
u16	TIM5CH1_CAPTURE_VAL;	//Enter capture value
/* Constants constant------------------------------------------------- -------------*/
/* Function  function------------------------------------------------- -------------*/

/*!
	\brief		Timer initialization
	\param[in]	loading value
	\param[in]	Frequency division factor
	\retval 	none
*/
void Tim5_Input_Init(uint16_t arr, uint16_t psc)
{	
	/*Timer structure*/
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitTypeDefstruct;
	/*Timer 5 input capture structure*/
	TIM_ICInitTypeDef  TIM5_ICInitStructure;
	/*interrupt controller structure*/
   	NVIC_InitTypeDef NVIC_InitStructure;
	
	/*Timer initialization configuration*/
	TIM_TimeBaseInitTypeDefstruct.TIM_Period = arr; //autoload value
	TIM_TimeBaseInitTypeDefstruct.TIM_Prescaler = psc; //Frequency division factor
	TIM_TimeBaseInitTypeDefstruct.TIM_CounterMode = TIM_CounterMode_Up;//count up mode
	TIM_TimeBaseInitTypeDefstruct.TIM_ClockDivision = TIM_CKD_DIV1;//clock frequency division
	/*Write Timer 5*/
	TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitTypeDefstruct);

	/*Initialize Timer 5 input capture parameters*/
	TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 select input IC1 is mapped to TI1
  	TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //Mapped to TI1  	
	TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;	//Rising edge capture
  	TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//Configure the input frequency division. If there is no frequency division, there is a rising edge capture. If the frequency division is 2, it will only start capturing after 2 rising edges. 
  	TIM5_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 Configure input filter No filter, no acquisition
  	
	/*Write to Timer 5 input capture channel*/
	TIM_ICInit(TIM5, &TIM5_ICInitStructure);
	
	/*Interrupt group initialization*/
	NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn; //TIM5 interrupt
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//preemption priority 2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //Sub Priority Level 0
	NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE; //Enable input capture
	
	/*write to the interrupt controller*/
	NVIC_Init(&NVIC_InitStructure);
	
	/*Enable updates, allow CCC1IE to capture interrupts*/
	TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);
	/*enable timer*/
	TIM_Cmd(TIM5,ENABLE);
	
	
}

/*!
	\brief		TIM5_IRQHandler
	\param[in]	none
	\param[in]	none
	\retval 	none
*/

void TIM5_IRQHandler(void)
{
	/*Judging whether a high level has been captured, we will start counting effectively when it is 0, otherwise exit the interrupt*/
	if((TIM5CH1_CAPTURE_STA & 0x80) == 0) //not yet captured
	{	/*Determine whether the timer is up*/
		if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)		 
		{	 /*High level has been captured*/   
			if(TIM5CH1_CAPTURE_STA&0X40)
			{	/*The high level is too long, the number of counting times is full, and the flag is directly forced to be*/
				if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)
				{
					TIM5CH1_CAPTURE_STA|=0X80;//mark a successful capture
					TIM5CH1_CAPTURE_VAL=0XFFFF;
				}
				else
				{	/*The counter update event plus 1 is used to calculate the high level time
					TIM5CH1_CAPTURE_STA*Timer setting + TIM5CH1_CAPTURE_VAL = high level time
					*/
					TIM5CH1_CAPTURE_STA++;
					
				} 

			}	 
		}
	}
	
	
	/*Determine whether capture has occurred*/
	if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET)
	{	/*Judging whether the high level was captured last time, if the last time
		If it is a high level, then this time it has captured a low level
		*/
		if(TIM5CH1_CAPTURE_STA&0X40)		//caught on a falling edge 		
		{	  			
			TIM5CH1_CAPTURE_STA|=0X80;		//The marker successfully captures a high level pulse width
			TIM5CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5); //Save the value of the capture compare register for calculating the time
		   	TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //CC1P=0 set as rising edge capture
		}else  		
		{	
			/*capture high level*/
			TIM5CH1_CAPTURE_STA=0;	//empty
			TIM5CH1_CAPTURE_VAL=0;
	 		TIM_SetCounter(TIM5,0); //Set the timer count to 0 to start recording the high level time
			TIM5CH1_CAPTURE_STA|=0X40;		//Flag captured on rising edge
		   	TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling);		//CC1P=1 set as falling edge capture
		}		    
	}
	
	/*clear interrupt flag*/
	TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update); 
}


/************************************************************** END OF FILE ****/

/**
  ******************************************************************************
  * @file           : user_mian.h
  * @brief          : V1.00
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Include Include------------------------------------------------- --------------*/
#include "stm32f10x.h"
#include <stdbool.h>
#include "user_gpio.h"
#include "user_delay.h"
#include "user_rcc_config.h"
#include "user_uart.h"
#include "user_timer.h"


/* Typedef type------------------------------------------------- ---------------*/
/* Define  definition------------------------------------------------- ---------------*/
/* Macro   macro ----------------------------------------------- -----------------*/
/* Variables variable------------------------------------------------- -------------*/
//Receive up to 200 bytes at a time
uint8_t USART_RX_BUF[200];
//receiving status
//bit15, receive completion flag
//bit14, received 0x0d
//bit13~0, the number of valid bytes received
uint16_t USART_RX_STA=0;       //receive status flag	
extern u8  TIM5CH1_CAPTURE_STA;		//input capture status		    				
extern u16	TIM5CH1_CAPTURE_VAL;	//Enter capture value	
/* Constants constant------------------------------------------------- -------------*/
/* Function  function------------------------------------------------- -------------*/


 int main(void)
 {	
	u32 temp=0;
	 
	/*Configure system interrupt grouping as 2-bit preemptive 2-bit response*/
	 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	 /*Delay function initialization*/
	 delay_init();
	/*RCC configuration*/
	 Rcc_config();
	/*GPIO initialization*/ 
	 Gpio_Init();
	/*USART1 initialization*/
	 Uart1_Init(9600);
	 /*Timer 5 initialization*/
	 Tim5_Input_Init(0xFFFF,72-1); //Counting at a frequency of 1Mhz, the counter overflows from 0 to FFFF, and one clock cycle is 1us
	/*Infinite loop*/ 
	 while(1){
			delay_ms(10);
		 /*successfully captured the completion*/
		if(TIM5CH1_CAPTURE_STA&0X80)
		{	/*How many times to take overflow*/
			temp=TIM5CH1_CAPTURE_STA&0X3F;
			/*Because every time the counter time is FFFF converted to decimal is 65535*/
			temp*=65536;//sum of overflow times
			temp+=TIM5CH1_CAPTURE_VAL;//The sum of the last capture + overflow time = get the total high time 
			printf("HIGH:%d ms\r\n",temp/1000);//Print the total high flat time
			TIM5CH1_CAPTURE_STA=0;//start next capture
		}

	 } 
		

}
 
 /************************************************************** END OF FILE ****/

 

 

Tags: stm32 Embedded system Single-Chip Microcomputer

Posted by brandtj on Sat, 26 Nov 2022 00:21:49 +0530