【STM32 HAL库】超声波测距实现与输入捕获

文章目录

  • HC-SR04 超声波模块简介
  • HC-SR04 工作原理
  • 如何使用HC-SR04模块
  • 程序效果
  • 一、工程配置
  • 代码
  • 如果您发现文章有错误请与我留言,感谢

  • HC-SR04 超声波模块简介

    HC-SR04 工作原理

    模块有2个超声波换能器(如图所示),一个发出声波,另一个接收物体反射回来的声波,这中间所经过的时间即声波传播的时间,再结合声速就能计算出:

  • 距离 = 声速 * 时间 ÷ 2请添加图片描述
  • 如何使用HC-SR04模块

    模块具有4个引脚,除了电源外,有TRIG、ECHO两个引脚需要操作:

  • 首先,向TRIG引脚发送一个高电平脉冲,来触发模块输出声波
  • 记录ECHO引脚输出高电平的时间,即声波的飞行时间
  • 距离 = 声速(340m/s) * 声波的飞行时间 ÷ 2
  • 请添加图片描述

  • 连接模块时请核对好线序:
  • 程序效果


    一、工程配置

  • 开启外部晶振:在Pinout&Configuration -> System Core -> RCC 页面,将 High Speed Clock (HSE) 配置为 Crystal/Ceramic Resonator请添加图片描述
  • 配置时钟频率:在Clock Configuration 页面,将PLL Source 选择为 HSE,将System Clock Mux 选择为 PLLCLK,然后在HCLK (MHz) 输入72并回车,将HCLK频率配置为 72 MHz
  • 请添加图片描述

  • 分配引脚:在Pinout&Configuration页面,将PA11、PA10分别配置为GPIO_Output、TIM1_CH3,并将PA11命名为TRIG
  • 配置TIM1:在Pinout&Configuration -> Timers -> TIM1
  • Mode -> Clock Source 设为 Internal Clock,Channel3 设为 Input Capture direct mode,即输入捕获
  • Configuration -> Parameter Settings -> Counter Settings -> Prescaler 设为 72-1,使定时器计数周期刚好为 1 us
  • Configuration -> NVIC Settings -> 勾选TIM1 capture compare interrupt,开启捕获中断
    请添加图片描述
  • 打开I2C1
  • 加上.c/.h文件


    代码

    复制四个文件

    我的Github

    main.c

    /* USER CODE BEGIN Header */
    /**
      ******************************************************************************
      * @file           : main.c
      * @brief          : Main program body
      ******************************************************************************
      * @attention
      *
      * Copyright (c) 2024 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 "i2c.h"
    #include "tim.h"
    #include "gpio.h"
    
    /* Private includes ----------------------------------------------------------*/
    /* USER CODE BEGIN Includes */
    #include <oled.h>
    #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 */
    
    /* 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 */
    
    //2 数据计算
    
    int upEdge = 0;//获取上升沿时刻计数值
    int downEdge = 0;//获取下降沿时刻计数值
    float distance = 0;
    
    // 输入捕获中断回调函数
    void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
    {
      if(htim == &htim1 && htim -> Channel == HAL_TIM_ACTIVE_CHANNEL_4)
      {
    	  //使用捕获寄存器数值的函数HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_3);
    	  upEdge = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_3);
    	  downEdge = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_4);
    	  distance = ((downEdge - upEdge) * 0.034) / 2 ;
      }
    }
    /* USER CODE END 0 */
    
    /**
      * @brief  The application entry point.
      * @retval int
      */
    int main(void)
    {
      /* USER CODE BEGIN 1 */
    
      /* 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_I2C1_Init();
      MX_TIM1_Init();
      /* USER CODE BEGIN 2 */
     HAL_Delay(20);
     OLED_Init();
    
     HAL_TIM_Base_Start(&htim1);//启动计时器计数
    
     //启用定时器对应通道的输入捕获功能
     HAL_TIM_IC_Start(&htim1,TIM_CHANNEL_3);//开启通道3的输入捕获
     //HAL_TIM_IC_Start_IT  当输入信号发生边沿变化时,会触发中断
     //HAL_TIM_Base_Start_IT 当定时器的计数器溢出时,会触发中断
    
     //启动输入捕获
     HAL_TIM_IC_Start_IT(&htim1,TIM_CHANNEL_4);//开启通道4的输入捕获,启用定时器对应通道的输入捕获功能
      char message [50] = "";
      /* USER CODE END 2 */
    
      /* Infinite loop */
      /* USER CODE BEGIN WHILE */
      while (1)
      {
    	  //1 触发测量 2 数据计算 3 数据展示
    
    	  //1  首先触发超声模块测距,先将Trig拉高
    	  HAL_GPIO_WritePin(Trig_GPIO_Port, Trig_Pin, GPIO_PIN_SET);
    	  //经过一段时间在拉低
    	  HAL_GPIO_WritePin(Trig_GPIO_Port, Trig_Pin, GPIO_PIN_RESET);
    
    	  //触发计数器时清零,我们就不用考虑doemEdge > upEdge 的情况了
    	  __HAL_TIM_SET_COUNTER(&htim1,0);
    	  HAL_Delay(20);
    
    	  //3 数据展示
    	  //下来把数据显示在屏幕上
    	  //先套上新建针和显示帧的函数
    
    	  OLED_NewFrame();
    	  sprintf(message,"距离 = %.2fcm",distance);
    	  OLED_PrintString(0, 0, message, &font16x16, OLED_COLOR_NORMAL);
    	  OLED_ShowFrame();
    
    
        /* USER CODE END WHILE */
    
        /* USER CODE BEGIN 3 */
      }
      /* 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 */
    
    /* 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 */
    
    

    如果您发现文章有错误请与我留言,感谢

    作者:马职音人

    物联沃分享整理
    物联沃-IOTWORD物联网 » 【STM32 HAL库】超声波测距实现与输入捕获

    发表回复