Máy hiện sóng cầm tay cho người mới: volt/div, time/div, kích hoạt, đầu đo x10, đo tín hiệu ESP32
Đọc màn hình máy hiện sóng, chỉnh volt/div, time/div, kích hoạt; dùng và bù đầu đo x10; đo PWM, sóng cosin từ DAC và dội phím nút nhấn của ESP32; an toàn khi đo.
Đồng hồ vạn năng cho biết một con số; máy hiện sóng (oscilloscope, dao động ký) cho thấy điện áp thay đổi theo thời gian: xung PWM có đủ 3,3 V không, sóng có méo không, nút nhấn dội bao nhiêu lần. Máy hiện sóng cầm tay nhỏ gọn, chạy pin, đủ dùng cho phần lớn mạch vi điều khiển. Bài này giải thích các thông số trên màn hình, cách chỉnh volt/div, time/div, kích hoạt (trigger), dùng đầu đo x10 và bù đầu đo, rồi đo ba tín hiệu do ESP32 tạo ra: PWM, sóng cosin từ DAC và dội phím của nút nhấn.
1. Máy hiện sóng cho thấy gì

Trục ngang là thời gian, trục dọc là điện áp. Màn hình chia lưới, mỗi ô gọi là một div (thường 10 ô ngang, 8 ô dọc). Đọc số đo bằng cách đếm ô rồi nhân với giá trị một ô. Khác với logic analyzer chỉ thấy 0 và 1, máy hiện sóng thấy điện áp thật: mức cao bao nhiêu volt, sườn lên nhanh hay chậm, có nhiễu, có vọt không.
Hai thông số chính khi chọn máy:
- Băng thông (MHz): tần số cao nhất máy đo còn đúng biên độ. Đo sóng vuông tần số f, nên chọn máy có băng thông từ khoảng 5f trở lên để còn thấy góc vuông.
- Tốc độ lấy mẫu (MSa/s): số điểm đo mỗi giây, nên gấp vài lần băng thông.
PWM vài kHz, UART, I2C tốc độ thường của ESP32 chỉ cần máy vài MHz. SPI vài chục MHz hay sóng radio thì cần máy mạnh hơn nhiều.
2. Đọc màn hình

- Mốc 0 V của mỗi kênh là mũi tên nhỏ bên trái. Dời mốc này lên xuống bằng núm vị trí dọc để nhiều kênh không chồng nhau.
- Volt/div: 1 V/div nghĩa là mỗi ô dọc là 1 V. PWM 3,3 V cao 3,3 ô.
- Time/div: 200 µs/div nghĩa là mỗi ô ngang là 200 µs. PWM 1 kHz có chu kỳ 1 ms, dài 5 ô; màn hình 10 ô chứa 2 chu kỳ.
- Đo tự động: phần lớn máy có mục đo (Measure) hiện tần số, đỉnh–đỉnh, độ rộng xung. Vẫn nên đếm ô để kiểm tra số máy báo.
3. Đầu đo x1, x10 và bù đầu đo

- x10 chia tín hiệu cho 10, trở kháng vào khoảng 10 MΩ, điện dung nhỏ nên ít làm ảnh hưởng mạch và giữ được băng thông. Dùng x10 cho hầu hết việc.
- x1 không chia, thấy được tín hiệu rất nhỏ, nhưng băng thông thấp hơn hẳn và tải mạch nhiều hơn.
- Đặt hệ số đầu đo trong menu kênh giống với công tắc trên đầu đo. Đầu đo để x10 mà máy đặt x1 thì mọi số đo nhỏ đi 10 lần.

Đầu đo x10 có một tụ chỉnh nhỏ cần chỉnh khớp với đầu vào của máy. Nhiều máy có chân phát sóng vuông khoảng 1 kHz để chỉnh: kẹp đầu đo vào chân đó, kẹp mass vào chân đất bên cạnh, dùng tua vít nhựa vặn vít chỉnh cho tới khi góc sóng vuông phẳng. Đầu đo chưa bù thì biên độ và sườn đo sai.
4. Chuẩn bị và nối dây
- ESP32 DevKit V1 30 chân và dây USB.
- Máy hiện sóng (cầm tay hoặc để bàn) với đầu đo x10; máy 1 kênh thì đo lần lượt từng tín hiệu.
- Một nút nhấn hai chân, breadboard và dây cắm.

Móc mũi đo vào một sợi dây cắm ngắn cắm vào hàng chân của breadboard, kẹp mass vào chân GND. Đừng chạm mũi đo trượt qua hai chân ESP32 cạnh nhau: dễ chập chân.
5. Chương trình tạo tín hiệu
Chương trình chỉ dùng thư viện có sẵn trong gói ESP32 cho Arduino IDE: GPIO27 phát PWM 1 kHz (gõ 1 đến 9 trong Serial Monitor để đổi độ rộng xung 10–90%), GPIO26 phát sóng cosin 1 kHz bằng bộ tạo sóng của DAC, GPIO4 đọc nút nhấn bằng ngắt và đếm số sườn xuống mỗi lần bấm, nhả.
// PYWORLD.VN - Tín hiệu mẫu để tập dùng máy hiện sóng: PWM, sóng cosin từ DAC, nút nhấn để xem dội phím
// PYWORLD.VN - GPIO27 PWM 1 kHz (gõ 1..9 trong Serial Monitor để đổi độ rộng xung 10..90 %), GPIO26 sóng cosin 1 kHz
// PYWORLD.VN - GPIO4 nút nhấn nối GND: đếm số sườn xuống mỗi lần bấm, nhả để so với màn hình máy hiện sóng
#include "driver/dac_cosine.h"
const int CHAN_PWM = 27;
const int CHAN_NUT = 4;
const uint32_t TAN_SO_PWM = 1000;
const uint8_t DO_PHAN_GIAI_PWM = 10; // 0..1023
const uint32_t TAN_SO_COSIN = 1000; // Hz, DAC kênh 1 là GPIO26
const uint32_t THOI_GIAN_LANG_MS = 50; // 50 ms không có sườn mới thì coi như xong một lần bấm hoặc nhả
volatile uint32_t soSuon = 0;
volatile uint32_t lucSuonDau = 0; // micros() của sườn đầu tiên
volatile uint32_t lucSuonCuoi = 0; // micros() của sườn gần nhất
uint32_t soLanBao = 0;
dac_cosine_handle_t kenhCosin;
void IRAM_ATTR khiCoSuonXuong() {
uint32_t bayGio = micros();
if (soSuon == 0) lucSuonDau = bayGio;
soSuon = soSuon + 1;
lucSuonCuoi = bayGio;
}
void datDoRongXung(uint32_t phanTram) {
uint32_t duty = ((1u << DO_PHAN_GIAI_PWM) * phanTram) / 100;
ledcWrite(CHAN_PWM, duty);
Serial.printf("PWM %u Hz, do rong xung %u %% (duty %u/%u)\n", (unsigned)TAN_SO_PWM, (unsigned)phanTram,
(unsigned)duty, (unsigned)(1u << DO_PHAN_GIAI_PWM));
}
void batSongCosin() {
dac_cosine_config_t cauHinh = {};
cauHinh.chan_id = DAC_CHAN_1; // GPIO26
cauHinh.freq_hz = TAN_SO_COSIN;
cauHinh.clk_src = DAC_COSINE_CLK_SRC_DEFAULT;
cauHinh.atten = DAC_COSINE_ATTEN_DB_6; // một nửa biên độ lớn nhất
cauHinh.phase = DAC_COSINE_PHASE_0;
cauHinh.offset = 0;
if (dac_cosine_new_channel(&cauHinh, &kenhCosin) == ESP_OK && dac_cosine_start(kenhCosin) == ESP_OK) {
Serial.printf("Song cosin %u Hz tren GPIO26\n", (unsigned)TAN_SO_COSIN);
} else {
Serial.println("Khong bat duoc song cosin tren GPIO26");
}
}
void setup() {
Serial.begin(115200);
ledcAttach(CHAN_PWM, TAN_SO_PWM, DO_PHAN_GIAI_PWM);
datDoRongXung(50);
batSongCosin();
pinMode(CHAN_NUT, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(CHAN_NUT), khiCoSuonXuong, FALLING);
Serial.println("Go 1..9 de doi do rong xung 10..90 %; bam nut GPIO4 de dem suon xuong");
}
void loop() {
if (Serial.available()) {
char c = Serial.read();
if (c >= '1' && c <= '9') datDoRongXung((uint32_t)(c - '0') * 10);
}
noInterrupts();
uint32_t n = soSuon, dau = lucSuonDau, cuoi = lucSuonCuoi;
interrupts();
if (n > 0 && micros() - cuoi > THOI_GIAN_LANG_MS * 1000) {
noInterrupts();
soSuon = 0;
interrupts();
soLanBao++;
// Sau 50 ms yên lặng: chân còn thấp là đang giữ nút (lần bấm), chân cao là vừa nhả nút
const char *loai = digitalRead(CHAN_NUT) == LOW ? "Bam nut" : "Nha nut";
Serial.printf("%u. %s: %u suon xuong trong %u us\n", (unsigned)soLanBao, loai, (unsigned)n, (unsigned)(cuoi - dau));
}
}
6. Đo PWM: chỉnh volt/div và time/div

