Ultrasonic Ranging Module · Trig / Echo Pulse Interface

HC-SR04

接线与代码参考手册 —— 测距原理、ESP32 / STM32 / 树莓派三种主控的接线图,以及可直接使用的示例代码。

  • 封装HC-SR04 四针模块
  • 尺寸45 × 20 × 15 mm
  • 测距范围2 – 400 cm
  • 精度约 ±0.3 cm
  • 探测角度≤ 15°
  • 逻辑电平5 V TTL
  • 工作频率40 kHz

Download

下载测试程序

三个平台的代码已经按文件夹打包,客户下载 ZIP 后解压,打开对应工程即可。ESP32 2.8 黄屏请用带 _tft 的版本。

Arduino UNO 代码下载

带 0.96 寸 OLED 显示,适合 UNO / Nano 教学演示,已烧录验证。

下载 Arduino UNO ZIP

ESP32 2.8 黄屏代码下载

真正驱动 2.8 黄屏 TFT 显示的版本。不要使用过渡的纯串口版,否则屏幕不会亮。

下载 ESP32 黄屏 ZIP

STM32 代码下载

蓝丸 + 0.96 寸 OLED 版本,包含 platformio.inisrc/main.cpp,适合 PlatformIO 打开。

下载 STM32 OLED ZIP

STM32 纯串口版

不接 OLED 时用这个精简版本,方便先验证 Trig/Echo 测距逻辑。

下载 STM32 串口版

全部代码总包

包含 Arduino UNO、ESP32 2.8 黄屏、STM32 OLED、STM32 串口版,适合客服一次发给客户。

下载全部代码 ZIP
1

概述

Overview

HC-SR04 是最常见的超声波测距模块,原理和蝙蝠回声定位一样:主控给它一个"喊话"信号,它发射一串 40kHz 的超声波,碰到前方物体反射回来,模块把"从喊话到听到回声"这段时间转换成一个电平脉冲告诉主控,主控再用声速换算成距离。整个模块只有 4 根针,不需要额外的库或者复杂配置,是最适合入门的测距传感器。

全系列还有 AJ-SR04M / JSN-SR04T(防水一体化外壳,适合车外或潮湿环境)等变种,接口协议和本文一致,选型时按外壳/功耗需求换一下即可,代码不用改。

同一款外观(双探头蓝板)实际有三种芯片方案,淘宝同一个链接的"颜色分类"里经常混着卖,选购/接线前建议对照实物丝印确认到底是哪种:

方案工作电压尺寸说明
双芯片(标准版)5V45.2×20×14.5mm最常见的版本,本文默认按这个写
双芯片(宽电压版)3.3–5V45.1×20×14.5mm背面丝印通常还带 Echo/Tx/SDATrig/Rx/SCL 字样,除了普通 Trig/Echo 模式,部分还支持 I2C/UART 等替代协议(本文只用最基础的 Trig/Echo 模式,其它模式不在本文范围);第 5 节 ESP32-2432S028 专项说明里推荐买的就是这个方案
单芯片(CS100A 方案)3–5.5V45.2×20×14.5mm用 CS100A 单颗芯片实现,同样是宽电压,背面丝印会印 "CS100A Inside"

三种方案的 Trig/Echo 基础用法和引脚定义完全一致,本文的接线图/代码对三种都适用;区别只在供电电压范围,3.3V 主控(ESP32/树莓派/STM32)优先选后两种宽电压方案,可以省掉第 4 节的分压电阻(前提仍是第 4 节反复强调的:接上后自己用万用表确认 Echo 电压)。

参数数值
工作电压DC 5V
工作电流约 15mA
工作频率40kHz
测距范围2cm – 400cm(近距离 <2cm 属于盲区,测不到)
测量精度约 ±0.3cm
探测角度不大于 15°(锥形范围,超出角度容易漏检)
触发信号Trig 引脚给 ≥10µs 的高电平脉冲
输出信号Echo 引脚输出与距离成正比的高电平脉冲(5V TTL)
2

引脚定义

Pinout
引脚类别说明
VCC电源5V 供电,模块内部没有稳压电路,必须是 5V,不能用 3.3V 供电(测不出来或测量严重不准)。
Trig输入触发引脚,主控给一个 ≥10µs 高电平脉冲,模块就发一串超声波。
Echo输出回声引脚,模块用它输出一个高电平脉冲,脉冲宽度(时间)代表测到的距离。这个引脚输出的是 5V 电平,接 3.3V 逻辑的主控前务必看第 4 节。
GND公共地。
3

测距原理与时序

