Logic analyzer 8 kênh và PulseView: bắt và giải mã UART, I2C, SPI, PWM của ESP32
Dùng logic analyzer 8 kênh giá rẻ với PulseView: nối dây với ESP32, cài driver bằng Zadig, bắt tín hiệu bằng kích hoạt, giải mã UART, I2C, SPI, đo PWM và chọn tốc độ lấy mẫu.
Chương trình gửi dữ liệu qua UART, I2C hay SPI mà thiết bị bên kia không phản hồi, câu hỏi đầu tiên là: tín hiệu có thật sự ra tới chân chưa, đúng tốc độ chưa, đúng byte chưa? Đồng hồ vạn năng không trả lời được, vì tín hiệu đổi mức hàng nghìn lần mỗi giây. Logic analyzer (máy phân tích logic) ghi lại mức 0/1 của nhiều chân cùng lúc, còn phần mềm PulseView vẽ dạng sóng và giải mã thành byte, địa chỉ, ACK. Bài này dùng một máy đo 8 kênh giá rẻ với ESP32: nối dây, cài PulseView, bắt và giải mã UART, I2C, SPI, đo PWM, chọn tốc độ lấy mẫu cho đúng.
1. Logic analyzer là gì

Logic analyzer đọc mỗi kênh ở những thời điểm cách đều nhau (tốc độ lấy mẫu, ví dụ 8 triệu lần mỗi giây) và chỉ ghi lại một trong hai giá trị: cao hay thấp. Dữ liệu chuyển qua USB vào máy tính, phần mềm vẽ lại thành dạng sóng và tự đọc ra nội dung theo giao thức bạn chọn.
- Máy 8 kênh giá rẻ phổ biến hiện nay dùng chip USB loại FX2, tốc độ lấy mẫu tối đa ghi 24 MHz, hợp với UART, I2C, SPI tốc độ vừa của ESP32 và Arduino.
- PulseView là phần mềm mã nguồn mở của dự án sigrok, chạy trên Windows, Linux, macOS, nhận loại máy này qua driver fx2lafw.
- Khác máy hiện sóng: logic analyzer có nhiều kênh và giải mã giao thức, nhưng không thấy điện áp thật. Muốn xem sườn chậm, nhiễu, điện áp bao nhiêu volt thì cần máy hiện sóng.
Mạch ESP32 dùng mức 3,3 V, đo trực tiếp được. Với mạch 5 V, xem thông số đầu vào của máy đang có; không nối kênh đo vào điện áp cao hơn 5 V hay vào điện lưới.
2. Chuẩn bị
- ESP32 DevKit V1 30 chân và dây USB.
- Logic analyzer 8 kênh loại USB (kèm dây đo) và máy tính Windows.
- Breadboard và dây cắm.
- Tùy chọn: màn hình OLED 0.96 inch I2C, để có một thiết bị trả lời ACK trên đường I2C.
3. Nối dây

