STM32 HAL库定时器输入捕获+更新中断

news2025/1/12 1:44:35

STM32 HAL库定时器输入捕获+更新中断


  • 📍相关参考:https://www.cnblogs.com/kevin-nancy/p/12569377.html#4621839
  • 📌相关篇《STM32 HAL库定时器输入捕获SlaveMode脉宽测量》
  • ✨高级定时器的输入捕获功能在脉宽信号测量方面是非常方便的。尤其时在使用HC-SR04超声波测距方面。高级定时器的结构相对而言比较复杂,配置一个完善的案例可以方便后续使用该功能时可以直接套用和借鉴。
  • 🌿输入捕获针对的是外部输入信号:上升沿或下降沿信号产生的中断

  • 🌿更新中断是内部定时器计数值超出了重装载值产生溢出的更新事件。当然也有可能是同时是被测量信号电平太长。

  • 测量HAL函数自带的HAL_Delay(1);1ms延时:
    在这里插入图片描述

  • 📏逻辑分析仪测量
    在这里插入图片描述

  • 🔖72MHz主频下,微秒延时函数测量

void delay_us(uint32_t udelay)
{
    uint32_t startval, tickn, delays, wait;
    startval = SysTick->VAL;
    tickn = HAL_GetTick();
    //sysc = 72000;  //SystemCoreClock / (1000U / uwTickFreq);
    delays = (udelay-3) * 72; //-3测量后修正,sysc / 1000 * udelay;
    if(delays > startval)
    {
        while(HAL_GetTick() == tickn)
        {

        }
        wait = 72000 + startval - delays;
        while(wait < SysTick->VAL)
        {

        }
    }
    else
    {
        wait = startval - delays;
        while(wait < SysTick->VAL && HAL_GetTick() == tickn)
        {

        }
    }
}

在这里插入图片描述

  • 📏逻辑分析仪测量
    在这里插入图片描述
  • HAL 定时器5(TIM5)参数配置:经过18分频后,采用的是4MHz,如果还想提供测量精度可以将分频系数分的设定更小。4MHz,最小测量时间理论等于其步长:1/4MHz,
    在这里插入图片描述

✨实际测量中发现,被测量的脉冲宽度大于1us脉冲信号才能读取正确。测量小于1us脉宽信号读取的计数值就不对了,可能代码上还是存在缺陷。

📑定时器捕获更新中断和溢出中断回调函数书写

  • 🌿定时器输入捕获更新中断回调函数:
//TIM5输入通道1:PA0
/* TIM5CH1_CAP_STA 各数据位说明
** bit7   捕获完成标志
** bit6   捕获到高电平标志
** bit5~0 捕获高电平后定时器溢出的次数*/
uint8_t TIM5CH1_CAP_STA = 0;
uint16_t TIM5CH1_CAP_VAL;
//定时器更新中断处理回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim)
{
    if((TIM5CH1_CAP_STA & 0X80) == 0)   //还未成功捕获
    {
        if(TIM5CH1_CAP_STA & 0X40)      //已经捕获到高电平
        {
            if((TIM5CH1_CAP_STA & 0X3F) == 0X3F)    //高电平时间太长了
            {
                TIM5CH1_CAP_STA |= 0X80;            //标记为完成一次捕获
                TIM5CH1_CAP_VAL = 0XFFFF;           //计数器值
            }
            else
                TIM5CH1_CAP_STA++;      //溢出次数加1
        }
    }
}
  • 🌿定时器输入捕获输入捕获上升沿或下降沿中断回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef* htim)
{
    if((TIM5CH1_CAP_STA & 0X80) == 0)   //还未成功捕获
    {
        if(TIM5CH1_CAP_STA & 0X40)      //捕获到上升沿后条件为真
        {
            TIM5CH1_CAP_STA |= 0X80;    //标记为完成一次高电平捕获
            TIM5CH1_CAP_VAL = HAL_TIM_ReadCapturedValue(&htim5, TIM_CHANNEL_1); //获取当前的计数器值
            TIM_RESET_CAPTUREPOLARITY(&htim5, TIM_CHANNEL_1);   //清除原来的设置
            TIM_SET_CAPTUREPOLARITY(&htim5, TIM_CHANNEL_1, TIM_ICPOLARITY_RISING);  //设置上升沿捕获
        }
        else
        {
            TIM5CH1_CAP_STA = 0;
            TIM5CH1_CAP_VAL = 0;
            TIM5CH1_CAP_STA |= 0X40;    //标记捕获到上升沿
            __HAL_TIM_DISABLE(&htim5);  //关闭定时器
            __HAL_TIM_SET_COUNTER(&htim5, 0);   //计数器值清零
            TIM_RESET_CAPTUREPOLARITY(&htim5, TIM_CHANNEL_1);   //清除原来的设置
            TIM_SET_CAPTUREPOLARITY(&htim5, TIM_CHANNEL_1, TIM_ICPOLARITY_FALLING); //设置下降沿捕获
            __HAL_TIM_ENABLE(&htim5);   //使能定时器
        }
    }
}
  • 🔖在HAL_TIM_PeriodElapsedCallback()回调函数中用以处理计数次数和时间;在HAL_TIM_IC_CaptureCallback()回调函数负责处理捕获到的上升沿和下降沿,并随着捕获到上升沿而更改为下降沿捕获, 随着捕获到下降沿而更改定时器为上升沿捕获.
  • ⚡以上中断回调函数都在中断函数:void HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim)中被调用。
void HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim)
{
  /* Capture compare 1 event */
  if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC1) != RESET)
  {
    if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC1) != RESET)
    {
      {
        __HAL_TIM_CLEAR_IT(htim, TIM_IT_CC1);
        htim->Channel = HAL_TIM_ACTIVE_CHANNEL_1;

        /* Input capture event */
        if ((htim->Instance->CCMR1 & TIM_CCMR1_CC1S) != 0x00U)
        {
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
          htim->IC_CaptureCallback(htim);
#else
          HAL_TIM_IC_CaptureCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
        }
        /* Output compare event */
        else
        {
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
          htim->OC_DelayElapsedCallback(htim);
          htim->PWM_PulseFinishedCallback(htim);
#else
          HAL_TIM_OC_DelayElapsedCallback(htim);
          HAL_TIM_PWM_PulseFinishedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
        }
        htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
      }
    }
  }
  /* Capture compare 2 event */
  if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC2) != RESET)
  {
    if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC2) != RESET)
    {
      __HAL_TIM_CLEAR_IT(htim, TIM_IT_CC2);
      htim->Channel = HAL_TIM_ACTIVE_CHANNEL_2;
      /* Input capture event */
      if ((htim->Instance->CCMR1 & TIM_CCMR1_CC2S) != 0x00U)
      {
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
        htim->IC_CaptureCallback(htim);
#else
        HAL_TIM_IC_CaptureCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
      }
      /* Output compare event */
      else
      {
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
        htim->OC_DelayElapsedCallback(htim);
        htim->PWM_PulseFinishedCallback(htim);
#else
        HAL_TIM_OC_DelayElapsedCallback(htim);
        HAL_TIM_PWM_PulseFinishedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
      }
      htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
    }
  }
  /* Capture compare 3 event */
  if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC3) != RESET)
  {
    if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC3) != RESET)
    {
      __HAL_TIM_CLEAR_IT(htim, TIM_IT_CC3);
      htim->Channel = HAL_TIM_ACTIVE_CHANNEL_3;
      /* Input capture event */
      if ((htim->Instance->CCMR2 & TIM_CCMR2_CC3S) != 0x00U)
      {
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
        htim->IC_CaptureCallback(htim);
#else
        HAL_TIM_IC_CaptureCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
      }
      /* Output compare event */
      else
      {
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
        htim->OC_DelayElapsedCallback(htim);
        htim->PWM_PulseFinishedCallback(htim);
#else
        HAL_TIM_OC_DelayElapsedCallback(htim);
        HAL_TIM_PWM_PulseFinishedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
      }
      htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
    }
  }
  /* Capture compare 4 event */
  if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC4) != RESET)
  {
    if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC4) != RESET)
    {
      __HAL_TIM_CLEAR_IT(htim, TIM_IT_CC4);
      htim->Channel = HAL_TIM_ACTIVE_CHANNEL_4;
      /* Input capture event */
      if ((htim->Instance->CCMR2 & TIM_CCMR2_CC4S) != 0x00U)
      {
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
        htim->IC_CaptureCallback(htim);
#else
        HAL_TIM_IC_CaptureCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
      }
      /* Output compare event */
      else
      {
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
        htim->OC_DelayElapsedCallback(htim);
        htim->PWM_PulseFinishedCallback(htim);
#else
        HAL_TIM_OC_DelayElapsedCallback(htim);
        HAL_TIM_PWM_PulseFinishedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
      }
      htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
    }
  }
  /* TIM Update event */
  if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_UPDATE) != RESET)
  {
    if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_UPDATE) != RESET)
    {
      __HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
      htim->PeriodElapsedCallback(htim);
#else
      HAL_TIM_PeriodElapsedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
    }
  }
  /* TIM Break input event */
  if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_BREAK) != RESET)
  {
    if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_BREAK) != RESET)
    {
      __HAL_TIM_CLEAR_IT(htim, TIM_IT_BREAK);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
      htim->BreakCallback(htim);
#else
      HAL_TIMEx_BreakCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
    }
  }
  /* TIM Trigger detection event */
  if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_TRIGGER) != RESET)
  {
    if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_TRIGGER) != RESET)
    {
      __HAL_TIM_CLEAR_IT(htim, TIM_IT_TRIGGER);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
      htim->TriggerCallback(htim);
#else
      HAL_TIM_TriggerCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
    }
  }
  /* TIM commutation event */
  if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_COM) != RESET)
  {
    if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_COM) != RESET)
    {
      __HAL_TIM_CLEAR_IT(htim, TIM_FLAG_COM);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
      htim->CommutationCallback(htim);
#else
      HAL_TIMEx_CommutCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
    }
  }
}
  • 📝main.c程序

