手把手教你玩转超声波传感器(原理+驱动)

我们都知道声音是由物体振动产生的,人能听到的频率在20Hz~20kHz。频率小于20Hz的叫次声波,频率大于20kHz的叫超声波。

超声波可以在空气、液体和固体中传播,可以被物体反射、折射、散射等,并且有频率高、波长短、绕射现象小、方向性好等特点。从而提供了丰富的用途,医学影像、清洁物品、材料检测、非接触测距等等。

本次我们要讲的超声波传感器就是非接触测距,用于测量物体与传感器之间的距离,可用于车辆安全(倒车雷达),安防系统(检测到移动物体并触发警报),工业自动化(物体定位、检测和避障)等等。

1. 源码下载及前置阅读

本文首发 良许嵌入式网https://www.lxlinux.net/e/ ,欢迎关注!

本文所涉及的源码及安装包如下(由于平台限制,请点击以下链接阅读原文下载):

https://www.lxlinux.net/e/stm32/hc-sr04-tutorial.html

如果你是嵌入式开发小白,那么建议你先读读下面几篇文章。

往期教程,有兴趣的小伙伴可以看看。

作者简介
大家好,我是良许,博客里所有的文章皆为我的原创。<br />下面是我的一些个人介绍,欢迎交个朋友:<br />· 211工科硕士,国家奖学金获得者;<br />· 深耕嵌入式11年,前世界500强外企高级嵌入式工程师;<br />· 书籍《速学Linux作者》,机械工业出版社专家委员会成员;<br />· 全网60W粉丝,博客分享大量原创成体系文章,全网阅读量累计超4000万;<br />· 靠自媒体连续年入百万,靠自己买房买车。

我本科及硕士都是学机械,通过自学成功进入世界500强外企。我已经将自己的学习经验写成了一本电子书,超千人通过此书学习并转行成功。现在将这本电子书免费分享给大家,希望对你们有帮助:

电子书链接:https://www.lxlinux.net/1024.html

2. HC-SR04介绍

超声波传感器有很多的信号:HC-SR04、UC-025、UC-026、UC-015、US-100等等,它们之间大同小异,无非是工作参数有点不一样,像是工作的电压或温度、探测距离或精度有点差别,引脚是一样的,都是4个引脚(US-100 多一个 GND 引脚),引脚顺序和功能也是一样的。

大家在学习和工作中可以自行选择合适的型号,这里我为大家介绍最常见的 HC-SR04 这个型号。

2.1 HC-SR04型号介绍

现在市面上的 HC- SR04 有新版和旧版,我们介绍的是新版。新版性能比老版的精度更高,测距范围更远,可达6米,高于一般超声波测距模块。采用 CS-100A 超声波测距 SOC 芯片,高性能,工业级,宽电压,价格在4块钱左右。

2.2 HC-SR04工作参数及引脚介绍

HC-SR04 工作参数:

  • 探测距离:2~600cm
  • 探测精度:0.1cm±1%
  • 感应角度:<15°
  • 输出方式:GPIO
  • 工作电压:DC 3~5.5V
  • 工作电流:5.3mA
  • 工作温度:-40~85℃

接线如下:

HC-SR04 STM32 备注
VCC 3.3/5V 外接直流电源
Trig 任意一个GPIO口 输入端
Echo 任意一个GPIO口 输出端
GND GND 接地

3. HC-SR04工作原理

3.1 原理简述

超声波测距的工作原理其实很简单,传感器发送超声波,超声波碰到障碍物反弹回来,被传感器接收到。芯片算出发送和接收的时间间隔,再利用公式:s = v × t,看下面示意图,所以实际距离 = 测量距离 / 2 = 速度 × 时间 / 2。

顺便一提,超声波在空气中的传播速度大概是 343m/s,传播速度受到环境条件的影响,如温度、湿度和气压等。

超声波模块上的两个超声波探头,一个是发送端,负责发送超声波;一个是接收端,负责接收超声波。

3.2 原理详述

接下来我们详细的介绍下超声波模块的工作时序,明白了时序以后才知道怎么写代码。

  • 正常测距时序图:
  1. 单片机给超声波模块发送大于 10us 的高电平的触发信号;
  2. 超声波模块收到触发信号后 Trig 端发送 8个40kHz 的超声波脉冲;
  3. Echo 端由低电平转为高电平,同时开始发送超声波;
  4. 超声波模块检测到返回信号,Echo 端由高电平转为低电平;
  5. Echo 端高电平宽度即为超声波传播时间。

如果觉得太生涩了,我给大家准备了趣味描述:

  • 超出测距范围时序图:

当测量距离超过 HC-SR04 的测量范围时,Echo 任会输出高电平,宽度约为66ms,后转为低电平。

4. 编程实战

4.1 硬件接线

本教程使用的硬件如下:

  • 单片机:STM32F103C8T6

  • 超声波传感器:HC-SR04

  • 串口:USB 转 TTL

  • 烧录器:ST-LINK V2

HC-SR04 STM32 USB 转 TTL
VCC 3.3/5V
Trig B6
Echo B7
GND G
A10 TX
A9 RX
G GND

烧录的时候接线如下表,如果不会烧录的话可以看我之前的文章【STM32下载程序的五种方法:https://www.lxlinux.net/e/stm32/five-ways-to-flash-program-to-stm32.html】。

ST-Link V2 STM32
SWCLK SWCLK
SWDIO SWDIO
GND GND
3.3V 3V3

接好如下图:

4.2 初始化引脚

我们将 Trig 引脚设置为推挽式输出,Echo 引脚设置为浮空输入。为什么这样设置呢?大家可以对照下表的 GPIO 的八种工作模式看看。

模式名称 性质 特征
浮空输入 数字输入 可读取引脚电平,若引脚悬空,则电平不确定
上拉输入 数字输入 可读取引脚电平,内部连接上拉电阻,悬空时默认高电平
下拉输入 数字输入 可读取引脚电平,内部连接下拉电阻,悬空时默认低电平
模拟输入 模拟输入 GPIO 无效,引脚直接接入内部 ADC
开漏输出 数字输入 可输出引脚电平,高电平为高阻态,低电平接 VSS
推挽输出 数字输入 可输出引脚电平,高电平接 VDD,低电平接 VSS
复用开漏输出 数字输入 由片上外设控制,高电平为高阻态,低电平接VSS
复用推挽输出 数字输入 由片上外设控制,高电平接VDD,低电平接VSS

引脚初始化代码如下:

 void HCSR04_GPIO_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    Trig_GPIO_CLK_ENABLE();                                 /* Trig引脚使能 */
    Echo_GPIO_CLK_ENABLE();                                 /* Echo引脚使能 */

    /* Trig低电平 */
    HAL_GPIO_WritePin(Trig_GPIO_PORT, Trig_GPIO_PIN, GPIO_PIN_RESET);

    GPIO_InitStruct.Pin = Trig_GPIO_PIN;                   /* Trig引脚 */
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;            /* 推挽输出 */
    GPIO_InitStruct.Pull = GPIO_NOPULL;                    /* 浮空 */
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;           /* 低速 */
    HAL_GPIO_Init(Trig_GPIO_PORT, &GPIO_InitStruct);       /* 初始化Trig引脚 */

    GPIO_InitStruct.Pin = Echo_GPIO_PIN;                   /* Echo引脚 */
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;                /* 输入 */
    GPIO_InitStruct.Pull = GPIO_NOPULL;                    /* 浮空 */
    HAL_GPIO_Init(Echo_GPIO_PORT, &GPIO_InitStruct);       /* 初始化Echo引脚 */
}

4.3 初始化定时器

需要初始化一个定时器,用于测量 Echo 高电平宽度,这里我们初始化了通用定时器2。

void TIM2_Init(void)
{
    TIM_ClockConfigTypeDef sClockSourceConfig = {0};            /* 定时器设置结构体 */
    TIM_MasterConfigTypeDef sMasterConfig = {0};

    htim2.Instance = TIM2;                                      /* 通用定时器2 */
    htim2.Init.Prescaler = 71;                                  /* 预分频系数 */
    htim2.Init.CounterMode = TIM_COUNTERMODE_UP;                /* 递增计数模式 */
    htim2.Init.Period = 65535;                                  /* 自动装载值 */
    htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
    HAL_TIM_Base_Init(&htim2);

    sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
    HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig);

    sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig);
}

4.4 测量距离

按照超声波的工作时序,

  1. 单片机给超声波模块发送大于 10us 的高电平的触发信号;
  2. Trig 的 8个40kHz 的超声波脉冲,不用管,我们不需要;
  3. Echo 端由低电平转为高电平,开启定时器;
  4. 超声波模块检测到返回信号,Echo 端由高电平转为低电平,关闭定时器;
  5. 得到超声波来回的总距离,进行计算,得到实际测量距离。
void HCSR04_Get_Length (void)  
{  
    int total_time=0;           //超声波来回的总时间
    float distance=0;           //实际测量距离

    HCSR04_GPIO_init();
    HAL_GPIO_WritePin(Trig_GPIO_PORT,Trig_GPIO_PIN,GPIO_PIN_SET);           //拉高
    __HAL_TIM_SetCounter(&htim2, 0);                                        //定时器归零
    delay_us(15);
    HAL_GPIO_WritePin(Trig_GPIO_PORT,Trig_GPIO_PIN,GPIO_PIN_RESET);         //拉低

    while(HAL_GPIO_ReadPin(Echo_GPIO_PORT,Echo_GPIO_PIN)==GPIO_PIN_RESET);  //Echo转到高电平
    HAL_TIM_Base_Start(&htim2);                                             //启动定时器

    while(HAL_GPIO_ReadPin(Echo_GPIO_PORT,Echo_GPIO_PIN)==GPIO_PIN_SET);    //Echo转回低电平
    HAL_TIM_Base_Stop(&htim2);                                              //停止定时器

    total_time = __HAL_TIM_GetCounter(&htim2);                              //得到高电平持续时间

    distance = total_time * 0.01715; //                                     //算出测量距离(343*0.000001*100/2 = 0.01715)
    printf("dis : %.2f cm\r\n",distance);
}

有的同学可能会好奇,这个“ * 0.01715 ”是什么,因为

实际距离 = 测量距离 / 2

            =  速度 × 总时间 / 2。

            = 343(m/s) * total_time(us)/ 2

            = 343(m/s) * total_time(us) * 0.000001(1s=1000000) * 100(1m=100cm)/2

            = 343 * 0.000001 * 100 / 2

            = 0.01715

所以我们就直接写 0.01715 啦,减轻一点计算负担,虽然本身也没多少。

.h文件内容如下:

#ifndef __HCSR04_H__
#define __HCSR04_H__

#include "stdio.h"
#include "stm32f1xx.h"

/* 引脚定义 */
#define Trig_GPIO_PORT                  GPIOB
#define Trig_GPIO_PIN                   GPIO_PIN_6
#define Trig_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)             /* PB口时钟使能 */

#define Echo_GPIO_PORT                  GPIOB
#define Echo_GPIO_PIN                   GPIO_PIN_7
#define Echo_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)             /* PB口时钟使能 */



void HCSR04_GPIO_init(void);
void TIM2_Init(void);
void HCSR04_Get_Length (void);

#endif

4.5 最终效果

串口输出如下,这是我用本子在超声波前来回移动的数据。记得给板子上电哦,光 STLink 供电可不够。

5. 小结

通过本文的学习与实践,相信大家已经了解并掌握 HC-SR04 的特性和使用,能够更好地应用于嵌入式开发。希望 HC-SR04 可以成为您的得力助手,让我们一起玩转 HC-SR04,peace and love!

另外,想进大厂的同学,一定要好好学算法,这是面试必备的。这里准备了一份 BAT 大佬总结的 LeetCode 刷题宝典,很多人靠它们进了大厂。

刷题 | LeetCode算法刷题神器,看完 BAT 随你挑!

有收获?希望老铁们来个三连击,给更多的人看到这篇文章

推荐阅读:

欢迎关注我的博客:良许嵌入式教程网,满满都是干货!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,252评论 6 516
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,886评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,814评论 0 361
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,869评论 1 299
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,888评论 6 398
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,475评论 1 312
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,010评论 3 422
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,924评论 0 277
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,469评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,552评论 3 342
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,680评论 1 353
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,362评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,037评论 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,519评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,621评论 1 274
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,099评论 3 378
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,691评论 2 361

推荐阅读更多精彩内容