| Kênh trong PulseView | Chân ESP32 | Tín hiệu |
|---|---|---|
| D0 | GPIO17 (TX2) | UART 9600 baud |
| D1 | GPIO22 | I2C SCL |
| D2 | GPIO21 | I2C SDA |
| D3 | GPIO18 | SPI SCK |
| D4 | GPIO23 | SPI MOSI |
| D5 | GPIO5 | SPI CS |
| D6 | GPIO25 | PWM 1 kHz |
| GND | GND | Đất chung, bắt buộc |
Dây GND là dây quan trọng nhất: thiếu nó, máy đo không có mốc để so mức, dạng sóng sẽ loạn hoặc đứng yên. Dùng dây ngắn, cắm chắc. Trên vỏ máy đo, kênh có thể ghi CH1–CH8 hoặc CH0–CH7; trong PulseView kênh đầu tiên luôn là D0.
4. Chương trình tạo tín hiệu mẫu
Chương trình chỉ dùng thư viện có sẵn trong gói ESP32 cho Arduino IDE. Cứ 500 ms phát một lượt: hai ký tự "PY" qua UART2, một gói I2C tới địa chỉ 0x3C (byte 0x00 và 0xAE, là lệnh tắt hiển thị nếu có màn hình SSD1306), hai byte 0xA5, 0x3C qua SPI. Kênh PWM chạy liên tục 1 kHz với độ rộng xung 25%.
// PYWORLD.VN - Tín hiệu mẫu để tập đo bằng logic analyzer và PulseView
// PYWORLD.VN - Mỗi 500 ms phát một lượt: UART 9600 baud, I2C 100 kHz, SPI 1 MHz; PWM 1 kHz chạy liên tục
// PYWORLD.VN - Nối kênh D0..D6 của logic analyzer theo bảng trong bài, GND chung với ESP32
#include <Wire.h>
#include <SPI.h>
// Chân phát tín hiệu
const int CHAN_UART_RX = 16; // Serial2 cần khai báo chân nhận, bài này không dùng
const int CHAN_UART_TX = 17; // -> D0
const int CHAN_SCL = 22; // -> D1
const int CHAN_SDA = 21; // -> D2
const int CHAN_SCK = 18; // -> D3
const int CHAN_MOSI = 23; // -> D4
const int CHAN_CS = 5; // -> D5
const int CHAN_MISO = 19; // SPI cần khai báo chân nhận, bài này không dùng
const int CHAN_PWM = 25; // -> D6
const uint32_t BAUD_UART = 9600;
const uint32_t TAN_SO_I2C = 100000;
const uint32_t TAN_SO_SPI = 1000000;
const uint32_t TAN_SO_PWM = 1000;
const uint8_t DO_PHAN_GIAI_PWM = 8; // 0..255
const uint32_t DUTY_PWM = 64; // 64/256 = 25 %
// Địa chỉ màn hình OLED 0.96 inch SSD1306. Không gắn thiết bị thì sẽ thấy NACK.
const uint8_t DIA_CHI_I2C = 0x3C;
uint32_t soLuot = 0;
void setup() {
Serial.begin(115200);
Serial2.begin(BAUD_UART, SERIAL_8N1, CHAN_UART_RX, CHAN_UART_TX);
Wire.begin(CHAN_SDA, CHAN_SCL, TAN_SO_I2C);
SPI.begin(CHAN_SCK, CHAN_MISO, CHAN_MOSI, -1);
pinMode(CHAN_CS, OUTPUT);
digitalWrite(CHAN_CS, HIGH); // CS nghỉ ở mức cao
ledcAttach(CHAN_PWM, TAN_SO_PWM, DO_PHAN_GIAI_PWM);
ledcWrite(CHAN_PWM, DUTY_PWM);
Serial.println("Tin hieu mau cho logic analyzer");
Serial.println("D0=GPIO17 UART D1=GPIO22 SCL D2=GPIO21 SDA D3=GPIO18 SCK D4=GPIO23 MOSI D5=GPIO5 CS D6=GPIO25 PWM");
}
void loop() {
// 1. UART: hai ký tự "PY" (0x50, 0x59), khung 8N1
Serial2.print("PY");
Serial2.flush(); // chờ phát xong bit cuối
delayMicroseconds(200);
// 2. I2C: địa chỉ 0x3C + ghi, byte điều khiển 0x00 (lệnh), lệnh 0xAE (tắt hiển thị của SSD1306)
Wire.beginTransmission(DIA_CHI_I2C);
Wire.write(0x00);
Wire.write(0xAE);
uint8_t ketQua = Wire.endTransmission();
delayMicroseconds(200);
// 3. SPI chế độ 0, bit cao trước: hai byte 0xA5, 0x3C liền nhau trong một lần CS thấp
const uint8_t goi[2] = {0xA5, 0x3C};
SPI.beginTransaction(SPISettings(TAN_SO_SPI, MSBFIRST, SPI_MODE0));
digitalWrite(CHAN_CS, LOW);
SPI.writeBytes(goi, sizeof(goi));
digitalWrite(CHAN_CS, HIGH);
SPI.endTransaction();
soLuot++;
if (ketQua == 0) {
Serial.printf("Luot %u: I2C 0x%02X -> ACK\n", (unsigned)soLuot, DIA_CHI_I2C);
} else if (ketQua == 2) {
Serial.printf("Luot %u: I2C 0x%02X -> NACK (khong co thiet bi tra loi)\n", (unsigned)soLuot, DIA_CHI_I2C);
} else {
Serial.printf("Luot %u: I2C loi ma %u\n", (unsigned)soLuot, (unsigned)ketQua);
}
delay(500);
}
Mở Serial Monitor ở 115200 baud: mỗi lượt in một dòng như Luot 12: I2C 0x3C -> ACK khi có màn hình OLED, hoặc NACK (khong co thiet bi tra loi) khi không gắn gì. Cả hai trường hợp đều đo được.
5. Cài PulseView và nhận máy đo

