1 Overview
Input capture mode can be used to measure pulse width or frequency. Except for TIM6 and TIM7, all other STM32 timers have input capture function. Simply put, STM32 input capture detects the edge signal on TIMx_CHx. When the edge signal changes (such as rising edge/falling edge), the current timer value (TIMx_CNT) is stored in the capture/compare register (TIMx_CCRx) of the corresponding channel to complete a capture. At the same time, you can also configure whether to trigger interrupt/DMA during capture.
2. Ideas
High-level capture: first set the input capture to rising edge detection, and record the value of TIM2_CNT when the rising edge occurs. Then configure the capture signal to fall edge capture. When the falling edge arrives, capture occurs, and the TIM2_CNT value at this time is recorded. In this way, the difference between the two TIM2_CNTs before and after is the pulse width of the high level. At the same time, we know the counting frequency of TIM2, so we can calculate the exact time of the high-level pulse width.
Working process: By detecting the edge signal on TIMx_CHx, when the edge signal changes (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.
3. Register Introduction
3.1 TIMx_ARR and TIMx_PSC
These two registers are used to set the auto-reload value and the clock divider of TIMx.
Introduction -> STM32 study notes 1. Timer interrupt
3.2 TIMx_CCMR1
Capture/compare mode register: each bit is described as shown below:
When used in input capture mode, the second row of the corresponding figure describes that TIMx_CCMR1 is configured for 2 channels. The lower eight bits [7: 0] are used to control capture/compare channel 1, while the upper eight bits [15: 8] are used to control capture/compare channel 2. Because TIMx also has the CCMR2 register, we know that CCMR2 is used to control channels 3 and 4.
The experiment uses the capture/compare channel 1 of TIM2, focusing on bits [7:0] of TIMx_CMMR1:
CC1S[1:0]: These two bits are used to configure the channel direction of CCR1. Here we set IC1S[1:0]=01, that is,
It is configured as input, and IC1 is mapped on TI1, CC1 corresponds to TIMx_CH1.
IC1PSC[1:0]: Input capture 1 prescaler. Here, one edge triggers one capture, so just select 00.
IC1F[3:0]: Input capture 1 filter. This is used to set the input sampling frequency and digital filter length. Where is the input frequency of the timer (TIMxCLK), which is generally 72Mhz, and is determined by the setting of CKD[1:0] of TIMx_CR1. If CKD[1:0] is set to 00, then . N value is the filter length. Let's take a simple example: Assume IC1F[3:0]=0011, and set IC1 to map to channel 1, and it is a rising edge trigger. Then when the rising edge is captured, the level of channel 1 is continuously sampled 8 times at a frequency of. If they are all high levels, it means that it is indeed a valid trigger, and the input capture interrupt will be triggered (if it is turned on). In this way, those pulse signals with a high-level pulse width less than 8 sampling cycles can be filtered out, thereby achieving the filtering effect. Here, we do not do filtering, so set IC1F[3:0]=0000. As long as the rising edge is collected, the capture is triggered.
3.3 TIMx_CCER:
Capture/compare enable register, the lowest 2 bits of this register, CC1E and CC1P, are used here. As shown below:
3.4 TIMx_DIER:
DMA/interrupt enable register.
We also only care about its 0th bit, which is the update interrupt enable bit. When the timer is updated, this bit should be set to 1 to allow the interrupt generated by the update event.
3.5 TIMx_CCR1:
Capture/compare register 1. This register is used to store the value of TIMx_CNT when capture occurs. We can read the TIMx_CNT value of channel 1 at the time of capture from TIMx_CCR1. By taking the difference between two captures (one rising edge capture and one falling edge capture), we can calculate the width of the high-level pulse.
Configuration procedure
4.1 Turn on the TIM2 clock and configure PA0 as a pull-down input.
To use TIM2, we must first turn on the clock of TIM2. Here we also need to configure PA0 as a pull-down input, because we want to capture the high-level pulse width on TIM2_CH1, and TIM2_CH1 is connected to PA0.
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //Enable TIM2 clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //Enable GPIOA clock
4.2 Initialize TIM2 and set ARR and PSC of TIM2
After turning on the clock of TIM2, we need to set the values of the two registers ARR and PSC to set the auto-reload value and counting frequency of the input capture. This is achieved through the TIM_TimeBaseInit function in the library function.
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = arr; //Set the counter to automatically reload value
TIM_TimeBaseStructure.TIM_Prescaler =psc; //Set the prescaler value
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM up counting mode
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //Initialize Tim2 according to the specified parameters
4.3 Set the input comparison parameters of TIM2 and enable input capture
The input comparison parameter settings include mapping, filtering, frequency division, and capture mode. Here we need to set channel 1 to input mode, and IC1 is mapped to TI1 (channel 1), and no filter (to improve response speed) is used, and rising edge capture is used. The library function initializes the input comparison parameters through the TIM_ICInit function:
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
Definition of parameter setting structure TIM_ICInitTypeDef:
typedef struct
{
uint16_t TIM_Channel;
uint16_t TIM_ICPolarity;
uint16_t TIM_ICSelection;
uint16_t TIM_ICPrescaler;
uint16_t TIM_ICFilter;
} TIM_ICInitTypeDef;
Parameter TIM_Channel: used to set the channel. We set it to channel 1, which is TIM_Channel_1.
Parameter TIM_ICPolarity: is used to set the effective capture polarity of the input signal. Here we set it to
TIM_ICPolarity_Rising, rising edge capture. At the same time, the library function also provides a function to set the capture polarity of channel 1 separately:
TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Falling)
This means that channel 1 is captured on the rising edge. There is also a similar function for the other three channels. When using it, you must clearly distinguish which channel to use and which function to call. The format is TIM_OCxPolarityConfig().
Parameter TIM_ICSelection: is used to set the mapping relationship. We configure IC1 to be directly mapped on TI1.
TIM_ICSelection_DirectTI.
Parameter TIM_ICPrescaler: used to set the input capture frequency division coefficient. We do not divide the frequency here, so select TIM_ICPSC_DIV1. In addition, there are 2, 4, and 8 divisions to choose from.
Parameter TIM_ICFilter: Set the filter length. We do not use the filter here, so set it to 0.
Configuration code:
TIM_ICInitTypeDef TIM2_ICInitStructure;
TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //Select input IC1 and map it to TI1
TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //Rising edge capture
TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //Map to TI1
TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //Configure input frequency division, no frequency division
TIM5_ICInitStructure.TIM_ICFilter = 0x00; //IC1F=0000 configure input filter to not filter
TIM_ICInit(TIM2, &TIM2_ICInitStructure);
4.4 Enable capture and update interrupt (set DIER register of TIM2)
Because we want to capture the pulse width of the high-level signal, the first capture is the rising edge, and the second capture is the falling edge After capturing the rising edge, we must set the capture edge to the falling edge. At the same time, if the pulse width is long, the timer will overflow. The overflow must be processed, otherwise the result will be inaccurate. We do both of these things in the interrupt, so we must enable the capture interrupt and update interrupt. Here we use the timer's interrupt function TIM_ITConfig to enable the capture and update interrupts:
TIM_ITConfig( TIM2,TIM_IT_Update|TIM_IT_CC1,ENABLE); //Enable update interrupt and capture interrupt
1
4.5 Set up interrupt groups and write interrupt service functions
The interrupt grouping is mainly done through the function NVIC_Init(). After the grouping is completed, key operations such as data processing and capture settings need to be completed in the interrupt function to achieve high-level pulse width statistics. In the interrupt service function, the interrupt type should be judged at the beginning of the interrupt, and the interrupt flag should be cleared at the end of the interrupt. The functions used are:
TIM_GetITStatus() function and TIM_ClearITPendingBit() function.
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET){}//Judge whether it is an update interrupt
if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET){}//Judge whether a capture event occurs
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1|TIM_IT_Update); //Clear interrupt and capture flags
4.6 Enable the timer (set the CR1 register of TIM2)
Finally, the timer counter switch must be turned on to start the TIM5 counter and start input capture TIM_Cmd(TIM2,ENABLE); // Enable timer 2 After the above 6 steps, channel 1 of timer 2 can start input capture.
5. Implementation Code
5.1 Timer 2 Channel 1 Input Capture Configuration:
TIM_ICInitTypeDef TIM2_ICInitStructure;
void TIM2_Cap_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //Enable TIM2 clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //Enable GPIOA clock
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PA0 clears the previous settings
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0 input
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_ResetBits(GPIOA,GPIO_Pin_0); //PA0 pull down
// Initialize timer 2 TIM2
TIM_TimeBaseStructure.TIM_Period = arr; //Set the counter to automatically reload value
TIM_TimeBaseStructure.TIM_Prescaler =psc; //Prescaler
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //Set clock division
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //Count up
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //Initialize the time base unit of TIMx
//Initialize TIM2 input capture parameters
TIM2_ICInitStructure.TIM_Channel = TIM_Channel_1; //Select input IC1 and map it to TI1
TIM2_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //Rising edge capture
TIM2_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //Map to TI1
TIM2_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //Configure input frequency division, no frequency division
TIM2_ICInitStructure.TIM_ICFilter = 0x00; //IC1F=0000 configure input filter to not filter
TIM_ICInit(TIM2, &TIM2_ICInitStructure);
//Interrupt group initialization
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //TIM2 interrupt
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //Preemption priority level 2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //From priority level 0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ channel is enabled
NVIC_Init(&NVIC_InitStructure); //Initialize peripheral NVIC registers
TIM_ITConfig(TIM2,TIM_IT_Update|TIM_IT_CC1,ENABLE);
//Allow update interrupt CC1IE capture interrupt
TIM_Cmd(TIM2,ENABLE ); //Enable timer 2
}
5.2 Timer 5 Interrupt Service Routine
u8 TIM2CH1_CAPTURE_STA=0; //Input capture status
u16 TIM2CH1_CAPTURE_VAL; // Input capture value
//Timer 5 interrupt service routine
void TIM2_IRQHandler(void)
{
if((TIM2CH1_CAPTURE_STA&0X80)==0)//Not captured successfully
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
if(TIM2CH1_CAPTURE_STA&0X40)//High level has been captured
{
if((TIM2CH1_CAPTURE_STA&0X3F)==0X3F)//The high level is too long
{
TIM2CH1_CAPTURE_STA|=0X80; //Marks a successful capture
TIM2CH1_CAPTURE_VAL=0XFFFF;
}
else
TIM2CH1_CAPTURE_STA++;
}
}
if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET) //Capture 1 Capture event occurs
{
if(TIM2CH1_CAPTURE_STA&0X40) //Capture a falling edge
{
TIM2CH1_CAPTURE_STA|=0X80; //Marks a successful capture of a rising edge
TIM2CH1_CAPTURE_VAL=TIM_GetCapture1(TIM2);
TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Rising);
//CC1P=0 Set to rising edge capture
}
else //Not started yet, capture the rising edge for the first time
{
TIM2CH1_CAPTURE_STA=0; //Clear
TIM2CH1_CAPTURE_VAL=0;
TIM_SetCounter(TIM2,0);
TIM2CH1_CAPTURE_STA|=0X40; //Mark captured the rising edge
TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Falling);
//CC1P=1 is set to capture the falling edge
}
}
}
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1|TIM_IT_Update); //Clear interrupt flag
}
Note:
TIM2CH1_CAPTURE_STA: is used to record the capture status, treat it as a register
To use. TIM2CH1_CAPTURE_STA bit description is shown in the following table:
TIM2CH1_CAPTURE_VAL: It is used to record the value of TIM2_CNT when the falling edge is captured.
Ideas for capturing high-level pulse width:
First, set TIM2_CH1 to capture the rising edge, which is set when the TIM2_Cap_Init function is executed, and then wait for the rising edge capture interrupt to arrive. When the rising edge interrupt is captured, if the 6th bit of TIM2CH1_CAPTURE_STA is 0, it means that the new rising edge has not been captured. Clear TIM2CH1_CAPTURE_STA, TIM2CH1_CAPTURE_VAL and TIM2->CNT, and then set the 6th bit of TIM2CH1_CAPTURE_STA to 1, marking the capture of the high level, and finally set it to the falling edge capture, waiting for the falling edge to arrive. If the timer overflows while waiting for the falling edge to arrive, count the number of overflows in TIM2CH1_CAPTURE_STA. When the maximum number of overflows is reached, the capture is forced to mark the completion (although the falling edge has not been captured at this time). When the falling edge arrives, first set the 7th bit of TIM2CH1_CAPTURE_STA to 1, marking a successful capture of a high level, then read the capture value of the timer at this time into TIM2CH1_CAPTURE_VAL, and finally set it to rising edge capture and return to the initial state. In this way, we have completed a high-level capture. As long as the 7th bit of TIM2CH1_CAPTURE_STA is always 1, the second capture will not be performed. After the main function processes the captured data, we set TIM2CH1_CAPTURE_STA to zero to start the second capture.
5.3 Main function implementation
extern u8 TIM2CH1_CAPTURE_STA; //Input capture status
extern u16 TIM2CH1_CAPTURE_VAL; // input capture value
int main(void)
{
u32 temp=0;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //Set NVIC interrupt group 2: 2-bit preemption priority
Priority, 2-bit response priority
delay_init(); //delay function initialization
uart_init(9600); //Serial port initialized to 9600
LED_Init(); //Initialize the hardware interface connected to the LED
TIM1_PWM_Init(899,0); //No frequency division. PWM frequency = 72000/(899+1) = 80Khz
TIM2_Cap_Init(0XFFFF,72-1); //Count at 1Mhz frequency
while(1)
{
delay_ms(10);
TIM_SetCompare1(TIM1,TIM_GetCapture1(TIM1)+1);
if(TIM_GetCapture1(TIM1)==300)TIM_SetCompare1(TIM1,0);
if(TIM2CH1_CAPTURE_STA&0X80)//Successfully captured a high level
{
temp=TIM2CH1_CAPTURE_STA&0X3F;
temp*=65536; //Total overflow time
temp+=TIM2CH1_CAPTURE_VAL; //Get the total high level time
printf("HIGH:%d us\r\n",temp); //Print the total high point flat time
TIM2CH1_CAPTURE_STA=0; //Start the next capture
}
}
}
refer to:
1. Implementation of the punctual atomic library function version
Previous article:STM32 study notes DMA transmission
Next article:SPI Topic (II)——STM32 Driver FLASH (W25Q64)
- Popular Resources
- Popular amplifiers
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- Huawei's Strategic Department Director Gai Gang: The cumulative installed base of open source Euler operating system exceeds 10 million sets
- Download from the Internet--ARM Getting Started Notes
- Learn ARM development(22)
- Learn ARM development(21)
- Learn ARM development(20)
- Learn ARM development(19)
- Learn ARM development(14)
- Learn ARM development(15)
- Analysis of the application of several common contact parts in high-voltage connectors of new energy vehicles
- Wiring harness durability test and contact voltage drop test method
- Working Principles and Applications of Embedded Systems
- A brief discussion on the application of PD and QC fast charging protocol deception chip circuit
- IAR prompts that the device cannot be connected
- I have a wireless radio code and I open it with IAR, but I don't have a board. How can I test it?
- MSP430G2553 Software UART and Hardware UART and Jumper Settings
- The "backplane problem" is broken down, let's see how we catch the monster
- Learn 3D visualization from scratch: Camera "sweet spot"
- Optimization of CCS for TMS320C66x
- What are the definitions of Alternate and Remap in the manual?
- Recommended "Intelligent Sensor Systems: Emerging Technologies and Their Applications", those who are interested in sensors can take a look