이번 예제에서는 LED가 꺼지는 순간 스위치 버튼을 빠르게 누르는 순발력 게임을 구현해 보겠습니다.
사람의 일반적인 반응속도는 200-250 ms 라고 합니다. 과연 이보다 빠르게 누를 수 있을까요?
0.2초 보다 짧은 시간으로 성공한 사람은 댓글에 기록을 남겨주세요.
준비물
LED 1개
330옴 저항 1개
스위치 버튼 2개
M2M 점퍼 와이어 다수
A Single-player Game
서킷 구성
1) LED : GP15 및 그라운드 연결. LED에 극성이 있으므로 긴다리(anode)를 GP15에 연결하는 것에 유의
2) 스위치 : GP14 및 3.3V 연결
왜 스위치에 3.3V를 연결할까?
모든 GPIO에는 보드 상에서 programmable 저항이 달려 있다. 모든 예제에서는 저항을 pull down 모드로 실행한다. 이말은 평소에 low level(0, False)로 낮춘 상태로 유지한다는 말이다. 스위치 버튼을 눌렀을 때는 반대로 high level(1, True)로 세팅하기 위해 스위치 버튼 다른쪽 다리를 통해 3.3V 전압을 인가해 준다.
소스코드
import machine
import utime
import urandom # 랜덤 모듈
pressed = False
led = machine.Pin(15, machine.Pin.OUT) #LED는 GP15로 연결. OUTPUT 모드
button = machine.Pin(14, machine.Pin.IN, machine.Pin.PULL_DOWN) # 스위치버튼은 GP14로 연결. INPUT 모드, 풀다운 모드
def button_handler(pin):
global pressed
if not pressed:
pressed=True
timer_reaction = utime.ticks_diff(utime.ticks_ms(), timer_start) # 시작 시간과 차이 측정
print("Your reaction time was " + str(timer_reaction) + " milliseconds!")
led.value(1) # LED 켜짐
utime.sleep(urandom.uniform(5, 10)) #5초~10초로 랜덤하게 sleep
led.value(0) # LED 꺼짐
timer_start = utime.ticks_ms() # 시작 시간 기록
button.irq(trigger=machine.Pin.IRQ_RISING, handler=button_handler) # 스위치 버튼 인터럽트 구성, trigger : 언제 인터럽트가 활성화 되는지 handler : 인터럽트가 활성화 될 경우 실행되는 함수
인터럽트는 동작 방식이 _thread와는 다릅니다. _thread 모듈에서는 main-thread와 sub-thread에 해당되는 스크립트가 각각 별도로 독립적으로 동작하는 반면 인터럽트는 트리거 되는 순간 handler argument에서 정의된 함수가 실행이 됩니다. 해당 함수가 종료될 때까지 다른 스크립트는 동작하지 않고 정지됩니다.
button.irq(trigger=machine.Pin.IRQ_RISING, handler=button_handler)
Pin 클래스의 irq 메서드에 관한 자세한 설명은 아래 링크를 참조 바랍니다.
https://docs.micropython.org/en/latest/library/machine.Pin.html#machine.Pin.irq
class Pin – control I/O pins — MicroPython 1.19.1 documentation
© Copyright - The MicroPython Documentation is Copyright © 2014-2022, Damien P. George, Paul Sokolovsky, and contributors. Last updated on 18 Jun 2022.
docs.micropython.org
trigger : 인터럽트가 동작될 조건. 언제 인터럽트가 활성화 되는지 명시. 여기서는 IRQ_RISING 사용. 스위치 버튼이 눌려서 high level로 변경이 될 때 인터럽트 동작. 버튼 값이 바뀔때 동작하게 하려면 'or' 연산자인 | (shift + 원화 기호) 를 사용하여 IRQ_RISING과 IRQ_FALLING을 조건으로 넣는다.trigger = machine.pin.IRQ_RISING | machine.pin.IRQ_FALLING
handler : 인터럽트 발생시 실행될 함수
스크립트를 실행시키면 LED가 5~10초 동안 랜덤하게 점등이 된다. 불이 꺼지자마자 스위치 버튼을 누르면 LED가 꺼지고 몇초만에 버튼을 눌렀는지 shell 창에 문구가 출력되며 LED가 꺼진다.
도전과제
1) LED 점등 시간을 조절 해보자. 길게, 짧게
2) 버튼 스위치를 눌렀을때 나오는 메세지를 수정해 보자.
Two-Player Game
서킷구성
1) 스위치 : GP16 및 3.3V 연결
2) 나머지는 single player game과 동일
소스코드
import machine
import utime
import urandom # 랜덤 모듈
pressed = False
led = machine.Pin(15, machine.Pin.OUT) #LED는 GP15로 연결. OUTPUT 모드
left_button = machine.Pin(14, machine.Pin.IN, machine.Pin.PULL_DOWN) # left 스위치 버튼은 GP14로 연결. INPUT 모드, 풀다운 모드
right_button = machine.Pin(16, machine.Pin.IN, machine.Pin.PULL_DOWN) # right 스위치 버튼은 GP16로 연결. INPUT 모드, 풀다운 모드
def button_handler(pin):
global pressed
if not pressed:
pressed=True
timer_reaction = utime.ticks_diff(utime.ticks_ms(), timer_start) # 시작 시간과 차이 측정
print("Your reaction time was " + str(timer_reaction) + " milliseconds!")
led.value(1) # LED 켜짐
utime.sleep(urandom.uniform(5, 10)) #5초~10초로 랜덤하게 sleep
led.value(0) # LED 꺼짐
timer_start = utime.ticks_ms() # 시작 시간 기록
left_button.irq(trigger=machine.Pin.IRQ_RISING, handler=button_handler) # 스위치 버튼 인터럽트 구성, trigger : 언제 인터럽트가 활성화 되는지 handler : 인터럽트가 활성화 될 경우 실행되는 함수
right_button.irq(trigger=machine.Pin.IRQ_RISING, handler=button_handler) # 스위치 버튼 인터럽트 구성, trigger : 언제 인터럽트가 활성화 되는지 handler : 인터럽트가 활성화 될 경우 실행되는 함수
둘이서 플레이 하기 위해 스위치 버튼을 한 개 더 추가하였습니다. 위의 스크립트 상에서 right_button을 선언해 주고 right_button.irq 메서드를 호출하였습니다.
그러나 여기서는 누가 이겼는지 알 수가 없으니 코드를 수정해 보겠습니다.
import machine
import utime
import urandom # 랜덤 모듈
pressed = False
led = machine.Pin(15, machine.Pin.OUT) #LED는 GP15로 연결. OUTPUT 모드
left_button = machine.Pin(14, machine.Pin.IN, machine.Pin.PULL_DOWN) # left 스위치 버튼은 GP14로 연결. INPUT 모드, 풀다운 모드
right_button = machine.Pin(16, machine.Pin.IN, machine.Pin.PULL_DOWN) # right 스위치 버튼은 GP16로 연결. INPUT 모드, 풀다운 모드
fastest_button = None
def button_handler(pin):
global pressed
if not pressed:
pressed=True
global fastest_button # fastest_button 전역 변수 추가
fastest_button = pin # button_handler 함수 호출에 사용된 pin을 저장
led.value(1) # LED 켜짐
utime.sleep(urandom.uniform(5, 10)) #5초~10초로 랜덤하게 sleep
led.value(0) # LED 꺼짐
timer_start = utime.ticks_ms() # 시작 시간 기록
left_button.irq(trigger=machine.Pin.IRQ_RISING, handler=button_handler) # 스위치 버튼 인터럽트 구성, trigger : 언제 인터럽트가 활성화 되는지 handler : 인터럽트가 활성화 될 경우 실행되는 함수
right_button.irq(trigger=machine.Pin.IRQ_RISING, handler=button_handler) # 스위치 버튼 인터럽트 구성, trigger : 언제 인터럽트가 활성화 되는지 handler : 인터럽트가 활성화 될 경우 실행되는 함수
while fastest_button is None: # 어떤 버튼도 눌리지 않았으면
utime.sleep(1) # 1초 대기
if fastest_button is left_button: # left 버튼이 먼저 눌렸으면
print("Left Player wins!") # left player 이김
elif fastest_button is right_button: # right 버튼이 먼저 눌렸으면
print("Right Player wins!") # right player 이김
fastest_button 객체를 선언하고 (fastest_button=None) 인터럽트를 발생시킨 pin을 저장합니다. (fastest_button = pin)
그리고 각 스위치 버튼에 따라서 문구를 다르게 출력합니다. (마지막에 if 구문)
스크립트를 실행하면 위처럼 누가 이겼는지 알 수 있는 문구가 출력이 됩니다.
도전과제
1) 세명이 같이 플레이 할 수 있도록 세번째 버튼 추가하기
2) 몇 초만에 눌렀는지 타이밍을 같이 표기하기
'MicroPython' 카테고리의 다른 글
Chapter 5 - 신호등 제어기 (0) | 2022.06.20 |
---|---|
Chapter 4 Physical computing w/ Raspberry Pi Pico (0) | 2022.06.17 |
Chapter 3 Physical computing - (3) (0) | 2022.06.16 |
Chapter 3 Physical computing - (2) (0) | 2022.06.16 |
Chapter 3 Physical computing - (1) (0) | 2022.06.16 |