- Tải bộ cài PulseView cho Windows ở trang tải về của dự án sigrok (sigrok.org). Bộ cài có kèm sẵn công cụ Zadig để đổi driver USB.
- Cắm máy đo, mở Zadig. Nếu không thấy thiết bị trong danh sách, bật Options → List All Devices. Chọn máy đo, chọn driver WinUSB, bấm cài (Replace Driver hoặc Install Driver).
- Mở PulseView, mở hộp kết nối thiết bị: chọn driver fx2lafw, giao diện USB, bấm quét thiết bị (Scan for devices), chọn máy đo rồi OK. Máy giá rẻ có thể hiện dưới tên một dòng máy khác vì dùng chung mã USB; vẫn chọn bình thường.
- Lần đầu kết nối, PulseView nạp firmware vào máy đo, máy đo kết nối lại với mã USB mới. Nếu PulseView báo không mở được thiết bị, mở Zadig gán WinUSB thêm một lần cho thiết bị mới hiện ra.
Windows nhớ driver theo cổng USB: cắm máy đo sang cổng khác thì có thể phải gán WinUSB lại.
6. Bắt một lượt tín hiệu
- Tốc độ lấy mẫu: 8 MHz (đủ cho SPI 1 MHz, xem mục 10).
- Số mẫu: 1 M mẫu ở 8 MHz là 125 ms, đủ chứa một lượt (khoảng 3 ms).
- Kích hoạt (trigger): bấm vào tên kênh D0, chọn sườn xuống. UART nghỉ ở mức cao, nên sườn xuống đầu tiên chính là bit start của chữ "P"; phần mềm bắt đầu ghi từ đó. Không dùng kích hoạt thì chọn số mẫu đủ dài hơn 500 ms (ví dụ 5 M mẫu ở 8 MHz).
- Bấm Run, phóng to quanh điểm kích hoạt bằng con lăn chuột.
7. Giải mã UART

Bấm nút thêm bộ giải mã giao thức, gõ tìm UART. Bấm vào tên bộ giải mã vừa thêm để đặt: chân RX = D0, tốc độ 9600, 8 bit dữ liệu, không parity, 1 bit stop; định dạng hiển thị chọn hex hoặc ASCII. Bên dưới D0 hiện các hàng chữ: bit start, từng bit dữ liệu, bit stop và byte 50 ('P'), 59 ('Y').
Đây cũng là cách đo tốc độ baud thật: một bit ở 9600 baud dài 104,2 µs. Đặt hai con trỏ đo thời gian của PulseView ở hai sườn cách nhau một bit để kiểm tra; nếu lệch nhiều, phía nhận sẽ đọc sai ký tự.
8. Giải mã I2C

Thêm bộ giải mã I2C, đặt SCL = D1, SDA = D2. PulseView ghi nhãn tiếng Anh như Start, Address write: 3C, ACK, Data write: 00, Stop; trong hình đã ghi lại bằng tiếng Việt. Không gắn thiết bị thì sau 8 bit đầu là NACK: SDA vẫn cao ở nhịp thứ 9, ESP32 dừng gói.
Gặp lỗi "không tìm thấy thiết bị I2C", logic analyzer cho biết ngay: ESP32 có gửi đúng địa chỉ không, thiết bị có ACK không, SDA có bị kéo xuống mãi không. Chỉ có điện trở kéo lên bên trong ESP32 (khá yếu) thì sườn lên chậm hơn; module OLED thường đã có sẵn điện trở kéo lên.
9. Giải mã SPI và đo PWM