- Đặt kênh 1 ở 1 V/div, ghép DC (DC coupling), mốc 0 V thấp hơn giữa màn hình 2 ô.
- Đặt 200 µs/div, kích hoạt sườn lên ở khoảng 1,6 V (giữa 0 và 3,3 V).
- Đọc: cao 3,3 ô là 3,3 V; chu kỳ 5 ô là 1 ms, tức 1 kHz; phần cao dài 2,5 ô là độ rộng xung 50%.
- Gõ
2trong Serial Monitor: phần cao còn 1 ô (20%), chu kỳ vẫn 5 ô.
Nhiều máy có nút Auto tự chọn volt/div, time/div. Tiện để bắt đầu, nhưng nên biết tự chỉnh vì Auto hay chọn sai với tín hiệu chỉ xuất hiện từng lúc.
7. Kích hoạt (trigger) giữ sóng đứng yên

Máy quét màn hình liên tục. Không có kích hoạt, mỗi lần quét bắt đầu ở một chỗ khác trên sóng, hình chạy loạn. Kích hoạt bảo máy: chỉ bắt đầu khi tín hiệu đi lên (hoặc đi xuống) qua một mức. Khi đó mọi lần quét đều bắt đầu cùng một điểm và hình đứng yên.
- Nguồn kích hoạt: chọn đúng kênh đang xem (kênh 2 cho sóng cosin).
- Mức kích hoạt: đặt trong khoảng sóng đi qua, ví dụ giữa đỉnh và đáy. Sóng cosin của DAC có biên độ khác nhau tùy mạch: đọc đỉnh và đáy trên màn hình rồi đặt mức ở giữa.
- Chế độ: Auto vẫn quét khi không có kích hoạt; Normal chỉ vẽ khi có kích hoạt; Single bắt một lần rồi dừng.
8. Bắt dội phím bằng chế độ Single

Chuyển đầu đo kênh 1 sang chân D4. Đặt 1 V/div, 100 µs/div, kích hoạt sườn xuống ở 1,6 V, chế độ Single, rồi bấm nút. Máy bắt đúng lúc tiếp điểm chạm và giữ hình lại: tiếp điểm kim loại nảy vài lần trong vài trăm micro giây trước khi chạm hẳn. Serial Monitor in số sườn xuống mà ngắt của ESP32 đếm được; con số này thường lớn hơn 1, đó là lý do chương trình đọc nút cần chống dội.
9. An toàn khi đo
- Kẹp mass của đầu đo nối với vỏ máy. Với máy để bàn cắm điện, vỏ máy nối đất của ổ điện: kẹp mass vào một điểm không phải đất sẽ gây chập.
- Kẹp mass của các kênh thường nối chung bên trong máy: luôn kẹp vào cùng một điểm GND.
- Không đo điện lưới 220 V hay mạch nguồn xung phía sơ cấp bằng đầu đo thường. Những phép đo này cần đầu đo vi sai hoặc đầu đo cách ly có cấp an toàn phù hợp và người có kinh nghiệm.
- Không vượt điện áp ghi trên đầu đo và trên đầu vào của máy.
10. Lỗi hay gặp
| Hiện tượng | Nguyên nhân thường gặp | Cách xử lý |
|---|---|---|
| Số đo nhỏ hoặc lớn gấp 10 lần | Hệ số đầu đo trong máy khác công tắc trên đầu đo | Đặt cùng x10 hoặc cùng x1 |
| Sóng chạy loạn, không đứng yên | Sai nguồn kích hoạt, mức kích hoạt nằm ngoài tín hiệu | Chọn đúng kênh, đặt mức giữa đỉnh và đáy |
| Màn hình trống ở chế độ Normal | Chưa có kích hoạt | Chuyển Auto để tìm sóng, rồi đặt lại mức |
| Sóng vuông có góc tròn hoặc vọt nhọn | Đầu đo x10 chưa bù | Chỉnh tụ bù bằng chân sóng vuông thử |
| Thấy sóng 50 Hz to, sóng cần đo bị nhòe | Chưa kẹp mass, dây mass quá dài | Kẹp mass vào GND gần điểm đo |
| Đường thẳng ở 0 V dù mạch có điện | Kênh để ghép GND, sai kênh | Đặt ghép DC, kiểm tra kênh đang bật |
11. Xem thêm
- Cách dùng đồng hồ vạn năng: đo điện áp, dòng, điện trở trước khi cần tới máy hiện sóng.
- Ngắt GPIO trên ESP32: đọc nút nhấn, chống dội.
- PWM trên ESP32 với LEDC.
- Vali đựng thiết bị đo lường: cất máy đo, đầu đo gọn và chống va đập.
- Bài logic analyzer và PulseView trong cùng loạt công cụ và chế tạo mạch: giải mã UART, I2C, SPI trên nhiều kênh.
Xem thêm