IoTLabs

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

Series 37 Module Cảm Biến – Nguyên Lý Passive Buzzer: PWM Điều Khiển Tần Số, Hàm tone() & Phát Nhạc Arduino ESP32

Passive buzzer khác active buzzer ở điểm then chốt: không có oscillator bên trong — chỉ là piezoelectric transducer thuần túy. MCU phải tự tạo xung vuông tần số mong muốn. Đổi lại, điều này cho phép phát bất kỳ tần số nào, từ đó chơi nhạc thực sự.

Nguyên Lý Hoạt Động

1. Piezoelectric Transducer Thuần Túy

Bên trong passive buzzer chỉ có một phần tử ceramic PZT mỏng gắn trên màng đồng:

Passive Buzzer — Cấu trúc:

          (+)     (-)
           │       │
    ┌──────┴───────┴──────┐
    │  Màng đồng (brass)  │
    │  ┌────────────────┐ │
    │  │ PZT Ceramic    │ │ ← Biến điện áp → biến dạng cơ học
    │  └────────────────┘ │
    └─────────────────────┘

Không có IC, không có oscillator

Hiệu ứng áp điện ngược (converse piezoelectric effect):

  • Điện áp DC → ceramic bị kéo dãn hoặc nén theo một chiều cố định
  • Điện áp xoay chiều (AC) → ceramic liên tục co giãn → rung → âm thanh
  • Tần số âm thanh = tần số xoay chiều đầu vào

Vì vậy: Passive buzzer cần MCU tạo xung vuông với tần số = tần số âm thanh mong muốn. Active buzzer tự tạo xung → passive không tự làm được.

2. So Sánh Active vs Passive

Active BuzzerPassive Buzzer
OscillatorTích hợpKhông có
Điều khiểndigitalWrite() HIGH/LOWtone(pin, frequency)
Tần sốCố định (~2-4kHz)Tùy chỉnh (20Hz-20kHz)
Phát nhạcKhông
Dùng MCUNhẹ (chỉ ON/OFF)Cần timer/PWM
Nhận biếtCó nhãn/stickerThường không có nhãn, thấy ceramic trong vỏ

3. Hàm tone() — Cách Arduino Tạo Tần Số

tone() dùng hardware timer của MCU để tạo xung vuông 50% duty cycle:

Xung vuông tone(pin, 440) — A4 = 440 Hz:

HIGH ┌──┐  ┌──┐  ┌──┐  ┌──┐
     │  │  │  │  │  │  │  │
LOW  ┘  └──┘  └──┘  └──┘  └──

     ←──────────────────────→
            1/440s = 2.27ms

Duty cycle = 50% → cả hai nửa chu kỳ bằng nhau

Arduino Uno: Timer2 (8-bit) → tone() thay thế PWM trên Pin 3 và Pin 11 khi đang dùng.

ESP32:

  • Arduino-ESP32 2.x: dùng LEDC peripheral → ledcWriteTone(channel, frequency)
  • Arduino-ESP32 3.x: tone(pin, frequency) hoạt động trực tiếp

4. Tần Số và Nốt Nhạc

Mỗi nốt nhạc tương ứng một tần số Hz cố định (hệ thống bình quân 12 âm):

NốtOctave 4 (Hz)Octave 5 (Hz)
C (Đô)262523
D (Ré)294587
E (Mi)330659
F (Fa)349698
G (Sol)392784
A (La)440880
B (Si)494988

Tần số tăng gấp đôi khi lên 1 octave: C4=262Hz, C5=523Hz, C6=1047Hz.

Thông Số Kỹ Thuật

Thông sốGiá trị
Điện áp hoạt động3.3V – 5V
Dòng tiêu thụ5-30 mA
Dải tần số20 Hz – 20 kHz
Trở kháng~8Ω (như loa nhỏ)
Đường kính12mm / 23mm (2 loại phổ biến)

Sơ Đồ Chân (Pinout)

Module KY-006 (3-pin)

┌──────────────────────────────┐
│    [PASSIVE BUZZER]          │
│    [Điện trở 100Ω nối tiếp] │
└──────────────────────────────┘
   GND     VCC     S
   (-)  (3.3-5V) (Signal PWM)
ChânKý hiệuMô tả
SSignalTín hiệu PWM từ MCU
VCC+Nguồn 3.3V-5V
GNDMass

Lưu ý: Module KY-006 thường chỉ có buzzer + điện trở nối tiếp (không có transistor). Tín hiệu S nối thẳng vào buzzer qua điện trở. Dòng qua buzzer ~5-10mA tại 3.3V → an toàn cho ESP32 GPIO (max 12mA).

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

KY-006 với ESP32 DevKit V1

ESP32 DevKit V1           KY-006 Module
─────────────────────     ─────────────────
GPIO5 (PWM Output)─────→  S    (Signal)
3V3  ─────────────────→  VCC  (hoặc để trống — buzzer lấy điện qua S)
GND  ─────────────────→  GND

GPIO5: PWM-capable, không phải strapping pin, an toàn.

Lưu ý: Thực tế nhiều module KY-006 chỉ cần cắm S và GND — buzzer lấy điện từ tín hiệu PWM. Nếu âm thanh yếu → cắm thêm VCC.

KY-006 với Arduino Uno

Arduino Uno               KY-006 Module
─────────────────────     ─────────────────
Pin 8 (Digital Output)─→  S    (Signal)
5V   ─────────────────→  VCC
GND  ─────────────────→  GND

Pin 8 trên Arduino Uno không phải hardware PWM pin — nhưng tone() dùng software timer nên hoạt động trên bất kỳ digital pin nào.

Code Arduino IDE

Code Tone Đơn Giản — Arduino Uno

/*
 * Passive Buzzer KY-006 — Phát tông đơn giản
 * Board: Arduino Uno
 * Kết nối: S→Pin8, VCC→5V, GND→GND
 *
 * tone(pin, frequency)      : bắt đầu phát tần số (không tự dừng)
 * tone(pin, frequency, dur) : phát trong dur milliseconds rồi tự dừng
 * noTone(pin)               : dừng phát
 */

const int BUZZER_PIN = 8;

void setup() {
  Serial.begin(9600);
  // Không cần pinMode() cho tone() — nhưng nên set để rõ ràng
  pinMode(BUZZER_PIN, OUTPUT);
  Serial.println("=== Passive Buzzer KY-006 ===");
}

void loop() {
  // Phát Do (C4 = 262 Hz) trong 500ms
  Serial.println("Phát Đô (C4 - 262 Hz)");
  tone(BUZZER_PIN, 262, 500);
  delay(600); // Chờ hơn duration để có khoảng lặng

  // Phát Sol (G4 = 392 Hz) trong 500ms
  Serial.println("Phát Sol (G4 - 392 Hz)");
  tone(BUZZER_PIN, 392, 500);
  delay(600);

  // Phát La (A4 = 440 Hz) trong 1 giây
  Serial.println("Phát La chuẩn (A4 - 440 Hz)");
  tone(BUZZER_PIN, 440, 1000);
  delay(1100);

  // Sweep tần số từ thấp đến cao
  Serial.println("Sweep 200 Hz → 2000 Hz");
  for (int freq = 200; freq <= 2000; freq += 50) {
    tone(BUZZER_PIN, freq, 50);
    delay(60);
  }
  noTone(BUZZER_PIN);
  delay(1000);
}

Code Phát Nhạc Twinkle Twinkle — Arduino Uno

/*
 * Passive Buzzer — Phát nhạc Twinkle Twinkle Little Star
 * Board: Arduino Uno
 * Kết nối: S→Pin8, VCC→5V, GND→GND
 */

const int BUZZER_PIN = 8;

// Tần số nốt nhạc (Hz) — octave 4 và 5
#define C4  262
#define D4  294
#define E4  330
#define F4  349
#define G4  392
#define A4  440
#define B4  494
#define C5  523
#define REST 0    // Nghỉ (không phát âm)

// Thời gian nốt nhạc (ms)
#define QUARTER  400  // Nốt đen
#define HALF     800  // Nốt trắng

// Bài Twinkle Twinkle Little Star
// Format: {nốt, thời_gian}
int melody[][2] = {
  {C4, QUARTER}, {C4, QUARTER}, {G4, QUARTER}, {G4, QUARTER},
  {A4, QUARTER}, {A4, QUARTER}, {G4, HALF},
  {F4, QUARTER}, {F4, QUARTER}, {E4, QUARTER}, {E4, QUARTER},
  {D4, QUARTER}, {D4, QUARTER}, {C4, HALF},
  {G4, QUARTER}, {G4, QUARTER}, {F4, QUARTER}, {F4, QUARTER},
  {E4, QUARTER}, {E4, QUARTER}, {D4, HALF},
  {G4, QUARTER}, {G4, QUARTER}, {F4, QUARTER}, {F4, QUARTER},
  {E4, QUARTER}, {E4, QUARTER}, {D4, HALF},
  {C4, QUARTER}, {C4, QUARTER}, {G4, QUARTER}, {G4, QUARTER},
  {A4, QUARTER}, {A4, QUARTER}, {G4, HALF},
  {F4, QUARTER}, {F4, QUARTER}, {E4, QUARTER}, {E4, QUARTER},
  {D4, QUARTER}, {D4, QUARTER}, {C4, HALF},
};

int noteCount = sizeof(melody) / sizeof(melody[0]);

void setup() {
  Serial.begin(9600);
  pinMode(BUZZER_PIN, OUTPUT);
  Serial.println("Phát Twinkle Twinkle Little Star...");
}

