STM32 learning notes one by one input capture

Publisher:740322lwjLatest update time:2019-01-09 Source: eefocusKeywords:STM32 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

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.


Write the picture description here


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.


Write the picture description here

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:


Write the picture description here


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:


Write the picture description here


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 Write the picture description hereis 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. Write the picture description hereWrite the picture description here Write the picture description here


3.3 TIMx_CCER:

Capture/compare enable register, the lowest 2 bits of this register, CC1E and CC1P, are used here. As shown below:


Write the picture description here


3.4 TIMx_DIER:

DMA/interrupt enable register.


Write the picture description here


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


Keywords:STM32 Reference address:STM32 learning notes one by one input capture

Previous article:STM32 study notes DMA transmission
Next article:SPI Topic (II)——STM32 Driver FLASH (W25Q64)

Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号