Chạm tay bật đèn: nút cảm ứng trên ESP32 cho học sinh, không cần linh kiện
Dự án STEM với chân cảm ứng của ESP32: nối một dây vào D4, đọc giá trị cảm ứng, chạm tay bật tắt đèn trên mạch, giải thích điện dung, giá trị nền, hai ngưỡng và thí nghiệm.
Mạch ESP32 có một khả năng thú vị: một số chân của nó nhận biết được khi ngón tay chạm vào, giống màn hình cảm ứng điện thoại. Chỉ cần nối một sợi dây vào chân đó, chạm tay vào đầu dây là chương trình nhận ra. Bài viết hướng dẫn học sinh làm nút cảm ứng chạm tay bật, tắt đèn với ESP32, không cần nút bấm hay linh kiện nào khác ngoài một dây cắm.
Qua dự án, trẻ học được ba điều: cơ thể người có thể làm thay đổi một đại lượng điện (điện dung), cách đọc và quan sát số đo từ cảm biến, và cách chọn ngưỡng để quyết định "đang chạm" hay "không chạm".
1. Chuẩn bị
- Một mạch ESP32 DevKit V1 và dây USB nạp code.
- Một dây cắm test board loại một đầu cái (cắm vào chân mạch), một đầu đực (để chạm).
- Tùy chọn: một miếng giấy bạc dán lên bìa cứng làm "nút bấm" to hơn.
- Arduino IDE đã cài gói esp32 và chọn board DOIT ESP32 DEVKIT V1, như bài nháy đèn trong cùng loạt.
2. Nối dây

Cắm dây vào chân D4 (GPIO4). Đây là kênh cảm ứng T0 của ESP32. Đầu dây còn lại để trống, hoặc kẹp vào miếng giấy bạc. Đèn dùng chính đèn LED có sẵn trên mạch ở GPIO2.
Trên mạch ESP32 DevKit V1 30 chân còn các chân cảm ứng khác: D13, D14, D27, D32, D33 (cùng D2, D12, D15). Người mới nên tránh D2 vì đã nối với đèn, và tránh D12, D15 vì hai chân này ảnh hưởng tới cách mạch khởi động.
3. Vì sao chạm tay thì mạch biết?

Sợi dây nối chân D4 và ngón tay giống hai bản của một tụ điện, linh kiện có khả năng tích điện. Khi ngón tay chạm hoặc đến rất gần dây, khả năng tích điện (điện dung) của chân D4 tăng lên. ESP32 đo được sự thay đổi này và trả về một con số qua lệnh touchRead(). Trên chip ESP32, con số này thường giảm khi chạm tay.
Con số không giống nhau giữa các mạch: nó phụ thuộc độ dài dây, vật nối vào dây, và phiên bản phần mềm. Vì vậy chương trình không dùng một con số cố định, mà đo giá trị nền lúc chưa chạm rồi so độ lệch.
4. Chương trình 1: đọc và quan sát giá trị cảm ứng
// PYWORLD.VN - ESP32 DevKit V1: đọc giá trị cảm ứng ở chân D4 (kênh T0)
// Nối một dây cắm vào D4, chạm tay vào đầu kim loại của dây và xem số thay đổi
// Mở Serial Monitor hoặc Serial Plotter ở tốc độ 115200 baud
const int CHAN_CAM_UNG = 4; // GPIO4 là kênh cảm ứng T0 của ESP32
void setup() {
Serial.begin(115200);
delay(500);
Serial.println("Cham tay vao day noi chan D4");
}
void loop() {
uint32_t giaTri = touchRead(CHAN_CAM_UNG);
Serial.print("cam_ung:"); // nhãn để Serial Plotter vẽ đường có tên
Serial.println(giaTri);
delay(100); // đọc 10 lần mỗi giây
}
Nạp chương trình, mở Tools > Serial Plotter ở 115200 baud. Đường "cam_ung" chạy ngang khi không chạm, tụt xuống khi chạm tay vào đầu dây. Có thể mở Serial Monitor để xem từng con số.
Thí nghiệm cho trẻ: ghi lại số khi không chạm, khi chạm nhẹ, khi nắm chặt đầu dây, khi chạm qua một tờ giấy, khi chạm bằng bút chì. Lập bảng và nhận xét.
5. Chương trình 2: chạm tay bật, tắt đèn
// PYWORLD.VN - ESP32 DevKit V1: chạm tay bật, tắt đèn LED trên mạch
// Mỗi lần chạm vào dây nối chân D4 (kênh T0), đèn ở GPIO2 đổi trạng thái
// Lúc khởi động, không chạm tay để chương trình đo giá trị nền
const int CHAN_CAM_UNG = 4;
const int LED_PIN = 2;
const float LECH_CHAM = 0.30; // lệch hơn 30 % so với giá trị nền: coi là đang chạm
const float LECH_NHA = 0.15; // lệch dưới 15 %: coi là đã nhả tay (hai ngưỡng khác nhau để đèn không chập chờn)
uint32_t giaTriNen = 0;
bool dangCham = false;
bool denSang = false;
int soLanCham = 0;
// Đọc nhiều lần rồi lấy trung bình để số đỡ nhảy
uint32_t docTrungBinh(int soLan) {
uint32_t tong = 0;
for (int i = 0; i < soLan; i++) {
tong += touchRead(CHAN_CAM_UNG);
delay(5);
}
return tong / soLan;
}
// Độ lệch so với giá trị nền, tính theo tỉ lệ (0,30 nghĩa là 30 %)
float doLech(uint32_t giaTri) {
float chenh = (float)giaTri - (float)giaTriNen;
if (chenh < 0) chenh = -chenh;
return chenh / giaTriNen;
}
void setup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
delay(500);
Serial.println("Dung cham tay, dang do gia tri nen...");
giaTriNen = docTrungBinh(40);
if (giaTriNen == 0) giaTriNen = 1; // tránh chia cho 0
Serial.printf("Gia tri nen: %u\n", (unsigned)giaTriNen);
Serial.println("San sang! Cham tay de bat, tat den");
}
void loop() {
uint32_t giaTri = docTrungBinh(4);
float lech = doLech(giaTri);
if (!dangCham && lech > LECH_CHAM) { // vừa bắt đầu chạm
dangCham = true;
denSang = !denSang;
digitalWrite(LED_PIN, denSang ? HIGH : LOW);
soLanCham++;
Serial.printf("Cham lan %d: gia tri %u, lech %d%%, den %s\n", soLanCham, (unsigned)giaTri,
(int)(lech * 100), denSang ? "SANG" : "TAT");
} else if (dangCham && lech < LECH_NHA) { // đã nhả tay
dangCham = false;
}
delay(20);
}
Nạp chương trình và không chạm vào dây trong khoảng nửa giây đầu, để chương trình đo giá trị nền. Sau đó mỗi lần chạm tay, đèn trên mạch đổi trạng thái: đang tắt thì sáng, đang sáng thì tắt.

