First look at the door 32 series 08–input capture

Article directory

  • Timer programming practice 3: General timer input capture
    • hardware design
      • General-purpose timer input capture pulse width measurement principle
    • CubeMX configuration
    • General-purpose timer input capture experiment configuration steps
      • 1. Configure the basic working parameters of the timer
      • 2. Timer input capture MSP initialization
      • 3. Enable timer update interrupt and capture, capture interrupt and counter
      • 4. Write interrupt service function
      • 5. Write update interrupt and capture callback functions
      • 6. Serial data transmission

Timer programming practice 3: General timer input capture

Hardware design

The hardware resources used in this experiment are:
1) KEY_UP button
2) Serial port
3) Timer TIM2
The first two were introduced in previous experiments. In this experiment, we will capture the high level pulse on TIM2_CH1 (PA0)
Input the high level through the KEY_UP button, and print the high level pulse width from the serial port.
This experiment uses a serial port, so make changes in the project file of the serial port experiment.

Universal timer input capture pulse width measurement principle

Take capturing and measuring high-level pulse width as an example
Assumption: Up counting mode
ARR: the value of the automatic reload register
CCRx1: the value of CCRx at time t1
CCRx2: the value of CCRx at time t2

CubeMX configuration

In the TIMERS->TIM2 configuration item, set the value of Channel1 to Input Capture direct mode, and then select Internal Clock. As shown below

Enter the Configuration->Parameter Setting configuration item, the five options under the Counter Settings configuration column are used to configure the timer’s prescaler coefficient, automatic loading value, counting mode, and clock frequency division factor. In the Input Capture Channel 1 configuration column of the interface, configure the capture polarity, frequency division coefficient, mapping, filter and other parameters of the input capture channel 1, as shown in the figure below

Enter the System Core->NVIC configuration page, click the NVIC tab in the pop-up interface, configure the TIM2 global interrupt in the Intertupe Table, enable the interrupt, configure the preemption priority and the corresponding priority. As shown below

At the same time, the chip pin diagram on the right will automatically configure PA0, and the user does not need to change the configuration by default.
After performing the above operations, the next step is to generate engineering code.

Common timer input capture experiment configuration steps

1. Configure timer basic working parameters

The code here is for CubeMX configuration.

//tim.c file
TIM_HandleTypeDef htim2;

