《ESP32 入門》ESP32 超音波測距教學:HC-SR04 模組實作
用 ESP32搭配 HC-SR04 超音波模組實現距離量測。從原理、接線到程式碼,提供基礎版、中位數濾波版及距離警報器三個範例。
超音波測距是 Maker 入門最經典的感測器應用之一。HC-SR04 超音波模組價格親民、用起來也很簡單,搭配 ESP32 NodeMCU-32S 開發板,只需要幾條杜邦線就能搞定距離量測。這篇教學會從原理介紹、接線方式到程式碼實作,帶你完成超音波測距專案。
所需材料
| 品項 | 數量 | 說明 |
|---|---|---|
| ESP32 NodeMCU-32S 開發板 | 1 | 38 pin 版本 |
| HC-SR04 超音波模組 | 1 | 測距範圍 2cm ~ 400cm |
| 麵包板 | 1 | 全尺寸或半尺寸皆可 |
| 杜邦線(公對公) | 4 條 | — |
| Micro USB 傳輸線 | 1 | 連接電腦用 |



HC-SR04 超音波模組介紹
模組外觀與腳位
HC-SR04 模組上面有兩顆圓筒狀的超音波發射器跟接收器,模組總共有 4 支腳位:
- VCC:電源正極(5V)
- Trig:觸發腳位(輸入),送出 10μs 高電位脈衝啟動量測
- Echo:回波腳位(輸出),回傳高電位脈衝,脈衝寬度對應距離
- GND:電源負極(接地)

什麼是超音波?
人耳能聽到的聲音頻率大約在 20Hz ~ 20kHz 之間。超音波(Ultrasonic) 就是頻率高於 20kHz、超出人耳能聽到範圍的聲波。HC-SR04 用的頻率是 40kHz,所以我們在操作的時候完全聽不到它發出的聲音。
超音波跟一般聲波一樣,都是靠空氣中的分子振動來傳遞的機械波。當超音波碰到固體障礙物的時候,會像光照到鏡子一樣產生反射,模組就是利用這個反射特性來判斷障礙物的距離。這個原理跟蝙蝠在黑暗中靠回聲定位飛行是一樣的道理,所以超音波測距也被叫做「聲納(Sonar)」技術。
HC-SR04 模組內部構造
HC-SR04 模組上面那兩顆銀色圓筒,一顆是超音波發射器(Transmitter, T),另一顆是超音波接收器(Receiver, R)。發射器裡面有一片壓電陶瓷片,通電之後會以 40kHz 的頻率高速振動,把電能轉換成超音波。接收器的原理剛好相反,當反射回來的超音波打到壓電陶瓷片時,振動會轉換成微弱的電訊號,再經過模組上面的比較電路放大處理之後,輸出到 Echo 腳位。
模組上除了收發器之外,還有一顆主控 IC,負責處理觸發時序、發射 8 組脈衝、計算回波時間這些工作,所以我們只要控制 Trig 跟讀取 Echo 就好了。
測距原理與時序
超音波測距的完整工作流程長這樣:
- 觸發(Trigger):微控制器對 Trig 腳位送出一個至少 10 微秒(μs) 的高電位脈衝
- 發射(Transmit):模組收到觸發訊號後,自動透過發射器連續打出 8 組 40kHz 的超音波脈衝(Burst)
- 等待反射(Wait):超音波以音速向前傳播,碰到障礙物之後反射回來
- 接收(Receive):反射波被接收器偵測到
- 回報(Echo):Echo 腳位輸出一個高電位脈衝,脈衝持續的時間就等於超音波從發射到接收的來回時間
整個時序可以用下面這張示意圖來理解:
Trig 腳位:
┌──┐
─────────┘ └──────────────────────────────
|10μs|
模組發射:
┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐
──────────────┘└┘└┘└┘└┘└┘└┘└┘└─────────────
| 8 組 40kHz 脈衝 |
Echo 腳位:
┌──────────────────┐
────────────────────┘ └───
|← 高電位持續時間 →|
| = 超音波往返時間 |
重點在這裡:Echo 高電位的持續時間,就是超音波從發射到收到回波的總時間。我們在程式裡面用 pulseIn(echoPin, HIGH) 這個函式來量測這段時間,單位是微秒(μs)。
距離計算公式
知道超音波的來回時間之後,搭配音速就能算出距離:
距離(cm)= Echo 高電位持續時間(μs)× 音速(cm/μs)/ 2
音速是怎麼算出來的?
聲音在空氣中跑的速度會隨溫度改變。精確的公式是:
音速(m/s)= 331.3 + 0.606 × 溫度(°C)
在不同溫度下,音速大約為:
| 溫度 | 音速(m/s) | 音速(cm/μs) |
|---|---|---|
| 0°C | 331.3 | 0.03313 |
| 15°C | 340.4 | 0.03404 |
| 20°C | 343.4 | 0.03434 |
| 25°C | 346.5 | 0.03465 |
| 30°C | 349.5 | 0.03495 |
一般教學裡面,我們取常溫(大概 20~25°C)的近似值 0.034 cm/μs 來算,在大部分室內環境已經夠準了。如果你的應用場景溫差很大(像是戶外或工廠環境),可以搭配 DHT11 / DHT22 溫度感測器讀取即時溫度,動態修正音速,進一步拉高量測精度。
代入計算
以常溫 0.034 cm/μs 為例:
距離(cm)= Echo 高電位持續時間(μs)× 0.034 / 2
- 除以 2 是因為超音波走了「去程 + 回程」兩趟路,Echo 量到的是來回總時間,實際到障礙物的距離只有一半
舉個例子:如果 Echo 回傳的高電位持續了 1000μs,那距離 = 1000 × 0.034 / 2 = 17 cm。
HC-SR04 規格與限制
| 項目 | 規格 |
|---|---|
| 工作電壓 | 5V DC |
| 工作電流 | 約 15mA |
| 超音波頻率 | 40kHz |
| 最小量測距離 | 約 2cm |
| 最大量測距離 | 約 400cm(理論值) |
| 量測精度 | 約 ±3mm |
| 有效偵測角度 | 約 15° 錐形範圍 |
| 建議量測間隔 | ≥ 60ms(避免前次回波干擾) |
要特別注意的是偵測角度:HC-SR04 的超音波並不是一條直線射出去的,而是以大約 15 度的錐形向前擴散。也就是說,如果障礙物不在正前方、但在錐形範圍內,一樣會被偵測到。反過來講,如果障礙物太小(像是一根細桿子)或表面角度太斜,超音波可能沒辦法有效反射回來,就會造成量測失敗或數值不準。
另外,軟的材質(像布料、海綿)會吸收超音波,反射訊號很微弱,也容易造成量測不穩定。
接線說明
重要提醒:電壓相容性
HC-SR04 模組的工作電壓是 5V,Echo 腳位輸出的高電位也是 5V。但 ESP32 的 GPIO 是 3.3V 邏輯電位。
好消息是:大部分 ESP32 的 GPIO 都有 5V 容忍能力,實際上直接接通常都能正常動。不過如果你想要更保險一點,可以在 Echo 腳位跟 ESP32 GPIO 之間加一個簡單的分壓電路(用兩顆電阻,像是 1kΩ + 2kΩ 就行了)。
接線表
| HC-SR04 | ESP32 NodeMCU-32S |
|---|---|
| VCC | VIN(5V或3.3V) |
| Trig | GPIO 5 |
| Echo | GPIO 18 |
| GND | GND |
接線圖

