基于STM32F103的超声波测距实现(HC-SR04 + TIM2)

前言

鉴于本人之前写过一篇关于STM32F103搭配HCSR04模块实现测距功能的文章,内容不清楚代码相对混乱以及源码未放出,可能对读者造成一定误导,现重新整理了一份,代码相对比较垃圾仅供参考,希望对有需求的提供一点帮助。旧文章链接https://blog.youkuaiyun.com/weixin_44234294/article/details/114147929?spm=1001.2014.3001.5501

HC-SR04超声波测距模块技术详解

在这里插入图片描述
HC-SR04是一款广泛应用的超声波测距模块,基于超声波回波时间测量原理实现非接触式距离检测。其低成本、高可靠性、易用性等特点,使其成为机器人避障、液位检测、智能家居等领域的常用传感器。以下是该模块的详细技术信息。

一、模块概述

1. 基本功能

  1. 测距原理:发射超声波(40kHz),接收回波,通过计算发射与回波的时间差(Time of Flight, ToF)计算距离。
  2. 测距范围:2cm ~ 400cm(理论值),实际有效范围约2cm ~ 300cm(受环境温度、障碍物材质影响)。
  3. 分辨率:约0.3cm(依赖定时器精度)。
  4. 工作电压:5V DC(兼容3.3V逻辑电平)。
  5. 工作电流:静态<2mA,触发时约15mA。

2. 模块外观与引脚定义

引脚名称功能描述连接方式
VCC电源输入(5V)接5V电源
Trig触发信号输入(高电平脉冲)接MCU的GPIO(输出)
Echo回响信号输出(高电平脉冲)接MCU的GPIO(输入)
GND电源地接GND

二、工作原理

1. 工作流程

触发信号:

  1. MCU向Trig引脚发送至少10µs的高电平脉冲。
  2. HC-SR04收到触发信号后,自动发射8个周期的40kHz超声波。

回波检测:

  1. 模块内部接收器检测到回波后,Echo引脚输出高电平脉冲,脉冲宽度与超声波往返时间成正比。
  2. 计算公式
    在这里插入图片描述

2. 时序图

在这里插入图片描述
Trig脉冲:最小10µs,建议10~20µs。
Echo脉冲:最大持续时间约38ms(对应6.5米),实际应用中建议设置超时检测(如30ms)

三、关键参数

1. 电气特性

参数
工作电压5V ±0.5V
工作电流(静态)<2mA
工作电流(触发时)~15mA
超声波频率40kHz
探测角度≤15度(圆锥形)

2.性能参数

参数
最小检测距离2cm
最大检测距离400cm(理论)
实际有效距离20cm ~ 300cm
测量精度±3mm(理想条件)
响应时间<100ms

代码思路

  1. 将Trig引脚介入单片机PB8引脚,Echo引脚接入PB9(可自由选择合适引脚),然后配置定时器(可自由选择,本人选择了定时器2);
  2. 定时器2的配置是关键。要求1MHz频率,即每个计数1微秒,这样计算时间比较方便。需要计算预分频值,系统时钟是72MHz,预分频值应为71,因为72MHz/(71+1)=1MHz。同时,定时器设置为自由运行模式,重装载值0xFFFF,即最大65535,对应65.535ms,足够覆盖HC-SR04的最大测量时间(约23.5ms),所以溢出不是问题。
  3. 将Trig拉高信号,发出高电平,输入方波后,模块会自动发射8个40KHz的声波,与此同时回波引脚(echo)端的电平会由0变为1;在此时我们获取当前计数值
    T1;当超声波返回被模块接收到时,回波(echo)引
    脚端的电平会由1变为0;我们再获取计数值T2,两个时间计数差值T3即为总时间,我们可以带入上面公式进行计算。
  4. 时间T3的单位是微秒,因为每个计数是1us。所以距离为 (T3 * 340 m/s) /2,但单位要转换。例如,340m/s等于34000cm/s,等于0.034cm/us。所以距离cm = (T3 * 0.034) / 2 = T3 * 0.017 cm。或者也可以写成T3* 17 / 1000 cm,或者T3/ 58.0 cm(因为 1/58 ≈ 0.01724,因为声速在空气中可能取343m/s,这时系数是34300 cm/s = 0.0343 cm/us,所以距离是 (T3 * 0.0343)/2 = T3 *0.01715 ≈ T3 /58.3)。

代码实现

bsp_hcsr04.c

#include "bsp_hcsr04.h"
#include "delay.h"


void HCSR04GpioConfig()
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_APB2PeriphClockCmd(HCSR04_RCC,ENABLE);
	 
	GPIO_InitStructure.GPIO_Pin 	= HCSR04_TX_PIN;   
	GPIO_InitStructure.GPIO_Speed 	= GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode 	= GPIO_Mode_Out_PP;
	GPIO_Init(HCSR04_GPIO_PORT, &GPIO_InitStructure);
	GPIO_ResetBits(HCSR04_GPIO_PORT,HCSR04_TX_PIN);
	 
	GPIO_InitStructure.GPIO_Pin 	= HCSR04_RX_PIN;     
	GPIO_InitStructure.GPIO_Mode 	= GPIO_Mode_IN_FLOATING;
	GPIO_Init(HCSR04_GPIO_PORT, &GPIO_InitStructure);  	
}

