基于STM32和HC-SR04模块实现超声波测距功能

最近在学STM32做个简单的应用实践一下,顺便水一篇文章。

本文用的单片机是STM32F103C8T6,超声波测距模块是HC-SR04,显示测距结果用的是0.96寸OLED屏模块。

效果展示

下图中小于10cm时的显示结果有点问题,代码已修复并更新

修复后的结果:

视频演示:https://www.bilibili.com/video/BV1Sg411Z7ex/

基于STM32和HC-SR04模块实现超声波测距功能

HC-SR04硬件概述

HC-SR04超声波距离传感器的核心是两个超声波传感器。一个用作发射器,将电信号转换为40 KHz超声波脉冲。接收器监听发射的脉冲。如果接收到它们,它将产生一个输出脉冲,其宽度可用于确定脉冲传播的距离。就是如此简单!

该传感器体积小,易于在任何机器人项目中使用,并提供2厘米至400厘米(约1英寸至13英尺)之间出色的非接触范围检测,精度为3mm。

Operating Voltage工作电压 直流5V
Operating Current工作电流 15毫安
Operating Frequency运行频率 40K赫兹
Max Range最大范围 4m
Min Range最小范围 2厘米
Ranging Accuracy测距精度 3毫米
Measuring Angle测量角度 15度
Trigger Input Signal触发输入信号 10µS TTL脉冲
Dimension尺寸 45 x 20 x 15毫米

HC-SR04超声波传感器引脚

让我们看一下它的引脚排列。

VCC 是HC-SR04超声波距离传感器的电源,我们连接了5V的供电。

Trig (Trigger) 引脚用于触发超声波脉冲,下面例程中用的GPIOB5,所以连接STM32的GPIOB5。

Echo 回声当接收到反射信号时,引脚产生一个脉冲。脉冲的长度与检测发射信号所需的时间成正比,下面例程中用的GPIOB6,所以连接STM32的GPIOB6。

GND 应该连接到STM32的地。

HC-SR0如何工作?

当持续时间至少为10 µS(10微秒)的脉冲施加到触发引脚时,一切就开始了。响应于此,传感器以40 KHz发射八个脉冲的声音脉冲。这种8脉冲模式使设备的“超声特征”变得独一无二,从而使接收器能够将发射模式与环境超声噪声区分开。

八个超声波脉冲通过空气传播,远离发射器。同时,回声引脚变为高电平,开始形成回声信号的开始。

如果这些脉冲没有被反射回来,则回波信号将在38毫秒(38毫秒)后超时并返回低电平。因此38 ms的脉冲表示在传感器范围内没有阻塞。

如果这些脉冲被反射回去,则在收到信号后,Echo引脚就会变低。这会产生一个脉冲,其宽度在150 µS至25 mS之间变化,具体取决于接收信号所花费时间。

HC-SR04的时序图如下:

然后,将接收到的脉冲的宽度用于计算到反射物体的距离。这可以通过我们在初中学到的简单的距离-速度-时间方程来解决。

距离=速度x时间

接线

将HC-SR04和0.96寸OLED屏连接到STM32。

HC-SR04 STM32
VCC 5V
Trig GPIO PB5
Echo GPIO PB6
Gnd Gnd
OLED STM32
VCC 3.3V
GND GND
SCL GPIO PB12
SDA GPIO PB13

温度对距离测量的影响

尽管HC-SR04对于我们的大多数项目来说都相当准确,例如入侵者检测或接近警报;但是有时候您可能想设计一种要在户外或在异常炎热或寒冷的环境中使用的设备。在这种情况下,您可能要考虑到空气中的声速随温度,气压和湿度而变化的事实。

由于声音因素进入HC-SR04距离计算的速度,因此可能会影响我们的读数。如果已知温度(°C)和湿度,请考虑以下公式:

声速 m/s = 331.4 +(0.606 * 温度)+(0.0124 * 湿度)

购买地址

本文所用到的模块购买地址如下:

STM32F103C8T6开发板:https://s.click.taobao.com/8SoQMVu
ST-LINK V2仿真器:https://s.click.taobao.com/FEuPMVu
HC-SR04模块:https://s.click.taobao.com/Ing88Vu
0.96寸OLED模块:https://s.click.taobao.com/o4fPMVu
面包板:https://s.click.taobao.com/dBjPMVu
面包板专用跳线:https://s.click.taobao.com/7eG88Vu

程序