提示:Trig 跟 Echo 用的 GPIO 腳位可以自己換,只要在程式碼裡面跟著改就好。建議避開 GPIO 0、2、12、15 這幾支有開機功能的腳位。
Arduino IDE 環境設定
如果你還沒裝好 ESP32 的開發環境,先看一下之前的教學哦!

程式碼:基本測距
範例一:基礎版超音波測距
// ESP32 NodeMCU-32S + HC-SR04 超音波測距
// 傑森創工 jmaker.com.tw
const int trigPin = 5; // Trig 腳位
const int echoPin = 18; // Echo 腳位
long duration; // 超音波往返時間(μs)
float distance; // 計算出的距離(cm)
void setup() {
Serial.begin(115200);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
Serial.println("HC-SR04 超音波測距啟動!");
}
void loop() {
// 確保 Trig 為低電位
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// 送出 10μs 高電位脈衝
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// 讀取 Echo 腳位的高電位持續時間(μs)
duration = pulseIn(echoPin, HIGH);
// 計算距離(cm)
distance = duration * 0.034 / 2.0;
// 輸出結果
Serial.print("距離:");
Serial.print(distance);
Serial.println(" cm");
delay(500); // 每 0.5 秒量測一次
}
上傳程式之後,打開序列埠監控視窗(鮑率設定 115200),你應該就能看到持續更新的距離數值了。