Ranging Principle & Timing

整个测距过程只有三步:主控拉高 Trig 至少 10µs → 模块自动发出 8 个 40kHz 方波 → 模块把 Echo 拉高,一直等到收到反射回波才拉低。Echo 保持高电平的时间,就是超声波"跑一个来回"的时间。

Trig
≥10µs
超声波
8×40kHz
Echo
高电平时间 = 距离对应的往返时间

距离和 Echo 高电平时间的换算,最常用的是这个近似公式(声速取 340 m/s,除以 2 是因为时间算的是"去 + 回"两段路程):

换算公式

距离(cm) = Echo高电平时间(µs) ÷ 58

等价写法:距离(cm) = 时间(µs) × 0.017。如果追求更高精度,可以把 340 m/s 换成按温度修正的声速 331.4 + 0.606 × 温度(℃),一般教学/避障场景用不到这一步。

4

电平安全须知

3.3V ↔ 5V Level Shifting
⚠ ESP32 / STM32 / 树莓派都是 3.3V 逻辑,Echo 直接接会有风险

HC-SR04 是 5V 模块,Echo 引脚输出的高电平是 5V。ESP32、树莓派、以及绝大多数 STM32 型号的 GPIO 只能承受 3.3V 左右,5V 直接怼进去超出芯片规格,短期内可能看着正常,长期用容易把这个引脚"作旧"甚至直接损坏。网上不少教程图省事直接硬接,能跑不代表安全,本文档统一按规范接法来。

做法:Echo 出来后先过一个分压电阻,再进主控的 GPIO;Trig 是主控发向模块,3.3V 电平模块也能正常识别为高电平,不需要处理。

分压电阻:R1 = 1kΩ(串在 Echo 和 GPIO 之间) R2 = 2kΩ(从 GPIO 接到 GND) → 5V × 2/(1+2) ≈ 3.3V

后面第 5–7 节的接线图里,Echo 这一路统一按"过分压电阻"画。分压电阻是最省钱的方案,如果手头有现成的双向电平转换模块(logic level converter),效果一样,接法更简单,二选一即可。

5

接线 · ESP32