我是用的的ST标准库写的程序,文章中放出主要的程序,完整的工程文件请点下面链接下载。

完整工程文件下载:https://url.zeruns.tech/HCSR04

提取码:d9xr

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"
#include "HCSR04.h"uint64_t numlen(uint64_t num)//计算数字的长度
{uint64_t len = 1;        // 初始长度为1for(; num > 9; ++len)    // 判断num是否大于9,否则长度+1num /= 10;             // 使用除法进行运算,直到num小于1return len;              // 返回长度的值
}int main(void)
{   OLED_Init();        //初始化OLED屏Timer_Init();     //初始化定时器HC_SR04_Init();     //初始化超声波测距模块OLED_ShowString(1, 1, "Distance:");     //OLED屏输出字符串while (1){int Distance_mm=sonar_mm();           //获取距离测量结果,单位毫米(mm)        int Distance_m=Distance_mm/1000;    //转换为米(m)为单位,将整数部分放入Distance_mint Distance_m_p=Distance_mm%1000;   //转换为米(m)为单位,将小数部分放入Distance_m_pOLED_Clear_Part(2,1,16);           //将OLDE屏第2行清屏OLED_ShowNum(2, 1,Distance_m,numlen(Distance_m));  //显示测量结果的整数部分OLED_ShowChar(2, 1+numlen(Distance_m), '.');       //显示小数点if(Distance_m_p<100){                             //判断是否小于100毫米OLED_ShowChar(2, 1+numlen(Distance_m)+1,'0');                              //因为单位是米,所以小于10cm时要加0OLED_ShowNum(2, 1+numlen(Distance_m)+2,Distance_m_p,numlen(Distance_m_p));  //显示测量结果的小数部分OLED_ShowChar(2, 1+numlen(Distance_m)+2+numlen(Distance_m_p), 'm');            //显示单位}else                                                                         // https://blog.zeruns.tech{OLED_ShowNum(2, 1+numlen(Distance_m)+1,Distance_m_p,numlen(Distance_m_p));  //显示测量结果的小数部分OLED_ShowChar(2, 1+numlen(Distance_m)+1+numlen(Distance_m_p), 'm');            //显示单位}OLED_Clear_Part(3,1,16);         //将OLDE屏第3行清屏OLED_ShowNum(3, 1,Distance_mm,numlen(Distance_mm));        //显示单位为毫米的距离结果OLED_ShowString(3, 1 + numlen(Distance_mm), "mm");Delay_ms(300);                      //延时300毫秒}
}

Timer.c

#include "stm32f10x.h"                  // Device header
//blog.zeruns.tech
void Timer_Init(void)
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);       //启用TIM3时钟TIM_InternalClockConfig(TIM3);                                //设置TIM3使用内部时钟TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;            //定义结构体,配置定时器TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置1分频(不分频)TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;   //设置计数模式为向上计数TIM_TimeBaseInitStructure.TIM_Period = 10 - 1;         //设置最大计数值,达到最大值触发更新事件,因为从0开始计数,所以计数10次是10-1,每10微秒触发一次TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;         //设置时钟预分频,72-1就是每 时钟频率(72Mhz)/72=1000000 个时钟周期计数器加1,每1微秒+1TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;       //重复计数器(高级定时器才有,所以设置0)TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);          //初始化TIM3定时器TIM_ClearFlag(TIM3, TIM_FLAG_Update);           //清除更新中断标志位TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);       //开启更新中断NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);             //设置中断优先级分组NVIC_InitTypeDef NVIC_InitStructure;                     //定义结构体,配置中断优先级NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;               //指定中断通道NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;             //中断使能NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //设置抢占优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;         //设置响应优先级NVIC_Init(&NVIC_InitStructure);                                // https://blog.zeruns.techTIM_Cmd(TIM3, ENABLE);                           //开启定时器
}/*
void TIM3_IRQHandler(void)          //更新中断函数
{if (TIM_GetITStatus(TIM3, TIM_IT_Update) == SET)       //获取TIM3定时器的更新中断标志位{TIM_ClearITPendingBit(TIM3, TIM_IT_Update);         //清除更新中断标志位}
}*/

Timer.h

#ifndef __TIMER_H
#define __TIMER_Hvoid Timer_Init(void);#endif

HCSR04.c

