1. General timer input capture overview
1.STM32 input capture process
2.STM32 input capture process (channel 1 as an example)
By detecting the edge signal on TIMx_CHx, when the edge signal jumps (such as rising edge/falling edge), the current timer value (TIMx_CNT) is stored in the corresponding capture/compare register (TIMx_CCRx) to complete a capture .
1) Step 1: Set the input capture filter (channel 1 as an example)
2) Step 2: Set the input capture polarity (channel 1 as an example)
3) Step 3: Set the input capture mapping channel (channel 1 as an example)
4) Step 4: Set the input capture divider (channel 1 as an example)
5) Step 5: When a valid signal is captured, the interrupt can be enabled
6) Take the corresponding pin TIM5 of the timer channel as an example
2. Commonly used registers and library function configuration
1. The file where the basic functions and definitions of general timers are located
Stm32fxxx_hal_tim.c Location: Project Files - HALLIB - Stm32fxxx_hal_tim.c Stm32fxxx_hal_tim.h Location: Project Files - HALLIB - Stm32fxxx_hal_tim.c - Stm32fxxx_hal_tim.h
2. Common functions of timer input capture function
Location: Project Files - HALLIB - Stm32fxxx_hal_tim.c - Stm32fxxx_hal_tim.h
1) Timer input capture time base parameter initialization function:
HAL_StatusTypeDef HAL_TIM_IC_Init(TIM_HandleTypeDef *htim) Location: Project Files - HALLIB - Stm32fxxx_hal_tim.c
This function is the same as the HAL_TIM_Base_Init/HAL_TIM_PWM_Init function, the difference is that different callback functions are called.
typedef struct { uint32_t Prescaler; //Prescale factor uint32_t CounterMode; //Counting Mode: Up/Down uint32_t Period; //autoload value uint32_t ClockDivision; //Clock divider factor: Timer clock to digital filter divider ratio uint32_t RepetitionCounter; //Repeat count times: Advanced timer use } TIM_Base_InitTypeDef;
2) Timer input capture time base parameter initialization callback function
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim); Location: Project Files - HALLIB - Stm32fxxx_hal_tim.c
It is mainly used to write timer clock enable, channel IO configuration and interrupt priority setting.
__HAL_RCC_TIM5_CLK_ENABLE(); //Timer 3 clock enable
3) Input capture channel parameter configuration function
HAL_StatusTypeDef HAL_TIM_IC_ConfigChannel(TIM_HandleTypeDef htim,TIM_IC_InitTypeDef sConfig, uint32_t Channel); Location: Project Files - HALLIB - Stm32fxxx_hal_tim.c
typedef struct { uint32_t ICPolarity; //capture polarity uint32_t ICSelection; //input mapping uint32_t ICPrescaler; //input divider uint32_t ICFilter; //input filter } TIM_IC_InitTypeDef
4) Enable the timer and enable the input capture channel
HAL_StatusTypeDef HAL_TIM_IC_Start (TIM_HandleTypeDef *htim, uint32_t Channel); Location: Project Files - HALLIB - Stm32fxxx_hal_tim.c
HAL_StatusTypeDef HAL_TIM_IC_Start_IT (TIM_HandleTypeDef *htim, uint32_t Channel);
Location: Project File - HALLIB - Stm32fxxx_hal_tim.c
This function also enables capture interrupts.
5) Capture interrupt callback function
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) Location: Project Files - HALLIB - Stm32fxxx_hal_tim.c
Similar to the interrupt service function, we can write the function logic related to capture in it
6) Read the captured value
uint32_t HAL_TIM_ReadCapturedValue(TIM_HandleTypeDef *htim,uint32_t Channel); Location: Project Files - HALLIB - Stm32fxxx_hal_tim.c
3. Enter the general configuration key steps for capture:
①Enable timer clock and channel IO port clock.
②Configure IO port multiplexing mapping: HAL_GPIO_Init();
③Initialize the input capture time base parameters: HAL_TIM_IC_Init();
④Initialize input capture channel parameters: HAL_TIM_IC_ConfigChannel();
⑤Enable the timer (interrupt), set the priority: HAL_TIM_IC_Start_IT();
⑥ Write interrupt service callback function: HAL_TIM_IC_CaptureCallback();
3. Input capture experiment
1. Experimental purpose: measure the pulse width of the signal
Use the wake_up button on the board to simulate the pulse, then use the input capture to measure the duration of the high level and print it out through the serial port
Proceed as follows
①Enable timer clock and channel IO port clock.
②Configure IO port multiplexing mapping: HAL_GPIO_Init();
③Initialize the input capture time base parameters: HAL_TIM_IC_Init();
④Initialize input capture channel parameters: HAL_TIM_IC_ConfigChannel();
⑤Enable the timer (interrupt), set the priority: HAL_TIM_IC_Start_IT();
⑥ Write interrupt service callback function: HAL_TIM_IC_CaptureCallback();
2. Interpretation of the timer.c file
Location: Project File - HARDWARE - timer.c
code show as below:
#include "timer.h" #include "led.h" TIM_HandleTypeDef TIM3_Handler; //Timer 3PWM handle TIM_OC_InitTypeDef TIM3_CH4Handler; //Timer 3 channels 4 handles /*************************************************************************** **************************************************************************** The following is the source code of the PWM output experiment related functions **************************************************************************** ****************************************************************************/ //TIM3 PWM part initialization //PWM output initialization //arr: auto-reload value //psc: clock prescaler void TIM3_PWM_Init(u16 arr,u16 psc) { TIM3_Handler.Instance=TIM3; //timer 3 TIM3_Handler.Init.Prescaler=psc; //Timer divider TIM3_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;//count up mode TIM3_Handler.Init.Period=arr; //auto-reload value TIM3_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; HAL_TIM_PWM_Init(&TIM3_Handler); //Initialize PWM TIM3_CH4Handler.OCMode=TIM_OCMODE_PWM1; //Mode select PWM1 TIM3_CH4Handler.Pulse=arr/2; //Set the comparison value, this value is used to determine the duty cycle, //The default comparison value is half of the auto-reload value, i.e. a duty cycle of 50% TIM3_CH4Handler.OCPolarity=TIM_OCPOLARITY_LOW; //The output compare polarity is low HAL_TIM_PWM_ConfigChannel(&TIM3_Handler,&TIM3_CH4Handler,TIM_CHANNEL_4);//Configure TIM3 channel 4 HAL_TIM_PWM_Start(&TIM3_Handler,TIM_CHANNEL_4);//Turn on PWM channel 4 } //Timer bottom layer driver, clock enable, pin configuration //This function will be called by HAL_TIM_PWM_Init() //htim: timer handle void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim) { GPIO_InitTypeDef GPIO_Initure; __HAL_RCC_TIM3_CLK_ENABLE(); //enable timer 3 __HAL_RCC_GPIOB_CLK_ENABLE(); //Enable GPIOB clock GPIO_Initure.Pin=GPIO_PIN_1; //PB1 GPIO_Initure.Mode=GPIO_MODE_AF_PP; //Multiplexed push output GPIO_Initure.Pull=GPIO_PULLUP; //pull up GPIO_Initure.Speed=GPIO_SPEED_HIGH; //high speed GPIO_Initure.Alternate= GPIO_AF2_TIM3; //PB1 is multiplexed as TIM3_CH4 HAL_GPIO_Init(GPIOB,&GPIO_Initure); } //Set the duty cycle of TIM channel 4 //compare: compare values void TIM_SetTIM3Compare4(u32 compare) { TIM3->CCR4=compare; } //Get TIM capture/compare register value u32 TIM_GetTIM3Capture4(void) { return HAL_TIM_ReadCapturedValue(&TIM3_Handler,TIM_CHANNEL_4); } /*************************************************************************** **************************************************************************** The following is the input capture related source code experiment related function source code **************************************************************************** ****************************************************************************/ TIM_HandleTypeDef TIM5_Handler; //Timer 5 handle //Timer 5 Channel 1 Input Capture Configuration //arr: auto-reload value (TIM2,TIM5 are 32 bits!!) //psc: clock prescaler void TIM5_CH1_Cap_Init(u32 arr,u16 psc) { TIM_IC_InitTypeDef TIM5_CH1Config; TIM5_Handler.Instance=TIM5; //General purpose timer 5 TIM5_Handler.Init.Prescaler=psc; //Frequency division factor TIM5_Handler.Init.CounterMode=TIM_COUNTERMODE_UP; //up counter TIM5_Handler.Init.Period=arr; //autoload value TIM5_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; //clock divider HAL_TIM_IC_Init(&TIM5_Handler); //Initialize input capture time base parameters TIM5_CH1Config.ICPolarity=TIM_ICPOLARITY_RISING; //Rising edge capture TIM5_CH1Config.ICSelection=TIM_ICSELECTION_DIRECTTI; //Mapped to TI1 TIM5_CH1Config.ICPrescaler=TIM_ICPSC_DIV1; //Configure input frequency division, no frequency division TIM5_CH1Config.ICFilter=0; //Configure input filter, no filter HAL_TIM_IC_ConfigChannel(&TIM5_Handler,&TIM5_CH1Config,TIM_CHANNEL_1);//Configure TIM5 channel 1 HAL_TIM_IC_Start_IT(&TIM5_Handler,TIM_CHANNEL_1); //Enable capture channel 1 of TIM5 and enable capture interrupt __HAL_TIM_ENABLE_IT(&TIM5_Handler,TIM_IT_UPDATE); //Enable update interrupt } //Timer 5 bottom layer driver, clock enable, pin configuration //This function will be called by HAL_TIM_IC_Init() //htim: Timer 5 handle void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim) { GPIO_InitTypeDef GPIO_Initure; //Initialize GPIO if(htim -> Instance == TIM5) //Determine whether timer 5 triggers an interrupt { __HAL_RCC_TIM5_CLK_ENABLE(); //Enable TIM5 clock __HAL_RCC_GPIOA_CLK_ENABLE(); //Enable GPIOA clock GPIO_Initure.Pin=GPIO_PIN_0; //PA0 GPIO_Initure.Mode=GPIO_MODE_AF_PP; //Multiplexed push-pull output GPIO_Initure.Pull=GPIO_PULLDOWN; //drop down GPIO_Initure.Speed=GPIO_SPEED_HIGH; //high speed GPIO_Initure.Alternate=GPIO_AF2_TIM5; //PA0 is multiplexed into TIM5 channel 1 HAL_GPIO_Init(GPIOA,&GPIO_Initure); HAL_NVIC_SetPriority(TIM5_IRQn,2,0); //Set interrupt priority, preempt priority 2, sub priority 0 HAL_NVIC_EnableIRQ(TIM5_IRQn); //Enable ITM5 interrupt channel } } //capture state //[7]: 0, no successful capture; 1, one successful capture. //[6]: 0, the low level has not been captured; 1, the low level has been captured. //[5:0]: The number of overflows after capturing the low level (for 32-bit timers, the 1us counter is incremented by 1, and the overflow time: 4294 seconds) u8 TIM5CH1_CAPTURE_STA=0; //input capture state u32 TIM5CH1_CAPTURE_VAL; //Input capture value (TIM2/TIM5 are 32 bits) //Timer 5 interrupt service function void TIM5_IRQHandler(void) { HAL_TIM_IRQHandler(&TIM5_Handler);//Timer common processing function } //Timer update interrupt (count overflow) interrupt processing callback function, this function will be called in HAL_TIM_IRQHandler void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//Executed when an update interrupt (overflow) occurs { if((TIM5CH1_CAPTURE_STA&0X80)==0)//Not yet successfully captured { if(TIM5CH1_CAPTURE_STA&0X40)//high level has been captured { if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//high level too long { TIM5CH1_CAPTURE_STA|=0X80; //Marker successfully captured once TIM5CH1_CAPTURE_VAL=0XFFFFFFFF; }else TIM5CH1_CAPTURE_STA++; } } } //Timer input capture interrupt processing callback function, which will be called in HAL_TIM_IRQHandler void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)//Executed when a capture interrupt occurs { if((TIM5CH1_CAPTURE_STA&0X80)==0)//Not yet successfully captured { if(TIM5CH1_CAPTURE_STA&0X40) //captured to a falling edge { TIM5CH1_CAPTURE_STA|=0X80; //The marker successfully captures a high-level pulse width TIM5CH1_CAPTURE_VAL=HAL_TIM_ReadCapturedValue(&TIM5_Handler,TIM_CHANNEL_1);//Get the current capture value. TIM_RESET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1); //Be sure to clear the original settings first! ! TIM_SET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING);//Configure TIM5 channel 1 rising edge capture }else //Not yet started, first capture rising edge { TIM5CH1_CAPTURE_STA=0; //empty TIM5CH1_CAPTURE_VAL=0; TIM5CH1_CAPTURE_STA|=0X40; //Flag captures the rising edge __HAL_TIM_DISABLE(&TIM5_Handler); //turn off timer 5 __HAL_TIM_SET_COUNTER(&TIM5_Handler,0); TIM_RESET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1); //Be sure to clear the original settings first! ! TIM_SET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING);//Timer 5 channel 1 is set to capture on falling edge __HAL_TIM_ENABLE(&TIM5_Handler);//enable timer 5 } } }
It can be seen that the code is divided into two parts, the upper part is the PWM part, the following is the input capture related code, and the following focuses on the input capture related code.
1) Timer 5 channel 1 input capture configuration
The settings here are the same as the ordinary timer settings. For details, please refer to the previous notes.
TIM5_Handler.Init.Prescaler=psc; //Frequency division coefficient
This paragraph determines the sampling frequency of input capture, because the fundamental frequency of F429 is 90Mhz,
The sampling frequency of input capture here = base frequency is 90Mhz/(frequency division factor + 1)
TIM5_Handler.Init.Period=arr; //Auto load value
Determine the timer overflow time. After writing the auto-load value, an interrupt will be generated after the counter counts from 0 to the auto-load value.
The following is the input capture channel parameter configuration code:
TIM5_CH1Config.ICPolarity=TIM_ICPOLARITY_RISING; //Rising edge capture
Set the capture polarity, that is, capture the rising edge or the falling edge
TIM5_CH1Config.ICSelection=TIM_ICSELECTION_DIRECTTI; //Mapped to TI1
Which channel to map the captured instruction to, F429 has four channels: TI1, TI2, TI3, TI4
TIM5_CH1Config.ICPrescaler=TIM_ICPSC_DIV1; //Configure input frequency division, no frequency division
The frequency division here means that several events are captured to trigger an interrupt. The specific corresponding registers are in this article: 1. 2. 4) Set the input capture divider (channel 1 as an example)
TIM5_CH1Config.ICFilter=0; //Configure the input filter without filtering
HAL_TIM_IC_ConfigChannel(&TIM5_Handler,&TIM5_CH1Config,TIM_CHANNEL_1);//Configure TIM5 channel 1
2) Write input capture callback function
Note that PA0 is set to pull-down mode here, that is, it outputs a low level when there is no response to capture.
3) Interrupt service function, timer update interrupt
Because the button is pressed and not released, the counter will continue to count, and the limited value of the counter may cause overflow, so we need to update the timer interrupt, the program is as shown above
3. Interpretation of the main.c file
#include "sys.h" #include "delay.h" #include "usart.h" #include "led.h" #include "timer.h" extern u8 TIM5CH1_CAPTURE_STA; //input capture state extern u32 TIM5CH1_CAPTURE_VAL; //Enter capture value int main(void) { long long temp=0; HAL_Init(); //Initialize the HAL library Stm32_Clock_Init(360,25,2,8); //Set clock, 180Mhz delay_init(180); //Initialize delay function uart_init(115200); //Initialize USART LED_Init(); //Initialize the LED s TIM3_PWM_Init(500-1,90-1); //90M/90=1M count frequency, auto reload is 500, then PWM frequency is 1M/500=2kHZ TIM5_CH1_Cap_Init(0XFFFFFFFF,90-1); //Count at 1MHZ while(1) { delay_ms(10); TIM_SetTIM3Compare4(TIM_GetTIM3Capture4()+1); if(TIM_GetTIM3Capture4()==300)TIM_SetTIM3Compare4(0); if(TIM5CH1_CAPTURE_STA&0X80) //A high level was successfully captured { temp=TIM5CH1_CAPTURE_STA&0X3F; temp*=0XFFFFFFFF; //sum of overflow time temp+=TIM5CH1_CAPTURE_VAL; //get the total high time printf("HIGH:%lld us\r\n",temp);//Print the total high average time TIM5CH1_CAPTURE_STA=0; //Start the next capture } } }
So far, the input capture experiment code is explained