Giải thích các ý chính
- Giá trị nền:
docTrungBinh(40)đọc 40 lần lúc khởi động rồi lấy trung bình. Đây là "mức bình thường" khi không ai chạm. - Độ lệch:
doLech()tính số đọc được khác giá trị nền bao nhiêu phần trăm. Dùng phần trăm nên chương trình chạy được với mọi mạch, dù con số tuyệt đối khác nhau. - Hai ngưỡng: lệch hơn 30 % mới tính là chạm, lệch dưới 15 % mới tính là đã nhả tay. Nếu dùng một ngưỡng, khi số đo dao động quanh ngưỡng, đèn sẽ bật tắt liên tục. Hai ngưỡng tạo một "vùng đệm" ở giữa.
- Chỉ đổi đèn lúc bắt đầu chạm: biến
dangChamnhớ là tay đang đặt trên dây, nên giữ tay lâu cũng chỉ tính một lần.
6. Ý tưởng thử nghiệm
| Vật nối vào dây | Câu hỏi cho trẻ |
|---|---|
| Miếng giấy bạc trên bìa cứng | Miếng to hay nhỏ thì nhạy hơn? Chạm qua lớp giấy mỏng có được không? |
| Quả chuối, quả táo (cắm đầu dây vào quả) | Chạm vào quả có bật đèn không? Quả nào nhạy hơn? |
| Nét vẽ bút chì đậm trên giấy | Than chì dẫn điện yếu; vẽ đậm, nhạt có khác nhau? |
| Cốc nước (thả đầu dây vào nước) | Chạm mặt nước có được không? Nước muối thì sao? |
Khi đổi vật nối, giá trị nền thay đổi, nên cần bấm nút EN (reset) trên mạch để chương trình đo lại giá trị nền.
7. Xử lý lỗi thường gặp
| Hiện tượng | Nguyên nhân thường gặp | Cách xử lý |
|---|---|---|
| Đèn tự bật tắt khi không ai chạm | Chạm tay lúc khởi động nên giá trị nền sai; dây quá dài, nằm gần dây USB | Bấm EN, không chạm trong lúc đo nền; dùng dây ngắn hơn |
| Chạm mà đèn không đổi | Độ lệch chưa tới 30 % | Xem số lệch trên Serial Monitor; giảm LECH_CHAM xuống 0,20 và LECH_NHA xuống 0,10 |
| Chạm một lần đèn đổi hai lần | Số đo dao động quanh ngưỡng | Tăng khoảng cách giữa hai ngưỡng; tăng số lần đọc trung bình |
| Số đọc được luôn bằng 0 hoặc không đổi | Cắm nhầm chân | Kiểm tra dây cắm đúng chân D4 |
8. Gợi ý dùng trong giờ học STEM
- Khoa học: vật nào làm thay đổi số đo nhiều nhất? Vì sao chạm qua găng tay cao su thì khó nhận ra?
- Toán: tính phần trăm lệch từ số đo; vẽ đồ thị số đo theo thời gian từ dữ liệu Serial.
- Kỹ thuật: thiết kế một "công tắc cảm ứng" đẹp bằng giấy bạc, bìa cứng, hộp giấy; đặt ở đâu thì dễ dùng?
- Thời lượng gợi ý: 2 buổi, mỗi buổi 45 phút: buổi 1 đọc số và thí nghiệm, buổi 2 bật tắt đèn và làm công tắc.
Mạch chỉ dùng nguồn USB 5 V từ máy tính; không nối dây cảm ứng vào thiết bị điện khác.
9. Xem thêm
Bài trước trong loạt là bài nháy đèn và mã Morse với ESP32. Ở đợt bài tiếp theo, chân cảm ứng sẽ được dùng để làm đàn piano trái cây. Muốn điều khiển thiết bị lớn hơn đèn trên mạch, xem bài ESP32 điều khiển module relay an toàn; muốn đọc nút bấm thật, xem bài ngắt GPIO và chống dội nút nhấn.
Xem thêm