버튼을 읽다 - 디지털 입력¶
🎯 이 장에서 배우는 것¶
- 디지털 입력이 무엇인지 이해하고 버튼 상태(눌림/안 눌림)를 읽을 수 있다
- 버튼을 눌렀을 때 LED가 켜지거나 부저가 울리게 만들 수 있다
- 버튼을 누를 때마다 LED가 켜졌다 꺼졌다 하는 '토글' 기능을 구현할 수 있다
- 버튼 바운싱 현상을 이해하고 해결할 수 있다
💡 왜 이걸 배우나요?¶
지금까지 우리는 Pico에게 일방적으로 명령만 내렸어. "LED 켜", "LED 꺼", "깜빡여"... Pico는 우리가 시킨 대로만 했지, 우리의 반응을 알 수 없었어.
하지만 진짜 유용한 시스템은 사용자의 입력에 반응해야 해!
지금까지 (출력만) 앞으로 (입력 + 출력)
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Pico │ → LED 켜 │ 버튼 │ → │ Pico │ → LED 켜
│ │ │ (입력) │ │ (처리) │ → 부저 울림
└─────────┘ └─────────┘ └─────────┘
일방적 명령 사용자 반응에 따라 다르게 동작!
실제로 어디에 쓰일까? - 🚦 횡단보도 버튼 → 신호등 바뀜 - 🎮 게임 컨트롤러 → 캐릭터 움직임 - 🔔 초인종 → 벨 소리 - ⏸️ 음악 플레이어 재생/정지 버튼
이번 챕터에서 버튼을 배우면, 드디어 입력 → 처리 → 출력의 완전한 사이클을 완성하게 돼!
📚 핵심 개념¶
개념 1: 디지털 입력¶
비유로 시작: 디지털 입력은 마치 Yes/No 질문과 같아. - "버튼 눌렸어?" → "응(1)" 또는 "아니(0)" - "문 열렸어?" → "응(1)" 또는 "아니(0)"
정확히 말하면: 디지털 입력은 두 가지 상태(0 또는 1)만 읽을 수 있는 입력 방식이야. - 0 (LOW, False): 버튼 안 눌림, 스위치 꺼짐 - 1 (HIGH, True): 버튼 눌림, 스위치 켜짐
예를 들어:
버튼 상태 Pico가 읽는 값
┌─────────┐ ┌─────────┐
│ ○ │ → │ 0 │ (안 눌림)
│ 안눌림 │ │ LOW │
└─────────┘ └─────────┘
┌─────────┐ ┌─────────┐
│ ● │ → │ 1 │ (눌림)
│ 눌림 │ │ HIGH │
└─────────┘ └─────────┘
쉽게 말하면: 버튼은 0과 1, 딱 두 가지 신호만 보내는 가장 단순한 입력 장치야.
개념 2: Pull-up과 Pull-down 저항¶
버튼을 연결할 때 한 가지 문제가 있어. 버튼을 안 눌렀을 때 전선이 어디에도 연결되지 않으면, Pico는 뭘 읽어야 할지 몰라서 이상한 값(0도 1도 아닌)이 나올 수 있어.
비유로 시작: 버튼은 마치 문과 같아. 문이 열려 있으면(버튼 안 눌림) 바람이 어디로 불지 모르지. 그래서 "기본적으로 바람이 이쪽으로 분다"라고 정해주는 게 필요해.
Pull-up 저항 (우리가 사용할 방식)
───────────────────────────────
3.3V
│
├──[저항]──┬── GPIO 핀 (입력)
│
[버튼]
│
GND
버튼 안 눌림: GPIO = 1 (3.3V로 끌어올려짐)
버튼 눌림: GPIO = 0 (GND로 연결됨)
다행히! Pico 내부에 이미 Pull-up/Pull-down 저항이 있어서, 코드에서 간단히 설정할 수 있어.
쉽게 말하면: Pull-up 저항은 "버튼 안 눌리면 기본값 1"로 정해주는 장치야.
개념 3: 버튼 바운싱 (Bouncing)¶
비유로 시작: 버튼을 누르는 건 마치 탁구공을 바닥에 던지는 것과 같아. 한 번 던졌지만 공은 통통 여러 번 튀지?
정확히 말하면: 물리적인 버튼은 눌리는 순간 내부 접점이 몇 밀리초 동안 여러 번 접촉했다 떨어졌다를 반복해. 사람 눈에는 "한 번 누름"이지만, 아주 빠른 Pico는 "여러 번 눌림"으로 인식할 수 있어.
사람이 보는 것: 버튼 한 번 "꾹"
────────────────
Pico가 보는 것: 1-0-1-0-1-1-1-1-1
││││└───────────── 안정적으로 눌림
││││
└┴┴┴────────────── 바운싱! (여러 번 튄 것처럼 보임)
시간: 약 5~20ms 동안 발생
해결 방법 (디바운싱): 1. 하드웨어 방식: 커패시터 추가 (우리는 안 함) 2. 소프트웨어 방식: 짧은 시간 대기 후 다시 확인 (우리가 사용할 방법!)
쉽게 말하면: 버튼 누르면 실제로는 아주 짧은 시간 동안 "통통통" 튀어. 이걸 무시하는 처리가 필요해.
개념 4: 토글 (Toggle)¶
비유로 시작: 토글은 마치 형광등 스위치와 같아. 한 번 누르면 켜지고, 다시 누르면 꺼지지.
정확히 말하면: 토글은 버튼을 누를 때마다 상태가 반대로 바뀌는 동작이야.
단순 버튼 vs 토글 버튼: | 방식 | 동작 | 예시 | |------|------|------| | 단순 버튼 | 누르는 동안만 켜짐 | 초인종, 자동차 경적 | | 토글 버튼 | 누를 때마다 상태 전환 | 전등 스위치, 음악 재생/정지 |
쉽게 말하면: 토글은 "누를 때마다 ON↔OFF 전환"이야.
🔧 준비물¶
하드웨어¶
| 부품 | 수량 | 설명 |
|---|---|---|
| Raspberry Pi Pico | 1 | 메인 보드 |
| Grove Shield for Pico | 1 | 센서 연결용 |
| Grove 버튼 | 1 | 디지털 입력 |
| Grove LED (빨강) | 1 | 출력 확인용 |
| Grove 부저 | 1 | 소리 출력용 |
| Grove 케이블 | 3 | 연결용 |
연결 다이어그램¶
┌─────────────────────────────────────────────────────────────┐
│ Grove Shield for Pico │
├─────────────────────────────────────────────────────────────┤
│ │
│ D16 ──────── Grove 버튼 (디지털 입력) │
│ │
│ D18 ──────── Grove LED (디지털 출력) │
│ │
│ D20 ──────── Grove 부저 (디지털 출력) │
│ │
└─────────────────────────────────────────────────────────────┘
※ Grove 케이블로 연결하면 전원(VCC, GND)은 자동 연결됨
🔨 따라하기¶
Step 1: 버튼 상태 읽기 (기본)¶
목표: 버튼이 눌렸는지 안 눌렸는지 확인하기
# === WHAT: 버튼 상태를 읽어서 출력하는 코드 ===
# 버튼을 누르면 0, 떼면 1이 출력됩니다 (Pull-up 방식)
from machine import Pin # GPIO 핀을 제어하기 위한 모듈
import time # 시간 관련 기능 (대기)
# --- WHY: 버튼을 입력으로 설정해야 상태를 읽을 수 있음 ---
# Pin.IN: 이 핀을 "입력"으로 사용하겠다
# Pin.PULL_UP: 내부 풀업 저항 사용 (버튼 안 누르면 1)
button = Pin(16, Pin.IN, Pin.PULL_UP)
# 반복해서 버튼 상태 확인
while True:
# HOW: button.value()는 버튼 상태를 0 또는 1로 반환
state = button.value()
# 상태 출력
print(f"버튼 상태: {state}")
# 0.1초 대기 (너무 빠르게 출력하면 읽기 어려움)
time.sleep(0.1)
실행 결과:
버튼 상태: 1 ← 버튼 안 누른 상태 (Pull-up이라 기본값 1)
버튼 상태: 1
버튼 상태: 1
버튼 상태: 0 ← 버튼 누른 순간!
버튼 상태: 0
버튼 상태: 0
버튼 상태: 1 ← 버튼 뗀 순간
버튼 상태: 1
여기서 잠깐! 🤔
Pull-up 방식에서는 버튼을 누르면 0, 떼면 1이야. 직관과 반대라서 헷갈릴 수 있어!
버튼 상태 value() 값 이유 안 누름 1 (HIGH) 풀업 저항이 3.3V로 끌어올림 누름 0 (LOW) GND로 연결되어 전압 0
Step 2: 버튼으로 LED 제어하기 (누르는 동안 켜짐)¶
목표: 버튼을 누르고 있는 동안 LED가 켜지게 만들기
# === WHAT: 버튼을 누르면 LED가 켜지는 코드 ===
# 초인종처럼 누르는 동안만 반응합니다
from machine import Pin
import time
# --- WHY: 입력(버튼)과 출력(LED)을 각각 설정 ---
button = Pin(16, Pin.IN, Pin.PULL_UP) # 버튼 (입력)
led = Pin(18, Pin.OUT) # LED (출력)
print("버튼을 누르면 LED가 켜집니다!")
while True:
# HOW: 버튼 상태에 따라 LED 제어
if button.value() == 0: # 버튼 눌림 (Pull-up이라 0이 눌림)
led.value(1) # LED 켜기
print("LED ON!")
else: # 버튼 안 눌림
led.value(0) # LED 끄기
time.sleep(0.05) # 50ms 대기
실행 결과: ``` 버튼을 누르면 LED가 켜집니다! LED ON! ←