🔖内含一些无关的测试函数和代码。

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
//TIM5输入通道1:PA0
/* TIM5CH1_CAP_STA 各数据位说明
** bit7   捕获完成标志
** bit6   捕获到高电平标志
** bit5~0 捕获高电平后定时器溢出的次数*/
uint8_t TIM5CH1_CAP_STA = 0;
uint16_t TIM5CH1_CAP_VAL;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/*
for循环实现延时us
*/
static void for_delay_us(uint32_t nus)
{
    uint32_t Delay = nus * 72 / 4;//72MHz
    do
    {
        __NOP();
    }
    while(Delay --);
}
void delay_us(uint32_t udelay)
{
    uint32_t startval, tickn, delays, wait;

    startval = SysTick->VAL;
    tickn = HAL_GetTick();
    //sysc = 72000;  //SystemCoreClock / (1000U / uwTickFreq);
    delays = (udelay-3) * 72; //-3修正,sysc / 1000 * udelay;
    if(delays > startval)
    {
        while(HAL_GetTick() == tickn)
        {

        }
        wait = 72000 + startval - delays;
        while(wait < SysTick->VAL)
        {

        }
    }
    else
    {
        wait = startval - delays;
        while(wait < SysTick->VAL && HAL_GetTick() == tickn)
        {

        }
    }
}
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
    /* USER CODE BEGIN 1 */
    long long temp = 0;
    /* USER CODE END 1 */

    /* MCU Configuration--------------------------------------------------------*/

    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    HAL_Init();

    /* USER CODE BEGIN Init */

    /* USER CODE END Init */

    /* Configure the system clock */
    SystemClock_Config();

    /* USER CODE BEGIN SysInit */

    /* USER CODE END SysInit */

    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_TIM5_Init();
    MX_USART1_UART_Init();
    /* USER CODE BEGIN 2 */
    HAL_TIM_IC_Start_IT(&htim5, TIM_CHANNEL_1);   //一定要开启TIM5通道1的捕获中断,TIM5通道1:PA0
    __HAL_TIM_ENABLE_IT(&htim5, TIM_IT_UPDATE);   //一定要开启TIM5的更新中断
    printf("This is TIM_CAP test...\n");
    /* USER CODE END 2 */

    /* Infinite loop */
    /* USER CODE BEGIN WHILE */
    while(1)
    {
        /* USER CODE END WHILE */

        /* USER CODE BEGIN 3 */

//			 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7,GPIO_PIN_SET);//用于产生超声波Trig触发信号
        GPIOA->BSRR = GPIO_PIN_7;
        //			for_delay_us(10);//超声波触发时间大于等于10us,不要超过1ms,否则不正常
        delay_us(500);
//        HAL_Delay(1);
//			__NOP(); __NOP(); __NOP(); __NOP();
//			__NOP(); __NOP(); __NOP(); __NOP();
//			__NOP(); __NOP(); __NOP(); __NOP();
//			__NOP(); __NOP(); __NOP(); __NOP();
//			 __NOP(); __NOP();__NOP();__NOP();
//         HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7,GPIO_PIN_RESET);
        GPIOA->BSRR = (uint32_t)GPIO_PIN_7 << 16u;
        if(TIM5CH1_CAP_STA & 0X80)      //完成一次高电平捕获
        {
            temp = TIM5CH1_CAP_STA & 0X3F;
            temp *= 65536;              //溢出总时间
            temp += TIM5CH1_CAP_VAL;    //总的高电平时间
            temp /= 4; //TIM5:4MHz
            printf("High level duration:%lld us\r\n", temp);
            TIM5CH1_CAP_STA = 0;        //准备下一次捕获
        }
        HAL_Delay(1000);
        HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_5);
        HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5);
    }
    /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    /** Initializes the RCC Oscillators according to the specified parameters
    * in the RCC_OscInitTypeDef structure.
    */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
    RCC_OscInitStruct.HSIState = RCC_HSI_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
    if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
        Error_Handler();
    }

    /** Initializes the CPU, AHB and APB buses clocks
    */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
                                  | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

    if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
    {
        Error_Handler();
    }
}

