Bài 2 · Công nghệ · Tin học
Điều khiển LED bằng nút nhấn
máy biết chờ, và biết hỏi lại liên tục
Bài 1 dạy máy tự làm theo thời gian. Bài này dạy máy nhìn ra ngoài rồi mới quyết định. Chỉ thêm một nút nhấn, nhưng đó là bước từ điều khiển sang phản hồi.
01 Mục tiêu và yêu cầu cần đạt
Ở Bài 1, chương trình chạy một mình từ đầu đến cuối, không quan tâm bên ngoài có gì. Bài này thêm đúng một thứ — một cái nút — nhưng nó đổi hẳn bản chất: lần đầu tiên máy phải hỏi trước khi làm.
Sau bài này học sinh làm được
- Nối một nút nhấn vào chân GPIO mà không cần điện trở ngoài.
- Giải thích được vì sao nút chưa nhấn thì đọc ra 1, nhấn rồi mới ra 0.
- Dùng cấu trúc rẽ nhánh
if … elseđể chọn giữa hai việc. - Hiểu chương trình không "nhìn thấy" nút, mà hỏi đi hỏi lại rất nhanh.
- Đoán được điều gì xảy ra khi tăng khoảng nghỉ giữa hai lần hỏi.
- Công nghệ 12 — mạch nội dung Vi điều khiển: đọc tín hiệu số đầu vào và điều khiển thiết bị đầu ra.
- Tin học 10–11 — cấu trúc rẽ nhánh, biểu thức lôgic, biến kiểu đúng/sai.
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
Chân thả nổi
Hỏi cả lớp trước khi cắm dây: nút có hai chân, vậy khi chưa nhấn thì chân GPIO nối vào đâu? Đáp: chẳng nối vào đâu cả — mạch hở. Chân GPIO hở không phải mức 0 cũng không phải mức 1, nó lơ lửng và đọc ra số ngẫu nhiên theo nhiễu xung quanh.
Điện trở kéo lên
Nối chân GPIO lên 3,3 V qua một điện trở lớn. Chưa nhấn thì chân được kéo lên mức 1 một cách yếu ớt nhưng dứt khoát; nhấn thì nút nối thẳng chân xuống GND — nối thẳng mạnh hơn hẳn kéo qua điện trở, nên chân tụt về 0.
ESP32 có sẵn điện trở kéo lên bên trong chip, chỉ cần một chữ:
nut = Pin(4, Pin.IN, Pin.PULL_UP) Hệ quả: nhấn nút thì đọc ra 0. Đừng chữa bằng "cứ nhớ thế", hãy quay lại sơ đồ — nhấn = nối xuống GND = 0 V = mức 0.
Trong chương trình viết nut.value() == 0 rồi đặt tên biến là
dang_nhan. Từ đó trở đi mọi câu lệnh đều thuận, không ai phải
nhớ chuyện ngược nữa. Đặt tên biến tử tế cũng là một kỹ năng lập trình.
Máy không nhìn, máy hỏi
Chương trình không "thấy" lúc nút bị nhấn. Nó chạy vòng lặp, mỗi vòng hỏi đúng một câu — ngay lúc này nút có đang bị nhấn không? — làm theo câu trả lời, nghỉ một chút, rồi hỏi lại.
Nghỉ 50 ms tức hỏi 20 lần mỗi giây. Ngón tay người không nhanh đến thế nên ta có cảm giác đèn phản ứng tức thì. Mục Hiệu chuẩn bên dưới sẽ cho học sinh phá vỡ cảm giác ấy.
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 |
| Nút nhấn 4 chân | Loại cắm breadboard. Xem hộp cạm bẫy về cách chọn cặp chân | 1 · 1k |
| LED 5 mm | Dùng lại LED của Bài 1 | 1 · 500đ |
| Điện trở 220 Ω | Cho LED. Nút nhấn KHÔNG cần điện trở ngoài | 1 · 200đ |
| Breadboard và dây cắm | Loại 400 lỗ là đủ | 1 bộ · 30k |
04 Lắp mạch và sơ đồ nối dây
| Khối | Nối dây | Nguồn |
|---|---|---|
| Nút nhấn | GPIO4 → một chân nút · chân chéo góc → GND | Không cần nguồn riêng |
| LED | GPIO23 → điện trở 220 Ω → chân dài (+) · chân ngắn (−) → GND | Lấy từ chính chân GPIO |
Hai nhánh tách bạch: nhánh ra là GPIO23 → điện trở 220 Ω → LED → GND, nhánh vào là GPIO4 → nút nhấn → GND. Nút không cần điện trở ngoài vì điện trở kéo lên đã nằm sẵn trong chip.
Chính mạch ấy khi đã cắm xong: LED vàng và điện trở ở nửa trên breadboard, nút nhấn cắm vắt qua rãnh giữa ở nửa dưới. Đèn nguồn đỏ trên bo đang sáng vì cáp USB đã cắm; LED vàng chưa sáng vì chưa nạp chương trình.
Bốn thao tác
- Giữ nguyên mạch LED của Bài 1:
GPIO23→ điện trở 220 Ω → chân dài LED, chân ngắn →GND. - Cắm nút nhấn vắt ngang rãnh giữa breadboard, hai chân mỗi bên.
- Dây trắng: một chân nút →
GPIO4. - Dây đen: chân chéo góc với chân vừa nối →
GND.
Nút nhấn cắm breadboard thường có bốn chân, nhưng bên trong chúng đã nối sẵn thành từng cặp. Hai chân cùng một cặp lúc nào cũng thông nhau, bấm hay không cũng thế. Nếu học sinh vô tình dùng đúng một cặp đó, đèn sẽ sáng liên tục và không nút nào chữa được.
Quy tắc an toàn: luôn dùng hai chân chéo góc nhau. Cặp chéo góc chắc chắn thuộc hai cặp khác nhau. Cắm nút vắt ngang rãnh giữa breadboard cũng giúp tránh nhầm, vì hai chân cùng cặp khi đó nằm khác phía.
LED thì bắt buộc có điện trở 220 Ω. Nút nhấn thì không, vì điện trở kéo lên
đã nằm sẵn trong chip và được bật bằng Pin.PULL_UP. Học sinh hay
cắm thừa một con điện trở ở đây vì tưởng linh kiện nào cũng cần.
05 Mã nguồn
Toàn bộ mã trong bài chạy trên MicroPython 1.28 cho ESP32. Chép vào bo rồi đổi tên thành main.py là chạy mỗi lần cấp nguồn.
Bước 0 — nhìn thấy tín hiệu trước đã# ------------------------------------------------------------
# Bai 2 - Doc thu trang thai nut nhan
# Chua dieu khien gi ca, chi in ra man hinh de nhin thay tin hieu.
# ------------------------------------------------------------
from machine import Pin
import time
nut = Pin(4, Pin.IN, Pin.PULL_UP)
while True:
print(nut.value())
time.sleep_ms(200) Nạp vào rồi nhấn giữ nút, màn hình in ra:
1 1 1 0 <-- luc dang giu nut 0 1
Bước này đáng giá cả mục lí thuyết. Học sinh nhìn thấy số 1 đổi thành 0 đúng lúc ngón tay ấn xuống. Đừng bỏ qua để chạy thẳng vào chương trình chính.
Chương trình chính — nhấn thì sáng, thả thì tắt# ------------------------------------------------------------
# Bai 2 - Dieu khien LED bang nut nhan
# Phan cung: GPIO4 -> mot chan nut -> chan con lai -> GND
# GPIO23 -> dien tro 220 ohm -> chan dai LED -> GND
# ------------------------------------------------------------
from machine import Pin
import time
# ===== CẤU HÌNH =====
CHAN_NUT = 4 # nut nhan cam o GPIO4
CHAN_LED = 23 # LED cam o GPIO23
THOI_GIAN_NGHI = 50 # ms - bao lau doc lai nut mot lan
# ====================
nut = Pin(CHAN_NUT, Pin.IN, Pin.PULL_UP)
led = Pin(CHAN_LED, Pin.OUT)
while True:
dang_nhan = nut.value() == 0
if dang_nhan:
led.on()
else:
led.off()
time.sleep_ms(THOI_GIAN_NGHI)
Ba dòng if … else ở giữa chính là toàn bộ nội dung Tin học của
bài. Trước đó chương trình chỉ biết làm tuần tự; từ đây nó biết chọn.
# Bien the: nhan mot lan BAT, nhan lan nua TAT (nhu cong tac den)
from machine import Pin
import time
nut = Pin(4, Pin.IN, Pin.PULL_UP)
led = Pin(23, Pin.OUT)
dang_sang = False
truoc_do = False
while True:
dang_nhan = nut.value() == 0
# Chi doi trang thai o dung KHOANH KHAC nut vua bi nhan xuong
if dang_nhan and not truoc_do:
dang_sang = not dang_sang
led.value(dang_sang)
time.sleep_ms(200) # bo qua nhieu doi tiep diem
truoc_do = dang_nhan
time.sleep_ms(20)
Bản này khó hơn hẳn và nên để dành cho nhóm nhanh. Nó cần hai ý mới: nhớ lại
trạng thái vòng trước bằng biến truoc_do, và chỉ hành động ở đúng
khoảnh khắc chuyển chứ không phải suốt lúc đang giữ. Đây cũng chính
là cách Bài 4 đếm số lần nhấn.
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ử
Phép thử làm hỏng cảm giác "đèn phản ứng tức thì"
Chương trình chính đang nghỉ 50 ms mỗi vòng. Cho học sinh tăng dần
THOI_GIAN_NGHI rồi nhấn nút thật nhanh:
| Thời gian nghỉ | Máy hỏi mấy lần mỗi giây | Cảm giác khi nhấn nhanh |
|---|---|---|
| 50 ms | 20 | Như tức thì |
| 300 ms | khoảng 3 | Hơi trễ, nhận ra được |
| 1000 ms | 1 | Nhấn nhanh thì đèn bỏ qua hẳn |
Ở mức 1000 ms, học sinh sẽ bấm mà đèn không thèm phản ứng. Đó không phải lỗi — đó là bằng chứng cho thấy máy chỉ hỏi mỗi giây một lần, và ngón tay đã kịp nhấn xong rồi thả ra giữa hai lần hỏi. Không có cách nào giải thích khái niệm "tần suất lấy mẫu" rẻ và rõ hơn thế.
Danh sách kiểm trước khi coi là xong
- Bước 0 in ra 1 khi thả, 0 khi giữ nút.
- Chương trình chính: nhấn thì đèn sáng, thả thì đèn tắt, không trễ thấy được.
- Đổi
THOI_GIAN_NGHIthành 1000 thì đèn bỏ sót cú nhấn nhanh. - Đảo
led.on()vàled.off()cho nhau thì hành vi ngược lại đúng như dự đoán. - Học sinh giải thích được vì sao
== 0lại nghĩa là "đang nhấn".
07 Kinh nghiệm và cạm bẫy
Trong mọi lỗi của bài này, cắm nhầm hai chân cùng một cặp là lỗi tốn thời gian nhất, vì nó không giống lỗi. Đèn sáng ngay từ lúc cấp nguồn, chương trình chạy đúng, không thông báo gì. Học sinh sẽ đi soi chương trình trong khi mạch mới là chỗ sai.
Cách phát hiện trong mười giây: chạy Bước 0. Nếu màn hình in ra 0
liên tục ngay cả khi không ai chạm vào nút, thì hai chân đang dùng vốn đã
thông nhau sẵn. Rút nút ra, xoay 90°, cắm lại.
Vì vậy Bước 0 mới đứng trước chương trình chính trong bài này. Nó không phải thủ tục thừa, nó là công cụ chẩn đoán.
Tiếp điểm kim loại trong nút không đóng dứt khoát một lần. Nó nảy vài lần trong khoảng vài mili giây đầu, nên chương trình đọc rất nhanh sẽ thấy 0-1-0-1 rồi mới yên.
Chương trình chính không gặp vấn đề này, vì nó chỉ quan tâm trạng thái hiện tại: nảy vài lần thì đèn nhấp nháy vài mili giây, mắt không thấy. Nhưng bản biến thể "nhấn một lần bật, nhấn lần nữa tắt" thì hỏng ngay — một cú bấm có thể bị đếm thành ba, đèn bật rồi tắt rồi bật.
Đó là lí do bản biến thể có dòng time.sleep_ms(200) ngay sau khi
đổi trạng thái. Nếu nhóm nào gặp đèn "loạn" ở bản biến thể, hãy để các em tự
tìm ra nguyên nhân trước khi chỉ dòng đó.
Hai hộp trên viết từ quá trình dựng và chạy thử bài. Sau buổi dạy đầu tiên, xin thầy cô thay bằng tình huống đã thực sự xảy ra ở lớp mình — đó mới là thứ đồng nghiệp đọc để tránh.
08 Ứng dụng trong dạy học
Tin học — rẽ nhánh có hậu quả nhìn thấy được
Trên giấy, if … else là hai nhánh của một sơ đồ khối. Ở đây nó là
một cái đèn nghe lời ngón tay. Cho học sinh xoá hẳn nhánh else rồi
chạy lại: đèn sáng lên rồi không bao giờ tắt nữa. Câu hỏi tiếp theo tự
nó bật ra — vì sao bỏ else thì đèn không tắt được?
Công nghệ — vào và ra trong cùng một vòng
Bài 1 chỉ có đầu ra. Bài này đủ cả ba khối của mọi hệ thống điều khiển: đọc đầu vào, xử lí, xuất đầu ra. Toàn bộ các bài cảm biến về sau chỉ thay nút nhấn bằng cảm biến nhiệt độ, ánh sáng hay khoảng cách — còn khung chương trình thì y nguyên. Hãy nói rõ điều đó, vì nó giúp học sinh thấy mình đang học một khuôn mẫu chứ không phải học thuộc từng bài.
Hoạt động 1 — Xác định vấn đề. Khi làm thí nghiệm, nhóm cần gọi giáo viên mà không được rời chỗ và không được la lớn làm ảnh hưởng nhóm khác. Cần một nút bấm bật đèn báo ở bàn giáo viên.
Tiêu chí sản phẩm: đèn sáng ngay khi bấm; nhìn rõ từ bàn giáo viên; đèn phải giữ sáng cho tới khi được xử lí, chứ không tắt ngay khi thả tay.
Hoạt động 2 — Kiến thức nền. Điện trở kéo lên; đọc tín hiệu số; rẽ nhánh; và khái niệm nhớ trạng thái.
Hoạt động 3 — Đề xuất và chọn phương án. Tiêu chí "giữ sáng" khiến bản đơn giản không đạt. Các nhóm phải tự nhận ra và chuyển sang bản biến thể có nhớ trạng thái.
Hoạt động 4 — Chế tạo và thử. Lắp, lập trình, bấm thử nhiều kiểu: bấm nhanh, bấm giữ lâu, bấm liên tục.
Hoạt động 5 — Báo cáo và điều chỉnh. Nhóm khác thử phá: bấm thật nhanh nhiều lần xem đèn có loạn không. Nhóm nào bị phá thành công thì phân tích hiện tượng dội tiếp điểm rồi sửa.
- Thêm nút thứ hai: một nút bật, một nút tắt.
- Ghép với Bài 3 đèn giao thông: bấm nút để chuyển sang chế độ ưu tiên người đi bộ.
- Ghép với Bài 10 buzzer: bấm nút phát ra một nốt nhạc.
- Bài 4 sẽ đếm số lần nhấn — dùng lại đúng ý "chỉ hành động ở khoảnh khắc chuyển" của bản biến thể.
- Hướng thi Khoa học kĩ thuật: nút gọi hỗ trợ không dây cho người cao tuổi sống một mình.