STM32外设系列—HC-SR04(超声波)

2023-11-07 13:40

本文主要是介绍STM32外设系列—HC-SR04(超声波),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


🎀 文章作者:二土电子

🌸 关注文末公众号获取其他资料和工程文件!

🐸 期待大家一起学习交流!


文章目录

  • 一、超声波测距基本原理
  • 二、超声波传感器简介
  • 三、HC-SR04测距实现思路
  • 四、超声波测距程序实现
    • 4.1 HC-SR04初始化程序
    • 4.2 TIM开关程序
    • 4.3 获取定时时间
    • 4.4 计算测量距离
    • 4.5 宏定义
  • 五、应用实例
  • 六、拓展应用

一、超声波测距基本原理

超声波测距的原理非常简单,超声波发生器在某一时刻发出一个超声波信号,当这个超声波信号遇到被测物体后会反射回来,被超声波接收器接收到。这样只要计算出从发出超声波信号到接收到返回信号所用的时间,就可以计算出超声波发生器与反射物体的距离。

距离的计算公::d=s/2=(c*t)/2

其中 d 为被测物与测距器的距离,s 为声波的来回路程,c 为声波,t 为声波来回所用的时间。

由于超声波也是一种声波,其声速 c 与温度有关,在不同温度下的超声波声速不同。在使用时,如果温度变化不大,则可认为声速是基本不变的。如果测距精度要求很高,则应通过温度补偿的方法加以校正。声速校正后,只要测得超声波往返的时间,即可求得距离。不同外温度下的超声波声速表如下

不同温度下超声波声速表

补充说明

最近在问答区发现有小伙伴疑惑为什么在计算距离时是根据Echo输出的高电平持续时间来计算距离。这里简单解释一下,仅供参考

  1. 实际超声波测距的原理就是上面介绍的,记录的时间是从超声波发出到回波被接收的时间,然后这个时间除以2,再乘超声波的传播速度得到距离。超声波测距模块实际也是这么做的。模块内部会记录超声波发出的时刻,在接收到回波后会立刻以高电平的形式从Echo引脚输出高电平,高电平的持续时间就是超声波从发出到被接收到的时间间隔。这么做是模块为了方便单片机处理,快速得到超声波从发出到被接收到的时间间隔。
  2. 实际大家可以自己测试一下,初始化一个定时器,从给Trig引脚10us高电平结束时刻开启定时器,到Echo引脚接收到高电平的时刻停止计时,用这个时间来计算距离,实际和用高电平持续时间来计算距离得到的结果基本是相同的。
  3. 给Trig引脚10us高电平并不是说只发送10us的超声波。10us的高电平是为了触发模块工作。10us高电平结束后,模块会发送一个8个40KHz的方波。

二、超声波传感器简介

总体上讲,超声波发生器可以分为两大类:一类是用电气方式产生超声波类是用机械方式产生超声波。电气方式包括压电型、磁致伸缩型和电动型等:机械方式有加尔统笛、液哨和气流旋笛等。他们所产生的超声波的频率、功率和声波特性各不相同,因而用途也各不相同。目前较为常用的是压电式超声波发生。

压电式超声波发生器实际上是利用压电晶体的谐振来工作的。它有两个压电晶片和一个共振板。当它的两极外加脉冲信号,其频率等于压电晶片的固有振荡频率时,压电晶片将会发生共振,并带动共振板振动,便产生超声波。反之,如果两极间未外加电压,当共振板接收到超声波时,将压迫压电晶片作振动,将机械能转换为电信号,这时它就成为超声波接收器了。这里介绍的是一个超声波测距模块——HC-SR04。

HC-SR04

三、HC-SR04测距实现思路

这里就不再针对HC-SR04模块的原理和电路做详细介绍了,直接介绍利用该模块实现测距的思路。该模块有四个引脚。

  • VCC —— 通常是5V供电
  • GND —— 地
  • Trig —— 给该引脚大于10us的高电平,超声波发射头会发送一个超声波信号
  • Echo —— 该引脚在接收到返回的超声波信号后会变为高电平

Echo接收到的高电平持续时间即为超声波一个来回所用的时间,利用该时间除以2再乘上光速,即可得到测量距离。

四、超声波测距程序实现

4.1 HC-SR04初始化程序

HC-SR04初始化程序主要包括两部分,一部分是初始化HC-SR04的GPIO,Trig引脚设置为推挽式输出,Echo引脚设置为浮空输入。另一部分是初始化TIM2。初始化TIM2之后,没有立即使能,而是等到Echo接收到高电平的时刻,开启TIM2。