/* USER CODE BEGIN 4 */

//定时器更新中断处理回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim)
{
    if((TIM5CH1_CAP_STA & 0X80) == 0)   //还未成功捕获
    {
        if(TIM5CH1_CAP_STA & 0X40)      //已经捕获到高电平
        {
            if((TIM5CH1_CAP_STA & 0X3F) == 0X3F)    //高电平时间太长了
            {
                TIM5CH1_CAP_STA |= 0X80;            //标记为完成一次捕获
                TIM5CH1_CAP_VAL = 0XFFFF;           //计数器值
            }
            else
                TIM5CH1_CAP_STA++;      //溢出次数加1
        }
    }
}
//输入捕获中断处理回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef* htim)
{
    if((TIM5CH1_CAP_STA & 0X80) == 0)   //还未成功捕获
    {
        if(TIM5CH1_CAP_STA & 0X40)      //捕获到上升沿后条件为真
        {
            TIM5CH1_CAP_STA |= 0X80;    //标记为完成一次高电平捕获
            TIM5CH1_CAP_VAL = HAL_TIM_ReadCapturedValue(&htim5, TIM_CHANNEL_1); //获取当前的计数器值
            TIM_RESET_CAPTUREPOLARITY(&htim5, TIM_CHANNEL_1);   //清除原来的设置
            TIM_SET_CAPTUREPOLARITY(&htim5, TIM_CHANNEL_1, TIM_ICPOLARITY_RISING);  //设置上升沿捕获
        }
        else
        {
            TIM5CH1_CAP_STA = 0;
            TIM5CH1_CAP_VAL = 0;
            TIM5CH1_CAP_STA |= 0X40;    //标记捕获到上升沿
            __HAL_TIM_DISABLE(&htim5);  //关闭定时器
            __HAL_TIM_SET_COUNTER(&htim5, 0);   //计数器值清零
            TIM_RESET_CAPTUREPOLARITY(&htim5, TIM_CHANNEL_1);   //清除原来的设置
            TIM_SET_CAPTUREPOLARITY(&htim5, TIM_CHANNEL_1, TIM_ICPOLARITY_FALLING); //设置下降沿捕获
            __HAL_TIM_ENABLE(&htim5);   //使能定时器
        }
    }
}
/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
    /* USER CODE BEGIN Error_Handler_Debug */
    /* User can add his own implementation to report the HAL error return state */
    __disable_irq();
    while(1)
    {
    }
    /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t* file, uint32_t line)
{
    /* USER CODE BEGIN 6 */
    /* User can add his own implementation to report the file name and line number,
       ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
    /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

  • 👉🏻HC-SR04超声波测距相关代码
//		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7,GPIO_PIN_SET);//用于产生超声波Trig触发信号
        GPIOA->BSRR = GPIO_PIN_7;//Echo
       for_delay_us(15);//超声波触发时间大于等于10us,不要超过1ms,否则不正常
  //         HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7,GPIO_PIN_RESET);
        GPIOA->BSRR = (uint32_t)GPIO_PIN_7 << 16u;
        if(TIM5CH1_CAP_STA & 0X80)      //完成一次高电平捕获
        {
            temp = TIM5CH1_CAP_STA & 0X3F;
            temp *= 65536;              //溢出总时间
            temp += TIM5CH1_CAP_VAL;    //总的高电平时间
            temp /= 4; //TIM5:4MHz
      float     dist = high_time / 1000.0 * 340 / 2;//cm
            printf("High level duration:%lld us, %.2f \r\n", temp,dist);
            TIM5CH1_CAP_STA = 0;        //准备下一次捕获
        }

📚工程源码

链接:https://pan.baidu.com/s/17dt-7ESvB01K304rGhrG8w 
提取码:dgkj

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/781153.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

代码随想录算法训练营第二十一天 | 读PDF复习环节1

读PDF复习环节1 本博客的内容只是做一个大概的记录&#xff0c;整个PDF看下来&#xff0c;内容上是不如代码随想录网站上的文章全面的&#xff0c;并且PDF中有些地方的描述&#xff0c;是很让我疑惑的&#xff0c;在困扰我很久后&#xff0c;无意间发现&#xff0c;其网站上的讲…

JavaEE——Spring中存取Bean的注解

目录 一、存储Bean对象 1、定义 2、存储方式 &#xff08;1&#xff09;、类注解 【1】、Controller&#xff08;控制器存储&#xff09; 【2】、Service&#xff08;服务存储&#xff09; 【3】、Repository&#xff08;仓库存储&#xff09; 【4】、Component&#xf…

创造型模式-原型模式(场景体验-》方案解决===代码图解)

创造型模式-原型模式 创建重复对象-场景体验解决方案&#xff08;原型模式&#xff09;原型模式定义 创建重复对象-场景体验 今天来一个大客户&#xff0c;他要求帮他下100个订单。每个订单除了用户ID&#xff0c;和用户名不同之外&#xff0c;其他个人信息完全相同。 订单类 …

DASCTF 2023 0X401七月暑期挑战赛RE题解

比赛期间没有什么时间&#xff0c;赛后做的题。 TCP 这题最难&#xff0c;耗时最久&#xff0c;好像做出来的人不多。 程序开始有个初始化随机数的过程&#xff0c;数据写入qword_5060开始的48个字节。 这里是主函数&#xff0c;连接到服务器以后&#xff0c;先接收32个字节…

c函数学习

函数的概念 函数是c语言的功能单位&#xff0c;实现一个功能可以封装一个函数来实现。定义函数的时候一切以功能为目的&#xff0c;根据功能去定义函数的参数和返回值 函数的分类 从定义角度分类&#xff1a;库函数&#xff08;c库实现的&#xff09;&#xff0c;自定义函数&…

springboot集成

maven配置 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency><groupId>org.apache.commons</groupId><artifactId>…

小程序中vant-weapp时间选择使用方法

一、选择单个时间点&#xff1a; wxml&#xff1a; <van-celltitle"选择预约时间"value"{{ time }}"bind:click"onDisplay"/><van-calendarshow"{{ show }}"bind:close"onClose"bind:confirm"onConfirm"…

数学建模学习(3):综合评价类问题整体解析及分析步骤

一、评价类算法的简介 对物体进行评价&#xff0c;用具体的分值评价它们的优劣 选这两人其中之一当男朋友&#xff0c;你会选谁&#xff1f; 不同维度的权重会产生不同的结果 所以找到每个维度的权重是最核心的问题 0.25 二、评价前的数据处理 供应商ID 可靠性 指标2 指…

Redis应用(2)——Redis的项目应用(一):验证码 ---> UUID到雪花ID JMeter高并发测试 下载安装使用

目录 引出Redis的项目应用&#xff08;一&#xff09;&#xff1a;验证码1.整体流程2.雪花ID1&#xff09;UUID&#xff08;Universally Unique Identifier&#xff0c;通用唯一识别码&#xff09;2&#xff09;Twitter 的雪花算法&#xff08;SnowFlake&#xff09; 雪花ID优缺…

Jenkins常用管理功能配置 - 插件管理

Jenkins插件介绍 Jenkins是一个流行的开源持续集成/持续交付(CI/CD)工具&#xff0c;它有大量的插件来扩展其功能。这些插件可以用于构建、测试、部署和监控软件项目。下面是一些常用的Jenkins插件及其简单介绍和使用方法&#xff1a; 1. Git插件&#xff1a;允许Jenkins从Gi…

网络概念,《TCP/IP五层网络模型》与《数据的网络传输---“封装”与“分用”过程》

文章目录 概念协议协议分层TCP/IP五层网络模型数据的网络传输---“封装”与“分用”“封装”与“分用” 的过程 接收过程 概念 局域网&#xff1a;把一些设备通过交换机/路由器连接起来。 广域网&#xff1a;把更多的局域网也相互连接称为广域网。 交换机&#xff1a;交换机是…

采用桥接模式使虚拟机\笔记本\linux台式机互通

目录 一、环境&#xff1a;二、连接模式1. 桥接模式2. 主机共享模式3. NAT模式 三、配置1. 笔记本WIFI网络配置2. VM配置3.虚拟机配置3.1. 先看网络信息&#xff0c;确定修改ens333.2. 修改ens333.3. 重启网络 四、测试五、错误解决5.1 现象5.2 解决办法5.3 结果 一、环境&…

Spring中Bean的作用域和Spring生命周期

从前面的文章中我们看出Spring是用来存储和读取Bean的&#xff0c;因此Spring中Bean是最核心的资源&#xff0c;所以我们将对Bean进行深入的理解。 Bean的作用域 现在有一个公共的Bean&#xff0c;提供给了两个用户去使用&#xff0c;但是在使用过程中&#xff0c;用户一修改…

Android Studio 修改AVD模拟器文件默认存储路径

AndroidStudio默认的模拟器文件路径为&#xff1a;C:\Users\用户名\.android\avd路径&#xff0c;通常windows系统上&#xff0c;C盘不是太大&#xff0c;而avd文件却不小&#xff0c;通常几个GB&#xff0c;所以有必要将avd路径换到一个非系统盘。 更换方法如下&#xff1a;H…

LeetCode:6. N 字形变换

&#x1f34e;道阻且长&#xff0c;行则将至。&#x1f353; &#x1f33b;算法&#xff0c;不如说它是一种思考方式&#x1f340; 算法专栏&#xff1a; &#x1f449;&#x1f3fb;123 题解目录 一、&#x1f331;[6. N 字形变换](https://leetcode.cn/problems/zigzag-conv…

5.3 Bootstrap 模态框(Modal)插件

文章目录 Bootstrap 模态框&#xff08;Modal&#xff09;插件用法选项方法事件 Bootstrap 模态框&#xff08;Modal&#xff09;插件 模态框&#xff08;Modal&#xff09;是覆盖在父窗体上的子窗体。通常&#xff0c;目的是显示来自一个单独的源的内容&#xff0c;可以在不离…

C语言:杨氏矩阵中查找某数(时间复杂度小于O(N))

题目&#xff1a; 有一个数字矩阵&#xff08;二维数组&#xff09;&#xff0c; 矩阵的每行从左到右是递增的&#xff0c;矩阵从上到下是递增的&#xff0c; 请编写程序在这样的矩阵中查找某个数字是否存在&#xff0c; 要求&#xff1a;时间复杂度小于O(N)。 思路&#xff1…

Linux中docker的基本操作

文章目录 一、docker概述1.1 什么是docker1.2 Docker与虚拟机的特性区别1.3 容器在内核中支持2种重要技术1.4 docker的核心概念 二、安装docker三、Docker 镜像操作四、Docker 容器操作 一、docker概述 1.1 什么是docker 是一个开源的应用容器引擎&#xff0c;基于go语言开发…

Spring Web MVC 详解(1)

目录 一、介绍 MVC 二、Spring MVC 的三个基本功能 1.1 连接功能 1.2 Spring MVC 的创建和使用 1.3 RequestMappig 介绍 1.4 Spring MVC 实现用户和 Spring 程序的连接 1.5 GetMapping 和 PostMaping 注解 1.6 Get 和 Post请求注解的多种写法 2.1 获取请求中参数的功…

Redis的内存回收与内存淘汰策略

对于redis这样的内存型数据库而言&#xff0c;如何删除已过期的数据以及如何在内存满时回收内存是一项很重要的工作。 常见的redis内存回收的工作主要分为两个方面&#xff1a; 清理过期的key在内存不足时回收到足够的内存用以存储新的key 清理过期的key 我们很少在redis中…