《ESP32 入門》ESP32 聲音感測模組教學
學習用 ESP32 NodeMCU-32S 搭配聲音感測模組,從類比讀取、數位觸發到拍手聲控 LED,四個範例帶你快速上手聲音偵測應用。
你是否想過讓 ESP32 能「聽見」周遭的聲音?不管是偵測拍手來開關燈、監測環境噪音,還是做一個簡易的聲控裝置,聲音感測模組都是入門的好選擇。這篇教學會帶你從零開始,用 ESP32 NodeMCU-32S 搭配聲音感測模組,完成類比與數位雙模式的聲音偵測實作。
聲音偵測模組介紹
以我們常見的聲音偵測模組為例,核心元件是一顆駐極體電容麥克風(Electret Condenser Microphone),搭配 LM393 比較器晶片,提供類比輸出(AO)與數位輸出(DO)兩種訊號。
模組腳位說明
| 腳位 | 功能說明 |
|---|---|
| VCC(+) | 電源正極,接 3.3V 或 5V |
| GND(G) | 電源負極,接地 |
| AO | 類比輸出,輸出與音量成比例的電壓值 |
| DO | 數位輸出,當聲音超過門檻值時輸出 LOW |
模組特性
- 工作電壓:3.3V ~ 5V(與 ESP32 的 3.3V 相容)
- 藍色可變電阻(VR1):用來調整 DO 的觸發靈敏度門檻值
- LED1(電源指示燈):模組通電時亮起
- LED2(觸發指示燈):當偵測到的聲音超過門檻值時亮起
小提醒:LM393 適合用來偵測「有沒有聲音」或「聲音大不大」,但它不是錄音用的麥克風模組,無法擷取音訊波形。如果你需要錄音功能,請參考 INMP441 或 MAX9814 等模組。
所需材料
| 品項 | 數量 |
|---|---|
| ESP32 NodeMCU-32S 開發板 | 1 |
| LM393聲音感測模組 | 1 |
| 麵包板 | 1 |
| 杜邦線(公對母) | 4 條 |
| Micro USB 傳輸線 | 1 |
| LED(選用,用於聲控展示) | 1 |
| 220Ω 電阻(選用,搭配 LED) | 1 |




接線方式
基本接線(類比 + 數位讀取)
| KY-038 腳位 | ESP32 腳位 | 說明 |
|---|---|---|
| VCC(+) | 3.3V | 供電 |
| GND(G) | GND | 接地 |
| AO | GPIO 34 | 類比輸入(ADC1_CH6) |
| DO | GPIO 27 | 數位輸入 |

注意:ESP32 的 ADC2 在啟用 Wi-Fi 時無法使用,所以類比輸入請使用 ADC1 的腳位(GPIO 32~39)。這裡選用 GPIO 34 屬於 ADC1,不會有衝突問題。

範例一:類比值讀取(基礎版)
這個範例會持續讀取類比輸出值,並透過 Serial Monitor 觀察音量變化。
// ===================================
// ESP32 + 聲音模組 聲音感測 - 類比讀取
// 傑森創工 blog.jmaker.com.tw
// ===================================
const int aoPin = 34; // AO 接 GPIO34
void setup() {
Serial.begin(115200);
Serial.println("聲音感測模組 - 類比讀取模式");
Serial.println("===================================");
}
void loop() {
int analogValue = analogRead(aoPin);
Serial.print("類比值: ");
Serial.print(analogValue);
// 簡易音量條顯示
int bars = map(analogValue, 0, 4095, 0, 30);
Serial.print(" |");
for (int i = 0; i < bars; i++) {
Serial.print("█");
}
Serial.println("|");
delay(100);
}

觀察重點
- ESP32 的 ADC 為 12 位元,讀取值範圍是 0 ~ 4095
- 安靜時,類比值大約在 1800 ~ 2100 左右浮動(因為 AO 輸出是以中間電壓為基準)
- 對著麥克風大聲說話、拍手或吹氣,數值會明顯跳動
- Serial Plotter(序列繪圖器)可以更直觀地看到波形變化
調整靈敏度
模組上的藍色可變電阻(VR1)是用來調整 DO 的觸發門檻:
- 順時針旋轉:降低靈敏度(需要更大的聲音才會觸發)
- 逆時針旋轉:提高靈敏度(小聲音也會觸發)
建議調整方式:先將可變電阻轉到 LED2 剛好熄滅的位置,此時靈敏度最高且不會誤觸發。

一般來說,LM393的效果並不如大家預期,你可能只會在很大的聲響時看到音量的變化。若是想改善,建議直接換其它更敏感的模組,像是LM386就是很好的選擇。只是貴一點囉^^


範例二:數位觸發偵測
利用 模組的 DO 腳位,偵測聲音是否超過門檻值。觸發時 DO 輸出 LOW。
// ===================================
// ESP32 + 聲音模組 聲音感測 - 數位觸發
// 傑森創工 blog.jmaker.com.tw
// ===================================
const int doPin = 27; // DO 接 GPIO27
void setup() {
Serial.begin(115200);
pinMode(doPin, INPUT);
Serial.println("聲音感測模組 - 數位觸發模式");
Serial.println("請調整模組上的藍色可變電阻來設定靈敏度");
Serial.println("=====================================");
}
void loop() {
int digitalValue = digitalRead(doPin);
if (digitalValue == LOW) {
Serial.println(">>> 偵測到聲音! <<<");
}
delay(50);
}