/**==============================================================================*函数名称:Drv_Hcsr04_Init*函数功能:初始化HC-SR04*输入参数:无*返回值:无*备  注:初始化HC-SR04引脚的同时,初始化了TIM2,用来记录高电平持续时间初始化完TIM2后,没有使能,当Echo收到高电平后使能*==============================================================================*/
void Drv_Hcsr04_Init (void)   // Hc-sr04初始化
{    // 结构体定义TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;   // 生成用于定时器设置的结构体  GPIO_InitTypeDef GPIO_InitStructure;   // GPIO结构体NVIC_InitTypeDef NVIC_InitStructure;   // NVIC结构体RCC_APB2PeriphClockCmd(HCSR04_CLK, ENABLE);   // 使能GPIO时钟// GPIO初始化  GPIO_InitStructure.GPIO_Pin =HCSR04_TRIG;   // 发送电平引脚  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   // 推挽式输出  GPIO_Init(HCSR04_PORT, &GPIO_InitStructure);  GPIO_ResetBits(HCSR04_PORT,HCSR04_TRIG);  GPIO_InitStructure.GPIO_Pin = HCSR04_ECHO;   // 返回电平引脚  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;   // 浮空输入  GPIO_Init(HCSR04_PORT, &GPIO_InitStructure);    GPIO_ResetBits(HCSR04_PORT,HCSR04_ECHO);      // 定时器初始化 使用基本定时器TIM2  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);   // 使能对应RCC时钟  // 配置定时器基础结构体  TIM_DeInit(TIM2);  TIM_TimeBaseStructure.TIM_Period = (1000-1);   // 设置在下一个更新事件装入活动的自动重装载寄存器周期的值(计数到1000为1ms ) TIM_TimeBaseStructure.TIM_Prescaler =(72-1);   // 设置用来作为TIMx时钟频率除数的预分频值  1M的计数频率 1US计数  TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;   // 不分频  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;   // TIM向上计数模式  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);   // 根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位         TIM_ClearFlag(TIM2, TIM_FLAG_Update);   // 清除更新中断,免得一打开中断立即产生中断  TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);   // 打开定时器更新中断  // NVIC配置	     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);   // 设置中断优先级分组为组2:2位抢占优先级,2位响应优先级 NVIC_InitStructure.NVIC_IRQChannel =TIM2_IRQn;   // 选择定时器2中断  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;   // 抢占式中断优先级设置为0  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;   // 响应式中断优先级设置为0  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;   // 使能中断  NVIC_Init(&NVIC_InitStructure);  TIM_Cmd(TIM2,DISABLE);       
}

4.2 TIM开关程序

/**==============================================================================*函数名称:Drv_Hcsr04_OpenTimerForHc*函数功能:打开定时器*输入参数:无*返回值:无*备  注:无*==============================================================================*/
void Drv_Hcsr04_OpenTimerForHc (void)   // 打开定时器  
{  TIM_SetCounter(TIM2,0);   // 清除计数  gMsHcCount = 0;  TIM_Cmd(TIM2, ENABLE);   // 使能TIMx外设  
}
/**==============================================================================*函数名称:Drv_Hcsr04_CloseTimerForHc*函数功能:关闭定时器*输入参数:无*返回值:无*备  注:无*==============================================================================*/
void Drv_Hcsr04_CloseTimerForHc (void)   // 关闭定时器  
{  TIM_Cmd(TIM2, DISABLE);   // 使能TIMx外设  
}  

定时器中断服务函数如下

/**==============================================================================*函数名称:TIM2_IRQHandler*函数功能:定时器2中断服务程序 *输入参数:无*返回值:无*备  注:无*==============================================================================*/
void TIM2_IRQHandler (void)   // TIM2中断  
{  if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)   // 检查TIM2更新中断发生与否  {  TIM_ClearITPendingBit(TIM2, TIM_IT_Update);  // 清除TIMx更新中断标志   gMsHcCount++;  }  
}   

4.3 获取定时时间

/**==============================================================================*函数名称:Drv_Hcsr04_GetEchoTimer*函数功能:获取定时器定时时间 *输入参数:无*返回值:无*备  注:无*==============================================================================*/
u32 Drv_Hcsr04_GetEchoTimer (void)  
{  u32 t = 0;  t = gMsHcCount * 1000;   // 得到MS  t += TIM_GetCounter(TIM2);   // 得到US  TIM2 -> CNT = 0;   // 将TIM2计数寄存器的计数值清零  delay_ms(50);return t;  
}

4.4 计算测量距离

