Raspberry Pi Button Debounce (Chống Nhiễu Nút Nhấn)
Khi một nút nhấn được bấm hoặc thả ra, hoặc khi một công tắc được chuyển đổi, người mới bắt đầu thường cho rằng trạng thái của nó đơn giản chỉ thay đổi từ LOW sang HIGH hoặc HIGH sang LOW. Trên thực tế, điều này không phải như vậy. Do các đặc tính cơ học và vật lý, trạng thái của nút nhấn (hoặc công tắc) có thể được chuyển đổi giữa LOW và HIGH nhiều lần. Hiện tượng này được gọi là chattering (nhiễu tiếp xúc). Chattering có thể khiến một lần nhấn được đọc thành nhiều lần nhấn, dẫn đến trục trặc trong một số ứng dụng.
Phương pháp để ngăn ngừa vấn đề này được gọi là debouncing hoặc debounce (chống nhiễu). Hướng dẫn này sẽ chỉ bạn cách thực hiện khi sử dụng nút nhấn với Raspberry Pi. Chúng ta sẽ học qua các bước sau:
Mã Raspberry Pi không có debouncing cho nút nhấn.
Mã Raspberry Pi có debouncing cho nút nhấn.
Mã Raspberry Pi có debouncing cho nhiều nút nhấn.
| 1 | × | Raspberry Pi 5 | | |
| 1 | × | Nút Nhấn Gắn Breadboard Có Nắp | | |
| 1 | × | Bộ Kit Nút Nhấn Gắn Breadboard | | |
| 1 | × | Nút Nhấn Gắn Panel | | |
| 1 | × | mô-đun nút nhấn | | |
| 1 | × | breadboard (Bo Mạch Thí Nghiệm) | | |
| 1 | × | Dây Jumper | | |
| 1 | × | (Khuyến nghị) Screw Terminal Block Shield for Raspberry Pi | | |
| 1 | × | (Khuyến nghị) Raspberry Pi Prototyping Base Plate & Breadboard Kit | | |
| 1 | × | (Khuyến nghị) HDMI Touch Screen Monitor for Raspberry Pi | | |
Or you can buy the following kits:
| 1 | × | DIYables Sensor Kit (30 sensors/displays) | | |
| 1 | × | DIYables Sensor Kit (18 sensors/displays) | | |
Nếu bạn chưa quen thuộc với nút nhấn, bao gồm sơ đồ chân, cách hoạt động và cách lập trình chúng, các hướng dẫn sau có thể cung cấp cho bạn thêm thông tin:

