IoTLabs

Nghiên cứu, Sáng tạo và Thử nghiệm

Series 37 Module Cảm Biến – Nguyên Lý Sound Sensor: Microphone Electret, LM393 Comparator & Phát Hiện Tiếng Ồn

Sound sensor module KY-038 không chỉ là một microphone — bên trong có chuỗi xử lý: electret microphone với FET tích hợp, mạch khuếch đại, và LM393 comparator để phát hiện ngưỡng âm thanh. Bài này giải thích từng tầng, và cách đọc đúng cả AOUT (analog) lẫn DOUT (digital).

Nguyên Lý Hoạt Động

1. Electret Microphone — FET Tích Hợp

Electret microphone là tụ điện với màng điện môi được tích điện vĩnh viễn:

Electret Microphone — Cắt ngang:

  Âm thanh
     ↓
  ┌────────────────────────────┐
  │  Màng electret (diaphragm) │ ← Tích điện vĩnh viễn ~200V (rất nhỏ)
  │          ↕                 │
  │  Cực cố định (backplate)   │ ← Tụ điện C biến đổi theo âm thanh
  │          ↓                 │
  │  FET (JFET tích hợp)       │ ← Khuếch đại, trở kháng cao → thấp
  └────────────────────────────┘
    Drain (→ tín hiệu ra)
    Source (→ GND)

Chuỗi hoạt động:

  1. Âm thanh → màng rung → C thay đổi
  2. C thay đổi → điện tích Q không đổi (Q=CV) → điện áp V thay đổi
  3. FET: biến tín hiệu điện áp cao trở kháng → dòng tín hiệu thấp trở kháng
  4. Đầu ra: tín hiệu AC nhỏ vài mV, chồng lên DC bias

Bias voltage — bắt buộc: FET cần điện áp DC để hoạt động. Trên module: điện trở pull-up từ VCC cấp bias cho Drain của FET. Không có bias → microphone không hoạt động.

2. Khuếch Đại và Comparator LM393

Trên module KY-038, tín hiệu từ microphone đi qua:

Electret Mic
     │
     ↓
[Điện trở bias 4.7kΩ]  ← Pull-up từ VCC cấp bias cho FET
     │
     ↓  Tín hiệu AC vài mV
[Khuếch đại (op-amp)]  ← Tăng biên độ lên ~100x (tùy module)
     │
     ├──────────────────────→ AOUT (analog — tín hiệu khuếch đại)
     │
     ↓
[LM393 Comparator]
  (+) In ← Tín hiệu mic khuếch đại
  (-) In ← Ngưỡng từ Trimmer (trimmer pot)
     │
     ↓ (open-collector output)
[Pull-up 10kΩ lên VCC]
     │
     →  DOUT (digital — HIGH bình thường, LOW khi vượt ngưỡng)

3. LM393 Open-Collector — Hiểu Đúng Output

LM393 là comparator open-collector (không phải push-pull):

  • Output chỉ có thể kéo xuống LOW (transistor dẫn)
  • Để có mức HIGH cần pull-up resistor bên ngoài (module đã có sẵn ~10kΩ)
  • Khi tiếng ồn > ngưỡng: Output transistor dẫn → DOUT = LOW
  • Khi im lặng: Output transistor tắt → pull-up kéo DOUT = HIGH

DOUT logic: HIGH = im lặng, LOW = phát hiện âm thanh (active LOW).

4. AOUT vs DOUT — Khi Nào Dùng Cái Nào

AOUT (Analog)DOUT (Digital)
Tín hiệuAnalog: 0-VCC, phản ánh âm lượngDigital: HIGH hoặc LOW
Đọc bằngADC (analogRead)digitalRead hoặc interrupt
Thông tinMức âm thanh tương đốiChỉ có/không vượt ngưỡng
Điều chỉnhKhông cần trimmerCần chỉnh trimmer
Ứng dụngSound level meter, phân tíchClap detection, switch

Thông Số Kỹ Thuật