範例三:拍手聲控 LED 開關(實用版)
結合類比讀取與去彈跳邏輯,實作一個「拍手開/關 LED」的聲控裝置。
// =============================================
// ESP32 + 聲音模組 拍手聲控 LED 開關
// 傑森創工 blog.jmaker.com.tw
// =============================================
const int aoPin = 34; // AO 接 GPIO34
const int ledPin = 2; // LED 接 GPIO2
const int threshold = 2800; // 聲音觸發門檻(可依環境調整)
const int cooldown = 300; // 冷卻時間(毫秒),避免連續觸發
bool ledState = false;
unsigned long lastTrigger = 0;
void setup() {
Serial.begin(115200);
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);
Serial.println("拍手聲控 LED 開關");
Serial.println("拍一下手切換 LED 狀態");
Serial.println("========================");
}
void loop() {
int analogValue = analogRead(aoPin);
unsigned long now = millis();
// 超過門檻且不在冷卻期間
if (analogValue > threshold && (now - lastTrigger > cooldown)) {
ledState = !ledState; // 切換狀態
digitalWrite(ledPin, ledState ? HIGH : LOW);
lastTrigger = now;
Serial.print("觸發!類比值: ");
Serial.print(analogValue);
Serial.print(" -> LED ");
Serial.println(ledState ? "開" : "關");
}
delay(10);
}

調校建議
threshold 的值需要依照你的環境噪音來調整:
- 先用範例一觀察安靜時的類比值範圍
- 拍手時觀察類比值會跳到多高
- 將
threshold設在兩者之間(例如安靜時約 2000,拍手時跳到 3200,那就設 2800)
範例四:即時音量監測(進階版)
加入取樣統計,計算一段時間內的音量 RMS 值,更準確地反映環境音量。
// =============================================
// ESP32 + 聲音模組即時音量監測(RMS 計算)
// 傑森創工 blog.jmaker.com.tw
// =============================================
const int aoPin = 34;
const int sampleWindow = 50; // 取樣視窗(毫秒)
void setup() {
Serial.begin(115200);
Serial.println("即時音量監測(RMS 模式)");
Serial.println("========================");
}
void loop() {
unsigned long startMillis = millis();
long sumSquares = 0;
int sampleCount = 0;
int peakToPeak = 0;
int signalMax = 0;
int signalMin = 4095;
// 在取樣視窗內連續取樣
while (millis() - startMillis < sampleWindow) {
int sample = analogRead(aoPin);
// 峰對峰值計算
if (sample > signalMax) signalMax = sample;
if (sample < signalMin) signalMin = sample;
// RMS 計算用
int centered = sample - 2048; // 以中間值為零點
sumSquares += (long)centered * centered;
sampleCount++;
}
peakToPeak = signalMax - signalMin;
float rms = sqrt((float)sumSquares / sampleCount);
// 將 RMS 映射到 0-100 的音量百分比
int volumePercent = map((int)rms, 0, 1500, 0, 100);
volumePercent = constrain(volumePercent, 0, 100);
Serial.print("RMS: ");
Serial.print(rms, 1);
Serial.print(" 峰對峰: ");
Serial.print(peakToPeak);
Serial.print(" 音量: ");
Serial.print(volumePercent);
Serial.print("% ");
// 視覺化音量條
int bars = volumePercent / 5;
Serial.print("[");
for (int i = 0; i < 20; i++) {
if (i < bars) Serial.print("=");
else Serial.print(" ");
}
Serial.println("]");
delay(100);
}

常見問題排解
Q1:類比值一直都很低或不會變化?
- 確認接線是否正確,特別是 AO 腳位是否接到 ESP32 的 ADC1 腳位
- 確認模組的 VCC 有正常供電(電源 LED 應亮起)
- 嘗試將 VCC 接到 5V(Vin)而非 3.3V,有些模組在 3.3V 下輸出範圍較小
Q2:數位輸出(DO)不會觸發?
- 用螺絲起子調整模組上的藍色可變電阻
- 調整時觀察模組上的 LED2,轉到 LED2 剛好熄滅的位置附近即為最佳靈敏度
Q3:讀取值不穩定,跳動很大?
- 這是正常的,麥克風本身就會收到環境噪音
- 使用範例四的 RMS 取樣方式可以得到更平穩的讀數
- 也可以在硬體上加一顆 100nF 的電容在 AO 和 GND 之間做簡單濾波
Q4:Wi-Fi 開啟後讀不到類比值?
- ESP32 的 ADC2(GPIO 0, 2, 4, 12-15, 25-27)在 Wi-Fi 啟用時無法使用
- 請確保類比輸入使用 ADC1 的腳位:GPIO 32, 33, 34, 35, 36, 39
延伸應用
學會了基本的聲音偵測之後,你可以嘗試以下進階專案:
- 智慧聲控燈:搭配繼電器模組,用拍手控制家電開關
- 噪音監測站:結合 OLED 顯示器,即時顯示分貝值與音量圖表
- 嬰兒哭聲偵測器:偵測到持續大音量時透過 LINE Notify 發送通知
- 節奏偵測器:分析拍手節奏,做出更複雜的聲控指令(例如拍兩下開燈、拍三下關燈)
- Wi-Fi 音量記錄器:將音量數據透過 MQTT 傳送到 Home Assistant 儀表板
結語
入門級的聲音感測模組搭配 ESP32 的處理能力,已經可以做出不少有趣的互動專案。這篇教學從基礎的類比與數位讀取,一路到 RMS 音量計算和拍手聲控,希望能幫你快速上手。如果你想做更精確的音訊處理,可以進一步研究 ESP32 的 I2S 介面搭配 INMP441 數位麥克風模組,那又是另一個有趣的主題了!