void MX_TIM2_Init(void)
{<!-- -->
  TIM_ClockConfigTypeDef sClockSourceConfig = {<!-- -->0}; //clock source structure
  TIM_MasterConfigTypeDef sMasterConfig = {<!-- -->0}; //Main mode structure
  TIM_IC_InitTypeDef sConfigIC = {<!-- -->0}; //Output capture structure

  htim2.Instance = TIM2; //General timer 2
  htim2.Init.Prescaler = 95; //Frequency division coefficient
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP; //Up counter
  htim2.Init.Period = 0XFFFFFFFF; //auto load value
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;//clock division factor
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;//Disable autoreload value preload
  if (HAL_TIM_Base_Init( & htim2) != HAL_OK)
  {<!-- -->
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; //internal clock
  if (HAL_TIM_ConfigClockSource( &htim2, &sClockSourceConfig) != HAL_OK)
  {<!-- -->
    Error_Handler();
  }
  if (HAL_TIM_IC_Init( & amp;htim2) != HAL_OK) //Initialize input capture time base parameters
  {<!-- -->
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization( &htim2, &sMasterConfig) != HAL_OK)
  {<!-- -->
    Error_Handler();
  }
  sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING; //Rising edge capture
  sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI; //map to TI1
  sConfigIC.ICPrescaler = TIM_ICPSC_DIV1; //Configure input frequency division, no frequency division
  sConfigIC.ICFilter = 0; //Configure the input filter without filtering
  if (HAL_TIM_IC_ConfigChannel( & amp;htim2, & amp;sConfigIC, TIM_CHANNEL_1) != HAL_OK)//Configure TIM2 channel 1
  {<!-- -->
    Error_Handler();
  }
}

2. Timer input capture MSP initialization

The code here is for CubeMX configuration.

//tim.c
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{<!-- -->
  GPIO_InitTypeDef GPIO_InitStruct = {<!-- -->0};
  if(tim_baseHandle->Instance==TIM2)
  {<!-- -->
    /* TIM2 clock enable */
    __HAL_RCC_TIM2_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**TIM2 GPIO Configuration
    PA0-WKUP ------> TIM2_CH1
    */
    GPIO_InitStruct.Pin = GPIO_PIN_0;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLDOWN;
    GPIO_InitStruct. Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
    HAL_GPIO_Init(GPIOA, & GPIO_InitStruct);

    /* TIM2 interrupt Init */
    HAL_NVIC_SetPriority(TIM2_IRQn, 2, 0);
    HAL_NVIC_EnableIRQ(TIM2_IRQn);
  }
}

3. Enable timer update interrupt and capture, capture interrupt and counter

//tim.c
void MX_TIM2_Init(void)
{<!-- -->
  /* MX CODE BEGIN */
  //. . . . . . . .
  /* MX CODE END */
 
  /* USER CODE BEGIN */
  HAL_TIM_IC_Start_IT( &htim2,TIM_CHANNEL_1);
  __HAL_TIM_ENABLE_IT( &htim2,TIM_IT_UPDATE);
  /* USER CODE END */
}

4. Write interrupt service function

The TIM2_IRQHandler function code here is configured with CubeMX and will be generated in the stm32f4xx_it.c file.
If you do not need to configure the project with cubemx later, you can cut this code into the tim.c file. If you use cubemx to configure the project later, you need to indicate some variables extern in other stm32f4xx_it.c files.

//tim.c
void TIM2_IRQHandler(void)
{<!-- -->
HAL_TIM_IRQHandler( & amp;TIM2_Handler); //Timer shared processing function
}

5. Write update interrupt and capture callback function

//tim.c
/* USER CODE BEGIN */
uint8_t g_timxchy_cap_sta = 0; /* input capture status */
uint16_t g_timxchy_cap_val = 0; /* input capture value */
/* Timer input capture interrupt processing callback function */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{<!-- -->
    if (htim->Instance == TIM2)
    {<!-- -->
        if ((g_timxchy_cap_sta & amp; 0X80) == 0) /* not successfully captured yet */
        {<!-- -->
            if (g_timxchy_cap_sta & amp; 0X40) /* capture a falling edge */
            {<!-- -->
                g_timxchy_cap_sta |= 0X80; /* mark successfully captured a high level pulse width */
                g_timxchy_cap_val = HAL_TIM_ReadCapturedValue( & amp;htim2, TIM_CHANNEL_1); /* Get the current captured value */
                TIM_RESET_CAPTUREPOLARITY( & amp;htim2, TIM_CHANNEL_1); /* Be sure to clear the original settings first */
                TIM_SET_CAPTUREPOLARITY( & amp;htim2, TIM_CHANNEL_1, TIM_ICPOLARITY_RISING); /* Configure TIM5 channel 1 rising edge capture */
            }
            else /* not yet started, the first rising edge is captured */
            {<!-- -->
                g_timxchy_cap_sta = 0; /* clear */
                g_timxchy_cap_val = 0;
                g_timxchy_cap_sta |= 0X40; /* mark has captured the rising edge */
                __HAL_TIM_DISABLE( & amp;htim2); /* Disable timer 5 */
                __HAL_TIM_SET_COUNTER( & amp;htim2, 0); /* Timer 5 counter clear */
                TIM_RESET_CAPTUREPOLARITY( & amp;htim2, TIM_CHANNEL_1); /* Be sure to clear the original settings first! ! */
                TIM_SET_CAPTUREPOLARITY( & amp;htim2, TIM_CHANNEL_1, TIM_ICPOLARITY_FALLING); /* Timer 5 channel 1 is set as falling edge capture */
                __HAL_TIM_ENABLE( & amp;htim2); /* enable timer 5 */
            }
        }
    }
}

/* Timer update interrupt callback function */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{<!-- -->
    if (htim->Instance == TIM2)
    {<!-- -->
        if ((g_timxchy_cap_sta & amp; 0X80) == 0) /* not successfully captured yet */
        {<!-- -->
            if (g_timxchy_cap_sta & amp; 0X40) /* High level has been captured */
            {<!-- -->
                if ((g_timxchy_cap_sta & amp; 0X3F) == 0X3F) /* high level is too long */
                {<!-- -->
                    TIM_RESET_CAPTUREPOLARITY( & amp;htim2, TIM_CHANNEL_1); /* Be sure to clear the original settings first */
                    TIM_SET_CAPTUREPOLARITY( & amp;htim2, TIM_CHANNEL_1, TIM_ICPOLARITY_RISING);/* Configure TIM5 channel 1 rising edge capture */
                    g_timxchy_cap_sta |= 0X80; /* mark a successful capture */
                    g_timxchy_cap_val = 0XFFFF;
                }
                else /* accumulated timer overflow times */
                {<!-- -->
                    g_timxchy_cap_sta++;
                }
            }
        }
    }
}
/* USER CODE END */

6. Serial port data transmission

To use the printf function, you need to add the official SYSTEM file plus the sys, delay, and usart files in the project to use it normally.

//main.c
/* USER CODE BEGIN */
extern uint8_t g_timxchy_cap_sta; /* input capture status */
extern uint16_t g_timxchy_cap_val; /* input capture value */
/* USER CODE END */

int main(void)
{<!-- -->
  /* USER CODE BEGIN */
  uint32_t temp = 0;
  /* USER CODE END */
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_TIM2_Init();
  while (1)
  {<!-- -->
    /* USER CODE BEGIN */
   if (g_timxchy_cap_sta & amp; 0X80) /* successfully captured a high level */
      {<!-- -->
        temp = g_timxchy_cap_sta & 0X3F;
        temp *= 0XFFFFFFFF; /* overflow time sum */
        temp + = g_timxchy_cap_val; /* get the total high time */
        printf("HIGH:%lld us\r\
",temp);//print the total high level time
        g_timxchy_cap_sta = 0; /* start the next capture */
      }
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_0);
    HAL_Delay(200);
    /* USER CODE END */
  }
}