Thông sốGiá trị
Điện áp hoạt động3.3V – 5V
Dòng tiêu thụ~5mA
MicrophoneElectret (có FET)
ComparatorLM393
Độ nhạyĐiều chỉnh qua trimmer
Ngưỡng phát hiệnThấp nhất ~50dB (tùy chỉnh)
Số chân4 (VCC, GND, AOUT, DOUT)

Sơ Đồ Chân (Pinout)

KY-038 Sound Sensor Module:

┌─────────────────────────────────────┐
│  [Electret Mic]  [LED nguồn]        │
│  [LED DOUT]      [Trimmer]          │
│  [LM393]                            │
└─────────────────────────────────────┘
  GND   VCC   AOUT   DOUT
ChânKý hiệuMô tả
GNDMass
VCC+Nguồn 3.3V-5V
AOUTA0Analog output — tín hiệu mic khuếch đại
DOUTD0Digital output — HIGH/LOW theo ngưỡng

LED trên module:

  • LED nguồn (thường đỏ): luôn sáng khi có nguồn
  • LED DOUT: sáng khi DOUT = LOW (phát hiện âm thanh)

Kết Nối Phần Cứng

KY-038 với ESP32 DevKit V1

ESP32 DevKit V1           KY-038 Module
─────────────────────     ─────────────────
3V3  ─────────────────→  VCC
GND  ─────────────────→  GND
GPIO34 (ADC Input) ────→  AOUT  ← Input-only pin, ADC1 Ch6
GPIO4  (Input)─────────→  DOUT  ← Digital input

Tại sao GPIO34? GPIO34 là input-only (không có output driver), 12-bit ADC — lý tưởng cho tín hiệu analog. Không kết nối với mạch output.

Lưu ý ESP32 ADC: ADC2 không dùng được khi WiFi bật. ADC1 (GPIO32-39) luôn hoạt động. GPIO34 thuộc ADC1.

KY-038 với Arduino Uno

Arduino Uno               KY-038 Module
─────────────────────     ─────────────────
5V   ─────────────────→  VCC
GND  ─────────────────→  GND
A0 (Analog Input)─────→  AOUT
Pin 2 (INT0) ─────────→  DOUT  ← Pin 2 hỗ trợ interrupt

Pin 2 hỗ trợ attachInterrupt(0, ...) — tốt cho clap detection cần phản hồi nhanh.

Chỉnh Trimmer Ngưỡng

Bước 1: Cấp nguồn, mở Serial Monitor, đọc AOUT ở môi trường bình thường (~300-400 với 10-bit ADC ở 5V).

Bước 2: Vặn trimmer theo chiều kim đồng hồ (CW) → ngưỡng tăng → khó trigger hơn.

Bước 3: Vỗ tay một lần, kiểm tra LED DOUT có sáng không. Chỉnh đến khi LED sáng khi vỗ tay, tắt khi im lặng.

Code Arduino IDE

Code Đọc AOUT + DOUT Cơ Bản — Arduino Uno

/*
 * Sound Sensor KY-038 — Đọc cả AOUT và DOUT
 * Board: Arduino Uno
 * Kết nối: VCC→5V, GND→GND, AOUT→A0, DOUT→Pin2
 *
 * DOUT: HIGH = im lặng, LOW = phát hiện âm (active LOW)
 */

const int AOUT_PIN = A0;   // Tín hiệu analog từ microphone
const int DOUT_PIN = 2;    // Tín hiệu digital từ LM393

void setup() {
  Serial.begin(9600);
  pinMode(DOUT_PIN, INPUT);
  Serial.println("=== Sound Sensor KY-038 ===");
  Serial.println("AOUT | DOUT | Trạng thái");
  Serial.println("-----|------|----------");
}

