스위치를 이용한 3 Color LED 제어 > 스마트기기시스템

본문 바로가기

[실습] 스위치를 이용한 3 Color LED 제어

필기자
23시간 36분전 79 2
  • - 첨부파일 : KakaoTalk_20240223_175217786.mp4 (4.7M) - 다운로드

본문

스위치를 이용한 3 Color LED 제어

목 적
  • 라즈베리파이에 GPIO 이벤트 방식에 대해 이해한다.
  • 라즈베리파이에 복합적인 액츄레이터 모듈 구현에 대해 이해한다.
목 차
1. LED 버튼 앳츄레이터 묘듈 설치
2. LED 버튼 앳츄레이터 묘듈 구동

1. LED 버튼 앳츄레이터 뮤듈 설치
  • YwRobot LED 버튼 모듈
    • 내장된 LED를 가진 푸시버튼 스위치로 버튼을 누르면 LED가 켜지거나 꺼진다.
    • 학습, 실험, 프로토타이핑에 주로 사용되며, 마이크로컨트롤러 보드에 쉽게 연결할 수 있다.
    • 전원(VCC), 접지(GND), 신호(OUT) 등의 핀을 포함하며, 디지털 입력으로 버튼 상태를 마이크로컨트롤러가 읽는다.
    • 다양한 전자 프로젝트에 사용자 인터페이스 요소로 활용된다.
    • GPIO 연결
      • GND  : Ground 접지(핀 14)
      • VCC : 5V Power(핀 2) -> 수정 3.3V Power
      • OUT : GPIO 18(핀 12)
3529946169_0pId3TWO_e01bf8bf7ec02ed55a1baca7f4c142d67dac00db.png


3529946169_GyRsgpez_f3fbdba5b3ef29dafd84b616093e6f6506a7db04.png

2. LED 버튼 앳츄레이터 묘듈 구동
  • 라즈베리파이 가상환경에서 파이썬 코딩
    • VSCode에서 3_color_led_switch.py 파일 생성
    • GPIO 17, 27, 22 핀을 출력 모드로 설정, GPIO 18 핀을 입력 모드로 설정
    • GPIO 18 핀의 이벤트에 따라 LED 색상 변경
3529946169_8tN9Xkxb_bfce1af2881b60ae159904631a1ad9d8cf242dbc.png

import RPi.GPIO as GPIO
import time
# 핀 번호 설정
BUTTON_PIN = 18
BLUE_PIN = 17
GREEN_PIN = 22
RED_PIN = 27
# 글로벌 변수
led_state = 0
# GPIO 설정 함수
def setup_gpio():
    GPIO.setwarnings(False)
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.setup(BLUE_PIN, GPIO.OUT)
    GPIO.setup(GREEN_PIN, GPIO.OUT)
    GPIO.setup(RED_PIN, GPIO.OUT)
# 모든 LED 끄는 함수
def turn_off_leds():
    global led_state
    led_state = 0
    GPIO.output(BLUE_PIN, GPIO.LOW)
    GPIO.output(GREEN_PIN, GPIO.LOW)
    GPIO.output(RED_PIN, GPIO.LOW)
# LED 상태 변경 함수
def change_led_state():
    global led_state
    led_state += 1
    if led_state > 3:
        led_state = 1
    if led_state == 1:
        GPIO.output(BLUE_PIN, GPIO.HIGH)
        GPIO.output(GREEN_PIN, GPIO.LOW)
        GPIO.output(RED_PIN, GPIO.LOW)
    elif led_state == 2:
        GPIO.output(BLUE_PIN, GPIO.LOW)
        GPIO.output(GREEN_PIN, GPIO.HIGH)
        GPIO.output(RED_PIN, GPIO.LOW)
    elif led_state == 3:
        GPIO.output(BLUE_PIN, GPIO.LOW)
        GPIO.output(GREEN_PIN, GPIO.LOW)
        GPIO.output(RED_PIN, GPIO.HIGH)
# 버튼 처리 함수 (기존 callback 그대로 유지)
def button_callback(channel):
    start_time = time.time()
    # 버튼 눌린 상태 유지 확인
    while GPIO.input(channel) == GPIO.LOW:
        time.sleep(0.01)
    button_press_duration = time.time() - start_time
    if button_press_duration >= 1:
        turn_off_leds()
    else:
        change_led_state()