/**==============================================================================*函数名称:Med_Hcsr04_GetLength*函数功能:获取测量距离*输入参数:无*返回值:无*备  注:一次获取超声波测距数据 两次测距之间需要相隔一段时间,隔断回响信号为了消除余震的影响,取五次数据的平均值进行加权滤波*==============================================================================*/
float Med_Hcsr04_GetLength (void )  
{  u32 t = 0;  int i = 0;  float lengthTemp = 0;  float sum = 0;  while(i!=5)  {  TRIG_Send = 1;   // 发送口高电平输出  delay_us(20);TRIG_Send = 0;  while(ECHO_Reci == 0);   // 等待接收口高电平输出  Drv_Hcsr04_OpenTimerForHc();   //打开定时器  i = i + 1;  while(ECHO_Reci == 1);  Drv_Hcsr04_CloseTimerForHc();   // 关闭定时器  t = Drv_Hcsr04_GetEchoTimer();   // 获取时间,分辨率为1uslengthTemp = ((float)t/58.0);   // cm  sum = lengthTemp + sum ;        }  lengthTemp = sum/5.0;  return lengthTemp;  
}

4.5 宏定义

#define HCSR04_PORT   GPIOB   // 定义IO口
#define HCSR04_CLK    RCC_APB2Periph_GPIOB   // 开启GPIO时钟  
#define HCSR04_TRIG   GPIO_Pin_8   // 定义Trig对应引脚
#define HCSR04_ECHO   GPIO_Pin_9   // 定义Echo对应引脚#define TRIG_Send  PBout(8)   // 将TRIG_Send映射到PB8
#define ECHO_Reci  PBin(9)   // 将ECHO_Reci映射到PB9void Drv_Hcsr04_Init(void);   // Hc-sr04初始化
void Drv_Hcsr04_OpenTimerForHc (void);   //打开定时器
void Drv_Hcsr04_CloseTimerForHc (void);   //关闭定时器
u32 Drv_Hcsr04_GetEchoTimer(void);   // 获取定时器时间

五、应用实例

利用串口打印距离信息,main函数如下

float gDistance = 0;   //定义获取返回距离变量int main(void)
{Med_Mcu_Iint();   // 系统初始化while(1){gDistance = Med_Hcsr04_GetLength();   //获取返回距离printf ("距离为:%.3f cm\n",gDistance);   //串口打印返回距离delay_ms(500);   //延时500ms = 0.5s}
}

六、拓展应用

超声波测距比较常用的,比如利用超声波测距模块实现智能车的自动避障,这个在后续实战项目系列中会有,在此就不再详细介绍了。主要思路就是根据HC-SR04测得的与障碍物的距离,来决定是否要停止或转弯,以及往那边转弯。

这篇关于STM32外设系列—HC-SR04(超声波)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/363976

相关文章

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入(Embedding)方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节:嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以被看作是自然语言处理中的“翻译机”,它将文本中的单词或短语转换成计算机能够理解的数学形式,即向量。 正如翻译机将一种语言

【STM32】SPI通信-软件与硬件读写SPI

SPI通信-软件与硬件读写SPI 软件SPI一、SPI通信协议1、SPI通信2、硬件电路3、移位示意图4、SPI时序基本单元(1)开始通信和结束通信(2)模式0---用的最多(3)模式1(4)模式2(5)模式3 5、SPI时序(1)写使能(2)指定地址写(3)指定地址读 二、W25Q64模块介绍1、W25Q64简介2、硬件电路3、W25Q64框图4、Flash操作注意事项软件SPI读写W2

flume系列之:查看flume系统日志、查看统计flume日志类型、查看flume日志

遍历指定目录下多个文件查找指定内容 服务器系统日志会记录flume相关日志 cat /var/log/messages |grep -i oom 查找系统日志中关于flume的指定日志 import osdef search_string_in_files(directory, search_string):count = 0

STM32(十一):ADC数模转换器实验

AD单通道: 1.RCC开启GPIO和ADC时钟。配置ADCCLK分频器。 2.配置GPIO,把GPIO配置成模拟输入的模式。 3.配置多路开关,把左面通道接入到右面规则组列表里。 4.配置ADC转换器, 包括AD转换器和AD数据寄存器。单次转换,连续转换;扫描、非扫描;有几个通道,触发源是什么,数据对齐是左对齐还是右对齐。 5.ADC_CMD 开启ADC。 void RCC_AD

STM32内部闪存FLASH(内部ROM)、IAP

1 FLASH简介  1 利用程序存储器的剩余空间来保存掉电不丢失的用户数据 2 通过在程序中编程(IAP)实现程序的自我更新 (OTA) 3在线编程(ICP把整个程序都更新掉) 1 系统的Bootloader写死了,只能用串口下载到指定的位置,启动方式也不方便需要配置BOOT引脚触发启动  4 IAP(自己写的Bootloader,实现程序升级) 1 比如蓝牙转串口,

GPT系列之:GPT-1,GPT-2,GPT-3详细解读

一、GPT1 论文:Improving Language Understanding by Generative Pre-Training 链接:https://cdn.openai.com/research-covers/languageunsupervised/language_understanding_paper.pdf 启发点:生成loss和微调loss同时作用,让下游任务来适应预训

FreeRTOS-基本介绍和移植STM32

FreeRTOS-基本介绍和STM32移植 一、裸机开发和操作系统开发介绍二、任务调度和任务状态介绍2.1 任务调度2.1.1 抢占式调度2.1.2 时间片调度 2.2 任务状态 三、FreeRTOS源码和移植STM323.1 FreeRTOS源码3.2 FreeRTOS移植STM323.2.1 代码移植3.2.2 时钟中断配置 一、裸机开发和操作系统开发介绍 裸机:前后台系

寻迹模块TCRT5000的应用原理和功能实现(基于STM32)

目录 概述 1 认识TCRT5000 1.1 模块介绍 1.2 电气特性 2 系统应用 2.1 系统架构 2.2 STM32Cube创建工程 3 功能实现 3.1 代码实现 3.2 源代码文件 4 功能测试 4.1 检测黑线状态 4.2 未检测黑线状态 概述 本文主要介绍TCRT5000模块的使用原理,包括该模块的硬件实现方式,电路实现原理,还使用STM32类