void loop() {
  int analogValue = analogRead(AOUT_PIN);   // 0-1023 (10-bit)
  int digitalValue = digitalRead(DOUT_PIN); // HIGH hoặc LOW

  // DOUT active LOW: LOW = phát hiện âm thanh
  String status = (digitalValue == LOW) ? "CÓ TIẾNG ỒN!" : "Im lặng";

  Serial.print(analogValue);
  Serial.print("  | ");
  Serial.print(digitalValue == HIGH ? "HIGH" : "LOW ");
  Serial.print("  | ");
  Serial.println(status);

  delay(100);
}

Code Clap Switch — Bật/Tắt Đèn Bằng Vỗ Tay (Arduino Uno)

/*
 * Sound Sensor — Clap Switch: vỗ tay 1 lần bật, vỗ lần 2 tắt
 * Board: Arduino Uno
 * Kết nối: VCC→5V, GND→GND, DOUT→Pin2, LED→Pin13
 *
 * Dùng interrupt để phản hồi nhanh khi có âm thanh
 */

const int DOUT_PIN = 2;   // INT0 trên Arduino Uno
const int LED_PIN  = 13;  // LED nội

volatile bool clapDetected = false; // Cờ từ ISR

// ISR — gọi khi DOUT xuống LOW (phát hiện âm thanh)
void onSoundDetected() {
  clapDetected = true;
}

void setup() {
  Serial.begin(9600);
  pinMode(DOUT_PIN, INPUT);
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);

  // Trigger trên falling edge: HIGH→LOW khi có âm thanh
  attachInterrupt(digitalPinToInterrupt(DOUT_PIN), onSoundDetected, FALLING);

  Serial.println("Clap Switch sẵn sàng — vỗ tay để bật/tắt đèn");
}

bool ledState = false;
unsigned long lastClapTime = 0;
const unsigned long DEBOUNCE_MS = 500; // Bỏ qua tiếng ồn trong 500ms sau mỗi clap

void loop() {
  if (clapDetected) {
    clapDetected = false; // Reset cờ ngay

    unsigned long now = millis();
    // Debounce: bỏ qua nếu vừa detect trong 500ms trước
    if (now - lastClapTime > DEBOUNCE_MS) {
      lastClapTime = now;

      // Toggle LED
      ledState = !ledState;
      digitalWrite(LED_PIN, ledState ? HIGH : LOW);

      Serial.print("Clap! Đèn ");
      Serial.println(ledState ? "BẬT" : "TẮT");
    }
  }
}

Code Sound Level Meter — Hiện Mức Âm Trên Serial Plotter (Arduino Uno)

/*
 * Sound Sensor — Sound Level Meter với bar chart ASCII
 * Board: Arduino Uno
 * Kết nối: VCC→5V, GND→GND, AOUT→A0
 */

const int AOUT_PIN = A0;
const int SAMPLE_COUNT = 50; // Lấy nhiều mẫu để tính RMS

void setup() {
  Serial.begin(9600);
  Serial.println("=== Sound Level Meter ===");
}

// Tính biên độ peak-to-peak từ N mẫu
int measureAmplitude(int samples) {
  int minVal = 1023;
  int maxVal = 0;

  unsigned long startTime = millis();
  // Lấy mẫu trong 50ms
  while (millis() - startTime < 50) {
    int val = analogRead(AOUT_PIN);
    if (val < minVal) minVal = val;
    if (val > maxVal) maxVal = val;
  }

  return maxVal - minVal; // Peak-to-peak amplitude
}

// Hiển thị bar chart ASCII
void printBar(int value, int maxValue) {
  int barLength = map(value, 0, maxValue, 0, 40);
  Serial.print("Level: [");
  for (int i = 0; i < 40; i++) {
    Serial.print(i < barLength ? "█" : " ");
  }
  Serial.print("] ");
  Serial.println(value);
}

void loop() {
  int amplitude = measureAmplitude(50);
  printBar(amplitude, 300); // 300 = max expected amplitude (chỉnh theo môi trường)
}

Code ESP32 — DOUT Interrupt + AOUT ADC

/*
 * Sound Sensor KY-038 — ESP32, DOUT interrupt + AOUT ADC
 * Board: ESP32 DevKit V1
 * Kết nối: VCC→3V3, GND→GND, AOUT→GPIO34, DOUT→GPIO4
 */

