Khối A · GĐ 1 · phiên chính
Phiên 2 — Blink, nút nhấn, và hiện tượng nảy phím
Phiên đấu dây đầu tiên. Ba khối bài dẫn tới một phép đo duy nhất: nảy phím kéo dài bao nhiêu mili-giây trên chính cái nút đang cầm, và con số đó quyết định hằng số debounce của phiên sau.
Bốn mục đánh số ở dưới (01 đến 04) là phần kiến thức cơ sở, không tính vào timebox. Chúng được viết để đọc trước phiên. Ba block A, B, C là phần thực hành, tổng 80 phút, chừa dư cho phần mở đầu và phần đóng phiên.
Phiên này là lần đầu mạch rời khỏi mặt bàn và lên breadboard. Phần lớn rủi ro nằm ở lớp vật lý chứ không ở phần mềm, và đó là lý do quy tắc 30 phút cùng cái đồng hồ vạn năng tồn tại: khi mã nguồn đúng mà mạch không chạy, chỉ có phép đo mới phân biệt được nguyên nhân.
00. Trước khi bấm giờ
Mỗi mục dưới đây kiểm được bằng một thao tác. Thiếu một mục là hỏng cả phiên, nên hậu quả được ghi kèm.
- Toolchain của P1 còn chạy. Kiểm bằng cách nạp lại firmware cũ. Hỏng ở đây thì toàn bộ phiên biến thành phiên sửa toolchain.
- PulseView đã cài và chạy được. Cài trong phiên là mất 20 phút của Block C — khối duy nhất mang mục tiêu thật của phiên.
- Quyền truy cập USB cho logic analyzer đã cấu hình. Cùng họ vấn đề với quyền truy cập cổng serial ở P1. Xem Block C.
- Linh kiện đã ra bàn: breadboard, board, LED 5mm đỏ, kit điện trở, nút tactile 4 chân, dây M-M, đồng hồ vạn năng, logic analyzer kèm dây kẹp.
- Schematic của board đã mở sẵn Nguồn source · ví dụ wuxx/nanoESP32-C6 — schematic mã nguồn mở Board dùng trong lộ trình này: LED RGB nối GPIO nào, chân 3V3 lấy nguồn từ đâu, LDO là loại gì. Mở trong tab mới · Esc để đóng . Block A cần biết LED trên board nối vào chân nào và thuộc loại gì.
Bốn mục kiến thức cơ sở dưới đây dài khoảng 25 phút đọc. Đọc chúng trong phiên chính là đổi thời gian đấu dây lấy thời gian đọc — mà đọc thì làm được ở bất cứ đâu, còn đấu dây thì không.
01. Chân GPIO nhìn từ phía điện
Trước khi nối bất cứ thứ gì vào một chân GPIO, cần biết chân đó là loại nguồn điện gì.
Tầng ra của một chân GPIO ở chế độ push-pull gồm hai transistor mắc nối tiếp giữa nguồn và đất, điểm giữa nối ra chân. Mức cao bật transistor phía trên, mức thấp bật transistor phía dưới. Điều quan trọng: cả hai đều có điện trở dẫn khác không, nên chân GPIO không phải một nguồn áp lý tưởng — điện áp ra sụt theo dòng lấy ra.
Datasheet ESP32-C6 định lượng chuyện đó bằng bốn tham số Nguồn datasheet ESP32-C6 Datasheet (Espressif) Mục Electrical Characteristics cho V_OH/drive strength, và mục strapping pin quyết định chân nào được dùng. Mở trong tab mới · Esc để đóng :
| Tham số | Ý nghĩa | Giá trị |
|---|---|---|
| V_OH | Điện áp ra mức cao, tối thiểu | ≥ 0.8 × VDD |
| V_OL | Điện áp ra mức thấp, tối đa | ≤ 0.1 × VDD |
| I_OH | Dòng cấp ra ở mức cao, giá trị điển hình | 40 mA |
| I_OL | Dòng hút vào ở mức thấp, giá trị điển hình | 28 mA |
Ở VDD = 3.3 V, V_OH tối thiểu là 2.64 V — tức chân GPIO ở mức cao được phép chỉ ra 2.64 V mà vẫn đúng đặc tả. Đây là chi tiết hay bị bỏ qua khi tính toán mạch.
Hai điều kiện đo kèm theo I_OH và I_OL đáng đọc kỹ: cả hai đo tại PAD_DRIVER = 3, tức
mức drive strength cao nhất, và V_OH khi đó chỉ còn 2.64 V.
Con số "40 mA" được lưu truyền rộng rãi như giới hạn tuyệt đối cho một chân GPIO của ESP32. Điều đó không có cơ sở trong tài liệu: bảng Absolute Maximum Ratings của datasheet ESP32-C6 chỉ chứa điện áp chân nguồn và nhiệt độ lưu kho — không có bất kỳ dòng nào giới hạn dòng ra hay dòng vào của GPIO Nguồn datasheet ESP32-C6 Datasheet (Espressif) Mục Electrical Characteristics cho V_OH/drive strength, và mục strapping pin quyết định chân nào được dùng. Mở trong tab mới · Esc để đóng .
40 mA là giá trị điển hình đo được ở mức drive strength cao nhất, ghi trong bảng DC Characteristics — một phép đặc trưng hoá, không phải một cam kết an toàn. Espressif cũng không công bố giới hạn tổng cho toàn bộ GPIO.
Hệ quả thực hành không đổi: thiết kế nằm xa dưới con số đó. Nhưng lý do phải nói cho đúng — "vì datasheet cấm" là sai, "vì không có cam kết nào ở vùng đó" mới đúng.
Drive strength là một tham số cấu hình được
Mỗi chân có bốn mức drive strength chọn được, tương ứng khoảng 5, 10, 20 và 40 mA. Giá trị sau khi reset là 20 mA cho mọi chân, trừ GPIO12 và GPIO13 mặc định 40 mA Nguồn datasheet ESP32-C6 Datasheet (Espressif) Mục Electrical Characteristics cho V_OH/drive strength, và mục strapping pin quyết định chân nào được dùng. Đọc thêm tài liệu chip ESP32-C6 Technical Reference Manual Nơi tra khi HAL không đủ — thanh ghi, sơ đồ khối peripheral. Mở trong tab mới · Esc để đóng .
Trong esp-hal, đây là một trường của OutputConfig Nguồn tài liệu chính chủ esp-hal trên docs.rs API reference; mục esp_hal::gpio cho Output/Input/Level/Pull/OutputConfig. Mở trong tab mới · Esc để đóng . Enum có tên
DriveStrength, và các biến thể bắt đầu bằng dấu gạch dưới vì định danh Rust không
được mở đầu bằng chữ số: _5mA, _10mA, _20mA, _40mA.
LED không phải điện trở
Một điện trở tuân theo định luật Ohm: dòng tỉ lệ tuyến tính với áp. Diode phát quang thì không. Dưới điện áp ngưỡng nó gần như không dẫn; vượt ngưỡng rồi thì dòng tăng theo hàm mũ đối với áp đặt vào. Hệ quả là không thể đặt dòng qua LED bằng cách đặt điện áp — một sai lệch nhỏ về áp cho ra sai lệch lớn về dòng, và điện áp ngưỡng thì thay đổi theo lô sản xuất lẫn theo nhiệt độ.
Cách xử lý tiêu chuẩn là mắc nối tiếp một phần tử có tuân theo định luật Ohm. Vì mắc
nối tiếp nên dòng qua hai phần tử là một; điện áp nguồn bị chia thành phần sụt trên LED
(gần như cố định, ký hiệu V_f) và phần còn lại rơi trên điện trở. Từ đó:
R = (V_nguồn − V_f) / IBa đại lượng vế phải có ba tư cách khác nhau, và đây là chỗ đáng phân biệt:
| Đại lượng | Tư cách | Ghi chú |
|---|---|---|
V_nguồn | Do mạch quyết định | 3.3 V với chân GPIO của C6 |
V_f | Do linh kiện quyết định | 1.8–2.1 V cho LED đỏ 5mm; xanh dương và trắng khoảng 3.0–3.2 V |
I | Do người thiết kế chọn | Đây là biến tự do duy nhất |
LED đỏ 5mm nhìn rõ từ 3 mA trở lên. Con số 20 mA thường thấy trên mạng là mức sáng tối đa của linh kiện, không phải mức cần dùng — và trùng hợp thay, nó cũng bằng đúng drive strength mặc định của chân, khiến hai khái niệm khác nhau bị nhầm thành một.
| R | Dòng ước tính | Nhận xét |
|---|---|---|
| 150 Ω | 8.7 mA | Sáng rõ |
| 220 Ω | 5.9 mA | Cân bằng |
| 330 Ω | 3.9 mA | Nhẹ nhất cho GPIO mà vẫn thấy rõ |
| 1 kΩ | 1.3 mA | Mờ nhưng nhìn được |
(Tính với V_f = 2.0 V. Giá trị thật phụ thuộc con LED cụ thể — đó chính là thứ Block A đo.)
Không có điện trở nối tiếp, dòng chỉ còn bị giới hạn bởi điện trở dẫn của tầng ra GPIO và điện trở nội rất nhỏ của LED. LED vẫn sáng, thậm chí sáng hơn, nên phép thử trông như thành công.
Nhưng chân GPIO đang làm việc ngoài vùng có cam kết, và LED suy giảm dần theo thời gian. Đây là dạng hỏng nguy hiểm nhất trong toàn bộ điện tử: hỏng mà biểu hiện giống đang chạy tốt. Không có phép đo nào phát hiện ra nó ở thời điểm mắc lỗi, chỉ có phép tính.
Block A — LED ngoài và bài toán giới hạn dòng
Khoảng 20 phút.
Cơ chế
Block này tồn tại để biến một phép tính trên giấy thành một con số đo được. Chuỗi
chọn dòng mong muốn → tính điện trở → lắp → đo lại dòng thật → đo lại V_f thật là chuỗi
sẽ lặp lại ở GĐ 3 với ampe kế mắc nối tiếp trên mạch khó hơn nhiều. Tập trên một mạch có
đúng ba linh kiện, nơi mọi con số đều dự đoán được, là cách rẻ nhất để làm quen với thao
tác đó.
Chọn chân — ràng buộc trước, sở thích sau
Không phải chân nào cũng dùng được. Bốn nhóm phải tránh, mỗi nhóm vì một lý do khác nhau Nguồn datasheet ESP32-C6 Datasheet (Espressif) Mục Electrical Characteristics cho V_OH/drive strength, và mục strapping pin quyết định chân nào được dùng. Mở trong tab mới · Esc để đóng :
| Chân | Vì sao tránh | Triệu chứng khi vi phạm |
|---|---|---|
| 4, 5, 8, 9, 15 | Strapping pin — mức lúc reset quyết định chip boot kiểu gì | Chip không boot, không phải LED không sáng |
| 12, 13 | USB-Serial-JTAG native (D− và D+) | Mất cổng USB native |
| 16, 17 | UART0 (TX và RX) | Mất đường log |
| 24–30 | Giao tiếp SPI với flash, không đưa ra header | Không truy cập được |
Nhóm an toàn: 2, 3, 10, 11, 18, 19, 20, 21, 22, 23.
Bảng Default Configuration of Strapping Pins ghi rõ: GPIO9 có weak pull-up khi reset; GPIO4, GPIO5, GPIO8 và GPIO15 thả nổi, không có điện trở nội nào Nguồn datasheet ESP32-C6 Datasheet (Espressif) Mục Electrical Characteristics cho V_OH/drive strength, và mục strapping pin quyết định chân nào được dùng. Mở trong tab mới · Esc để đóng . Với GPIO15, datasheet nói thêm rằng mức của nó phải do mạch ngoài quyết định và không được ở trạng thái trở kháng cao.
Chip đọc giá trị strapping trong khoảng 3 ms sau khi nguồn ổn định, chốt lại, rồi trả chân về làm GPIO thường. Nghĩa là một linh kiện mắc vào strapping pin chỉ gây hại trong 3 ms đầu tiên — nhưng 3 ms đó quyết định chip có boot hay không.
Tổ hợp GPIO8 = 0 cùng lúc với GPIO9 = 0 là không hợp lệ và datasheet yêu cầu tránh.
Việc cần làm
- Cắm board lên breadboard sao cho hai hàng chân nằm hai bên rãnh giữa.
- Chọn một chân trong nhóm an toàn. Ghi lại lý do loại từng nhóm kia — đây là phần sẽ được hỏi lại ở mục câu hỏi cuối phiên.
- Chọn dòng mong muốn, tính điện trở, chọn giá trị gần nhất có trong kit. Viết cả ba con số ra giấy trước khi lắp.
- Kiểm chiều LED bằng thang diode và kiểm thông mạch từng sợi dây trước khi cấp điện.
- Viết chương trình nhấp nháy LED bằng delay chặn, chu kỳ khoảng 500 ms. Cố ý dùng delay chặn — chưa dùng timer bất đồng bộ, vì Block ở phiên sau cần một bản "trước khi sửa" để so sánh.
- Mắc đồng hồ ở thang mA nối tiếp với LED, đọc dòng thật. So với con số đã tính.
- Đo điện áp hai đầu LED lúc đang sáng để biết
V_fthật của con LED đang cầm.
Về API: Output::new nhận ba tham số theo thứ tự (chân, mức khởi tạo, cấu hình), còn
OutputConfig mặc định là push-pull, drive strength _20mA, không kéo Nguồn tài liệu chính chủ esp-hal trên docs.rs API reference; mục esp_hal::gpio cho Output/Input/Level/Pull/OutputConfig. Mở trong tab mới · Esc để đóng .
Cấu hình được xây bằng chuỗi phương thức with_…. Phần logic nhấp nháy thì tự viết.
esp_hal::delay::Delay nằm sau feature unstable của esp-hal, và từ bản 1.0.0-beta.0 feature này không còn bật mặc định Nguồn source · ví dụ esp-hal — MIGRATING-0.23.md Bản ghi đổi API sang struct config và việc feature unstable thôi bật mặc định — lý do blog cũ không compile. Mở trong tab mới · Esc để đóng . Không bật thì lỗi hiện ra ở dạng "không tìm thấy module", dễ bị hiểu nhầm thành sai tên crate hoặc sai version.
Điều đáng biết rộng hơn: Input, Output và các struct cấu hình của chúng là API ổn định, nhưng delay, timer và toàn bộ đường ngắt GPIO thì không. Gần như mọi bài thực hành đều cần bật unstable Nguồn tài liệu chính chủ esp-hal trên docs.rs API reference; mục esp_hal::gpio cho Output/Input/Level/Pull/OutputConfig. Mở trong tab mới · Esc để đóng .
Nghiệm thu Block A
- LED nhấp nháy đúng chu kỳ đặt.
- Dòng đo được nằm trong khoảng ±20% so với con số đã tính trước.
V_fđo được đã ghi vào sổ, kèm màu LED.- Ghi được lý do loại từng nhóm chân, không chỉ ghi chân đã chọn.
Hiện lệnh đầy đủ · Block A — cấu hình dự án
# esp-hal khuyến nghị ghim bằng dấu ngã khi dùng unstable,
# vì phần unstable có thể thay đổi phá vỡ trong bản minor.
[dependencies]
esp-hal = { version = "~1.1", features = ["esp32c6", "unstable"] }$ cargo run --release # nạp rồi mở monitor luôn
$ cargo build --release # chỉ build, không nạp02. Mức logic, chân thả nổi, và điện trở kéo
Block A xử lý chân ở chế độ ra. Block B chuyển sang chế độ vào, và ở chế độ vào thì câu hỏi đổi hẳn: chân không tạo ra điện áp nữa mà phân loại điện áp bên ngoài thành 0 hoặc 1.
Phép phân loại đó có hai ngưỡng, và giữa chúng là một vùng không có cam kết nào Nguồn datasheet ESP32-C6 Datasheet (Espressif) Mục Electrical Characteristics cho V_OH/drive strength, và mục strapping pin quyết định chân nào được dùng. Mở trong tab mới · Esc để đóng :
| Tham số | Đặc tả | Quy ra ở VDD = 3.3 V |
|---|---|---|
| V_IL, tối đa | ≤ 0.25 × VDD | ≤ 0.825 V — dưới mức này chắc chắn đọc ra 0 |
| V_IH, tối thiểu | ≥ 0.75 × VDD | ≥ 2.475 V — trên mức này chắc chắn đọc ra 1 |
| Khoảng giữa | — | 1.65 V, đúng một nửa điện áp nguồn |
Một dải bất định rộng bằng nửa nguồn là con số lớn bất thường, và nó sẽ quay lại ở mục 03 khi bàn về mạch lọc RC.
Đặc tả chỉ cam kết hai vùng ngoài cùng. Điện áp nằm trong dải giữa cho kết quả không xác định — và với ESP32-C6 dải đó chiếm đúng một nửa điện áp nguồn.
Vì sao chân thả nổi đọc ra giá trị thay đổi
Cách giải thích thường gặp là "dòng rò làm điện áp trôi". Số liệu bác bỏ cách giải thích đó: dòng rò đầu vào của ESP32-C6 tối đa 50 nA Nguồn datasheet ESP32-C6 Datasheet (Espressif) Mục Electrical Characteristics cho V_OH/drive strength, và mục strapping pin quyết định chân nào được dùng. Mở trong tab mới · Esc để đóng . Qua một điện trở kéo 45 kΩ, 50 nA chỉ tạo ra sụt áp 2.25 µV — nhỏ hơn dải bất định khoảng sáu bậc độ lớn. Dòng rò không giải thích được gì cả.
Cơ chế thật là ghép điện dung. Chân đầu vào có điện dung khoảng 2 pF, cộng thêm điện dung của đoạn dây nối vào nó. Không có đường dẫn điện trở nào về một mức xác định, điện tích trên tụ đó chỉ bị chi phối bởi trường điện xung quanh: đường dây điện 50 Hz, bàn tay người đến gần, chính tín hiệu đang chuyển mức ở dây bên cạnh. Chân thả nổi không phải một đầu vào nhiễu — nó là một tụ điện nhỏ đang làm ăng-ten, và giá trị đọc ra là điện tích mà nó tình cờ đang giữ.
Điện trở kéo giải quyết chuyện đó bằng cách cấp một đường dẫn điện trở về một mức xác định. ESP32-C6 có điện trở kéo nội khoảng 45 kΩ, và datasheet chỉ cho giá trị điển hình, không cho min hay max Nguồn datasheet ESP32-C6 Datasheet (Espressif) Mục Electrical Characteristics cho V_OH/drive strength, và mục strapping pin quyết định chân nào được dùng. Mở trong tab mới · Esc để đóng — nên không được thiết kế dựa trên biên của nó.
| Pull-up nội (45 kΩ) | Pull-up ngoài (10 kΩ) | |
|---|---|---|
| Dòng khi nút đóng | ~73 µA | ~330 µA |
| Hằng số thời gian với 20 pF dây | ~0.9 µs | ~0.2 µs |
| Cần linh kiện | Không | Một điện trở |
| Dung sai được công bố | Không | Có, in trên thân trở |
Từ bảng trên rút ra tiêu chí chọn: pull-up nội đủ dùng khi dây ngắn và môi trường sạch; pull-up ngoài cần thiết khi dây dài, khi có nguồn nhiễu gần, hoặc khi cần biết chắc giá trị điện trở. Câu hỏi này quay lại ở GĐ 2 với bus I²C, nơi giá trị điện trở kéo ảnh hưởng trực tiếp tới tốc độ bus tối đa.
Trong esp-hal, điện trở kéo là một trường của InputConfig, mặc định là Pull::None — tức
thả nổi. Đây là lựa chọn thiết kế đáng chú ý: API bắt khai tường minh thay vì đoán ý
người dùng, nên quên khai không cho ra lỗi biên dịch mà cho ra một chân ăng-ten Nguồn tài liệu chính chủ esp-hal trên docs.rs API reference; mục esp_hal::gpio cho Output/Input/Level/Pull/OutputConfig. Mở trong tab mới · Esc để đóng .
Block B — Nút nhấn và phép đếm không khớp
Khoảng 25 phút.
Cơ chế
Block này tạo ra hiện tượng mà Block C sẽ đo. Mục tiêu không phải làm cho phép đếm đúng — mục tiêu là làm cho nó sai một cách quan sát được, rồi ghi lại mức độ sai.
Một điểm phân biệt quan trọng trước khi viết mã: đếm số lần trạng thái chuyển từ nhả sang bấm khác hẳn đếm số lần đọc thấy đang bấm. Cái sau chỉ đo tốc độ vòng lặp. Chỉ cái trước mới bộc lộ được nảy phím.
Nút tactile 4 chân có hai cặp nối cứng bên trong
Nút tactile 6×6 mm bốn chân thực chất là một công tắc hai chân, mỗi cực được đưa ra hai chân đối diện để dễ giữ cơ khí trên bo mạch. Trong bốn chân có sáu cặp, trong đó hai cặp luôn thông nhau bất kể có bấm hay không.
Chọn nhầm một trong hai cặp đó thì "nút" trở thành một đoạn dây nối cứng: mạch đúng về điện, chương trình đúng về logic, mà hành vi vẫn sai, và không có thông báo lỗi nào. Chế độ đo thông mạch có còi phân biệt được trong khoảng 30 giây: cặp đúng im khi thả và kêu khi bấm.
Việc cần làm
- Xác định cặp chân đúng của nút bằng đo thông mạch, trước khi cắm lên breadboard. Vẽ lại sơ đồ chân đã xác định.
- Đấu nút với một điện trở kéo. Ghi lại đã chọn kéo lên hay kéo xuống, nội hay ngoài, và lý do.
- Trong cùng vòng lặp đang nhấp nháy LED, đọc trạng thái nút bằng polling và đếm số lần chuyển mức.
- Bấm đúng 10 lần, đọc số đếm. Lặp lại phép thử ít nhất năm lượt.
- Ghi lại dải giá trị: thấp nhất và cao nhất qua năm lượt.
Bước 5 là bước hay bị rút gọn thành "bấm một lần rồi ghi một con số", và làm vậy là bỏ mất kết quả quan trọng nhất của Block B: con số không những sai, mà còn sai khác nhau mỗi lượt. Tính không lặp lại đó chính là dấu hiệu của một hiện tượng vật lý, phân biệt nó với một lỗi lập trình — lỗi lập trình thì sai giống nhau mỗi lần.
Nghiệm thu Block B
- Sơ đồ chân của nút đã vẽ, xác định bằng phép đo chứ không bằng suy đoán.
- Bấm 10 lần cho ra số đếm lớn hơn 10.
- Có bảng năm lượt thử với giá trị nhỏ nhất và lớn nhất.
- Ghi được lựa chọn điện trở kéo kèm lý do.
03. Nảy phím: cơ chế cơ học và thang thời gian
Vì sao tiếp điểm kim loại nảy
Nhà sản xuất relay định nghĩa hiện tượng này là "hiện tượng đóng cắt gián đoạn của tiếp điểm, sinh ra do va chạm giữa các phần kim loại chuyển động", và định nghĩa đó nêu rõ nó xảy ra cả khi đóng lẫn khi mở Nguồn tài liệu chính chủ Panasonic — Relay Terminology Định nghĩa hình thức của contact bounce từ phía nhà sản xuất, nêu rõ nó xảy ra ở cả hai chiều. Mở trong tab mới · Esc để đóng .
Cơ chế rút gọn thành bốn bước:
- Lá tiếp điểm có khối lượng, nên mang động năng khi lao vào tiếp điểm tĩnh.
- Vật liệu và cơ cấu có độ đàn hồi, nên va chạm không hoàn toàn phi đàn hồi — một phần động năng được trả lại.
- Lá nảy ra, mất tiếp xúc, rồi rơi lại: chu kỳ đóng-mở lặp lại nhiều lần.
- Biên độ nảy giảm dần do biến dạng dẻo và ma sát, cho tới khi ổn định.
Đó là lý do waveform nảy phím có dạng một chuỗi xung thưa dần rồi tắt, chứ không phải nhiễu ngẫu nhiên phân bố đều. Khi nhả, cơ cấu khác hẳn — lực đẩy đến từ lò xo hồi vị chứ không từ ngón tay — nên không có lý do vật lý nào để hai chiều giống nhau.
Nhiều tài liệu quy nảy phím ở mạch logic cho tia lửa điện giữa hai tiếp điểm. Ở 3.3 V điều đó không thể xảy ra. Bảng điện áp hồ quang tối thiểu theo vật liệu tiếp điểm cho thấy ngưỡng thấp nhất là 11 V với hợp kim palladium-bạc, và 12 V với bạc nguyên chất Nguồn tài liệu chính chủ Omron — Further Information of General Purpose Relays Bảng điện áp hồ quang tối thiểu theo vật liệu tiếp điểm, softening voltage, và màng oxide/sulfide. Mở trong tab mới · Esc để đóng .
Mạch nút bấm 3.3 V nằm dưới ngưỡng thấp nhất một khoảng lớn. Nảy phím ở mạch logic là hiện tượng thuần cơ học.
Thang thời gian: số liệu khảo sát so với số liệu datasheet
Nguồn định lượng đầy đủ nhất về nảy phím là khảo sát của Jack Ganssle: 18 loại công tắc khác nhau, mỗi loại bấm 300 lần, đo bằng mixed-signal oscilloscope, ghi cả giá trị nhỏ nhất lẫn lớn nhất cho cả chiều đóng và chiều mở Nguồn đo đạc · app note Jack Ganssle — A Guide to Debouncing (phần 1) Khảo sát 18 công tắc, mỗi con bấm 300 lần, đo bằng MSO — nguồn của mọi con số thống kê về nảy phím. Mở trong tab mới · Esc để đóng .
| Đại lượng | Giá trị |
|---|---|
| Nảy ngắn nhất quan sát được | dưới 100 ns — "khá phổ biến" |
| Trung bình của 16 công tắc, sau khi loại hai ngoại lệ | 1 557 µs |
| Lớn nhất trong nhóm 16 đó | 6 200 µs |
| Ngoại lệ thứ nhất | 157 ms, xảy ra lúc nhả, không phải lúc bấm |
| Ngoại lệ thứ hai | 11.3 ms |
| Khuyến nghị của tác giả | "Phần lớn dưới 10 ms. Dùng 20 ms cho chắc." |
Dải quan sát trải hơn sáu bậc độ lớn, từ dưới 100 ns tới 157 ms. Ba phát hiện đi kèm đáng ghi nhớ hơn cả con số trung bình:
- Bảy trong mười tám công tắc nảy khi đóng lâu hơn hẳn khi mở — nhưng con tệ nhất lại nảy khi mở. Không có quy luật chung, nên phải xử lý cả hai cạnh.
- Hai con cùng model lệch nhau hai lần. Đo một con không suy ra được con còn lại.
- Cùng một công tắc biến thiên rất lớn giữa các lần bấm. Đây chính là điều Block B quan sát được, và là lý do phải thử năm lượt chứ không một.
Đối chiếu với datasheet nhà sản xuất thì thấy một khoảng cách lớn. Datasheet công tắc tactile 6×6 mm của Omron ghi bounce time 5 ms max Nguồn datasheet Omron B3F — Tactile Switch datasheet (A070-E1-08) Bảng Ratings/Characteristics: bounce time, dòng danh định, và sự khác biệt của bản mạ vàng B3F-G. Mở trong tab mới · Esc để đóng , và một hãng độc lập khác cũng ghi ≤ 5 ms Nguồn datasheet C&K PTS645V — Tactile Switch datasheet Nhà sản xuất thứ hai để đối chiếu con số bounce time — hai hãng độc lập cùng ghi 5 ms. Mở trong tab mới · Esc để đóng — hai nguồn hội tụ.
Hai con số 5 ms và 157 ms không mâu thuẫn, vì chúng đo hai thứ khác nhau: datasheet là cam kết cho linh kiện mới, trong điều kiện thử của hãng; khảo sát đo các công tắc có sẵn trên bàn, gồm cả loại cũ và loại không rõ nguồn gốc. Chọn hằng số debounce theo datasheet là chọn theo trường hợp tốt nhất — lý do khuyến nghị chung là 20 ms chứ không phải 5 ms.
Cận dưới đến từ vật lý: nhỏ hơn thời gian nảy thật thì lọt xung. Cận trên đến từ cảm nhận người dùng — cùng khảo sát ghi nhận rằng độ trễ 50 ms vẫn cho cảm giác tức thì, còn 100 ms thì nhận ra rõ Nguồn đo đạc · app note Jack Ganssle — A Guide to Debouncing (phần 1) Khảo sát 18 công tắc, mỗi con bấm 300 lần, đo bằng MSO — nguồn của mọi con số thống kê về nảy phím. Mở trong tab mới · Esc để đóng .
Vậy cửa sổ hợp lý là 20–50 ms. Đây là một trong số ít bài toán nhúng mà ràng buộc trên đến từ tâm lý học chứ không từ điện tử.
Một chế độ hỏng khác, dễ nhầm với nảy phím
Với pull-up 10 kΩ ở 3.3 V, dòng qua tiếp điểm lúc đóng chỉ khoảng 330 µA. Đó là điều kiện dry circuit — dòng quá nhỏ để phá vỡ màng bẩn trên bề mặt tiếp điểm.
Tiếp điểm bạc bị sulfide hoá theo thời gian, và màng sulfide có ảnh hưởng lớn tới khả năng dẫn Nguồn tài liệu chính chủ Omron — Further Information of General Purpose Relays Bảng điện áp hồ quang tối thiểu theo vật liệu tiếp điểm, softening voltage, và màng oxide/sulfide. Mở trong tab mới · Esc để đóng . Bằng chứng gián tiếp nằm ngay trong datasheet: bản thường của công tắc Omron được đánh giá cho dòng từ 1 mA trở lên, còn bản mạ vàng đánh giá xuống tới 100 µA Nguồn datasheet Omron B3F — Tactile Switch datasheet (A070-E1-08) Bảng Ratings/Characteristics: bounce time, dòng danh định, và sự khác biệt của bản mạ vàng B3F-G. Mở trong tab mới · Esc để đóng — vàng không tạo màng.
Triệu chứng của chế độ hỏng này là nút thỉnh thoảng không ăn, không phải nút đếm thừa. Và debounce bằng phần mềm không cứu được, vì vấn đề là không có tiếp xúc, không phải tiếp xúc quá nhiều lần. Phân biệt hai chế độ này bằng phép đo: nảy phím thì waveform có chuỗi xung; tiếp điểm bẩn thì waveform không có cạnh nào cả.
Ba giải pháp và giới hạn của từng cái
Mạch lọc RC. Nạp và xả tụ làm mềm sườn tín hiệu. Nhưng đưa thẳng đầu ra RC vào một cổng logic thường là tạo ra một vấn đề mới, và vấn đề mới nghiêm trọng hơn.
Điện áp trên tụ biến thiên theo hàm mũ, nên nó nằm rất lâu trong dải bất định đã nói ở mục 02 — với ESP32-C6 là dải rộng 1.65 V.
Tài liệu ứng dụng của Texas Instruments mô tả chuyện gì xảy ra bên trong một cổng CMOS trong tình huống đó: cả transistor kênh N lẫn kênh P cùng dẫn, tạo đường dòng trực tiếp từ nguồn xuống đất. Dòng này có thể đạt 150 đến 200 mA, tức khoảng 1 W tiêu tán trong một con cổng logic tín hiệu nhỏ Nguồn đo đạc · app note TI SCBA004E — Implications of Slow or Floating CMOS Inputs Dòng crossbar 150–200 mA khi đầu vào nằm lâu trong dải ngưỡng, và bảng giới hạn độ dốc sườn theo họ logic. Mở trong tab mới · Esc để đóng .
Tệ hơn, dòng lớn đó chạy qua trở kháng đường đất làm nảy mức đất cục bộ, đẩy điện áp vào ngược qua ngưỡng, và đầu ra bắt đầu dao động. Kết quả trớ trêu: mạch thêm vào để khử nảy lại tự sinh ra một chuỗi xung mới — lần này ở thang nanosecond.
Schmitt trigger. Đây là lời giải cho vấn đề trên: đầu vào có hai ngưỡng khác nhau, ngưỡng đi lên cao hơn ngưỡng đi xuống, nên nhiễu biên độ nhỏ hơn khoảng chênh không thể gây lật lặp Nguồn đo đạc · app note Jack Ganssle — A Guide to Debouncing (phần 2) Mạch RC, vì sao cần Schmitt trigger, và các thuật toán debounce phần mềm kèm mã tham khảo. Mở trong tab mới · Esc để đóng .
Số liệu thật của một Schmitt trigger 74HC14 cho thấy một bài học phụ về cách đọc datasheet. Ở VDD = 4.5 V, hai nhà sản xuất công bố như sau:
| Tham số | Nexperia | Texas Instruments |
|---|---|---|
| V_T+ điển hình | 2.38 V | 2.5 V |
| V_T− điển hình | 1.4 V | 1.6 V |
| Hysteresis điển hình | 0.98 V | 0.9 V |
| Hysteresis tối thiểu | 0.4 V | 0.4 V |
| Hysteresis tối đa | 1.4 V | 2.1 V |
Nguồn: datasheet của từng hãng Nguồn datasheet Nexperia 74HC14 / 74HCT14 datasheet (Rev. 10) Bảng DC characteristics: V_T+, V_T− và hysteresis V_H của một Schmitt trigger thật. datasheet TI SN74HC14 datasheet (SCLS085L) Cùng mã linh kiện, hãng khác — đối chiếu để thấy tham số typ lệch nhau tới đâu. Mở trong tab mới · Esc để đóng . Giá trị điển hình lệch nhau, giá trị tối đa lệch tới 0.7 V, và chỉ giá trị tối thiểu trùng khớp. Bài học: "74HC14" là một họ chức năng, không phải một linh kiện chuẩn hoá về tham số — thiết kế phải dựa vào cột min/max của đúng hãng đã mua, không bao giờ dựa vào cột điển hình.
Debounce bằng phần mềm. Đây là hướng của phiên sau, nên chỉ nêu ranh giới ở đây. Nguyên tắc nền quan trọng nhất, phát biểu bởi cùng tác giả khảo sát ở trên: không nối một công tắc chưa debounce vào đầu vào ngắt của CPU, kể cả khi đã qua Schmitt trigger Nguồn đo đạc · app note Jack Ganssle — A Guide to Debouncing (phần 2) Mạch RC, vì sao cần Schmitt trigger, và các thuật toán debounce phần mềm kèm mã tham khảo. Mở trong tab mới · Esc để đóng . Lý do: Schmitt trigger làm sườn dốc và loại dao động do sườn chậm, nhưng không loại được nảy cơ học — mỗi lần đóng-mở thật vẫn là một cạnh hợp lệ và vẫn sinh một ngắt.
Chip không hỗ trợ điều khiển hysteresis. File khai báo năng lực phần cứng của ESP-IDF cho ESP32-C6 không có cờ hysteresis, trong khi bản của ESP32-H2 thì có Nguồn source · ví dụ ESP-IDF soc_caps.h — ESP32-C6 File khai báo năng lực phần cứng; đối chiếu với bản esp32h2 để thấy chip nào có hysteresis điều khiển được. Mở trong tab mới · Esc để đóng . Datasheet cũng không công bố tham số V_T+ hay V_T− nào — chỉ có V_IH và V_IL Nguồn datasheet ESP32-C6 Datasheet (Espressif) Mục Electrical Characteristics cho V_OH/drive strength, và mục strapping pin quyết định chân nào được dùng. Mở trong tab mới · Esc để đóng . Việc bộ đệm đầu vào có sẵn một chút hysteresis cố định trong silicon hay không thì chưa xác minh được; cách kiểm thực nghiệm nằm ở phần Stretch.
Cái chip thật sự có là glitch filter phần cứng: một bộ lọc cố định loại xung ngắn hơn hai chu kỳ clock lấy mẫu, cộng thêm tám bộ lọc cấu hình được độ rộng Nguồn tài liệu chính chủ ESP-IDF — GPIO & RTC GPIO (ESP32-C6) Pin glitch filter (lọc xung ngắn hơn 2 chu kỳ clock) và 8 flex glitch filter cấu hình được. Mở trong tab mới · Esc để đóng . Đừng nhầm chúng với debounce — chúng làm việc ở thang nanosecond tới microsecond, còn nảy phím ở thang millisecond. Chênh nhau ba bậc độ lớn.
04. Lấy mẫu một sự kiện thang mili-giây
Chu kỳ lấy mẫu là hạt lượng tử của mọi thời điểm cạnh
Quy tắc thường được trích ở đây là Nyquist — lấy mẫu ít nhất gấp đôi tần số cao nhất. Quy tắc đó đúng cho bài toán tái tạo một tín hiệu bị giới hạn băng thông, nhưng đây không phải bài toán đang làm. Câu hỏi ở đây là cạnh xảy ra lúc nào, và câu trả lời bị lượng tử hoá theo chu kỳ lấy mẫu bất kể Nyquist.
Máy chỉ nhìn tín hiệu tại các mốc cách nhau Ts = 1/fs. Một cạnh xảy ra ở thời điểm thật
t chỉ được ghi nhận tại mẫu đầu tiên sau nó, nên sai số mỗi cạnh nằm trong khoảng từ 0
đến Ts. Khi đo một khoảng giữa hai cạnh, hai sai số trừ nhau:
sai số = ± 1 chu kỳ lấy mẫu = ± Ts
#
muốn đo khoảng D với sai số tương đối N phần trăm:
fs ≥ 100 / (D × N)Mọi khoảng đo được luôn là bội số nguyên của Ts — đó là lý do con trỏ đo của PulseView
hiển thị được cả số mẫu nằm giữa hai mốc, bên cạnh thời gian và tần số Nguồn tài liệu chính chủ PulseView manual Mục 4.2 nói về trần sample rate thực tế, mục 4.3 về trigger, mục 5.1 về cursor đo khoảng thời gian. Mở trong tab mới · Esc để đóng .
Áp vào một burst nảy phím khoảng 1 ms:
| Sai số mong muốn trên burst 1 ms | Ts cần | fs cần | Số mẫu trong burst |
|---|---|---|---|
| ±10 % | 100 µs | 10 kHz | 10 |
| ±1 % | 10 µs | 100 kHz | 100 |
| ±0.1 % | 1 µs | 1 MHz | 1 000 |
| ±0.01 % | 100 ns | 10 MHz | 10 000 |
Một burst nảy phím 1 ms không phải một khoảng 1 ms duy nhất. Nó là một chuỗi nhiều xung ngắn nằm trong cửa sổ 1 ms. Độ chính xác phải tính theo đặc trưng ngắn nhất cần phân giải, không theo tổng burst.
Ở 1 MHz, một xung nảy riêng lẻ rộng 50 µs được đo với sai số ±2 %; một xung rộng 10 µs thì sai số ±10 %; một xung rộng 1 µs thì sai số ±100 % — tức vô dụng, dù tổng burst vẫn được đo với sai số ±0.1 %.
Xung hẹp nhất bảo đảm bắt được
Vì lấy mẫu bất đồng bộ với tín hiệu, một xung rộng W chỉ được ghi nhận nếu có ít nhất một
mốc lấy mẫu rơi vào trong nó. Các mốc cách nhau đúng Ts, nên:
- W ≥ Ts — luôn có ít nhất một mốc rơi vào. Bảo đảm bắt được.
- W < Ts — tồn tại pha khiến không mốc nào rơi vào. Xác suất bắt được xấp xỉ tỉ số W trên Ts.
Ở 1 MHz, xung hẹp nhất được bảo đảm bắt là 1 µs. Xung 500 ns có khoảng một nửa cơ hội; xung 100 ns khoảng một phần mười. Định nghĩa chính thức của một glitch, theo góc nhìn máy đo, chính là tín hiệu đổi mức nhiều hơn một lần giữa hai mẫu liên tiếp Nguồn đo đạc · app note Tektronix — The Importance of Timing Accuracy in a Logic Analyzer Định nghĩa glitch theo góc nhìn máy đo: tín hiệu đổi mức nhiều hơn một lần giữa hai mẫu liên tiếp. Mở trong tab mới · Esc để đóng .
Cần tách hai mức yêu cầu khác nhau: phát hiện một xung có tồn tại chỉ cần một mẫu rơi
vào; đo được bề rộng của nó thì cần nhiều mẫu. Một xung chỉ bắt được đúng một mẫu vẫn
hiện lên màn hình, nhưng bề rộng hiển thị là giả tạo — nó phản ánh Ts, không phản ánh
xung thật. Đây là lý do các hướng dẫn của nhà sản xuất khuyến nghị lấy mẫu nhanh gấp bốn
lần trở lên Nguồn tài liệu chính chủ Saleae — What Sample Rate Is Required? Quy tắc thực dụng 4× cho tín hiệu số, và ghi nhận rằng lấy mẫu nhanh hơn cải thiện độ phân giải thời gian. Mở trong tab mới · Esc để đóng .
1 MHz là điểm cân bằng cho bài này: sai số ±0.1 % trên tổng burst, ±2 % trên xung 50 µs, và chỉ chiếm 1 MB/s băng thông USB.
Ba đặc điểm của logic analyzer clone quyết định cách thao tác
Loại analyzer 8 kênh giá rẻ dùng chip Cypress FX2 có ba tính chất mà người mới thường không biết, và cả ba đều ảnh hưởng trực tiếp tới thao tác trong PulseView.
| Đặc điểm | Hệ quả thực hành |
|---|---|
| Không có bộ nhớ trên máy — stream thẳng qua USB | Độ dài capture bị giới hạn bởi băng thông USB, không bởi dung lượng bộ nhớ. Trần 24 MHz chỉ đạt được "trong điều kiện hoàn hảo" Nguồn tài liệu chính chủ PulseView manual Mục 4.2 nói về trần sample rate thực tế, mục 4.3 về trigger, mục 5.1 về cursor đo khoảng thời gian. Mở trong tab mới · Esc để đóng |
| Không có trigger phần cứng — trigger được so khớp bằng phần mềm trên máy tính Nguồn source · ví dụ libsigrok — driver fx2lafw Đọc protocol.c để thấy trigger được so khớp bằng phần mềm trên host và mỗi sample là đúng một byte. Mở trong tab mới · Esc để đóng | Thiết bị stream liên tục ngay từ lúc bấm Run. Không thể "nạp trigger rồi chờ vài giờ" |
| Tắt bớt kênh KHÔNG làm tăng sample rate | Mỗi mẫu luôn là một byte trọn vẹn cho tám kênh. Khác hẳn máy Saleae thật, nơi đánh đổi kênh lấy tốc độ là có thật Nguồn tài liệu chính chủ Saleae — What Sample Rate Is Required? Quy tắc thực dụng 4× cho tín hiệu số, và ghi nhận rằng lấy mẫu nhanh hơn cải thiện độ phân giải thời gian. Mở trong tab mới · Esc để đóng |
Vì sao GND của máy đo phải nối GND của mạch
Câu trả lời không phải "cho chắc" mà là một hệ quả của định nghĩa điện áp.
Điện áp là hiệu điện thế giữa hai điểm; "điện áp tại một điểm" không có nghĩa nếu không nói so với đâu. Datasheet của con buffer đầu vào dùng trong các máy clone ghi thẳng điều đó: "mọi điện áp được quy chiếu về GND", và ngưỡng logic của nó là phân số của điện áp nguồn Nguồn datasheet NXP 74HC245 / 74HCT245 datasheet Con buffer đầu vào của nhiều logic analyzer clone; datasheet ghi rõ mọi điện áp quy chiếu về chân GND của nó. Mở trong tab mới · Esc để đóng .
Nghĩa là khi máy quyết định một kênh đang là 0 hay 1, nó thực sự đang tính hiệu giữa điện thế chân tín hiệu và điện thế chân GND của chính nó, rồi so với ngưỡng.
- Có dây GND chung: điện thế GND của máy bị ép bằng GND của mạch qua một đường trở kháng thấp. Phép trừ cho ra đúng điện áp mạch tạo ra.
- Không có dây GND: không tồn tại đường dẫn một chiều nào giữa hai hệ. Số hạng thứ hai của phép trừ trôi tự do, bị chi phối bởi ghép tụ ký sinh. Hiệu đưa vào bộ so sánh là vô định.
Điều làm chế độ hỏng này nguy hiểm: tín hiệu vẫn trông như chạy, vì ghép tụ vẫn truyền được thành phần biến thiên nhanh. Waveform bắt được vẫn có dạng xung, vẫn có cạnh lên cạnh xuống, vẫn đủ hợp lý để tin. Chỉ mức một chiều là trôi, khiến ngưỡng bị vượt sai thời điểm. Với bài đo nảy phím, hậu quả trực tiếp là đếm sai số lần nảy — tức sai đúng vào con số là mục tiêu của cả phiên.
Nhà sản xuất chỉ yêu cầu tối thiểu một dây GND; nối GND cho từng kênh chỉ cần khi làm việc với tín hiệu tốc độ cao hoặc có nguồn xuyên âm Nguồn tài liệu chính chủ Saleae — Are the Ground Pins Required for Each Input Used? Tối thiểu một dây GND là bắt buộc; nối GND cho từng kênh chỉ cần khi lo signal integrity. Mở trong tab mới · Esc để đóng . Ở thang mili-giây, một dây là đủ. Cắm dây GND trước các dây tín hiệu và rút sau cùng.
Block C — Đo nảy phím trên logic analyzer
Khoảng 35 phút. Đây là khối mang mục tiêu thật của phiên.
Cơ chế
Cho tới hết Block B, sự tồn tại của nảy phím mới chỉ được suy ra từ chỗ con số không khớp. Suy ra và nhìn thấy là hai mức hiểu khác nhau, và khoảng cách giữa chúng lớn hơn vẻ ngoài: suy ra cho biết có gì đó sai, nhìn thấy cho biết sai bao nhiêu và theo hình dạng nào. Chỉ mức thứ hai mới cho ra được một hằng số thiết kế.
Kỹ năng dựng ở đây — cắm dây, chọn sample rate có lý do, đặt trigger, đọc con trỏ đo — là kỹ năng sẽ được dùng lại ở GĐ 2 khi bus I²C không trả về gì. Hôm nay tập trên một tín hiệu đơn giản, chậm, và đã biết trước kết quả nên sai là nhận ra ngay.
Mỗi lần lá tiếp điểm bật ra rồi chạm lại là một lần tín hiệu băng qua toàn bộ dải bất định. Chương trình polling đếm được bao nhiêu lần trong số đó là chuyện của tốc độ vòng lặp, chứ không phải của số lần nảy thật.
Việc cần làm
- Cắm logic analyzer, mở PulseView, xác nhận thiết bị được nhận diện. Nếu không thấy: đây là vấn đề quyền truy cập USB, cùng họ với vấn đề cổng serial ở P1 — xem spoiler bên dưới.
- Nối GND của analyzer với GND của board trước tiên, rồi mới kẹp kênh tín hiệu.
- Kẹp một kênh vào chân nút.
- Đặt sample rate. Tự tính trước rồi mới chọn: muốn phân giải tới xung hẹp cỡ nào thì cần Ts bao nhiêu? Ghi lại con số đã chọn kèm lý do.
- Đặt trigger ở cạnh phù hợp với hướng kéo đã chọn ở Block B, bấm nút, bắt lấy.
- Phóng to và đo bằng con trỏ. Phím 1 và 2 gắn từng mốc con trỏ vào chuột Nguồn tài liệu chính chủ PulseView manual Mục 4.2 nói về trần sample rate thực tế, mục 4.3 về trigger, mục 5.1 về cursor đo khoảng thời gian. Mở trong tab mới · Esc để đóng .
Ba con số phải ghi vào sổ
- Thời gian nảy tính từ cạnh đầu tới lúc tín hiệu ổn định, theo mili-giây.
- Số lần chuyển mức trong khoảng đó.
- Lúc nhả nút có nảy không, và nếu có thì khác lúc bấm thế nào.
Con số thứ nhất quyết định hằng số debounce ở phiên sau. Nó phải là con số đo được từ chính cái nút đang cầm — dữ liệu khảo sát ở mục 03 cho thấy hai con cùng model lệch nhau hai lần, nên một con số lấy từ internet không nói gì về linh kiện cụ thể trên bàn.
Nghiệm thu Block C
- Ảnh chụp màn hình PulseView có waveform nảy phím, đã phóng tới mức nhìn rõ từng lần chuyển mức.
- Ba con số ở trên nằm trong sổ.
- Sample rate đã chọn được ghi kèm lý do chọn, không chỉ ghi giá trị.
- Đối chiếu: số lần chuyển mức đo được so với số đếm thừa quan sát ở Block B có cùng bậc độ lớn không?
Hiện lệnh đầy đủ · Block C — cài PulseView và cấp quyền USB
sigrok phát hành ba file udev rules, mỗi file một vai trò: file 60 nhận diện thiết bị và đặt biến môi trường; file 61-plugdev cấp quyền theo group; file 61-uaccess cấp quyền theo phiên đăng nhập tại chỗ Nguồn source · ví dụ libsigrok — file udev rules Ba file: 60 nhận diện thiết bị, 61-plugdev cấp quyền theo group, 61-uaccess cấp theo phiên đăng nhập. Mở trong tab mới · Esc để đóng . Trên distro dùng systemd hiện đại, đường uaccess là đường mặc định và không cần thêm ai vào group nào.
$ sudo pacman -S pulseview sigrok-cli # Arch; distro khác đổi tên gói
#
# kiểm luật udev đã có chưa
$ ls /usr/lib/udev/rules.d/ | grep -i sigrok
$ ls /etc/udev/rules.d/ | grep -i sigrok
#
# nếu thiếu, tải ba file từ contrib/ của libsigrok vào /etc/udev/rules.d/
# rồi nạp lại và rút cắm lại thiết bị
$ sudo udevadm control --reload-rules
$ sudo udevadm trigger$ lsusb # clone Saleae thường là 0925:3881
$ sigrok-cli --scan # khong can sudo; neu can thi luat udev chua an
#
# bắt thử 1 triệu mẫu ở 1 MHz, ghi ra file rồi mở bằng PulseView
$ sigrok-cli --driver fx2lafw --config samplerate=1m --samples 1m -o bounce.srNếu đường plugdev là đường đang dùng thì thêm user vào group rồi đăng xuất đăng nhập lại: sudo usermod -aG plugdev "$USER". Triệu chứng khi chưa ăn giống hệt P1 — sigrok-cli --scan không thấy gì mà chạy với sudo thì thấy.
05. Bẫy đã biết, xếp theo nơi phát sinh
Bảng tra nhanh
| Triệu chứng | Kiểm cái này trước |
|---|---|
| LED không sáng lần nào | Thông mạch từng sợi dây, rồi chiều LED bằng thang diode, rồi rãnh giữa breadboard |
| LED sáng nhưng không nháy | Vòng lặp có chạy không — log có in đều không |
| Chip không boot, không có log gì cả | Chân đã chọn có phải strapping pin không |
| Số đếm chạy loạn cả khi không bấm | Điện trở kéo đã thực sự vào cấu hình chưa |
| Bấm nút mà không đếm gì | Cặp chân nút — đo thông mạch lại. Hoặc đang đếm mức thay vì đếm chuyển mức |
| PulseView không thấy thiết bị | Quyền truy cập USB, không phải cáp |
| Waveform trông hợp lý nhưng số liệu vô lý | GND đã nối chung chưa |
Không tìm thấy Delay hay TimerGroup | Feature unstable của esp-hal chưa bật |
Bẫy ở lớp linh kiện
LED nhiều màu hàn sẵn trên board thuộc loại địa chỉ hoá — nó nhận một chuỗi bit có định thời chặt chẽ trên một dây, mỗi bit phân biệt bằng độ dài xung, chứ không sáng theo mức điện áp Nguồn source · ví dụ wuxx/nanoESP32-C6 — schematic mã nguồn mở Board dùng trong lộ trình này: LED RGB nối GPIO nào, chân 3V3 lấy nguồn từ đâu, LDO là loại gì. Mở trong tab mới · Esc để đóng . Đặt chân lên mức cao sẽ không làm nó sáng.
Điều khiển nó cần peripheral RMT cộng một crate driver riêng. Và crate đó có một ràng buộc version cần kiểm trước khi thêm vào Nguồn source · ví dụ esp-rs/esp-hal-community — esp-hal-smartled Adapter RMT cho LED địa chỉ hoá; kiểm ràng buộc version esp-hal trong Cargo.toml trước khi thêm vào. Mở trong tab mới · Esc để đóng — bản hiện hành ghim esp-hal theo dấu ngã ở nhánh 1.0, nên không nhất thiết dùng chung được với bản esp-hal mới nhất.
Bẫy tự nhiên: thấy board có sẵn LED nên thử điều khiển cho đỡ phải đấu dây, không sáng, rồi mất nửa giờ tìm lỗi trong mã nguồn. Chân của LED đó còn là strapping pin — lý do thứ hai để không đụng vào trong phiên này.
Bẫy ở lớp breadboard
Rãnh giữa cắt đôi mỗi hàng lỗ. Hai lỗ cùng số nhưng khác bên rãnh không nối với nhau — board được cắm ngang rãnh chính là để tận dụng điều đó, mỗi chân có một dãy lỗ riêng.
Dây dupont đứt ngầm là lỗi không có triệu chứng riêng: vỏ còn nguyên, lõi đứt bên trong. Chỉ đo thông mạch mới phát hiện được.
Bẫy ở lớp phép đo
Ba điều đã nêu ở mục 04, gom lại để tra nhanh: không có bộ nhớ trên máy nên không thể nạp trigger rồi chờ lâu; trigger là phần mềm nên nó không giảm băng thông USB phải truyền; tắt kênh không làm tăng sample rate trên loại clone này.
Bẫy ở lớp thời gian
Block A được đặt 20 phút và trong thực tế nó có thể ăn nhiều hơn hẳn — đây là lần đầu tra datasheet để lấy một con số dùng thật, lần đầu mắc ampe kế nối tiếp, lần đầu sửa mạch trên breadboard. Cả ba là chi phí một lần, không lặp lại ở các phiên sau.
Nếu Block A tràn, quy tắc xử lý là: hoàn thành Block A cho tử tế, ghi ba dòng đóng phiên, và chuyển Block B với C sang phiên sau. Ba mục tiêu của phiên này độc lập với nhau về mặt nghiệm thu, nên đạt một phần vẫn là tiến bộ chỉ tay vào được.
Definition of Done
- LED ngoài nháy đúng chu kỳ đặt, dùng delay chặn.
- Dòng đo được khớp ±20% với con số tính trước;
V_fthật đã ghi. - Sơ đồ chân nút đã vẽ, xác định bằng đo thông mạch.
- Bảng năm lượt thử "bấm 10 lần", có giá trị nhỏ nhất và lớn nhất.
- Ảnh chụp waveform nảy phím từ PulseView, đã phóng đủ để đếm được từng lần chuyển mức.
- Ba con số của Block C nằm trong sổ.
- Ghi được: chân nào cho LED, chân nào cho nút, và vì sao chọn chúng.
- Sample rate đã chọn kèm lý do.
- Commit; ảnh chụp breadboard; ba dòng đóng phiên.
Câu hỏi kiểm tra cuối phiên
Trả lời vào sổ, không mở tài liệu hay mã nguồn.
Vì sao một chân input thả nổi đọc ra giá trị thay đổi? Giải thích bằng cơ chế, và nói rõ vì sao dòng rò không phải lời giải thích đúng.
Ý cần có
Chân input là một tụ điện nhỏ không có đường dẫn điện trở về mức xác định; điện tích trên nó do ghép điện dung với môi trường quyết định. Dòng rò tối đa 50 nA qua điện trở kéo 45 kΩ chỉ tạo sụt áp cỡ micro-vôn, nhỏ hơn dải bất định nhiều bậc độ lớn, nên không giải thích được hiện tượng. Điện trở kéo sửa bằng cách cấp đường dẫn điện trở về một mức xác định.Nảy phím kéo dài bao lâu trên cái nút vừa đo? Nếu chọn hằng số debounce nhỏ hơn con số đó thì hiện tượng gì xảy ra? Còn nếu chọn lớn hơn nhiều lần?
Ý cần có
Con số phải là số đo được của chính linh kiện đó. Nhỏ hơn thời gian nảy thì lọt xung, một lần bấm vẫn cho nhiều lần đếm. Lớn hơn nhiều thì mất sự kiện bấm nhanh và nút bắt đầu cho cảm giác trễ; ngưỡng cảm nhận nằm quanh 100 ms. Cửa sổ hợp lý 20–50 ms bị chặn dưới bởi vật lý và chặn trên bởi cảm nhận người dùng.Strapping pin là gì, và vì sao đấu một cái LED vào đó có thể làm chip không boot — trong khi cũng cái LED đó cắm vào một chân thường thì không sao?
Ý cần có
Chip đọc mức của một nhóm chân trong vài mili-giây đầu sau reset để quyết định chế độ boot, rồi chốt giá trị và trả chân về làm GPIO thường. Tải mắc vào chân đó kéo mức trong cửa sổ ngắn ấy, làm chip đọc ra tổ hợp sai. Chỉ có bốn trong năm chân đó thả nổi khi reset, nên chúng đặc biệt nhạy với tải ngoài. Chân thường không tham gia quyết định boot nên tải không gây hậu quả nào ngoài dòng.Máy đo lấy mẫu ở 1 MHz. Một xung nảy rộng 300 ns có được ghi lại không?
Ý cần có
Không bảo đảm. Chu kỳ lấy mẫu là 1 µs, lớn hơn bề rộng xung, nên tồn tại pha khiến không mốc lấy mẫu nào rơi vào trong xung; xác suất bắt được xấp xỉ 300 ns chia 1 µs, khoảng 30%. Xung hẹp nhất bảo đảm bắt được bằng đúng một chu kỳ lấy mẫu. Cần phân biệt phát hiện xung tồn tại với đo được bề rộng của nó — cái sau cần nhiều mẫu trong xung.Vì sao không nối GND thì waveform bắt được lại vô nghĩa, mà vẫn trông giống tín hiệu thật?
Ý cần có
Máy phân loại mức bằng hiệu giữa điện thế chân tín hiệu và điện thế chân GND của chính nó. Không có đường dẫn một chiều chung, số hạng thứ hai trôi tự do theo ghép tụ ký sinh nên hiệu đưa vào bộ so sánh vô định. Thành phần biến thiên nhanh vẫn truyền qua được bằng ghép tụ, nên waveform vẫn có cạnh và vẫn trông hợp lý — chỉ mức một chiều trôi, khiến ngưỡng bị vượt sai thời điểm và số lần nảy đếm ra sai.
Stretch
Không tính vào Definition of Done.
- Bắt waveform lúc nhả nút và so với lúc bấm. Dữ liệu khảo sát cho thấy hai chiều thường khác nhau, và con tệ nhất trong khảo sát lại nảy khi nhả.
- Kẹp thêm một kênh vào chân LED, bắt đồng thời cả hai. Đây là bản ghi "trước khi sửa" cho phiên chuyển sang bất đồng bộ — không có nó thì phiên đó không so sánh được gì.
- Kiểm giả thuyết "1 MHz là đủ". Bắt lại cùng một lần bấm ở 1 MHz rồi ở 8 MHz, dùng decoder đếm cạnh Nguồn source · ví dụ libsigrokdecode — decoder timing Tính thời gian giữa các cạnh; đặt format thành samples để nhìn thẳng vào hạt lượng tử hoá. Mở trong tab mới · Esc để đóng để so số cạnh. Không đổi là bằng chứng thực nghiệm cho thấy 1 MHz đã đủ với cái nút này.
- Đo xem chân input có hysteresis hay không. Đây là câu chưa xác minh được ở mục 03. Cấp vào chân một sườn lên rất chậm, cho chương trình phản chiếu mức đọc được ra một chân khác, rồi so điện áp vào tại thời điểm lật lên với thời điểm lật xuống. Bằng nhau nghĩa là không có hysteresis; lệch một khoảng lặp lại được chính là giá trị hysteresis.
- Đổi nút sang chân khác trong nhóm an toàn, xem con số nảy có đổi không. Không đổi thì nó là đặc tính của nút, không phải của chân.
Nguồn và đọc thêm
Đọc trước hoặc trong phiên
- datasheetESP32-C6 Datasheet (Espressif)
Mục Electrical Characteristics cho V_OH/drive strength, và mục strapping pin quyết định chân nào được dùng.
- source · ví dụesp-hal — MIGRATING-0.23.md
Bản ghi đổi API sang struct config và việc feature unstable thôi bật mặc định — lý do blog cũ không compile.
- source · ví dụwuxx/nanoESP32-C6 — schematic mã nguồn mở
Board dùng trong lộ trình này: LED RGB nối GPIO nào, chân 3V3 lấy nguồn từ đâu, LDO là loại gì.
- đo đạc · app noteJack Ganssle — A Guide to Debouncing (phần 1)
Khảo sát 18 công tắc, mỗi con bấm 300 lần, đo bằng MSO — nguồn của mọi con số thống kê về nảy phím.
- đo đạc · app noteTI SCBA004E — Implications of Slow or Floating CMOS Inputs
Dòng crossbar 150–200 mA khi đầu vào nằm lâu trong dải ngưỡng, và bảng giới hạn độ dốc sườn theo họ logic.
- tài liệu chính chủPulseView manual
Mục 4.2 nói về trần sample rate thực tế, mục 4.3 về trigger, mục 5.1 về cursor đo khoảng thời gian.
- source · ví dụlibsigrok — file udev rules
Ba file: 60 nhận diện thiết bị, 61-plugdev cấp quyền theo group, 61-uaccess cấp theo phiên đăng nhập.
- tài liệu chính chủSaleae — Are the Ground Pins Required for Each Input Used?
Tối thiểu một dây GND là bắt buộc; nối GND cho từng kênh chỉ cần khi lo signal integrity.
Tra khi cần, không đọc tuyến tính
- tài liệu chính chủesp-hal trên docs.rs
API reference; mục esp_hal::gpio cho Output/Input/Level/Pull/OutputConfig.
- datasheetOmron B3F — Tactile Switch datasheet (A070-E1-08)
Bảng Ratings/Characteristics: bounce time, dòng danh định, và sự khác biệt của bản mạ vàng B3F-G.
- datasheetC&K PTS645V — Tactile Switch datasheet
Nhà sản xuất thứ hai để đối chiếu con số bounce time — hai hãng độc lập cùng ghi 5 ms.
- tài liệu chính chủOmron — Further Information of General Purpose Relays
Bảng điện áp hồ quang tối thiểu theo vật liệu tiếp điểm, softening voltage, và màng oxide/sulfide.
- tài liệu chính chủPanasonic — Relay Terminology
Định nghĩa hình thức của contact bounce từ phía nhà sản xuất, nêu rõ nó xảy ra ở cả hai chiều.
- datasheetNexperia 74HC14 / 74HCT14 datasheet (Rev. 10)
Bảng DC characteristics: V_T+, V_T− và hysteresis V_H của một Schmitt trigger thật.
- datasheetTI SN74HC14 datasheet (SCLS085L)
Cùng mã linh kiện, hãng khác — đối chiếu để thấy tham số typ lệch nhau tới đâu.
- tài liệu chính chủESP-IDF — GPIO & RTC GPIO (ESP32-C6)
Pin glitch filter (lọc xung ngắn hơn 2 chu kỳ clock) và 8 flex glitch filter cấu hình được.
- source · ví dụESP-IDF soc_caps.h — ESP32-C6
File khai báo năng lực phần cứng; đối chiếu với bản esp32h2 để thấy chip nào có hysteresis điều khiển được.
- source · ví dụlibsigrok — driver fx2lafw
Đọc protocol.c để thấy trigger được so khớp bằng phần mềm trên host và mỗi sample là đúng một byte.
- source · ví dụlibsigrokdecode — decoder timing
Tính thời gian giữa các cạnh; đặt format thành samples để nhìn thẳng vào hạt lượng tử hoá.
- đo đạc · app noteTektronix — The Importance of Timing Accuracy in a Logic Analyzer
Định nghĩa glitch theo góc nhìn máy đo: tín hiệu đổi mức nhiều hơn một lần giữa hai mẫu liên tiếp.
- tài liệu chính chủSaleae — What Sample Rate Is Required?
Quy tắc thực dụng 4× cho tín hiệu số, và ghi nhận rằng lấy mẫu nhanh hơn cải thiện độ phân giải thời gian.
- datasheetNXP 74HC245 / 74HCT245 datasheet
Con buffer đầu vào của nhiều logic analyzer clone; datasheet ghi rõ mọi điện áp quy chiếu về chân GND của nó.
- tài liệu chipESP32-C6 Technical Reference Manual
Nơi tra khi HAL không đủ — thanh ghi, sơ đồ khối peripheral.
Để dành cho giai đoạn sau
- đo đạc · app noteJack Ganssle — A Guide to Debouncing (phần 2)
Mạch RC, vì sao cần Schmitt trigger, và các thuật toán debounce phần mềm kèm mã tham khảo.
- tài liệu chính chủCompuPhase — Debouncing switches with vertical counters
Thuật toán bit-parallel debounce nhiều nút cùng lúc trong bốn dòng, không vòng lặp.
- đo đạc · app noteTektronix — Fundamentals of Floating Measurements
Mục Ground Loops: vòng dây thành cuộn thứ cấp bị ngắn mạch, sinh chênh lệch tới hàng trăm mV.
- tài liệu chính chủesp-rtos
Thay thế esp-hal-embassy đã ngừng phát triển; trên RISC-V cần truyền thêm một SoftwareInterrupt.
- source · ví dụesp-rs/esp-hal-community — esp-hal-smartled
Adapter RMT cho LED địa chỉ hoá; kiểm ràng buộc version esp-hal trong Cargo.toml trước khi thêm vào.
Ba mẩu đáng nhớ
Con số 20 mA có hai nguồn gốc không liên quan gì nhau
Drive strength mặc định của một chân ESP32-C6 là 20 mA. Mức sáng tối đa thường ghi cho LED 5mm cũng là 20 mA. Hai con số này trùng nhau hoàn toàn ngẫu nhiên — một cái là năng lực của tầng ra bán dẫn, cái kia là giới hạn nhiệt của một khối epoxy.
Sự trùng hợp đó tạo ra một suy luận sai rất tự nhiên: "chân cấp được 20 mA, LED ăn 20 mA, vậy nối thẳng là vừa." Cả hai vế đều đúng, kết luận vẫn sai, vì không vế nào nói rằng dòng sẽ dừng lại ở 20 mA khi bỏ điện trở.
Một công tắc trông "ngon" lại là con tệ nhất trong khảo sát
Trong 18 công tắc được đo, con giữ kỷ lục nảy 157 ms được tác giả mô tả là "một nút bấm màu đỏ trông có vẻ ngon" Nguồn đo đạc · app note Jack Ganssle — A Guide to Debouncing (phần 1) Khảo sát 18 công tắc, mỗi con bấm 300 lần, đo bằng MSO — nguồn của mọi con số thống kê về nảy phím. Mở trong tab mới · Esc để đóng . Trong khi đó một microswitch chất lượng cao không bao giờ vượt quá 1.18 ms.
Điều khảo sát thực sự chứng minh không phải "đắt thì tốt hơn" hay ngược lại — nó chứng minh rằng vẻ ngoài và cảm giác bấm không dự đoán được hành vi điện. Ngay cả hai con cùng model cũng lệch nhau hai lần. Đó là toàn bộ lý do mục tiêu của phiên này là đo cái nút đang cầm, chứ không phải tra bảng.
Đường bất đồng bộ ổn định hơn đường ngắt
Trong esp-hal 1.1, các phương thức chờ cạnh của Input — chờ sườn lên, sườn xuống, hoặc
cạnh bất kỳ — thuộc API ổn định. Trong khi đó toàn bộ đường ngắt cổ điển, gồm listen,
enum Event, struct Io và macro handler, đều nằm sau feature unstable Nguồn tài liệu chính chủ esp-hal trên docs.rs API reference; mục esp_hal::gpio cho Output/Input/Level/Pull/OutputConfig. Mở trong tab mới · Esc để đóng .
Đây là một tuyên bố về hướng đi của dự án, không phải một chi tiết ngẫu nhiên: mô hình được cam kết ổn định trước là mô hình bất đồng bộ. Ghi nhớ điều này khi tới phiên chuyển từ polling sang xử lý sự kiện — con đường trông "cơ bản hơn" lại là con đường ít cam kết hơn.
Mọi con số điện trong trang này lấy từ bảng DC Characteristics của datasheet ESP32-C6; mọi con số về nảy phím lấy từ khảo sát 18 công tắc hoặc từ datasheet nhà sản xuất, và được ghi rõ nguồn nào ở từng chỗ. Chỗ chưa xác minh được — bộ đệm đầu vào của C6 có hysteresis nội tại hay không — được ghi rõ là chưa xác minh, kèm cách tự kiểm ở phần Stretch.