Wiring · ESP32 DevKit / ESP32-2432S028 (2.8"黄屏CYD)

ESP32 这块比 STM32 省事很多——板子自带 USB 转串口,一根 USB 线就能烧录+供电+看串口,不需要额外的编程器或 USB转TTL 模块。分两种情况:普通 DevKit(下面直接给接线)和 ESP32-2432S028 2.8寸黄屏/CYD(专用接口,见下方 ✅已验证 的详细说明)。

准备清单(DevKit 通用款)
  • ESP32 DevKit 开发板(一根 USB 线就能烧录,不用额外买编程器)
  • HC-SR04 模块 + 杜邦线若干
  • Arduino IDE,装好 ESP32 开发板支持(首选项填入 ESP32 板管理器URL,开发板管理器里搜"esp32"安装)

步骤1 · HC-SR04ESP32 DevKit

VCC5V
GNDGND
TrigGPIO5
Echo1k/2k 分压 → GPIO18
Echo 不要直接接 GPIO18,先经过第 4 节的分压电阻

步骤2 · 烧录 + 验证

USB 线接电脑,Arduino IDE 里开发板选对应的 ESP32 型号,端口选对应 COM 口,点上传。烧录完打开串口监视器(波特率115200),应该能看到持续打印的 Distance: xx cm。代码见第9节。


如果你用的是 ESP32-2432S028(2.8" 黄屏 / CYD)✅ 已实物验证

这块板子不是普通 DevKit,板上除了 ESP32 本体,屏幕/触摸已经占用了一大票 GPIO,只留了一个 CN1 4 针外接口:GND - IO22 - IO27 - 3V3(之前接 BNO085/VL53L5CX 这些 I2C 传感器时,IO22/IO27 是当 SCL/SDA 用的)。HC-SR04 不走 I2C,但这两个引脚本身就是普通 GPIO,代码里改成 pinMode() + digitalWrite()/digitalRead(),不要调用 Wire.begin(),接口照样能用:

2026-07-13 实物验证通过:Trig=IO22、Echo=IO27、VCC=CN1 3V3、GND=CN1 GND,串口实测能连续读出正确变化的距离值(约50–99cm 随物体移动实时变化)。厂家原厂原理图里 CN1 那张图纸只标了 IO27,没有 IO22,和这次实测、以及 01535 项目里三套已验证程序的接法对不上——这次以实测为准,原理图那份大概率是旧版本或者对不上这批板子的丝印,不代表 IO22 这条线接错了。

HC-SR04CN1说明
GNDGND公共地
VCC3V3⚠️ CN1 只有 3.3V,没有 5V,见下方说明
TrigIO22当普通输出脚用,不初始化 I2C
EchoIO27当普通输入脚用,见下方分压说明

代码不用换成 I2C 库,第 9 节 ESP32 代码原样能用,只要把 TRIG_PIN 改成 22ECHO_PIN 改成 27 就行,其它逻辑不变。

CN1 不出 5V,标准 5V-only 版 HC-SR04 没法只靠这个口供电——这次实测用的是第 1 节表格里的"双芯片宽电压版"(3.3–5V),VCC 接 CN1 的 3V3、Echo 不加分压直接接 IO27,功能完全正常(能连续测出正确变化的距离)。仍然没有拿万用表实测过 Echo 高电平的具体电压值——"能正常测距"不等于"电压绝对安全",追求稳妥的话还是建议实测一下 Echo 电压,确认在 3.3V 附近再长期使用。如果你买的是标准 5V-only 版(第1节表格第一行),不要照抄这一节的接法,CN1 供电不够,需要另找 5V 电源。


实拍 · 已去掉原始杂音并加入中文旁白。按上表接好 CN1 之后,2.8寸屏幕上直接显示大字号距离数字,随手移动实时变化,不用接电脑看串口。

HC-SR04 连接 ESP32-2432S028 2.8寸黄屏的接线原理图
接线原理图:HC-SR04 + ESP32-2432S028(2.8" 黄屏/CYD),Trig/Echo 借用 CN1 的 IO22/IO27,当成普通 GPIO 用(不走 I2C)。
6

接线 · STM32

Wiring · STM32F103C8T6 · ST-Link + CP2102 ✅ 已实物验证 · 从零开始一步步来

STM32 是本文四个平台里步骤最多的一个——板子本身不带 USB 口,需要额外的编程器和串口模块才能烧录/调试。这一节把"准备什么东西"到"烧录成功+验证"的每一步都拆开写,照着顺序做,中途遇到的坑本节也都记录了原因和解法。以 STM32F103C8T6 最小系统板(俗称"蓝丸",实际板型很多,有些还带独立的 4 针 SWD 调试口,跟经典两排排针的蓝丸不完全一样,接线前对照自己板子的丝印确认)为例。

准备清单
  • STM32F103C8T6 最小系统板("蓝丸")
  • ST-Link V2 编程器(正品或国产克隆都行)
  • USB转TTL模块,如 CP2102(用来看串口输出,不装也能烧录,只是看不到测距结果)
  • HC-SR04 模块 + 杜邦线若干
  • (可选)0.96 寸 OLED 显示屏(SSD1306,I2C接口)
  • 电脑装好 VS Code + PlatformIO(步骤1教怎么装)

步骤1 · 装开发环境
  1. VS Code(微软官网下载,免费)。
  2. VS Code 左侧扩展商店(Extensions)搜 PlatformIO IDE,装上,等它自己把底层工具链下载完(第一次装需要联网等几分钟)。
  3. 装好后 VS Code 左侧会多一个 PlatformIO 的蚂蚁图标,点开选 New Project:Board 选 Generic STM32F103C8(对应"蓝丸"),Framework 选 Arduino
  4. 新建的项目文件夹里,把 platformio.inisrc/main.cpp 换成第10节贴的内容。
  5. 项目文件夹路径不能含中文(见第10节的踩坑说明),用纯英文路径建项目。

步骤2 · HC-SR04STM32F103C8T6

VCC5V(宽电压款可接3.3V)
GNDGND
TrigPA0
Echo1k/2k 分压 → PA1

步骤3 · ST-Link V2STM32F103C8T6

3.3V3V3
GNDGND
SWCLKSWCLK
SWDIOSWDIO
这 4 根线负责烧录,同时也给整块板子供电——板子的电源就靠这一根 3.3V 线,接好后板子应该已经有电(板载电源LED会亮)

ST-Link V2 编程器接口引脚实拍特写,标注RST/SWDIO/GND/SWCLK/3.3V/5.0V
实拍 · ST-Link V2 编程器的10针接口,图上能看清每个孔位对应的信号名(RST/SWDIO/GND/SWCLK/3.3V/5.0V),照着丝印接就不会错。

步骤4 · 检查 BOOT0 / BOOT1 跳线

板上一般有 BOOT0(有些板子还有 BOOT1)跳线帽。只要是用 ST-Link 走 SWD 烧录(本节的接法),BOOT0 拨到 0(靠 GND 那一侧)就行,不需要去动它——SWD 烧录不经过芯片自带的系统引导程序,跟 BOOT0 无关。BOOT0 拨到 1 只在"不用 ST-Link,改用 USB 转串口走芯片内置串口 Bootloader 烧录"这种方案时才需要,本节不涉及,全程保持 BOOT0=0(有 BOOT1 的话也一起拨 0)即可。


STM32板子BOOT0/BOOT1跳线帽位置实拍,靠近复位按键
实拍 · BOOT0/BOOT1 跳线帽在板子上的实际位置(靠近 RESET 复位按键),本节接法两个跳线帽都保持在图中这个默认位置(拨向GND侧)不用动。

步骤5 · 写代码 + 烧录

把第10节的 platformio.inisrc/main.cpp 内容贴进步骤1建好的项目里,确认 ST-Link 接好(步骤3)、BOOT 跳线正常(步骤4),点 VS Code 底部状态栏的 →(Upload)图标,或者在终端跑 pio run -t upload。看到 SUCCESSVerified OK 字样就是烧录成功了。


步骤6 · CP2102(USB转TTL)STM32F103C8T6

GNDGND
TXDPA10
RXDPA9
⚠️ CP2102 的 VCC/3.3V 引脚不接(见下方双电源警告);TXD/RXD 是"交叉"接法,不是对应位置直连。接好后用 PlatformIO 的 Serial Monitor 或任意串口工具(115200 波特率)打开 CP2102 的 COM 口,应该能看到持续打印的 Distance: xx cm

CP2102 USB转TTL模块接口实拍特写,标注3V3/TXD/RXD/GND/+5V
实拍 · CP2102 模块上标着 TXD/RXD/GND/+5V 的丝印,对照这张图接线,注意 VCC/+5V 那个孔位本节不接(见下方双电源警告)。

⚠ ST-Link 和 CP2102 同时接一块板子时,只能有一个电源

ST-Link 和 CP2102 各自的 USB 头只负责给它们自己供电,不会自动给 STM32 板子供电——板子要通电,必须有一根独立的 3.3V 线接到板子的 3V3 脚。这根线只能接一次:本节接法是让 ST-Link 的 3.3V 供电,CP2102 的 VCC 就必须悬空不接;如果两边都接了 3.3V,两个电源会在同一条轨上"打架",轻则供电不稳,重则发烫损坏元件。两个 USB 头可以同时插着电脑(ST-Link 管供电+烧录,CP2102 只管收发数据),但供电的线只能有一条。


步骤7(可选)· 0.96" OLED (SSD1306)STM32F103C8T6

VCC3.3V
GNDGND
SCLPB6
SDAPB7
PB6/PB7 是 STM32duino 核心默认的硬件 I2C 引脚,不接也不影响串口输出。接好后屏幕应显示"HC-SR04 Distance"和实时距离数字

✅ 已实物验证(2026-07-13)+ 步骤8 · 常见问题排查

按上面步骤1~7走完,烧录成功、串口能连续读出正确变化的距离值、OLED 也能正常显示,有实拍视频为证。调试过程中实际遇到的坑,按出现频率排列:

  • ST-Link 克隆USB连接不稳定:偶尔烧录报"打开设备失败"(Error: open failed),纯粹是USB接触问题,跟接线/驱动无关,拔插一下USB(换个口更好)就恢复。
  • 板子/编程器发烫、完全不通电:多半是步骤6的"双电源"警告没注意——CP2102 和 ST-Link 的电源线同时接了 3.3V,两个电源打架。立刻断电,确认 CP2102 的 VCC 悬空后再通电。
  • UART 接反,串口读不到数据:CP2102 的 TXD/RXD 必须"交叉"接(TXD→PA10、RXD→PA9),如果按位置直连(TXD→PA9、RXD→PA10)两边都是同类角色,收不到任何数据。
  • OLED 黑屏排查:OLED 的 SCL/SDA 一定要接实际的 I2C 硬件引脚(PB6/PB7,不是随便两个 GPIO),接错引脚或者 GND 没接通,屏幕会一直黑屏且串口也读不到 I2C 设备——可以临时加一段 I2C 总线扫描代码(遍历地址调用 Wire.beginTransmission()),比反复猜接线快得多。
  • 串口工具里中文显示乱码:不同串口调试工具的默认解码编码不一样,中文字符串容易在某些工具里花掉——数字本身没问题,本文第10节的代码已经统一改成英文打印,不用担心这个问题。

实拍 · 已去掉原始杂音并加入中文旁白。按步骤1~7接完之后,OLED 屏幕实时显示测到的距离数字,会随手移动实时变化。

HC-SR04 连接 STM32F103C8T6 和 OLED 的接线原理图
接线原理图:HC-SR04 + STM32F103C8T6 + 0.96" OLED,ST-Link/CP2102 的接法见上方文字说明。
7

接线 · 树莓派

Wiring · Raspberry Pi (BCM 编号) ⚠ 仅资料整理,未实物验证

树莓派 40 针排针上物理引脚 2/4 是 5V,物理引脚 6 是 GND,本文用 BCM 编号对应 GPIO23 / GPIO24。树莓派的 GPIO 完全不能超过 3.3V,Echo 分压这一步在树莓派上是必须做的,不是"建议"。⚠ 这一节目前只是接线原理整理,手头没有树莓派实物,没有真正烧录测试过——跟 ESP32/STM32/Arduino 三节不一样,接线前建议自己先小范围验证一下。

HC-SR04Raspberry Pi

VCC物理引脚 2(5V)
GND物理引脚 6(GND)
TrigGPIO23(物理 16)
Echo1k/2k 分压 → GPIO24(物理 18)
8

接线 · Arduino + OLED

Wiring · Arduino Uno + SSD1306 ✅ 已实物验证

Arduino Uno 本身就是 5V 逻辑,和 HC-SR04 的 5V TTL 电平天然匹配——这是四个平台里唯一不用给 Echo 加分压电阻的,接线最省事,也不需要额外的编程器/USB转TTL模块(Uno 自带USB口),很适合当"第一次接线"的入门组合。屏幕用最常见的 0.96 寸 SSD1306 OLED(I2C 接口,4 根线),用来把测到的距离数字直接显示出来,不用接电脑看串口。

准备清单
  • Arduino Uno(一根 USB 线就能烧录+供电)
  • HC-SR04 模块 + 杜邦线若干
  • (可选)0.96 寸 OLED 显示屏(SSD1306,I2C接口)
  • Arduino IDE,装好 Adafruit_SSD1306 + Adafruit_GFX 库(用OLED的话)

步骤1 · HC-SR04Arduino Uno

VCC5V
GNDGND
TrigD9
EchoD8
Uno 是 5V 逻辑,Echo 可以直接接,不需要第 4 节的分压电阻

HC-SR04 + Arduino Uno + OLED 实物接线全貌,面包板实拍
实拍 · 步骤1+步骤2接完之后的接线全貌(面包板搭建)。

步骤2(可选)· 0.96" OLED (SSD1306)Arduino Uno

VCC5V
GNDGND
SCLA5
SDAA4
和 HC-SR04 各自独立接线,互不影响;OLED 走 I2C,Uno 上固定是 A4/A5

步骤3 · 烧录 + 验证

USB 线接电脑,Arduino IDE 里开发板选 Arduino Uno,端口选对应 COM 口,点上传。代码见第12节。接了 OLED 的话,屏幕应显示"HC-SR04 Distance"和实时距离数字;没接 OLED 就打开串口监视器(波特率115200)看数字。


实拍 · 已去掉原始杂音并加入中文旁白。手在 HC-SR04 前移动,OLED 屏幕上的距离数字实时跟着变化。

OLED 实时显示 HC-SR04 测距结果 177.6cm
实拍 · OLED 显示测距结果特写。

HC-SR04 连接 Arduino Uno 和 OLED 的接线原理图
接线原理图:HC-SR04 + Arduino Uno + 0.96" OLED,把上面两张 wiring-card 的接法画成一张整体示意图。
9

ESP32 代码

Arduino IDE · C++

用 Arduino IDE 烧录,开发板选对应的 ESP32 型号即可,不需要额外安装库,pulseIn() 是 Arduino 核心自带函数。

hcsr04_esp32.ino
// HC-SR04 · ESP32 · Trig=GPIO5, Echo=GPIO18(经分压)
#define TRIG_PIN 5
#define ECHO_PIN 18

void setup() {
  Serial.begin(115200);
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  digitalWrite(TRIG_PIN, LOW);
}

float getDistanceCM() {
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);          // ≥10us 触发脉冲
  digitalWrite(TRIG_PIN, LOW);

  // 30ms 超时:约等于5m的往返时间上限,避免物体太远时死等
  unsigned long duration = pulseIn(ECHO_PIN, HIGH, 30000);
  if (duration == 0) return -1;     // 没测到(超出量程/无反射)
  return duration / 58.0;
}

void loop() {
  float d = getDistanceCM();
  if (d < 0) {
    Serial.println("超出量程或无回波");
  } else {
    Serial.print("距离: ");
    Serial.print(d, 1);
    Serial.println(" cm");
  }
  delay(300);
}
10

STM32 代码

PlatformIO · STM32duino (Arduino 框架) ✅ 已实物验证

这一节改用 PlatformIO + STM32duino(STM32 官方维护的 Arduino 兼容核心),代码风格和前面 ESP32/Arduino 完全一样(pinMode/digitalWrite/pulseIn),不用再手搭 CubeMX 定时器、也不用切换到 C 语言的 HAL 写法。选这条路是因为它是本文档里唯一实际编译烧录、在真实硬件上测过的方案——CubeMX/HAL 那套理论上可行,但没有实测硬件可以验证,为了保证文档"代码要和实物一致",这里只保留验证过的版本。开发环境怎么装、接线怎么接、烧录完怎么验证,第 6 节按步骤1~8完整写了一遍,这里只放代码本身。

⚠ 项目路径不能有中文

Windows 下这套工具链(GCC ARM 编译器的链接器)遇到中文路径会在最后链接这一步报错(类似 Illegal byte sequence/打不开 .map 文件),前面每个源文件单独编译都不会报错,只有链接会炸。项目文件夹本身、以及它所在的上级目录,都不能含有中文字符,用纯英文路径(比如 D:\projects\hcsr04_stm32\)建项目就没有这个问题。


platformio.ini
[env:bluepill_f103c8]
platform = ststm32
board = bluepill_f103c8
framework = arduino
upload_protocol = stlink
monitor_speed = 115200
lib_deps =
    adafruit/Adafruit SSD1306@^2.5.13
    adafruit/Adafruit GFX Library@^1.11.11

最后两行 lib_deps 是给第 6 节那块可选的 0.96 寸 OLED 用的,PlatformIO 会自动下载;如果不接 OLED,删掉这两行也能正常编译烧录。

src/main.cpp
// HC-SR04 · STM32F103C8T6 · PlatformIO/STM32duino · Trig=PA0, Echo=PA1(经分压)
// 串口通过CP2102接PA9(TX)/PA10(RX) · OLED(SSD1306,I2C,0x3C)可选: SCL=PB6, SDA=PB7
#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define TRIG_PIN PA0
#define ECHO_PIN PA1
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

HardwareSerial DebugSerial(PA10, PA9);  // RX, TX —— 给 CP2102 看的调试串口
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

void setup() {
  DebugSerial.begin(115200);
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  digitalWrite(TRIG_PIN, LOW);

  Wire.begin();
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
}

float getDistanceCM() {
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);

  unsigned long duration = pulseIn(ECHO_PIN, HIGH, 30000);
  if (duration == 0) return -1;
  return duration / 58.0;
}

void loop() {
  float d = getDistanceCM();
  if (d < 0) {
    DebugSerial.println("No echo / out of range");
  } else {
    DebugSerial.print("Distance: ");
    DebugSerial.print(d, 1);
    DebugSerial.println(" cm");
  }

  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.println("HC-SR04 Distance");

  display.setTextSize(3);
  display.setCursor(10, 24);
  if (d < 0) {
    display.print("--.-");
  } else {
    display.print(d, 1);
  }

  display.setTextSize(1);
  display.setCursor(100, 40);
  display.println("cm");
  display.display();
  delay(300);
}

串口打印统一用英文(Distance: xx cm),不是不支持中文——而是不同串口调试工具的默认解码编码不一样(有的按 UTF-8,有的按 GBK),中文很容易在某些工具里显示成乱码,改英文就没有这个烦恼,跟接线、跟数据本身对不对没关系。

不需要 OLED 的话,把 Wire.h/Adafruit_* 相关的三行 #includedisplay 变量定义、Wire.begin()/display.begin() 这几行、以及 loop() 里画屏幕的那一段全部删掉,只留 DebugSerial 相关的部分,就是最精简的串口版。

11

树莓派代码

Python · RPi.GPIO

树莓派 OS 通常自带 RPi.GPIO 库,没有的话 pip install RPi.GPIO 装一下即可,然后 python3 直接运行。

hcsr04.py
import RPi.GPIO as GPIO
import time

TRIG = 23   # 物理引脚16
ECHO = 24   # 物理引脚18,经分压电阻接入

GPIO.setmode(GPIO.BCM)
GPIO.setup(TRIG, GPIO.OUT)
GPIO.setup(ECHO, GPIO.IN)
GPIO.output(TRIG, False)
time.sleep(0.5)   # 模块上电稳定

def get_distance_cm():
    GPIO.output(TRIG, True)
    time.sleep(0.00001)   # 10us 触发脉冲
    GPIO.output(TRIG, False)

    timeout = time.time() + 0.03
    while GPIO.input(ECHO) == 0:
        start = time.time()
        if start > timeout:
            return None

    timeout = time.time() + 0.03
    while GPIO.input(ECHO) == 1:
        end = time.time()
        if end > timeout:
            return None

    duration = end - start
    return round((duration * 34300) / 2, 1)   # 声速34300cm/s,除2是往返路程

try:
    while True:
        d = get_distance_cm()
        print(f"距离: {d} cm" if d is not None else "超出量程或无回波")
        time.sleep(0.3)
except KeyboardInterrupt:
    GPIO.cleanup()
12

Arduino 代码(OLED 显示)

Arduino Uno · pulseIn + SSD1306

需要先在库管理器里装 Adafruit SSD1306 和它依赖的 Adafruit GFX Library。大多数 0.96 寸 OLED 的 I2C 地址是 0x3C,少数是 0x3D,屏幕不亮先试试换这个地址。本页代码已在实物上烧录验证通过(Arduino Uno + 4 针 I2C OLED,实测效果见第 15 节实拍图)。

⚠ 先确认 OLED 的驱动芯片,不是所有 0.96"/1.3" OLED 都叫 SSD1306

市面上外观几乎一样的 I2C OLED,驱动芯片常见的有两种:SSD1306SH1106(丝印经常是 GND VDD SCK SDA 四针,光看外观和针脚名分辨不出是哪颗芯片)。两者命令集不完全一样,装错库常见表现是屏幕完全不亮、或者画面错位/重影。本页代码用的是 Adafruit_SSD1306 库——如果你的模块实际是 SH1106,先按这页代码试一下(部分 SH1106 模块对 SSD1306 库也有较好的兼容性,实测能正常显示),不行的话换成 Adafruit_SH110X 库(同样是 Adafruit 出的,装法一样),把头文件换成 #include <Adafruit_SH110X.h>,对象声明换成 Adafruit_SH1106G display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);display.begin(SSD1306_SWITCHCAPVCC, 0x3C) 换成 display.begin(0x3C, true),其余代码不用改(SSD1306_WHITE 换成 SH110X_WHITE)。

hcsr04_oled.ino
// HC-SR04 · Arduino Uno · Trig=D9,Echo=D8 · OLED(SSD1306, I2C, 0x3C)
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define TRIG_PIN 9
#define ECHO_PIN 8
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

void setup() {
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  digitalWrite(TRIG_PIN, LOW);

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
}

float getDistanceCM() {
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);

  unsigned long duration = pulseIn(ECHO_PIN, HIGH, 30000);
  if (duration == 0) return -1;
  return duration / 58.0;
}