void Timer2Init()
{
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); 
	
	TIM_TimeBaseStructure.TIM_Period 		= 0xffff; 
	TIM_TimeBaseStructure.TIM_Prescaler 	= 72 -1 ; 
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; 
	TIM_TimeBaseStructure.TIM_CounterMode 	= TIM_CounterMode_Up;  
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
	
	TIM_Cmd(TIM2, ENABLE); 
}

float Hcsr04GetLength(void)
{
	uint16_t timeStart = 0;
	uint16_t timeEnd = 0;
	uint16_t timeLast = 0;
	float length = 0;
	float sum = 0;
	uint16_t i = 0;
	
	while(i != 5)
	{
		//trig拉高信号,发出高电平
		GPIO_SetBits(HCSR04_GPIO_PORT,HCSR04_TX_PIN);
		delay_us(20);
		GPIO_ResetBits(HCSR04_GPIO_PORT,HCSR04_TX_PIN);
		/*Echo发出信号 等待回响信号*/
		/*输入方波后,模块会自动发射8个40KHz的声波,与此同时回波引脚(echo)端的电平会由0变为1;
		(此时应该启动定时器计时);当超声波返回被模块接收到时,回波引 脚端的电平会由1变为0;
		(此时应该停止定时器计数),定时器记下的这个时间即为
		超声波由发射到返回的总时长;*/
		//echo等待回响
		while(GPIO_ReadInputDataBit(HCSR04_GPIO_PORT,HCSR04_RX_PIN) == 0);
		//记录放送时间T1
		timeStart = TIM2->CNT;
		i = i+1; //每收到一次回响信号+1,收到5次就计算均值
		while(GPIO_ReadInputDataBit(HCSR04_GPIO_PORT,HCSR04_RX_PIN) == 1);
		//记录接收时间T2
		timeEnd = TIM2->CNT;
		/*获取Echo高电平时间时间T3*/
		timeLast = (timeEnd > timeStart) ? (timeEnd - timeStart) : (0xffff - timeStart + timeEnd);
		//单位时cm
		length = (float)timeLast / 58;
		sum += length;		
	}
	
	length = sum / 5;
	
	return length;
}

void HCSR04Init()
{
	HCSR04GpioConfig();
	Timer2Init();
}



mian.c

#include "stm32f10x.h"
#include "delay.h"
#include "usart.h"
#include "bsp_hcsr04.h"

 int main(void)
 {	
	delay_init();
	HCSR04Init();
	uart_init(115200);
	 
	while(1)
	{
		printf("cur dis = %fcm\r\n",Hcsr04GetLength());
		delay_ms(1000);
	}
 }

实验结果

在这里插入图片描述
代码有所不足仅供参考,比如超时检测:若Echo信号长时间无下降沿,强制结束测量并标记为无效数据。
链接: https://pan.baidu.com/s/1m_PGSEfQ_RIFdEoxj_jBAQ 提取码: 65kn
有需要其他模块需要测试的可以留言,抽空会实现并写博文,如果对你有帮助的话,一键三连一下,谢谢!

以下是基于STM32F103C8T6和HC-SR04实现超声波测距的代码,使用的是STM32CubeMX和Keil IDE进行开发: 1. 首先在STM32CubeMX中配置GPIO和定时器: GPIOA_Pin0:超声波传感器的Trig引脚 GPIOA_Pin1:超声波传感器的Echo引脚 TIM2_CH2:用于捕获超声波回波信号的定时器通道 2. 在Keil IDE中编写代码: #include "main.h" TIM_HandleTypeDef htim2; void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_TIM2_Init(void); int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_TIM2_Init(); while (1) { uint32_t pulse_width = 0; uint32_t distance = 0; // 发送超声波信号 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); HAL_Delay(10); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); // 等待回波信号 while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET); uint32_t start_time = HAL_GetTick(); // 捕获回波信号 while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_SET); uint32_t end_time = HAL_GetTick(); pulse_width = end_time - start_time; distance = pulse_width * 17 / 1000; // 声速340m/s,除以2得到往返时间,乘以17得到距离(单位:毫米) } } 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.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(); } } static void MX_TIM2_Init(void) { TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0}; TIM_IC_InitTypeDef sConfigIC = {0}; htim2.Instance = TIM2; htim2.Init.Prescaler = 72 - 1; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 0xFFFF; htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; if (HAL_TIM_Base_Init(&htim2) != HAL_OK) { Error_Handler(); } sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) { Error_Handler(); } if (HAL_TIM_IC_Init(&htim2) != HAL_OK) { Error_Handler(); } sConfigIC.ICPolarity = TIM_ICPOLARITY_RISING; sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI; sConfigIC.ICPrescaler = TIM_ICPSC_DIV1; sConfigIC.ICFilter = 0; if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_2) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) { Error_Handler(); } } static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOA_CLK_ENABLE(); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_1; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLDOWN; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } void Error_Handler(void) { __disable_irq(); while (1) { } } 3. 在main函数中,首先发送超声波信号,等待回波信号,然后捕获回波信号,计算出距离。最后通过distance变量获取距离值。 注意事项: 1. 超声波传感器回波信号的宽度与距离成正比,需要使用定时器捕获回波信号的上升沿和下降沿,计算出回波信号的脉宽。 2. 超声波传感器的Trig引脚需要在发送超声波信号前置为高电平,发送完毕后置为低电平。 3. 超声波传感器的Echo引脚需要设置为输入模式,使用下拉电阻。 4. 定时器的时钟频率需要根据具体的系统时钟频率进行调整。 5. 超声波传感器的测量范围一般为2cm-4m,超出范围会出现误差。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值