程式碼:進階版(含濾波與異常處理)
實際用起來的時候,超音波模組偶爾會吐出不太穩定的數值。下面這個進階版加入了中位數濾波跟超出範圍偵測,讓量測結果更穩、更可靠。
範例二:進階穩定版
// ESP32 NodeMCU-32S + HC-SR04 進階穩定版
// 傑森創工 jmaker.com.tw
const int trigPin = 5;
const int echoPin = 18;
const float MAX_DISTANCE = 400.0; // SR04 最大量測距離(cm)
const float MIN_DISTANCE = 2.0; // SR04 最小量測距離(cm)
const int NUM_SAMPLES = 5; // 取樣次數(中位數濾波)
void setup() {
Serial.begin(115200);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
Serial.println("HC-SR04 超音波測距(進階版)啟動!");
}
// 單次量測距離
float measureOnce() {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// 設定 timeout,避免程式卡住(最大距離約 23ms 往返)
long duration = pulseIn(echoPin, HIGH, 30000);
if (duration == 0) {
return -1; // 超時,回傳 -1 表示無效
}
float dist = duration * 0.034 / 2.0;
if (dist < MIN_DISTANCE || dist > MAX_DISTANCE) {
return -1; // 超出有效範圍
}
return dist;
}
// 氣泡排序(用於中位數濾波)
void bubbleSort(float arr[], int n) {
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
float temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
// 中位數濾波量測
float measureFiltered() {
float samples[NUM_SAMPLES];
int validCount = 0;
for (int i = 0; i < NUM_SAMPLES; i++) {
float d = measureOnce();
if (d > 0) {
samples[validCount] = d;
validCount++;
}
delay(30); // 每次量測間隔 30ms
}
if (validCount == 0) {
return -1; // 全部無效
}
// 排序後取中位數
bubbleSort(samples, validCount);
return samples[validCount / 2];
}
void loop() {
float distance = measureFiltered();
if (distance < 0) {
Serial.println("⚠ 量測失敗:物體超出範圍或無回波");
} else {
Serial.print("距離:");
Serial.print(distance, 1); // 保留一位小數
Serial.println(" cm");
}
delay(500);
}
實用應用:距離警報器
搭配一顆 LED 或蜂鳴器,就能做出簡單的距離警報器,偵測到東西太近的時候自動發出警報。


範例三:超音波距離警報器
// ESP32 + HC-SR04 距離警報器
// 傑森創工 jmaker.com.tw
const int trigPin = 5;
const int echoPin = 18;
const int ledPin = 2; // 板載 LED(GPIO 2)
const int buzzerPin = 4; // 蜂鳴器(選配)
const float ALERT_DISTANCE = 20.0; // 警報距離(cm)
void setup() {
Serial.begin(115200);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
pinMode(ledPin, OUTPUT);
pinMode(buzzerPin, OUTPUT);
Serial.println("距離警報器啟動!");
}
float getDistance() {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
long duration = pulseIn(echoPin, HIGH, 30000);
if (duration == 0) return -1;
return duration * 0.034 / 2.0;
}
void loop() {
float distance = getDistance();
if (distance > 0 && distance < ALERT_DISTANCE) {
// 物體太近 → 發出警報
digitalWrite(ledPin, HIGH);
tone(buzzerPin, 1000); // 1kHz 蜂鳴聲
Serial.print("⚠ 警報!距離:");
Serial.print(distance, 1);
Serial.println(" cm");
} else {
// 安全距離 → 關閉警報
digitalWrite(ledPin, LOW);
noTone(buzzerPin);
if (distance > 0) {
Serial.print("距離:");
Serial.print(distance, 1);
Serial.println(" cm");
}
}
delay(100);
}

常見問題排除
Q1:序列埠顯示的距離一直都是 0
- 先看一下 Trig 跟 Echo 的線有沒有接反
- 確認 GPIO 腳位編號跟程式碼裡面寫的一樣
Q2:距離數值跳來跳去
- 確定超音波模組前面沒有太小或太斜的東西(超音波碰到光滑斜面容易亂反射)
- 改用進階版的中位數濾波程式碼
- 把量測間隔時間(delay)拉長一點
Q3:距離最大只能到幾十公分
- HC-SR04 的標稱最大距離為 400cm,但實際受物體材質與大小影響
- 確認 VCC 供電是否穩定(供電不足會縮短量測距離)
Q4:pulseIn 經常超時
- 檢查模組是否正常(可以用萬用表測量 Trig 送出脈衝時 Echo 是否有回應)
- 確認 GND 有正確共地
- 嘗試更換一顆 HC-SR04 模組
延伸應用想法
學會超音波測距之後,你可以繼續嘗試這些專案:
- 智慧垃圾桶:偵測到有人靠近就自動開蓋(搭配舵機 Servo)
- 倒車雷達:不同距離發出不同頻率的蜂鳴聲
- 液位偵測器:放在水塔上方朝下偵測水面高度
- 自走車避障:搭配馬達模組,遇到障礙物自動轉向
- IoT 遠端監控:透過 ESP32 的 WiFi 功能,將距離數據上傳到雲端儀表板
總結
本篇教學介紹了如何使用 ESP32 NodeMCU-32S 搭配 HC-SR04 超音波模組進行距離量測。從基本原理到接線、程式碼都做了完整說明,並提供了基礎版、進階濾波版、以及距離警報器三個範例。HC-SR04 是非常適合入門的感測器,搭配 ESP32 強大的 WiFi 與藍牙功能,可以延伸出各種有趣的 IoT 應用。
傑森創工 JMaker Workshop https://jmaker.com.tw