void loop() {
  float d = getDistanceCM();

  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.println("HC-SR04 Distance");

  display.setTextSize(3);
  display.setCursor(10, 24);
  if (d < 0) {
    display.print("--.-");
  } else {
    display.print(d, 1);
  }

  display.setTextSize(1);
  display.setCursor(100, 40);
  display.println("cm");

  display.display();
  delay(300);
}
13

故障排查

Troubleshooting
一直测不到 / 一直超时
  1. 先确认 Trig、Echo 有没有接反——这是最常见的接线失误。
  2. 供电是否稳定:模块要独立接一路干净的 5V,杜邦线太细太长、和其他大电流器件共用电源,容易导致触发瞬间电压跌落。
  3. 物体是否在有效范围内:2cm–400cm 之内,且落在 15° 探测锥角内,斜面或太软的材料(棉布、海绵)会把回波弹开测不到。

数值跳动很大,忽近忽远

多次测量取平均值或中位数再显示,能滤掉大部分噪声;如果现场有两个以上超声波模块同时工作,会互相收到对方的回波造成串扰,简单的办法是把各个模块的触发时间错开(比如轮流触发,而不是同时触发)。


用了一段时间后,主控这个 GPIO 口开始不正常

检查 Echo 有没有漏接第 4 节说的分压电阻——5V 长期直接打到 3.3V 的 GPIO 上,即使当下测着正常,也在透支芯片寿命。


近距离(几厘米内)什么都测不到

这是模块物理盲区,属于正常现象,不是接线或代码问题,2cm 以内本来就测不了。


OLED 屏幕完全不亮

90% 是 I2C 地址不对:先试 0x3C,不行换 0x3D;剩下的大概率是 SCL/SDA 接反,或者 OLED 和 HC-SR04 同时占用面包板同一路电源导致压降太大,分开供电试试。


OLED 地址/接线都对,但还是不亮或者花屏

检查驱动芯片是不是搞反了——见第 12 节的驱动芯片提醒,SSD1306SH1106 长得几乎一样但库不通用。装错库常见表现就是"完全不亮"或者"画面错位/花屏",两个库都装上分别试一下,哪个能正常显示就用哪个。

14

小白视频讲解大纲

Beginner Video Script Outline

面向完全没接触过传感器、没接过线、不会写代码的观众,讲解顺序按"是什么 → 干什么用 → 怎么接 → 怎么跑起来 → 效果展示"来,专业名词尽量换成生活类比,具体电阻阻值、电压这些数字可以在画面里标出来,但口播不用逐字念参数。

  1. 开场类比:这个模块就像"电子蝙蝠"——蝙蝠喊一声,听回声判断前面有没有东西、有多远,HC-SR04 干的是一模一样的事,只是用的是人耳听不到的超声波。
  2. 能用来干嘛:扫地机器人避障、倒车雷达、自动感应门、水塔水位监测——都是同一个模块,换个应用场景而已。
  3. 认识这个模块:只有 4 根针——"通电的"、"接地的"、"喊话的"(Trig)、"听回声的"(Echo),不用记协议、不用装库,比很多传感器都简单。
  4. 接线要点(大白话版):直接说"听回声这根线要经过两个小电阻'降压'一下再给主控,因为它'嗓门'比主控能承受的要大,不降一下容易把主控的耳朵'震坏'"——不用讲分压公式,观众照图接就行。
  5. 代码怎么来:强调"代码是现成的,复制粘贴进去,只需要改开头两个引脚编号,跟你实际接的引脚对上就行"。
  6. 现场效果演示:拿一本书或者手掌,从远到近移动,数字跟着实时变化,直观证明"真的测出距离了"——配一块 OLED 小屏幕效果最好,数字直接显示在屏幕上,不用接电脑看串口,观众一眼就懂。
  7. 小白最容易翻车的点:杜邦线没插紧(数值乱跳的头号原因)、Trig/Echo 接反、供电用了太细的线或者跟电机之类大功率器件抢电。