This image is created using Fritzing. Click to enlarge image
Hãy cùng xem xét sự khác biệt giữa mã Raspberry Pi CÓ và KHÔNG CÓ debounce, cũng như hành vi tương ứng của chúng.
Trước khi hiểu về debouncing, hãy xem mã không có nó và quan sát hành vi của nó.
Đảm bảo bạn đã cài đặt Raspbian hoặc bất kỳ hệ điều hành tương thích Raspberry Pi nào khác trên Pi của mình.
Đảm bảo Raspberry Pi của bạn được kết nối với cùng mạng cục bộ như PC của bạn.
Đảm bảo Raspberry Pi của bạn được kết nối internet nếu bạn cần cài đặt một số thư viện.
Đảm bảo bạn đã cài đặt thư viện RPi.GPIO. Nếu chưa, hãy cài đặt nó bằng lệnh sau:
sudo apt-get update
sudo apt-get install python3-rpi.gpio
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
BUTTON_PIN = 16
GPIO.setup(BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
button_state = GPIO.input(BUTTON_PIN)
try:
while True:
current_state = GPIO.input(BUTTON_PIN)
if current_state != button_state:
if current_state == GPIO.HIGH:
print("Button released")
else:
print("Button pressed")
button_state = current_state
time.sleep(0.1)
except KeyboardInterrupt:
GPIO.cleanup()
python3 button_without_debounce.py
Script chạy trong vòng lặp vô hạn liên tục cho đến khi bạn nhấn Ctrl + C trong terminal.
Button pressed
Button pressed
Button pressed
Button released
Button released
Đôi khi, bạn chỉ nhấn và thả nút một lần. Tuy nhiên, Raspberry Pi nhận ra nó như nhiều lần nhấn và thả. Đây là hiện tượng chattering được đề cập ở đầu hướng dẫn. Hãy xem cách khắc phục điều này trong phần tiếp theo.
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
BUTTON_PIN = 16
DEBOUNCE_TIME_MS = 200
GPIO.setup(BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
button_state = GPIO.input(BUTTON_PIN)
prev_button_state = button_state
def button_callback(channel):
global button_state
button_state = GPIO.input(BUTTON_PIN)
GPIO.add_event_detect(BUTTON_PIN, GPIO.BOTH, callback=button_callback, bouncetime=DEBOUNCE_TIME_MS)
try:
while True:
if button_state != prev_button_state:
if button_state == GPIO.HIGH:
print("Button released")
else:
print("Button pressed")
prev_button_state = button_state
except KeyboardInterrupt:
GPIO.cleanup()
python3 button_debounce.py
Button pressed
Button released
Như bạn có thể quan sát thấy, bạn chỉ nhấn và thả nút một lần. Raspberry Pi phát hiện nó như một lần nhấn và thả duy nhất, do đó loại bỏ mọi nhiễu không cần thiết.
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
BUTTON_PIN_1 = 14
BUTTON_PIN_2 = 15
BUTTON_PIN_3 = 18
DEBOUNCE_TIME_MS = 200
GPIO.setup(BUTTON_PIN_1, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(BUTTON_PIN_2, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(BUTTON_PIN_3, GPIO.IN, pull_up_down=GPIO.PUD_UP)
button_state_1 = GPIO.input(BUTTON_PIN_1)
button_state_2 = GPIO.input(BUTTON_PIN_2)
button_state_3 = GPIO.input(BUTTON_PIN_3)
prev_button_state_1 = button_state_1
prev_button_state_2 = button_state_2
prev_button_state_3 = button_state_3
def button_callback_1(channel):
global button_state_1
button_state_1 = GPIO.input(BUTTON_PIN_1)
def button_callback_2(channel):
global button_state_2
button_state_2 = GPIO.input(BUTTON_PIN_2)
def button_callback_3(channel):
global button_state_3
button_state_3 = GPIO.input(BUTTON_PIN_3)
GPIO.add_event_detect(BUTTON_PIN_1, GPIO.BOTH, callback=button_callback_1, bouncetime=DEBOUNCE_TIME_MS)
GPIO.add_event_detect(BUTTON_PIN_2, GPIO.BOTH, callback=button_callback_2, bouncetime=DEBOUNCE_TIME_MS)
GPIO.add_event_detect(BUTTON_PIN_3, GPIO.BOTH, callback=button_callback_3, bouncetime=DEBOUNCE_TIME_MS)
try:
while True:
if button_state_1 != prev_button_state_1:
if button_state_1 == GPIO.HIGH:
print("Button 1 released")
else:
print("Button 1 pressed")
prev_button_state_1 = button_state_1
if button_state_2 != prev_button_state_2:
if button_state_2 == GPIO.HIGH:
print("Button 2 released")
else:
print("Button 2 pressed")
prev_button_state_2 = button_state_2
if button_state_3 != prev_button_state_3:
if button_state_3 == GPIO.HIGH:
print("Button 3 released")
else:
print("Button 3 pressed")
prev_button_state_3 = button_state_3
except KeyboardInterrupt:
GPIO.cleanup()
Sơ đồ minh họa kết nối dây cho đoạn mã được đề cập:

This image is created using Fritzing. Click to enlarge image
Việc sản xuất video tốn rất nhiều thời gian. Nếu video hướng dẫn hữu ích cho việc học của bạn, hãy đăng ký kênh YouTube để ủng hộ. Nếu nhu cầu đủ cao, chúng tôi sẽ cố gắng làm thêm nhiều video.