콘텐츠로 이동

버튼을 읽다 - 디지털 입력

🎯 이 장에서 배우는 것

  • 디지털 입력이 무엇인지 이해하고 버튼 상태(눌림/안 눌림)를 읽을 수 있다
  • 버튼을 눌렀을 때 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)

비유로 시작: 토글은 마치 형광등 스위치와 같아. 한 번 누르면 켜지고, 다시 누르면 꺼지지.

정확히 말하면: 토글은 버튼을 누를 때마다 상태가 반대로 바뀌는 동작이야.

버튼 누름 #1:  OFF → ON   (켜짐!)
버튼 누름 #2:  ON → OFF   (꺼짐!)
버튼 누름 #3:  OFF → ON   (다시 켜짐!)

단순 버튼 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! ←