#include "stm32f10x.h"
#include "Delay.h"/*
我的博客:blog.zeruns.tech
具体使用说明请到我博客看
*/#define Echo GPIO_Pin_6       //HC-SR04模块的Echo脚接GPIOB6
#define Trig GPIO_Pin_5     //HC-SR04模块的Trig脚接GPIOB5uint64_t time=0;            //声明变量,用来计时
uint64_t time_end=0;        //声明变量,存储回波信号时间void HC_SR04_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);   //启用GPIOB的外设时钟  GPIO_InitTypeDef GPIO_InitStructure;                    //定义结构体GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;     //设置GPIO口为推挽输出GPIO_InitStructure.GPIO_Pin = Trig;                       //设置GPIO口5GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;     //设置GPIO口速度50MhzGPIO_Init(GPIOB,&GPIO_InitStructure);                   //初始化GPIOBGPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;         //设置GPIO口为下拉输入模式GPIO_InitStructure.GPIO_Pin = Echo;                     //设置GPIO口6GPIO_Init(GPIOB,&GPIO_InitStructure);                 //初始化GPIOBGPIO_WriteBit(GPIOB,GPIO_Pin_5,0);                        //输出低电平Delay_us(15);                                            //延时15微秒
}int16_t sonar_mm(void)                                 //测距并返回单位为毫米的距离结果
{uint32_t Distance,Distance_mm = 0;GPIO_WriteBit(GPIOB,Trig,1);                     //输出高电平Delay_us(15);                                        //延时15微秒GPIO_WriteBit(GPIOB,Trig,0);                        //输出低电平while(GPIO_ReadInputDataBit(GPIOB,Echo)==0);     //等待低电平结束time=0;                                                //计时清零while(GPIO_ReadInputDataBit(GPIOB,Echo)==1);      //等待高电平结束time_end=time;                                     //记录结束时的时间if(time_end/100<38)                                    //判断是否小于38毫秒,大于38毫秒的就是超时,直接调到下面返回0{Distance=(time_end*346)/2;                     //计算距离,25°C空气中的音速为346m/sDistance_mm=Distance/100;                        //因为上面的time_end的单位是10微秒,所以要得出单位为毫米的距离结果,还得除以100}return Distance_mm;                                   //返回测距结果
}float sonar(void)                                      //测距并返回单位为米的距离结果
{uint32_t Distance,Distance_mm = 0;float Distance_m=0;GPIO_WriteBit(GPIOB,Trig,1);                  //输出高电平Delay_us(15);GPIO_WriteBit(GPIOB,Trig,0);                    //输出低电平while(GPIO_ReadInputDataBit(GPIOB,Echo)==0);time=0;while(GPIO_ReadInputDataBit(GPIOB,Echo)==1);time_end=time;if(time_end/100<38){Distance=(time_end*346)/2;Distance_mm=Distance/100;Distance_m=Distance_mm/1000;}return Distance_m;
}void TIM3_IRQHandler(void)         //更新中断函数,用来计时,每10微秒变量time加1
{if (TIM_GetITStatus(TIM3, TIM_IT_Update) == SET)       //获取TIM3定时器的更新中断标志位{time++;TIM_ClearITPendingBit(TIM3, TIM_IT_Update);          //清除更新中断标志位}
}

HCSR04.h

#ifndef __HCSR04_H
#define __HCSR04_Hvoid HC_SR04_Init(void);
int16_t sonar_mm(void);
float sonar(void);#endif

推荐阅读

  • 高性价比和便宜的VPS/云服务器推荐:https://blog.zeruns.tech/archives/383.html
  • ESP8266开发环境搭建及项目演示:https://blog.zeruns.tech/archives/526.html
  • Arduino读取DHT11,DHT22,SHTC3温湿度数据:https://blog.zeruns.tech/archives/527.html
  • 学生专属优惠权益大全,教育优惠:https://blog.zeruns.tech/archives/557.html
  • 怎样搭建个人博客:https://blog.zeruns.tech/archives/218.html
  • 使用NPS搭建内网穿透服务器,带Web面板:https://blog.zeruns.tech/archives/660.html

