STM32F103C8T6与HC-SR04超声波测距模块集成应用详解

引言

       在嵌入式系统开发中,距离测量是一个常见的需求,而HC-SR04超声波测距模块因其简单易用和成本低廉而广受欢迎。本文将结合两篇优秀的博客文章,详细介绍如何使用STM32F103C8T6微控制器与HC-SR04模块结合进行距离测量,并展示如何通过LED灯或OLED屏幕显示测量结果。

硬件准备

  • STM32F103C8T6开发板
  • HC-SR04超声波测距模块
  • LED灯或OLED屏幕(用于显示结果)
  • 杜邦线若干
  • 烧录器(如ST-Link)
  • 软件环境

  • 开发工具:Keil MDK
  • 配置工具:STM32CubeMX
  • 串口助手或OLED显示库(可选)
  • HC-SR04超声波测距模块

           HC-SR04是一款能够提供2cm至400cm范围内精度为3mm的超声波测距模块。它通过发送超声波脉冲并接收回波来测量距离。工作原理是模块发出至少10us的高电平信号后,自动发送8个40kHz的方波并检测回波信号。回波信号的高电平持续时间即为超声波往返时间,通过公式计算出实际距离。

    STM32CubeMX配置

    1. 芯片选择:选择STM32F103C8T6微控制器。

    2.时钟配置:配置RCC、SYS和时钟树以确保系统稳定运行。

     

     

     

    3.GPIO配置:将HC-SR04的Trig和Echo引脚分别连接到STM32的GPIO,并配置相应的模式。

    4.串口配置(如果使用串口助手):配置串口用于调试输出。

    5.定时器配置:配置定时器并开启中断,用于测量超声波往返时间。

    程序编写

    主要思路

    1. 初始化:初始化GPIO、定时器、串口或OLED等外设。
    2. 测距逻辑:发送10us以上的高电平信号至Trig引脚启动测距,然后在Echo引脚等待高电平输出,记录高电平持续时间。
    3. 距离计算:根据高电平时间计算距离,公式为:距离(cm)=高电平时间(us)×3402×10000距离(cm)=2×10000高电平时间(us)×340​。

    代码实现

  • 主函数:设置系统时钟,初始化外设,进入主循环。
  • /* USER CODE BEGIN Header */
    /**
      ******************************************************************************
      * @file           : main.c
      * @brief          : Main program body
      ******************************************************************************
      * @attention
      *
      * <h2><center>&copy; Copyright (c) 2022 STMicroelectronics.
      * All rights reserved.</center></h2>
      *
      * This software component is licensed by ST under BSD 3-Clause license,
      * the "License"; You may not use this file except in compliance with the
      * License. You may obtain a copy of the License at:
      *                        opensource.org/licenses/BSD-3-Clause
      *
      ******************************************************************************
      */
    /* USER CODE END Header */
    /* Includes ------------------------------------------------------------------*/
    #include "main.h"
    #include "tim.h"
    #include "usart.h"
    #include "gpio.h"
    
    /* Private includes ----------------------------------------------------------*/
    /* USER CODE BEGIN Includes */
    #include "SR04.h"
    #include "led.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 */
    
    /* 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_TIM2_Init();
      MX_USART1_UART_Init();
      /* USER CODE BEGIN 2 */
    
      /* USER CODE END 2 */
    
      /* Infinite loop */
      /* USER CODE BEGIN WHILE */
      while (1)
      {
          
          float distance = SR04_GetData();
          //HAL_Delay(1500);
          
        /* USER CODE END WHILE */
    
    	  // 根据距离计算闪烁频率
          uint32_t flashRate = CalculateFlashRate(distance);
            
          LED_Flash(flashRate); // 闪烁LED
        /* 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 */
    
    
  • 定时器中断:在Echo检测到高电平时开始计时,检测到低电平时停止计时并计算时间差。
  • #ifndef __SR04_H
    #define __SR04_H
    #include "main.h"
    #include "tim.h"
    #include "stdio.h"
    
    #define TRIG_H  HAL_GPIO_WritePin(Trig_GPIO_Port,Trig_Pin,GPIO_PIN_SET)
    #define TRIG_L  HAL_GPIO_WritePin(Trig_GPIO_Port,Trig_Pin,GPIO_PIN_RESET)
    
    void delay_us(uint32_t us);
    float SR04_GetData(void);
    
    #endif
    
    

  • #include "SR04.h"
    #include "stm32f1xx_hal.h" 
    
    float distant;      //测量距离
    uint32_t measure_Buf[3] = {0};   //存放定时器计数值的数组
    uint8_t  measure_Cnt = 0;    //状态标志位
    uint32_t high_time;   //超声波模块返回的高电平时间
    
    
    //===============================================读取距离
    float SR04_GetData(void)
    {
        switch (measure_Cnt)
        {
            case 0:
                TRIG_H;
                delay_us(30);
                TRIG_L;
                measure_Cnt++;
                __HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING);
                HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1); // 启动输入捕获
                break;
            case 3:
                high_time = measure_Buf[1] - measure_Buf[0]; // 高电平时间
                printf("\r\n----高电平时间-%d-us----\r\n", high_time);
                float distance = (high_time * 0.034f) / 2; // 单位cm
                printf("\r\n-检测距离为-%.2f-cm-\r\n", distance);
                measure_Cnt = 0; // 清空标志位
                TIM2->CNT = 0; // 清空计时器计数
                // 返回计算得到的距离值
                return distance;
        }
        return 0; // 如果没有测量完成,返回0或合适的默认值
    }
    
    
    //===============================================us延时函数
        void delay_us(uint32_t us)//主频72M
    {
        uint32_t delay = (HAL_RCC_GetHCLKFreq() / 4000000 * us);
        while (delay--)
    	{
    		;
    	}
    }
    
    //===============================================中断回调函数
    void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)//
    {
    	
    	if(TIM2 == htim->Instance)// 判断触发的中断的定时器为TIM2
    	{
    		switch(measure_Cnt){
    			case 1:
    				measure_Buf[0] = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1);//获取当前的捕获值.
    				__HAL_TIM_SET_CAPTUREPOLARITY(&htim2,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING);  //设置为下降沿捕获
    				measure_Cnt++;                                            
    				break;              
    			case 2:
    				measure_Buf[1] = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1);//获取当前的捕获值.
    				HAL_TIM_IC_Stop_IT(&htim2,TIM_CHANNEL_1); //停止捕获   或者: __HAL_TIM_DISABLE(&htim5);
    				measure_Cnt++;  
                             
    		}
    	
    	}
    	
    }
    
    
    
  • 外部中断:可选,用于更精细的控制测距过程。
  • 显示结果

  • LED灯:通过改变LED闪烁频率来反映距离变化。
  • OLED屏幕:显示实时测量的距离数值。
  • 结论

           本文介绍了STM32F103C8T6与HC-SR04超声波测距模块的结合使用,通过CubeMX的图形化配置和Keil MDK的开发环境,简化了开发流程并提高了开发效率。同时,通过实际代码示例,展示了如何实现超声波测距并展示结果。

    引用

    STM32F103C8T6 & HC-SR04超声波模块——超声波障碍物测距(HAl库)_stm32f103c8t6与hcsr04超声波-CSDN博客 https://www.cnblogs.com/soliang/p/17870635.html

    作者:2401_83651138

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32F103C8T6与HC-SR04超声波测距模块集成应用详解

    发表回复