1. The concept of input capture
In STM32 microcontrollers, input capture is a function used to measure external signal parameters. It is implemented through the timer module and can measure the frequency, duty cycle, pulse width, etc. of the signal.
Input capture timer based counter and capture compare unit. When the capture trigger condition is met, the value of the timer’s counter is captured and stored in the relevant registers of the capture comparison unit, and then the capture value can be obtained by reading these registers.
2. Principle and circuit
every capture
/
Compare channels are captured around a
/
Compare registers (including a shadow register), a capture input stage
sections (digital filtering, multiplexing and prescaler) and an output stage (comparator and output control).
The figure below provides an overview of a capture
/
Compare channels.
The input stage pairs the corresponding
TIx
The input is sampled and a filtered signal is generated.
f
. Then, with polarity selection function
An edge detector capable of generating a signal
(TIxFPx)
, this signal can be used as the trigger input of the slave mode controller or as
capture command. The signal is first pre-divided
(ICxPS)
, and then enter the capture register.
Capture
/
The compare module consists of a preload register and a shadow register. Preloads are always accessible through read and write operations
register.
In capture mode, the capture actually occurs in the shadow register, and then the contents of the shadow register are copied to the preload register
in the vessel.
In compare mode, the contents of the preload register are copied to the shadow register, and then the contents of the shadow register are compared with the calculated
Counter for comparison.
3. Input capture mode features
In input capture mode, when the corresponding
ICx
After the signal detects a transition edge, a capture
/
compare register
(TIMx_CCRx)
to latch the counter value. When a capture event occurs, the corresponding
CCXIF
flag (
TIMx_SR
register) set
1
,
and can send an interrupt or
DMA
request (if enabled). If a capture event occurs
CxI
The flag is already at a high level,
will duplicate the capture flag
CxO
(
TIMx_SR
register) set
1
. Available through software
CxI
write
0
Come and give
CxI
cleared, or read stored in
TIMx_CCRx
Captured data in register. Towards
CxO
write
0
will be discussed later
Its cleared.
4. Code
1. Use timer 14 to generate a square wave with a fixed frequency
void TIM14_PWM_Init(u32 arr,u32 psc) { //This part requires manual modification of the IO port settings \t GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; \t RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14,ENABLE); //TIM14 clock enable RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE); //Enable PORTF clock \t GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14); //GPIOF9 multiplex bit timer 14 \t GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //GPIOF9 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//Multiplex function GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //Speed 100MHz GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //Push-pull multiplexing output GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //Pull-up GPIO_Init(GPIOF, & amp;GPIO_InitStructure); //Initialize PF9 \t TIM_TimeBaseStructure.TIM_Prescaler=psc; //Timer frequency division TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //Up counting mode TIM_TimeBaseStructure.TIM_Period=arr; //Automatically reload value TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; \t TIM_TimeBaseInit(TIM14, & amp;TIM_TimeBaseStructure); \t //Initialize TIM14 Channel1 PWM mode TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //Select timer mode: TIM pulse width modulation mode 2 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //Compare output enable TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //Output polarity: TIM output has higher polarity TIM_OCInitStructure.TIM_Pulse=0; TIM_OC1Init(TIM14, & TIM_OCInitStructure); //Initialize the peripheral TIM3 OC2 according to the parameters specified by T TIM_OC2PreloadConfig(TIM14, TIM_OCPreload_Enable); //Enable the preload register of TIM3 on CCR2 TIM_ARRPreloadConfig(TIM14,ENABLE); \t TIM_Cmd(TIM14, ENABLE); //Enable TIM14 }
Input capture initialization
#define TIMx TIM3 #define TIMx_CLK RCC_APB1Periph_TIM3 #define TIMx_IRQn TIM3_IRQn #define TIMx_IRQHandler TIM3_IRQHandler #define TIMx_CHANNEL TIM_Channel_1 #define TIMx_GPIO_PORT GPIOA #define TIMx_GPIO_CLK RCC_AHB1Periph_GPIOA #define TIMx_PIN GPIO_Pin_6 #define TIMx_SOURCE GPIO_PinSource6 #define TIMx_AF GPIO_AF_TIM3 volatile uint32_t capture1 = 0; volatile uint32_t capture2 = 0; volatile uint32_t timeDifference = 0; void PWM_Capture_Init() { GPIO_InitTypeDef gpioInitStruct; TIM_ICInitTypeDef icInitStruct; NVIC_InitTypeDef nvicInitStruct; TIM_TimeBaseInitTypeDef timeBaseInitStruct; RCC_AHB1PeriphClockCmd(TIMx_GPIO_CLK, ENABLE);//GPIO enable RCC_APB1PeriphClockCmd(TIMx_CLK, ENABLE);//TIM clock enable gpioInitStruct.GPIO_Pin = TIMx_PIN; gpioInitStruct.GPIO_Mode = GPIO_Mode_AF; //Multiple functions gpioInitStruct.GPIO_Speed = GPIO_Speed_100MHz; gpioInitStruct.GPIO_OType = GPIO_OType_PP; gpioInitStruct.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(TIMx_GPIO_PORT, & amp;gpioInitStruct); GPIO_PinAFConfig(TIMx_GPIO_PORT, TIMx_SOURCE, TIMx_AF);//Port multiplexing timer 5 timeBaseInitStruct.TIM_Period = 65535; //1MHZ/10=100kHZ timeBaseInitStruct.TIM_Prescaler = 84-1; //High frequency does not divide by 0 // Assume that the CPU frequency is 84 MHz 84000000/84=1MHZ timeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; timeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//up counting mode timeBaseInitStruct.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIMx, & timeBaseInitStruct); icInitStruct.TIM_Channel = TIMx_CHANNEL; icInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;//rising edge capture icInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;//Mapped to TI1 icInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;//Configure input frequency division, no frequency division icInitStruct.TIM_ICFilter = 0x0;//IC1F=0000 configure input filter without filtering TIM_ICInit(TIMx, & icInitStruct); TIM_ClearITPendingBit(TIMx, TIM_IT_CC1);//Clear flag bit TIM_ITConfig(TIMx, TIM_IT_CC1, ENABLE); //Allow update interrupt nvicInitStruct.NVIC_IRQChannel = TIMx_IRQn; nvicInitStruct.NVIC_IRQChannelPreemptionPriority = 2;//Preemption priority nvicInitStruct.NVIC_IRQChannelSubPriority = 0;//Sub priority nvicInitStruct.NVIC_IRQChannelCmd = ENABLE;//IRQ channel enable NVIC_Init( & amp;nvicInitStruct);//Initialize the VIC register according to the specified parameters TIM_Cmd(TIMx, ENABLE);//Enable timer } uint32_t PWM_Capture_GetFreq() { if(capture1>capture2) { timeDifference=(65535-capture1) + capture2; } return (int)1000000/timeDifference; } void TIMx_IRQHandler(void) { if (TIM_GetITStatus(TIMx, TIM_IT_CC1) != RESET) { if (capture1 == 0) { capture1 = TIM_GetCapture1(TIMx); } else if (capture2 == 0) { capture2 = TIM_GetCapture1(TIMx); timeDifference = capture2 - capture1; } TIM_ClearITPendingBit(TIMx, TIM_IT_CC1); } }
Called in main function
int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//Set system interrupt priority group 2 TIM14_PWM_Init(50000-1,84-1); //The counting frequency of 84M/84=1Mhz counts to 500, and the PWM frequency is 1M/500=2Khz PWM_Capture_Init(); uart_init(115200); TIM_SetCompare1(TIM14,30000); printf("Initialization successful\ "); \t \t while(1) { printf("The captured frequency is: %dhz\ ",PWM_Capture_GetFreq()); delay_ms(500); //delay 500ms } }