- SPI: thêm bộ giải mã SPI, đặt CLK = D3, MOSI = D4, CS = D5 (kích hoạt mức thấp), chế độ 0 (CPOL = 0, CPHA = 0), bit cao trước, 8 bit mỗi từ. Hàng MOSI hiện
A5,3C. Chọn sai chế độ, các byte sẽ lệch một bit. - PWM: thêm bộ giải mã PWM cho D6, mỗi chu kỳ hiện tỉ lệ độ rộng xung (25%). Dùng con trỏ đo thời gian để thấy chu kỳ 1 ms, tức 1 kHz.
10. Chọn tốc độ lấy mẫu

Phần mềm chỉ biết mức ở các điểm lấy mẫu, nên vị trí sườn có thể lệch tới một khoảng mẫu. Ở 20 kHz mỗi bit UART 9600 baud chỉ có khoảng 2 mẫu, mô phỏng cho thấy chỉ khoảng 42% số lần đọc đúng "PY". Từ khoảng 5 mẫu mỗi bit trở lên thì đọc đúng ổn định. Quy tắc dễ nhớ: lấy mẫu nhanh gấp 4 lần trở lên so với tốc độ bit hoặc xung nhịp nhanh nhất, gấp 10 lần nếu cần đo thời gian chính xác.
| Tín hiệu | Tốc độ bit / xung nhịp | Lấy mẫu tối thiểu | Nên dùng |
|---|---|---|---|
| UART 9600 baud | 9,6 kHz | 50 kHz | 100 kHz – 1 MHz |
| UART 115200 baud | 115,2 kHz | 500 kHz | 1–2 MHz |
| I2C 100 kHz | 100 kHz | 500 kHz | 1–2 MHz |
| I2C 400 kHz | 400 kHz | 2 MHz | 4–8 MHz |
| SPI 1 MHz | 1 MHz | 4 MHz | 8–12 MHz |
Máy 24 MHz giá rẻ đọc tốt tới khoảng vài MHz xung nhịp. SPI nhanh hơn (ví dụ thẻ nhớ, màn hình chạy 10–40 MHz) thì nên giảm tốc độ SPI trong chương trình khi cần đo, hoặc dùng máy đo nhanh hơn. Tốc độ cao cũng làm đầy bộ đệm USB nhanh: nếu PulseView dừng giữa chừng, giảm tốc độ lấy mẫu hoặc cắm máy đo thẳng vào máy tính, không qua hub.
11. Lỗi hay gặp
| Hiện tượng | Nguyên nhân thường gặp | Cách xử lý |
|---|---|---|
| PulseView không thấy máy đo | Chưa gán WinUSB, chọn sai driver | Gán WinUSB bằng Zadig, chọn fx2lafw, quét lại |
| Báo không mở được thiết bị | Driver gắn với mã USB cũ hoặc cổng cũ | Rút cắm lại, gán WinUSB lần hai cho thiết bị mới hiện ra |
| Mọi kênh là đường thẳng | Thiếu GND chung, cửa sổ ghi không có lượt tín hiệu | Nối GND; dùng kích hoạt sườn xuống ở D0 hoặc tăng số mẫu |
| UART ra ký tự lạ, báo lỗi khung | Sai baud, sai kênh RX, lấy mẫu chậm | Đặt đúng 9600, RX = D0, lấy mẫu từ 100 kHz trở lên |
| I2C toàn NACK | Không có thiết bị, sai địa chỉ (0x3C hay 0x3D), dây SDA/SCL đảo | Kiểm tra dây, thử địa chỉ còn lại |
| Byte SPI lệch một bit | Sai chế độ SPI hoặc thứ tự bit | Đặt chế độ 0, bit cao trước |
12. Xem thêm
- UART là gì: khung truyền, tốc độ baud và Serial2 trên ESP32
- I2C là gì: START, STOP, địa chỉ, ACK
- SPI là gì: MOSI, MISO, SCK, CS và bốn chế độ
- PWM trên ESP32 với LEDC
- Mức logic 3,3 V và 5 V
- Bài máy hiện sóng cầm tay trong cùng loạt công cụ và chế tạo mạch: xem điện áp thật, sườn và nhiễu mà logic analyzer không thấy.
Xem thêm