HC-SR04超声波测距模块使用方法和例程(STM32)相关推荐

  1. 学习HC-SR04超声波测距模块,代码附带卡尔曼滤波

    硬件引脚 VCC-供5V的电压(一定要是5v) GND-接地 Trig-HC-SR04超声波测距模块上的触发引脚,用于向模块发送一个10微秒的高电平触发信号,触发模块开始进行距离测量 Echo-用于接 ...

  2. hc sr04流程图_超声波测距模块工作原理_HC-SR04模块详解

    超声波测距模块有好多种类型,目前比较常用的有URM37超声波传感器默认是232接口,可以调为TTL接口,URM05大功率超声波传感器测试距离能到10米,算是目前来说测试距离比较远的一款了,另外还有比较 ...

  3. STM32单片机基于HAL库开发HC-SR04 超声波测距模块(终极版)

    参考: 某宝HC-SR04 超声波测距模块商品详情页 STM32L051C8T6 HAL库 输入捕获进行超声波测距 案例 STM32CubeMX学习笔记3--TIM2输入捕获(SR-04测距) cub ...

  4. arduino超声波测距接线图详细_Arduino系列之超声波测距模块代码(一)

    这里我将简单介绍超声波测距模块 SR04超声波传感器: 是利用超声波特性检测距离的传感器,其带有两个超声波探头,分别用作于发射和接收超声波.范围在3-450cm. 工作原理: 超声波发射器向某一方向发 ...

  5. 超声波测距模块(HC-SR04模块)特点及使用介绍

    超声波测距模块(HC-SR04模块)特点及使用介绍 前言 一.超声波测距模块(HC-SR04模块)外观 二.原理图 三.相关参数讲解 1.参数 2.测量范围 3.计算公式 4.优点 5.产品特性(根据 ...

  6. 学习并使用HC-SR04超声波测距模块+STM32

    ** 超声波测距原理 ** 参考博客: https://blog.csdn.net/qq_40734815/article/details/105992801 https://blog.csdn.ne ...

  7. stm32控制超声波测距模块HC-SR04

    引脚:PB15 TRIG,PB0 ECHO: 不同距离,LED对应不良.闪烁.亮状态,并通过串口发送到PC; TIM3定时中断,测出脉宽长度,没有像野火一样使用捕捉功能: 1.HS-SR04模块实物图 ...

  8. HC-SR04超声波测距模块

    1.产品特点 HC-SR04超声波测距模块可提供2cm-400cm 的非接触式距离感测功能,测距精度可达高到3mm:模块包括超声发射器.接收器与控制电路. 基本工作原理:         (1)采用 ...

  9. HC-SR04超声波测距模块功能简述

    HC-SR04是一款升级的超声波测距模块.新增加UART,IIC 及 1-WIRE(单总线)功能,模式可以通过外围电阻设置. 2CM 超小盲区,4M 典型最远测距,2mA 超低工作电流.采用自研超声波 ...

最新文章

  1. 测量 XW-HLR26-24G 微波雷达模块的性能测试
  2. android开发模式,Android开发中无处不在的设计模式
  3. CRM Fiori:Complex note optimization design
  4. C++set容器-插入和删除
  5. java和Mysql数据一致性_java web开发中数据一致性的问题
  6. 高甜预警|甜齁你的情人节促销海报设计模板
  7. 【转】查看linux服务器的系统信息
  8. 5319. 删除回文子序列
  9. python上下文管理器ContextLib及with语句
  10. 配置centOS下的Python
  11. Erlang/Elixir: 外部通信之-NIF
  12. 防止javascript脚本读取cookie信息
  13. VBS QQ微信消息轰炸
  14. php 一天是多少秒,1天 等于 86400 秒?
  15. Ardupilot动力分配-混控部分分析
  16. css设置文字外发光
  17. 【GamePlay】时空回溯效果
  18. 海康、大华等网络摄像头RTSP_Onvif网页无插件直播流媒体服务器EasyNVR鉴权出现跨域问题的解决方法
  19. 植物代谢组学-线虫信息素的植物代谢介导植物与线虫的相互作用
  20. R实战| 雷达图(Radar Chart)

热门文章

  1. 51 nod 1625 夹克爷发红包【贪心、二进制枚举】
  2. xampp mysql密码忘记_XAMPP重置MySQL密码
  3. 汇报工作就使用麦肯锡的结构化思考、SCQA表达框架
  4. iQQ 学习笔记2 :借助新浪微博输入验证码、远程控制退出
  5. make px4fmu-v2_default报错:ninja:no work to do
  6. ASP.NET 权限管理 页面静态化 OA系统培训 三层架构
  7. cad高程测绘图lisp_已知CAD中的高程测绘图,很多点,如何求出所有高程的平均值呢?难道只能用计算器一个一个的相加来算吗?...
  8. cdma200 matlab 仿真,CDMA通信系统的MATLAB仿真
  9. C语言 | 自由落地,求第10次落地共经过多少米
  10. avg制作工具 开源_23种开源视听制作工具