
HC-SR04 大概是所有超声波模块里出现频率最高的一颗:四根引脚、几块钱一颗、量程标称 2cm 到 400cm,标称测距精度可达 3mm。它不需要任何总线协议,靠一个 Trig 触发脉冲和一个 Echo 回波电平就能工作,几乎任何单片机都能驱动。这篇把它的原理、接线、代码和几个容易踩的坑一次讲清楚,代码搬运自 How To Mechatronics 的实测教程,逐字符未改动。
HC-SR04 的引脚与测距原理
模块一共四个引脚:VCC(5V 供电)、Trig(触发)、Echo(回波)、GND。两个金属罐状的部件,一个是 T 发射头,一个是 R 接收头,各对应一片超声波换能器。模块尺寸约 45mm × 20mm × 15mm,板中心距 40mm × 13mm,打安装孔时可以直接按这个尺寸来。

工作过程分四步:Trig 收到 10 微秒高电平后,模块从发射头发出 8 个 40kHz 的超声波脉冲;声波碰到障碍物反射回来,接收头捕捉到回波;Echo 引脚随即输出一段高电平,其宽度等于声波往返的总时间;主控用 pulseIn() 之类的办法量出这个时间,再算出距离。

计算公式很简单:距离 = 时间 × 声速 ÷ 2。声速取 340m/s,换算成 0.034cm/微秒,除以 2 是因为声波走了一个来回。

还有一点容易被忽略:发射头和接收头的夹角很小,有效反射窗口其实比较窄,打斜的墙面可能漏测,这点选型一节还会提到。
四根线接 Arduino
接线没有任何难度,按下面这张表接即可:
| HC-SR04 | Arduino Uno |
|---|---|
| VCC | 5V |
| Trig | D9(任意数字脚) |
| Echo | D10(任意数字脚) |
| GND | GND |

Trig 和 Echo 用哪两个数字脚都行,代码里对应改一下就好。唯一要注意的是供电:模块按 5V 设计,接 3.3V 的板子(比如部分 ESP32 引脚逻辑)时电平匹配要另做处理,Uno 上直接插就行。
测距代码:从 Trig 脉冲到串口读数
核心代码如下,思路是「拉低归零 → 给 10 微秒触发脉冲 → pulseIn 量 Echo 高电平时长 → 换算距离」,完整可烧录:
/*
Ultrasonic Sensor HC-SR04 and Arduino Tutorial
by Dejan Nedelkovski,
www.HowToMechatronics.com
*/
// defines pins numbers
const int trigPin = 9;
const int echoPin = 10;
// defines variables
long duration;
int distance;
void setup() {
pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
pinMode(echoPin, INPUT); // Sets the echoPin as an Input
Serial.begin(9600); // Starts the serial communication
}
void loop() {
// Clears the trigPin
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Sets the trigPin on HIGH state for 10 micro seconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPin, HIGH);
// Calculating the distance
distance = duration * 0.034 / 2;
// Prints the distance on the Serial Monitor
Serial.print("Distance: ");
Serial.println(distance);
}打开串口监视器(波特率 9600),把手掌放在探头前慢慢移动,就能看到 Distance 值实时跟着变。如果一直显示 0,先查 Echo 是否接对——pulseIn 一直等不到上升沿,返回值就是 0。
进阶:LCD 实时显示、NewPing 库与温度补偿
串口看数只能接着电脑玩,想脱离电脑,接一块 LCD1602 就够。原教程用 LiquidCrystal 库把厘米和英寸两行同时打到屏上:Trig 仍接 9、Echo 仍接 10,LCD 数据脚按 rs=1、enable=2、d4 到 d7 接 4 至 7 的顺序初始化,loop 里先照常量出 duration,再用 duration × 0.034 ÷ 2 算厘米、duration × 0.0133 ÷ 2 算英寸,两次 setCursor 分别写进第一行和第二行,每次打印后 delay(10) 给屏留刷新时间。完整代码在原教程页面可整段复制,这里不重复占篇幅。

如果项目里传感器多了、不想自己管触发时序,可以直接上 NewPing 库。它把触发和回波读数封装成一行,还内置了防串扰的中值滤波:
#include "NewPing.h"
#define TRIGGER_PIN 9
#define ECHO_PIN 10
#define MAX_DISTANCE 400 // Maximum distance we want to measure (in centimeters).
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
void setup() {
Serial.begin(9600);
}
void loop() {
delay(50); // Wait 50ms between pings (about 20 pings/sec). 29ms should be the shortest delay between pings.
int distance = sonar.ping_cm(); // Send ping, get distance in cm and print result (0 = outside set distance range)
Serial.print("Distance: ");
Serial.print(distance);
Serial.println("cm");
}再较真一点,可以做温度补偿。声速并非恒定 340m/s,而是随温度变化:0°C 约 331.4m/s,30°C 能到 350m/s 左右,温差大时误差肉眼可见。教程里用一颗 DHT22 读环境温度,按 331.4 + 0.6×T(°C)修正声速再算距离,实测精度确实比固定声速好一截:

选型与使用注意
最后从器件角度给几条实用提醒。第一,标称 3mm 精度是理想条件,实际普通白墙环境下 ±1cm 左右更常见,做避障够用,做精确测量要上 ToF 激光类方案。第二,HC-SR04 的探测波束角约 15 度,软布、海绵这类吸声材料基本测不到,大面积斜面也可能回波丢失,返回 0 要想到这一层。第三,同型号兼容板鱼龙混杂,3.3V 逻辑的 RCWL-9610、防水的一体化 JSN-SR04T 是常见替代,选型时按供电和封装需求挑,别只看名字带 SR04 就下单。第四,两次测量之间至少留 60ms 间隔,间隔太近上一轮回波会串进下一轮,NewPing 示例里的 delay(50) 加上 ping 本身耗时正好在这个量级。
整套东西一颗模块、一块 Uno、四根杜邦线就能跑通,适合作为给机器人加避障感知的第一课。代码里的引脚号、声速系数都留了注释,换成自己的引脚布局改动量很小。











请问Trig和Echo能不能接其他引脚?比如11和12,代码里改const int那两行就行了吗?
温度补偿那段很实用,夏天空调房和冬天室温差十几度,固定340算出来确实飘
这个模块测软的东西基本没戏,试过对着窗帘一直回0,换成硬纸板立马正常
pulseIn等不到上升沿返回0这个坑我踩过,Echo线接反了查了一下午,看到这篇直接泪目
几块钱的芯片能玩出这么多花样,建议人手一颗