Bài 10 · Vật lí · Công nghệ · Toán
Phát âm bằng buzzer
tần số quyết định độ cao của âm
Bài nhập môn nối được ba thứ: một chân PWM của ESP32, khái niệm tần số trong Vật lí, và cấp số nhân trong Toán. Chỉ cần một con buzzer giá tám nghìn đồng.
01 Mục tiêu và yêu cầu cần đạt
Bài này dùng một con buzzer để trả lời một câu hỏi mà học sinh nào cũng từng thắc mắc: vì sao tiếng này cao, tiếng kia thấp? Và trả lời bằng cách cho các em tự tạo ra từng nốt một.
Sau bài này học sinh làm được
- Giải thích được độ cao của âm do tần số quyết định, không phải do độ to.
- Dùng chân PWM của ESP32 để phát ra một tần số cho trước.
- Đo lại tần số thật bằng điện thoại và so với tần số đặt.
- Nhận ra thang âm 12 nửa cung là một cấp số nhân, công bội
2^(1/12). - Xác định được vùng tần số mà tai mình nghe được, và vùng buzzer kêu to nhất.
- Vật lí 11 — mạch nội dung Sóng: đặc trưng vật lí của âm (tần số, cường độ) và đặc trưng sinh lí (độ cao, độ to).
- Công nghệ 12 — mạch nội dung Vi điều khiển: xuất tín hiệu điều khiển thiết bị.
- Toán 11 — cấp số nhân, và hàm mũ cơ số 2.
Trích nguyên văn yêu cầu cần đạt từ Phụ lục Thông tư 32/2018 trước khi đưa vào kế hoạch bài dạy.
02 Lí thuyết
Tần số quyết định độ cao
Màng buzzer rung, nén rồi giãn lớp không khí trước mặt, chuỗi nén–giãn lan tới màng nhĩ. Số lần nén–giãn trong một giây là tần số, đơn vị héc. Rung 440 lần/giây ra nốt La; 880 lần vẫn là La nhưng cao hơn một quãng tám.
Hỏi cả lớp: vặn to loa lên thì bài hát có cao giọng hơn không?
Không. Vặn to là đổi biên độ; đổi nốt là đổi
tần số. Trong bài: tần số đặt bằng buzzer.freq(),
độ to bằng buzzer.duty_u16() — cho học sinh đổi từng cái một.
ESP32 tạo tần số bằng PWM
Chân GPIO chỉ có 0 V và 3,3 V, không tạo được sóng sin. Nhưng nó bật tắt rất nhanh và rất đều — với màng buzzer thế là đủ. Khai báo hai thứ:
freq— số lần bật tắt mỗi giây, chính là tần số âm.duty_u16— phần thời gian bật trong mỗi chu kì, từ 0 (im) đến 65535 (bật suốt). Với buzzer, 32768 tức một nửa cho âm to nhất.
Bật suốt nghĩa là chân giữ nguyên 3,3 V — màng bị đẩy ra rồi đứng yên. Không rung thì không có âm. Màng chỉ rung khi điện áp đổi qua đổi lại, và nửa bật nửa tắt là lúc đổi mạnh nhất.
Thang âm 12 nửa cung — chỗ Toán bước vào
Hai nốt cách một quãng tám thì tần số gấp đôi: La4 440 Hz, La5 880 Hz. Giữa chúng chia 12 nửa cung bằng nhau.
"Bằng nhau" không phải bằng về hiệu số. Tai người cảm nhận độ cao theo tỉ lệ, nên mỗi nửa cung phải nhân với cùng một số. Nhân 12 lần ra gấp đôi:
r¹² = 2 → r = 2^(1/12) ≈ 1,059463
Thang âm là một cấp số nhân công bội 2^(1/12) — thứ học sinh lớp
11 vừa học, xuất hiện ở chỗ không ai ngờ.
Nốt cách La4 đúng n nửa cung (lên dương, xuống âm):
f = 440 × 2^(n/12)
Thử: Đô4 nằm dưới La4 chín nửa cung →
f = 440 × 2^(−9/12) = 261,63 Hz, đúng bằng con số in trong mọi
bảng nhạc lí.
03 Linh kiện
| Linh kiện | Mô tả, lưu ý khi mua | Số lượng · giá |
|---|---|---|
| ESP32 DevKit V1 | Bo 30 chân, cổng micro-USB hoặc Type-C | 1 · 90–150k |
| Buzzer thụ động | Loại KHÔNG có mạch dao động bên trong. Xem hộp cạm bẫy bên dưới | 1 · 5–10k |
| Điện trở 100 Ω | Hạn dòng cho chân GPIO | 1 · 200đ |
| Breadboard và dây cắm | Loại 400 lỗ là đủ | 1 bộ · 30k |
| Điện thoại có app đo tần số | Phys Toolbox, Spectroid… đều miễn phí | mỗi nhóm 1 |
04 Lắp mạch và sơ đồ nối dây
| Khối | Nối dây | Nguồn |
|---|---|---|
| Buzzer thụ động | Chân (+) → điện trở 100 Ω → GPIO25 · chân (−) → GND | Lấy từ chính chân GPIO |
Mạch đã cắm trên breadboard: ESP32, buzzer, điện trở 100 Ω. Chụp chếch 45°, đủ gần để đếm được lỗ breadboard, dây đỏ và đen đúng quy ước.
Khung giữ chỗ — thay bằng ảnh chụp thật khi cóCận cảnh hai loại buzzer đặt cạnh nhau, lật mặt đáy: loại chủ động có mạch điện tử bên trong, loại thụ động chỉ thấy màng và hai chân. Đây là ảnh chống mua nhầm.
Khung giữ chỗ — thay bằng ảnh chụp thật khi cóHọc sinh cầm điện thoại chạy app đo tần số hướng vào buzzer, màn hình hiện đỉnh phổ ở 440 Hz. Chụp thấy cả buzzer lẫn màn hình.
Khung giữ chỗ — thay bằng ảnh chụp thật khi cóBa bước lắp
- Cắm buzzer lên breadboard, chú ý dấu
+in trên thân. - Nối chân
+qua điện trở 100 Ω sangGPIO25. - Nối chân còn lại xuống
GND.
Ngoài chợ có hai loại nhìn gần giống hệt nhau:
- Buzzer chủ động — bên trong đã có sẵn mạch dao động. Cấp điện là nó kêu, nhưng chỉ kêu đúng một tần số cố định. Với bài này thì vô dụng.
- Buzzer thụ động — chỉ có màng và cuộn dây. Nó kêu theo đúng tần số ta cấp. Đây là loại cần mua.
Cách phân biệt tại chỗ: lật mặt đáy lên. Loại chủ động thường bịt kín bằng miếng nhựa hoặc keo đen; loại thụ động hở, nhìn thấy bảng mạch xanh và cuộn dây. Cách chắc hơn: chấm nhẹ hai chân vào pin 3 V — kêu một tiếng "tít" liên tục là chủ động, chỉ kêu "tách" một cái rồi im là thụ động.
Khi đặt hàng, hãy tìm đúng chữ passive buzzer. Tôi từng mua nhầm cả chục con và chỉ phát hiện ra vào tối trước buổi dạy.
Buzzer có điện trở rất thấp. Nối thẳng vào GPIO thì dòng có thể vượt quá 12 mA mà chân ESP32 chịu được, làm hỏng chân — kiểu hỏng khó chịu vì bo vẫn chạy, chỉ mỗi chân đó chết.
Con điện trở 100 Ω giữ dòng ở mức an toàn. Âm nhỏ đi một chút, nhưng trong phòng học thì vẫn thừa to.
05 Mã nguồn
Toàn bộ mã trong bài có sẵn tại kho GitHub, thư mục cap-1/bai-05-buzzer/. Chép tệp vào bo mạch rồi đổi tên thành main.py là chạy.
Chương trình chính — chạy hết một quãng tám# ------------------------------------------------------------
# Bai 10 - Phat am bang buzzer: thang am 12 nua cung
# Phan cung: buzzer thu dong noi GPIO25 qua dien tro 100 ohm
# ------------------------------------------------------------
from machine import Pin, PWM
import time
CHAN_BUZZER = 25
F_LA4 = 440.0 # not La quang tam 4, moc chuan quoc te
buzzer = PWM(Pin(CHAN_BUZZER))
buzzer.duty_u16(0) # im lang khi khoi dong
TEN_NOT = ["Do", "Do#", "Re", "Re#", "Mi", "Fa",
"Fa#", "Sol", "Sol#", "La", "La#", "Si"]
def tan_so_cua(nua_cung_so_voi_la):
"""Moi nua cung nhan them 2^(1/12) lan."""
return F_LA4 * (2 ** (nua_cung_so_voi_la / 12))
def keu(f_hz, thoi_gian_ms=400):
buzzer.freq(int(f_hz))
buzzer.duty_u16(32768) # 50% - to nhat
time.sleep_ms(thoi_gian_ms)
buzzer.duty_u16(0) # tat han giua hai not
time.sleep_ms(60)
# Do quang tam 4 nam duoi La 9 nua cung
for i in range(13):
f = tan_so_cua(i - 9)
ten = TEN_NOT[i % 12]
print("{:5s} {:7.2f} Hz".format(ten, f))
keu(f)
buzzer.deinit() Màn hình in ra bảng tần số của từng nốt trong lúc buzzer kêu:
Do 261.63 Hz Do# 277.18 Hz Re 293.66 Hz Re# 311.13 Hz Mi 329.63 Hz Fa 349.23 Hz Fa# 369.99 Hz Sol 392.00 Hz Sol# 415.30 Hz La 440.00 Hz La# 466.16 Hz Si 493.88 Hz Do 523.25 Hz
Chú ý dòng cuối bảng: nốt Đô ở cuối đúng bằng gấp đôi nốt Đô ở đầu — 523,25 so với 261,63. Đây là chỗ để dừng lại và hỏi cả lớp.
Chương trình phụ — quét tìm vùng buzzer kêu to nhất# Quet tan so tu 100 Hz den 5000 Hz de tim vung buzzer keu to nhat
from machine import Pin, PWM
import time
buzzer = PWM(Pin(25))
buzzer.duty_u16(32768)
f = 100
while f <= 5000:
buzzer.freq(f)
print(f, "Hz")
time.sleep_ms(300)
f = int(f * 1.15) # tang 15% moi buoc - tai nghe deu hon la tang deu
buzzer.duty_u16(0)
buzzer.deinit() Em mô tả bằng tiếng Việt, hệ thống dựng thuật toán và chương trình, rồi nạp thẳng xuống ESP32 qua Wi-Fi.
06 Hiệu chuẩn và kiểm thử
Đo lại xem máy có nói thật không
Đây là bước biến một trò chơi thành một phép đo, và nó chỉ mất năm phút.
- Cho học sinh cài một app đo tần số miễn phí trên điện thoại (Phyphox, Physics Toolbox, hay Spectroid đều được).
- Chạy chương trình, dừng lại ở nốt La (440 Hz).
- Hướng micro điện thoại vào buzzer, đọc đỉnh phổ.
- Ghi lại: máy đặt bao nhiêu, điện thoại đo được bao nhiêu.
Kết quả thường lệch dưới 1%. Nếu lệch nhiều hơn thì gần như chắc chắn là phòng quá ồn hoặc app đang bắt một hài bậc cao chứ không phải tần số cơ bản.
Danh sách kiểm trước khi coi là xong
- Buzzer kêu rõ ràng khác nhau ở nốt Đô và nốt Đô cao.
- Điện thoại đo được 440 ± 5 Hz khi máy đặt 440 Hz.
- Đặt
duty_u16(65535)thì buzzer im — học sinh giải thích được vì sao. - Chương trình kết thúc bằng
deinit()và buzzer không rít nữa.
Nếu chương trình dừng giữa chừng (bấm Stop, hoặc lỗi), chân PWM vẫn giữ nguyên trạng thái cuối và buzzer rít liên tục — rất khó chịu khi có tám nhóm cùng lúc.
Cách chữa: luôn gọi buzzer.duty_u16(0) rồi
buzzer.deinit() ở cuối. Và trong lúc thử nghiệm, hãy nhớ tổ
hợp cứu hộ: gõ PWM(Pin(25)).deinit() thẳng trong REPL là im ngay.
07 Kinh nghiệm và cạm bẫy
Buổi đầu tiên tôi cho cả tám nhóm chạy cùng lúc. Kết quả là một mớ âm thanh hỗn độn, không nhóm nào phân biệt nổi nốt của mình, và lớp bên cạnh sang gõ cửa.
Từ đó tôi làm ba việc: đặt thời lượng mỗi nốt xuống 250 ms cho nhanh gọn; cho các nhóm chạy lệch nhau — nhóm 1–4 chạy trước, nhóm 5–8 quan sát rồi đổi vai; và dán một mẩu băng dính lên miệng buzzer để giảm bớt độ to mà không ảnh hưởng tần số. Mẩu băng dính ấy hóa ra lại là một thí nghiệm phụ rất hay: nó đổi độ to mà không đổi độ cao — đúng thứ ta muốn dạy.
Sau khi chạy hết thang âm, tôi hỏi: "Từ Đô lên Rê tăng 32 Hz. Vậy từ Đô cao lên Rê cao tăng bao nhiêu?"
Gần như cả lớp trả lời "32 Hz". Rồi các em nhìn bảng số liệu do chính máy in ra: 523,25 lên 587,33, tức là tăng 64 Hz. Gấp đôi.
Khoảnh khắc "ơ, sao lại thế" đó đáng giá hơn cả buổi giảng về cấp số nhân. Và nó chỉ xảy ra được khi các em có bảng số liệu thật trước mặt.
- Buzzer kêu nhưng mọi nốt nghe như nhau. Đang dùng buzzer chủ động. Xem lại mục lắp mạch.
- Nốt cao nghe to hơn hẳn nốt thấp. Bình thường — buzzer nhỏ có tần số cộng hưởng riêng, thường quanh 2–4 kHz. Đây là cơ hội nói về cộng hưởng, và là lí do có chương trình quét ở trên.
- Số hiện ra nhưng không có tiếng. Kiểm tra
duty_u16có bằng 0 không, và kiểm tra chân cắm đúng GPIO25 chưa.
08 Ứng dụng trong dạy học
Vật lí — đặc trưng vật lí và đặc trưng sinh lí của âm
Đây là bài lí tưởng để tách hai khái niệm mà sách giáo khoa đặt cạnh nhau nhưng học sinh vẫn lẫn. Cho các em thay đổi một đại lượng và giữ nguyên đại lượng kia:
| Thay đổi | Giữ nguyên | Tai nghe thấy gì |
|---|---|---|
| freq() | duty_u16() | Đổi độ cao, độ to gần như không đổi |
| duty_u16() | freq() | Đổi độ to, độ cao không đổi |
Hai dòng bảng này thay được cả một trang lí thuyết.
Toán — cấp số nhân có thật ngoài đời
Cho học sinh lập bảng tần số 13 nốt, rồi tính tỉ số giữa hai nốt liên tiếp. Tỉ số ấy luôn bằng 1,0595 — chính là công bội. Sau đó hỏi ngược: nếu muốn chia quãng tám thành 24 phần đều nhau (nhạc Ả Rập có làm thế) thì công bội là bao nhiêu?
Công nghệ — điều khiển bằng vi điều khiển
Bài này là ví dụ nhỏ nhất và rõ nhất của mạch nội dung "Vi điều khiển": một chân ra, một tín hiệu số, một thiết bị chấp hành. Từ đây mở sang điều khiển đèn, quạt, động cơ đều cùng một nguyên lí.
Hoạt động 1 — Xác định vấn đề. Trường dùng chung một tiếng chuông cho mọi việc. Lớp cần một chuông riêng để báo ba tình huống khác nhau: hết giờ làm bài, đến lượt nhóm báo cáo, và cảnh báo im lặng.
Tiêu chí sản phẩm: ba giai điệu phân biệt được khi nghe ở cuối lớp; mỗi giai điệu dài dưới 3 giây; dùng đúng một buzzer; và một bạn lớp khác nghe ba lần phải đoán đúng cả ba.
Hoạt động 2 — Kiến thức nền. Tần số và độ cao; PWM; cấp số nhân trong thang âm.
Hoạt động 3 — Đề xuất và chọn phương án. Mỗi nhóm thiết kế ba giai điệu trên giấy trước khi lập trình, và giải thích vì sao chọn tần số đó cho tình huống đó.
Hoạt động 4 — Chế tạo và thử. Lập trình, chạy thử ở cuối lớp, đo mức âm bằng điện thoại nếu có.
Hoạt động 5 — Báo cáo và điều chỉnh. Mời lớp khác nghe và đoán. Nhóm nào bị đoán sai thì phân tích vì sao rồi sửa.
- Ghép thêm nút nhấn của Bài 2 để chọn giai điệu.
- Ghép với cảm biến khoảng cách (Bài 24) làm nhạc cụ Theremin đơn giản: đưa tay lại gần thì âm cao lên.
- Dùng micro của Bài 31 để đo lại chính tần số mình phát ra — khép kín vòng phát và thu.
- Hướng thi Khoa học kĩ thuật: thiết bị hỗ trợ luyện tai nghe nhạc cho học sinh khiếm thị, phát nốt và chấm câu trả lời.