15

实物图与动画演示

Product Photos & Animated Demos

下面是淘宝卖家实拍图,用来对照实物长相和常见配件,以及两段接线原理动图(本节是文档里少数允许用图片/动图的地方,其余章节按要求保持纯文本);Arduino + OLED 组合已经实物验证并拍了真实效果图,下方还留了两个位置,等 ESP32/STM32/树莓派也实物验证后陆续补上。

HC-SR04 连接 Arduino Uno 和 OLED 的接线原理动图
接线原理动图:HC-SR04 + Arduino Uno + OLED —— Trig 触发 → 发出超声波 → Echo 收回波 → 屏幕刷新距离,循环演示测距的完整周期。

HC-SR04 连接 ESP32 2.8寸黄屏的接线原理动图
接线原理动图:HC-SR04 + ESP32-2432S028(2.8" 黄屏/CYD)—— 同样的测距周期,直接在大屏幕上显示距离数值。

HC-SR04 单品实拍图,正面双探头+背面电路板
淘宝卖家实拍:HC-SR04 单品图,正面双探头(T发射/R接收)+ 背面电路板丝印。图片来源见 说明.md。

HC-SR04 及同系列多规格实拍图
淘宝卖家实拍:HC-SR04(1–3号,蓝板)、HYSRF05(4号,蓝板五针)及其余同系列变种(5–8号,绿板)。图片来源见 说明.md。

HC-SR04 常见配件与变型实拍图
淘宝卖家实拍:固定支架(多色)、数码管显示驱动板、一体化防水带线版本等常见配套配件,选购时按需搭配。

〔待插入:自己实拍的模块正面 / 背面照片〕

HC-SR04 + Arduino Uno + OLED 实物接线全貌,面包板实拍
实拍 · HC-SR04 + Arduino Uno + OLED 接线全貌(面包板搭建,2026-07-13 验证通过)。

OLED 实时显示 HC-SR04 测距结果 177.6cm
实拍 · OLED 实时显示测距结果,第 12 节代码烧录后的真实效果(非模拟)。

〔待插入:树莓派实际接线照片(尚未实物验证);ESP32黄屏CYD/STM32 的实拍图和演示视频已经分别嵌入第5/6节对应步骤里了〕