# GPIO 종료 함수
def cleanup_gpio():
    GPIO.cleanup()
# 메인 함수 (polling 적용)
def main():
    setup_gpio()
    turn_off_leds()
    prev_state = GPIO.input(BUTTON_PIN)
    try:
        while True:
            current_state = GPIO.input(BUTTON_PIN)
            # 버튼 눌림 감지 (HIGH → LOW)
            if prev_state == GPIO.HIGH and current_state == GPIO.LOW:
                button_callback(BUTTON_PIN)
            prev_state = current_state
            time.sleep(0.01)  # debounce + CPU 보호
    except KeyboardInterrupt:
        pass
    finally:
        cleanup_gpio()
# 실행
if __name__ == "__main__":
    main()
  • GPIO.add_event_detect()
    • GPIO 핀에 이벤트 감지(callback) 기능을 추가하는 데 사용된다.
    • 특정 핀의 상태 변경(예: 라이징 엣지, 폴링 엣지)을 비동기적으로 감지한다.
    • 변경이 감지될 때마다 지정된 콜백 함수를 자동으로 호출할 수 있다. 
인자 이름 데이터 타입 기능
channel int 이벤트 감지를 추가할 GPIO 핀의 번호.
GPIO.RISING, GPIO.FALLING, GPIO.BOTH   감지할 이벤트의 종류를 지정. RISING은 0에서 1로의 변화, FALLING은 1에서 0으로의 변화, BOTH는 둘 다 감지.
callback function 이벤트가 감지될 때 호출될 콜백 함수.
bouncetime int 선택적. 이벤트 콜백 호출 사이에 적용될 디바운스(신호안정) 시간(밀리초 단위).
 
이벤트 감지 플레그 설명
GPIO.RISING GPIO 핀의 신호가 LOW에서 HIGH로 변할 때
GPIO.FALLING GPIO 핀의 신호가 HIGH에서 LOW로 변할 때
GPIO.BOTH GPIO 핀의 신호가 변화할 때(LOW에서 HIGH 또는 HIGH에서 LOW)
 
  • 3_color_led_switch.py 실행
    • VSCode > 하단 터미널 > python 3_color_led_switch.py 실행
3529946169_KTd9sEcN_275a7ebde49aee1f93dc258ed78bec89b5dc3919.png

3529946169_EZT2jOSJ_31e3c0da6468f5f5477c2a0e14d0a80be2f6de15.gif

[문제: RGB LED 색상 조합 제어 실습]
  • 하나의 공통형 RGB LED를 사용하여, 버튼을 누를 때마다 LED 색상이 아래 순서대로 변경되도록 하시오.
    • 3_color_led_switch_ranibow.py 파일 생성
    • 버튼 누를 때마다 색상 변경 순서
      • 1. 빨강
      • 2. 초록
      • 3. 파랑
      • 4. 노랑
      • 5. 하늘
      • 6. 보라
      • 7. 흰색
      • 8. OFF
※ 버튼은 짧게 누를 때만 반응, 길게 눌렀을 때는 무시.
※ 버튼은 GPIO.FALLING 이벤트로 감지.
※ LED 색의 정보는 배열을[0~7] 활용 함. 


import RPi.GPIO as GPIO
import time
# 핀 설정
BUTTON_PIN = 18
RED_PIN = 27
GREEN_PIN = 22
BLUE_PIN = 17

# 상태 변수
led_state = 0  # 0: OFF, 1~7: 색 조합
# GPIO 설정
def setup_gpio():
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.setup(RED_PIN, GPIO.OUT, initial=GPIO.LOW)
    GPIO.setup(GREEN_PIN, GPIO.OUT, initial=GPIO.LOW)
    GPIO.setup(BLUE_PIN, GPIO.OUT, initial=GPIO.LOW)
# LED 색상 설정
def set_color(state):
    colors = (
        (0, 0, 0),  # off
        (1, 0, 0),  # 빨강
        (0, 1, 0),  # 초록
        (0, 0, 1),  # 파랑
        (1, 1, 0),  # 노랑
        (0, 1, 1),  # 하늘
        (1, 0, 1),  # 보라
        (1, 1, 1),  # 흰색
    )
    r, g, b = colors[state]
    #GPIO.output(RED_PIN, GPIO.HIGH if r else GPIO.LOW) # r == 1 ? GPIO.HIGH : GPIO.LOW
    #GPIO.output(GREEN_PIN, GPIO.HIGH if g else GPIO.LOW)
    #GPIO.output(BLUE_PIN, GPIO.HIGH if b else GPIO.LOW)
    #GPIO.output(RED_PIN, r) # r == 1 ? GPIO.HIGH : GPIO.LOW
    #GPIO.output(GREEN_PIN, g)
    #GPIO.output(BLUE_PIN, b)
    GPIO.output([RED_PIN, GREEN_PIN, BLUE_PIN], [r,g,b])

# 버튼 콜백
def button_callback(channel):
    global led_state
    start = time.time()
    while GPIO.input(BUTTON_PIN) == GPIO.LOW:
        time.sleep(0.01)
    duration = time.time() - start
    if duration < 1:
        led_state += 1
        if led_state > 7:
            led_state = 0
        set_color(led_state)
# 메인
def main():
    setup_gpio()
    GPIO.add_event_detect(BUTTON_PIN, GPIO.FALLING, callback=button_callback, bouncetime=300)
    try:
        while True:
            time.sleep(0.1)
    except KeyboardInterrupt:
        pass
    finally:
        GPIO.cleanup()
if __name__ == "__main__":
    main()

댓글목록2

필기자님의 댓글

필기자
23시간 36분전
cp -r /usr/lib/python3/dist-packages/RPi /home/pi/iot/iot/lib/python3.11/site-packages/
pip install lgpio
python -c "import RPi.GPIO as GPIO; print(GPIO.__file__)"

필기자님의 댓글

필기자
20시간 45분전
사용법
import RPi.GPIO as GPIO
import gpio_patch
GPIO.setwarnings(False)


#gpio_patch.py
import RPi.GPIO as GPIO
import time
import threading

_original_add_event_detect = GPIO.add_event_detect

# 등록된 핀 관리
_event_registry = {}
_polling_thread = None
_running = False

def _start_polling():
    global _polling_thread, _running

    if _polling_thread is not None:
        return

    _running = True

    def worker():
        prev_states = {}

        # 초기 상태 저장
        for pin in _event_registry:
            prev_states[pin] = GPIO.input(pin)

        while _running:
            for pin, cfg in _event_registry.items():
                curr = GPIO.input(pin)
                prev = prev_states[pin]

                edge = cfg["edge"]
                callback = cfg["callback"]
                last_time = cfg["last_time"]
                bouncetime = cfg["bouncetime"]

                trigger = False

                if edge == GPIO.FALLING and prev == 1 and curr == 0:
                    trigger = True
                elif edge == GPIO.RISING and prev == 0 and curr == 1:
                    trigger = True
                elif edge == GPIO.BOTH and prev != curr:
                    trigger = True

                now = time.time() * 1000

                if trigger:
                    if now - last_time >= bouncetime:
                        cfg["last_time"] = now
                        if callback:
                            callback(pin)

                prev_states[pin] = curr

            time.sleep(0.005)  # 고속 polling

    _polling_thread = threading.Thread(target=worker, daemon=True)
    _polling_thread.start()

def _safe_add_event_detect(pin, edge, callback=None, bouncetime=200):
    # 기존 제거
    try:
        GPIO.remove_event_detect(pin)
    except:
        pass

    # 정상 시도
    try:
        _original_add_event_detect(pin, edge,
                                  callback=callback,
                                  bouncetime=bouncetime)
        return
    except RuntimeError:
        pass

    # fallback 등록
    print(f"[FALLBACK] pin {pin} polling 등록")

    _event_registry[pin] = {
        "edge": edge,
        "callback": callback,
        "bouncetime": bouncetime,
        "last_time": 0
    }

    _start_polling()

# override
GPIO.add_event_detect = _safe_add_event_detect
게시판 전체검색