const int AOUT_PIN = 34; // ADC1 Ch6 — input only
const int DOUT_PIN = 4;  // Digital input

volatile bool soundDetected = false;

// ISR — gọi khi DOUT xuống LOW
void IRAM_ATTR onSoundISR() {
  soundDetected = true;
}

void setup() {
  Serial.begin(115200);
  pinMode(DOUT_PIN, INPUT);

  // Trigger trên falling edge
  attachInterrupt(digitalPinToInterrupt(DOUT_PIN), onSoundISR, FALLING);

  Serial.println("=== Sound Sensor ESP32 ===");
}

unsigned long lastSoundTime = 0;

void loop() {
  // Đọc mức âm thanh analog mỗi 200ms
  int analogLevel = analogRead(AOUT_PIN); // 0-4095 (12-bit ESP32)

  // Hiển thị nếu phát hiện âm thanh qua interrupt
  if (soundDetected) {
    soundDetected = false;

    unsigned long now = millis();
    if (now - lastSoundTime > 300) { // Debounce 300ms
      lastSoundTime = now;
      Serial.print("TIẾNG ỒN! Level AOUT = ");
      Serial.println(analogLevel);
    }
  }

  // In mức analog mỗi 500ms để monitor
  static unsigned long lastPrint = 0;
  if (millis() - lastPrint > 500) {
    lastPrint = millis();
    Serial.print("AOUT = ");
    Serial.println(analogLevel);
  }
}

Kết Quả Mong Đợi

=== Sound Sensor ESP32 ===
AOUT = 312
AOUT = 318
TIẾNG ỒN! Level AOUT = 1834    ← Khi vỗ tay
AOUT = 321
AOUT = 315
TIẾNG ỒN! Level AOUT = 2104    ← Vỗ tay lần 2

Ứng Dụng Thực Tế

Ứng dụngChi tiết
Clap switchBật/tắt đèn, quạt bằng tiếng vỗ tay
Báo động tiếng ồnCảnh báo khi tiếng ồn vượt ngưỡng (nhà xưởng, phòng ngủ)
Smart home voice triggerPhát hiện có người nói chuyện → bật màn hình
Đồ chơi phản hồi âm thanhRobot phản ứng theo tiếng vỗ
Logger tiếng ồnGhi lại biên độ âm thanh theo thời gian

Lưu Ý Khi Sử Dụng

1. Chỉnh trimmer trước khi code

Trimmer sai → DOUT luôn LOW hoặc luôn HIGH → mọi code đều không hoạt động đúng. Kiểm tra LED DOUT phản hồi trực quan khi vỗ tay trước khi đọc vào MCU.

2. AOUT không đo được dB tuyệt đối

AOUT chỉ phản ánh biên độ tín hiệu tương đối. Để đo dB thực cần: hiệu chỉnh với nguồn âm thanh chuẩn đã biết SPL, hoặc dùng module chuyên dụng (I2S microphone INMP441).

3. Nhiễu tần số cao trên AOUT

MCU polling nhanh (< 1ms) có thể bắt nhiễu RF. Cách fix: trung bình nhiều mẫu, hoặc thêm tụ 100nF từ AOUT xuống GND để lọc nhiễu cao tần.

4. ESP32 ADC không tuyến tính

ESP32 ADC có độ phi tuyến đáng kể ở dải 0-150mV và trên 3100mV. Nếu cần chính xác: dùng analogSetAttenuation(ADC11db) để dải đọc 0-3.3V, và hiệu chỉnh bằng bảng tra (espadc_cal).

5. DOUT phản hồi rất nhanh — cần debounce

Một tiếng vỗ tay có thể trigger nhiều lần do reverb và nhiễu. Debounce 300-500ms là đủ cho clap detection. Nếu cần detect 2 tiếng vỗ liên tiếp → logic timing phức tạp hơn.

Bài tiếp theo: