《ESP32 入門》ESP32 超音波測距教學:HC-SR04 模組實作

用 ESP32搭配 HC-SR04 超音波模組實現距離量測。從原理、接線到程式碼,提供基礎版、中位數濾波版及距離警報器三個範例。

《ESP32 入門》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 連接電腦用
NodeMCU-32S 相容版本 ESP32開發板 WiFi 藍牙 可用Arduino IDE
全腳位引出,還保持迷你的身型,插上麵包後還能插杜邦線,真的是太棒了! 和NodeMCU V2幾乎一樣尺寸! 有5V供電輸出,非常方便! 有了ESP32開發板,真的可以忘記原來的那些Arduino板子了! 可以用Arduino IDE開發,但效能更強大,還內建WiFi 傑森實測記錄,大家可以到 F 粉 絲 團 B 看貼文哦! ESP32-D0WDQ6 內置兩個低功耗 Xtensa® 32-bit LX6 MCU。片上存儲包括: • 448 KB 的 ROM,用於程序啟動和內核功能
HC-SR04 超音波感測器 避障 測距
技術參數: 1:使用電壓:DC5V 2:靜態電流:小於2mA 3:電平輸出:高5V 4:電平輸出:底0V 5:感應角度:不大於15度 6:探測距離:2cm-450cm 7:高精度:可達0.3cm 接線方式,VCC、trig(控制端)、 echo(接收端)、 GND 工作原理: (1)採用IO觸發測距,給至少10us的高電平信號; (2)模塊自動發送8個40khz的方波,自動檢測是否有信號返回; (3)有信號返回,通過IO輸出一高電平,高電平持續的時間就是超聲波從發射到返回的時間.測試距離=(高
ESP32S擴展板 適用於Nodemcu-32s 38Pin全引出
※ 不含ESP32S開發板,需另購! ESP32S專用擴展板 適用於Nodemcu-32s,其它型號都不相容哦!請留意。 38Pin全引出,無敵方便!

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 就好了。

測距原理與時序

超音波測距的完整工作流程長這樣:

  1. 觸發(Trigger):微控制器對 Trig 腳位送出一個至少 10 微秒(μs) 的高電位脈衝
  2. 發射(Transmit):模組收到觸發訊號後,自動透過發射器連續打出 8 組 40kHz 的超音波脈衝(Burst)
  3. 等待反射(Wait):超音波以音速向前傳播,碰到障礙物之後反射回來
  4. 接收(Receive):反射波被接收器偵測到
  5. 回報(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 的開發環境,先看一下之前的教學哦!

在Arduino IDE中新增ESP32的開發板-以Nodemcu-32s為例
雖然Arduino Uno方便好用,如果真的需要WiFi功能,傑森一律建議直接換塊ESP32的板子,這是最直接的方法。 但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 入門》NodeMCU-32S搞定 有源蜂鳴器、無源蜂鳴器
用 ESP32 NodeMCU-32S 學習有源與無源蜂鳴器。有源蜂鳴器用 HIGH/LOW 控制開關,無源蜂鳴器透過 LEDC 產生不同頻率播放旋律,含完整接線、程式碼與常見問題。

範例三:超音波距離警報器


// 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