void playMelody() {
  for (int i = 0; i < noteCount; i++) {
    int note = melody[i][0];
    int duration = melody[i][1];

    if (note == REST) {
      noTone(BUZZER_PIN);
    } else {
      tone(BUZZER_PIN, note, duration);
    }

    // Khoảng lặng 10% giữa các nốt (để nốt không dính vào nhau)
    delay(duration * 1.1);
    noTone(BUZZER_PIN);
  }
}

void loop() {
  playMelody();
  delay(2000); // Nghỉ 2 giây rồi phát lại
}

Code ESP32 — tone() và Sweep Tần Số

/*
 * Passive Buzzer KY-006 — ESP32 (Arduino-ESP32 2.x+)
 * Board: ESP32 DevKit V1
 * Kết nối: S→GPIO5, VCC→3V3, GND→GND
 *
 * Arduino-ESP32 2.x+: tone() dùng LEDC nội bộ
 * Không cần ledcSetup() thủ công — tone() tự cấu hình
 */

const int BUZZER_PIN = 5;

// Nốt nhạc
#define C4  262
#define D4  294
#define E4  330
#define F4  349
#define G4  392
#define A4  440
#define B4  494
#define C5  523

void setup() {
  Serial.begin(115200);
  Serial.println("=== Passive Buzzer ESP32 ===");
}

// Phát 1 nốt nhạc với duration ms
void playNote(int frequency, int durationMs) {
  if (frequency == 0) {
    noTone(BUZZER_PIN);
  } else {
    tone(BUZZER_PIN, frequency, durationMs);
  }
  delay(durationMs * 1.05); // Chờ hơn 5% để nốt không dính
  noTone(BUZZER_PIN);
}

// Scale Đô Ré Mi từ C4 đến C5
void playScale() {
  int notes[] = {C4, D4, E4, F4, G4, A4, B4, C5};
  Serial.println("Phát scale Đô Ré Mi...");
  for (int i = 0; i < 8; i++) {
    playNote(notes[i], 300);
  }
}

// Chuông báo động: 3 tiếng tăng dần
void alertBeep() {
  Serial.println("Chuông cảnh báo...");
  playNote(880, 100);  // A5
  delay(50);
  playNote(988, 100);  // B5
  delay(50);
  playNote(1047, 300); // C6
}

void loop() {
  playScale();
  delay(500);

  alertBeep();
  delay(2000);
}

Kết Quả Mong Đợi

=== Passive Buzzer ESP32 ===
Phát scale Đô Ré Mi...      ← Nghe: Đô Ré Mi Fa Sol La Si Đô
Chuông cảnh báo...           ← Nghe: 3 tiếng tăng dần cao
Phát scale Đô Ré Mi...
...

Ứng Dụng Thực Tế

Ứng dụngMô tả
Chuông cửaPhát melody ngắn khi nhấn button
Nhạc chuông báo thứcKết hợp với DS3231 RTC (Bài 37)
Âm thanh phản hồi UIBeep xác nhận khi bấm nút
Cảnh báo mức nguy hiểmTone khác nhau theo severity
Dạy nhạc đơn giảnHiển thị nốt trên LCD + phát âm

Lưu Ý Khi Sử Dụng

1. Phân biệt active/passive trước khi code

Nếu code tone() nhưng dùng active buzzer → âm thanh không ổn định, tần số sai. Kiểm tra: cấp nguồn thẳng → active kêu ngay, passive im lặng.

2. tone() trên Arduino Uno chiếm Timer2

Khi dùng tone(), Timer2 bận → PWM của Pin 3 và Pin 11 bị disable. Tránh dùng analogWrite() trên 2 pin này khi đang phát âm thanh.

3. Khoảng lặng giữa các nốt (articulation)

Nếu delay = đúng bằng duration → các nốt dính vào nhau, khó phân biệt. Cách fix:

tone(BUZZER_PIN, note, duration);
delay(duration * 1.1); // 10% extra pause
noTone(BUZZER_PIN);

4. Âm lượng nhỏ — tăng bằng điện trở thấp hơn hoặc transistor

Module KY-006 có điện trở nối tiếp giới hạn dòng → âm lượng vừa phải. Để to hơn: thêm transistor NPN khuếch đại dòng hoặc dùng buzzer 8Ω 0.5W kết hợp với op-amp/transistor.

5. ESP32 — kiểm tra phiên bản Arduino-ESP32

  • Arduino-ESP32 1.x: tone() có thể không hoạt động → dùng ledcSetup() + ledcWriteTone()
  • Arduino-ESP32 2.x+: tone() hoạt động bình thường
  • Kiểm tra trong Arduino IDE: Tools → Board → Board Manager → esp32 → version

Bài tiếp theo: