【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

相关推荐
逐步前行14 分钟前
STM32_外部中断_寄存器操作
stm32·单片机·嵌入式硬件
程序猿编码15 分钟前
轻量又灵活:一款伪造TCP数据包的iptables扩展实现解析(C/C++代码实现)
linux·c语言·网络·c++·tcp/ip·内核·内核模块
AI科技星42 分钟前
从v=c螺旋时空公理出发的引力与电磁常数大统一
c语言·开发语言·人工智能·线性代数·算法·矩阵·数据挖掘
J987T1 小时前
C语言、微机原理等
c语言·开发语言
Saniffer_SH1 小时前
【高清视频】AI服务器调试利器:PCIe功耗分析设备 Quarch PAM 深度解析
网络·人工智能·驱动开发·嵌入式硬件·测试工具·计算机外设·压力测试
安庆平.Я1 小时前
STM32——FreeRTOS - 任务创建和删除*
stm32·单片机·嵌入式硬件
BT-BOX9 小时前
第三章|新建STM32CubeMX工程生成keil工程和proteus联调仿真
stm32·嵌入式硬件·proteus
努力中的编程者10 小时前
栈和队列(C语言底层实现环形队列)
c语言·开发语言
forAllforMe10 小时前
用STM32+LAN9252, 生成一个etherCAT 从机系统,实现数据采集功能
网络·stm32·嵌入式硬件
一叶落43810 小时前
题目:15. 三数之和
c语言·数据结构·算法·leetcode