【stm32简单外设篇】- HC-SR04 超声波测距模块

一、适用场景

适用场景:距离测量(避障小车、液位检测、门/物体接近报警)、简单测距仪、机器人避障、环境感知原型与嵌入式定时/中断练习。

二、器材清单

HC-SR04 超声波模块 ×1

stm32f103(或其它 STM32)开发板 ×1

若干杜邦线(母对母/公对母)×1组

面包板 / 电源线(模块需稳定 5V)

三、工作原理(要点)

工作流程:MCU 向 TRIG 引脚发送至少 10µs 的高电平触发脉冲,模块发出 40kHz 超声波(8 个周期或更多);如果前方有物体,超声波被反射,模块在 ECHO 引脚输出一个高电平脉冲,脉冲宽度等于超声波从发射到接收的往返时间(µs)。

距离换算(常用公式):速度 ≈ 343 m/s(在 20°C),即 0.0343 cm/µs。往返时间需除以 2 得到单程距离:

distance_cm ≈ (time_us × 0.0343) / 2 ≈ time_us / 58.3。

在工程中常用近似整数公式:distance_cm = time_us / 58。

测量限制与超时:HC-SR04 有盲区(约 2cm 以下测量不稳定),最大量程通常 ~300--400 cm(超远时回波微弱)。对应 4m 的往返时间约 23.3 ms(400 cm × 58.3 ≈ 23320 µs),建议超时设 30ms。

四、接线示意
VCC → +5V

GND → GND

标准库

TRIG → PA3

ECHO → PA1

HAL库

TRIG → PA0

ECHO → PA8

五、示例代码

标准库

cpp 复制代码
#include "forward_direction.h"


int count;

void tim_init()
{	
	GPIO_InitTypeDef PA;
	NVIC_InitTypeDef nvic;
	TIM_TimeBaseInitTypeDef tim;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	
	PA.GPIO_Pin = GPIO_Pin_1 |  GPIO_Pin_2;
	PA.GPIO_Mode = GPIO_Mode_Out_PP;
	PA.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&PA);
	
	PA.GPIO_Pin = GPIO_Pin_3;
	PA.GPIO_Mode = GPIO_Mode_IPD;
	GPIO_Init(GPIOA,&PA);
	
	tim.TIM_Period = (1000-1);
	tim.TIM_Prescaler = (72-1);
	tim.TIM_ClockDivision = TIM_CKD_DIV1;
	tim.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInit(TIM2,&tim);
	
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	nvic.NVIC_IRQChannel = TIM2_IRQn;
	nvic.NVIC_IRQChannelPreemptionPriority = 0;
	nvic.NVIC_IRQChannelSubPriority = 0;
	nvic.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&nvic);
	
	TIM_Cmd(TIM2,DISABLE);
}

void start_hc()
{
	int i;
	GPIO_ResetBits(GPIOA,GPIO_Pin_1);
	GPIO_SetBits(GPIOA,GPIO_Pin_1);
	for(i=0;i<1000000;i++);
	GPIO_ResetBits(GPIOA,GPIO_Pin_1);
}

void opentime()
{
	TIM_SetCounter(TIM2,0);
	count = 0;
	TIM_Cmd(TIM2,ENABLE);
}

void closetime()
{
	TIM_Cmd(TIM2,DISABLE);
}

uint32_t get_time()
{
	uint32_t tim_time = 0;
	tim_time = count * 1000;
	tim_time+=TIM_GetCounter(TIM2);
	TIM_SetCounter(TIM2,0);
	return tim_time;
}
	

double get_area()
{
	uint32_t time = 0;
	start_hc();
	while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3) == 0);
	opentime();
	while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3) == 1);
	closetime();
	
	time = get_time();
	return ((double)time*0.034/2);
}

void TIM2_IRQHandler()
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)
	{
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
		count++;
	}
}

int main()
{
	double dismiddle;
	int j;
	tim_init();
	while(1)
	{
		dismiddle = get_area();
		if(dismiddle < 10)
		{
			GPIO_SetBits(GPIOA,GPIO_Pin_2);
		}else
		{
			GPIO_ResetBits(GPIOA,GPIO_Pin_2);
		}
		for(j=0;j<1000000;j++);
	}
//	return 0;
}

HAL库

cpp 复制代码
int main(void)
{

  /* USER CODE BEGIN 1 */
	char usart[20]={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_TIM1_Init();
  MX_USART3_UART_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		//1.让计数器CNT归零
		__HAL_TIM_SET_COUNTER(&htim1,0);
		//2.清除cC1\cC2标志位
		__HAL_TIM_CLEAR_FLAG(&htim1,TIM_FLAG_CC1);
		__HAL_TIM_CLEAR_FLAG(&htim1,TIM_FLAG_CC2);
		//3.启动输入捕获
		HAL_TIM_IC_Start(&htim1,TIM_CHANNEL_1);
		HAL_TIM_IC_Start(&htim1,TIM_CHANNEL_2);
		//4.向Trig发送脉冲
		HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_SET);
//		for (volatile uint32_t i = 0; i < 15; i++);
		for(uint32_t i=0; i<10; i++); 
		HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET);
		//5.等待测量结束
		uint8_t success=0;
		uint32_t expireTime = HAL_GetTick()+ 50;
		while(expireTime > HAL_GetTick())
		{
			uint32_t cc1Flag = __HAL_TIM_GET_FLAG(&htim1,TIM_FLAG_CC1);
			uint32_t cc2Flag = __HAL_TIM_GET_FLAG(&htim1,TIM_FLAG_CC2);
			if(cc1Flag && cc2Flag)
			{
				success = 1;
				break;
			}
		}
		//6.关闭定时器
		HAL_TIM_IC_Stop(&htim1,TIM_CHANNEL_1);
		HAL_TIM_IC_Stop(&htim1,TIM_CHANNEL_2);
		//7.计算测量结果
		if(success ==1)
		{
			uint16_t ccr1 = __HAL_TIM_GET_COMPARE(&htim1,TIM_CHANNEL_1);
			uint16_t ccr2 = __HAL_TIM_GET_COMPARE(&htim1,TIM_CHANNEL_2);
			float pulseWidth = (ccr2 - ccr1) * 1e-6f;
			float distance = 340.0f * pulseWidth / 2.0f;
			sprintf(usart,"%.3lf\r\n",distance);
		  HAL_UART_Transmit(&huart3,usart,strlen(usart),HAL_MAX_DELAY);
			if(distance < 0.2)
				HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);
			else
				HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);
		}

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

六、讲解视频

https://www.bilibili.com/video/BV16NSwBhEHx/?spm_id_from=333.1387.upload.video_card.click&vd_source=f7dfe1b14f260b9cc3a146d2dbfd0719

https://www.bilibili.com/video/BV1aHSwBSEyT/?spm_id_from=333.1387.upload.video_card.click&vd_source=f7dfe1b14f260b9cc3a146d2dbfd0719

https://www.bilibili.com/video/BV173SwBtERo/?spm_id_from=333.1387.upload.video_card.click&vd_source=f7dfe1b14f260b9cc3a146d2dbfd0719

相关推荐
SystickInt3 小时前
32 DMA实现ROM与RAM通信
stm32·单片机·嵌入式硬件
俊昭喜喜里5 小时前
STM32开发板电源设计( DCDC 电路和 LDO 电路 )
stm32·单片机·嵌入式硬件
m0_555762905 小时前
方案再再对比
单片机
路弥行至5 小时前
FreeRTOS任务管理详解中: FreeRTOS任务创建与删除实战教程(动态方法)
c语言·开发语言·笔记·stm32·操作系统·freertos·入门教程
boneStudent6 小时前
Day20:串口基本配置与收发
stm32·单片机·嵌入式硬件
了一梨6 小时前
外设与接口:input子系统
linux·c语言
紫阡星影6 小时前
基于Arduino模拟烟雾监测系统
单片机·嵌入式硬件·arduino
我是华为OD~HR~栗栗呀6 小时前
23届(华为od)-C开发面经
java·c语言·c++·python·华为od·华为·面试
liu****6 小时前
8.栈和队列
c语言·开发语言·数据结构·c++·算法
HIZYUAN7 小时前
嵌入式开发踩坑记: AG32硬件设计指南(一)
stm32·单片机·嵌入式硬件·fpga开发·硬件设计·最小系统·agm ag32