라즈베리파이 Python 9 - 버튼 채터링 방지, 디바운스
버튼을 누르거나 놓을 때 또는 스위치를 토글할 때 초보자는 단순히 상태가 LOW에서 HIGH로 또는 HIGH에서 LOW로 변경된다고 가정하는 경우가 많습니다.
실제로는 그렇지 않습니다. 기계적, 물리적 특성으로 인해 버튼(또는 스위치)의 상태가 LOW와 HIGH 사이를 여러 번 전환할 수 있습니다. 이 현상을 채터링이라고 합니다. 채터링으로 인해 한 번의 누르기가 여러 번 누르는 것처럼 읽혀 특정 응용 프로그램에서 오작동이 발생할 수 있습니다.
강의 순서
라즈베리파이 Python 4 - Delay 없는 LED Blink
이러한 문제를 방지하는 방법을 디바운싱(debounce) 또는 디바운스(debounce)라고 합니다. 이 튜토리얼에서는 Raspberry Pi에서 버튼을 사용할 때 이를 수행하는 방법을 설명합니다. 우리는 아래 단계를 통해 배울 것입니다:
- 버튼을 디바운싱하지 않은 라즈베리 파이 코드.
- 버튼을 디바운싱하는 라즈베리 파이 코드.
- 여러 버튼에 대한 디바운싱 기능이 있는 Raspberry Pi 코드입니다.
버튼 연결도
다음 GPIO 라이브러리를 설치합니다.
설치 제거
sudo apt remove python3-rpi.gpio
새로운 라이브러리를 설치합니다.
sudo apt-get update
sudo apt install python3-rpi-lgpio
아래 스크립트를 button_bounce.py로 입력하세요.
"""
This Raspberry Pi code was developed by newbiely.com
This Raspberry Pi code is made available for public use without any restriction
For comprehensive instructions and wiring diagrams, please visit:
https://newbiely.com/tutorials/raspberry-pi/raspberry-pi-button-debounce
"""
import RPi.GPIO as GPIO
import time
# Set the GPIO mode to BCM
GPIO.setmode(GPIO.BCM)
# Define the GPIO pin for your button
BUTTON_PIN = 16
# Set the initial state and pull-up resistor for the button
GPIO.setup(BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
# Initialize the button state
button_state = GPIO.input(BUTTON_PIN)
try:
# Main loop
while True:
# Read the current button state
current_state = GPIO.input(BUTTON_PIN)
# Check if the button state has changed and print when it does
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) # Adjust the sleep time as needed
except KeyboardInterrupt:
# Clean up GPIO on exit
GPIO.cleanup()
실행 결과입니다.
파일을 저장하고 터미널에서 다음 명령을 실행하여 Python 스크립트를 실행합니다.
$python3 button_bounce.py 스크립트는 터미널에서 Ctrl + C를 누를 때까지 무한 루프로 계속 실행됩니다.
버튼을 몇 초간 누르고 있다가 놓습니다.
- 결과는 터미널에서 확인하세요.
- 라즈베리 파이 버튼을 눌렀습니다.
때로는 버튼을 한 번만 눌렀다가 떼는 경우도 있습니다. 그럼에도 불구하고 Raspberry Pi는 이를 여러 번의 누름과 뗀 상태로 인식합니다. 튜토리얼 초반에 언급했던 채터링 현상입니다. 다음 부분에서 어떻게 수정하는지 살펴보겠습니다.
아래 스크립트는 디바운스 기능을 가진 파이선 스크립트입니다. 일단 버튼을 누르거나 뗄 떼 200ms 시간 지연을 줌으로 바운스를 감지하지 못하게 하는 방법입니다.
"""
This Raspberry Pi code was developed by newbiely.com
This Raspberry Pi code is made available for public use without any restriction
For comprehensive instructions and wiring diagrams, please visit:
https://newbiely.com/tutorials/raspberry-pi/raspberry-pi-button-debounce
"""
import RPi.GPIO as GPIO
# Set the GPIO mode to BCM
GPIO.setmode(GPIO.BCM)
# Define the GPIO pin for your button
BUTTON_PIN = 16
# Define debounce time in milliseconds
DEBOUNCE_TIME_MS = 200 # 200 milliseconds
# Set the initial state and pull-up resistor for the button
GPIO.setup(BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
# Initialize the button state and previous state
button_state = GPIO.input(BUTTON_PIN)
prev_button_state = button_state
# Define a function to handle button presses
def button_callback(channel):
global button_state
button_state = GPIO.input(BUTTON_PIN)
# Add an event listener for the button press
GPIO.add_event_detect(BUTTON_PIN, GPIO.BOTH, callback=button_callback, bouncetime=DEBOUNCE_TIME_MS)
try:
# Main loop
while True:
# Check if the button state has changed
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:
# Clean up GPIO on exit
GPIO.cleanup()
아래 스크립트는 버튼 여러개에 대한 디바운스 기능을 가진 스크립트입니다.
"""
This Raspberry Pi code was developed by newbiely.com
This Raspberry Pi code is made available for public use without any restriction
For comprehensive instructions and wiring diagrams, please visit:
https://newbiely.com/tutorials/raspberry-pi/raspberry-pi-button-debounce
"""
import RPi.GPIO as GPIO
# Set the GPIO mode to BCM
GPIO.setmode(GPIO.BCM)
# Define the GPIO pins for your buttons
BUTTON_PIN_1 = 14
BUTTON_PIN_2 = 15
BUTTON_PIN_3 = 18
# Define debounce time in milliseconds
DEBOUNCE_TIME_MS = 200 # 200 milliseconds
# Set the initial state and pull-up resistor for the buttons
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)
# Initialize the button states and previous states for all buttons
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
# Define a function to handle button presses
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)
# Add event listeners for the buttons
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:
# Main loop
while True:
# Check if the button states have changed and print when they do
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:
# Clean up GPIO on exit
GPIO.cleanup()
위 코드에 대한 연결도는 아래와 같습니다.
고생하셨습니다.,
이글의 원문은 이 링크를 따라가면 보실 수 있습니다. 이어서 계속해야 하는데 왜 안하지?
'라즈베리파이 5' 카테고리의 다른 글
라즈베리파이 하둡/스파크 클러스터 구축하기 (1) | 2024.09.19 |
---|---|
라즈베리 파이 5 NVMe 프로토콜 M.2 솔리드 스테이트 드라이브용 어댑터 (0) | 2024.09.10 |
라즈베리파이5 ssd1306 OLED Test (4) | 2024.09.04 |
시드 스튜디오, 초소형 라즈베리파이 RP2350 기반 XIAO RP2350 발표 (3) | 2024.08.31 |
라즈베리파이 Python 8 - 버튼 (1) | 2024.08.26 |
라즈베리파이 python 7 - 교통 신호등 (0) | 2024.08.23 |
라즈베리파이 python 6 - RGB LED (0) | 2024.08.23 |
라즈베리파이 Python 5 - LED Fade 구현 (0) | 2024.08.22 |
더욱 좋은 정보를 제공하겠습니다.~ ^^