콘텐츠로 이동

Chapter 03: 버튼과 대화 - 입력 받기


🎯 이 장에서 배우는 것

  • [ ] Pin.IN과 PULL_DOWN의 개념을 설명할 수 있다
  • [ ] Grove 버튼의 상태를 읽을 수 있다
  • [ ] if문으로 버튼에 따른 LED 제어를 구현할 수 있다
  • [ ] 버튼 토글 기능을 만들 수 있다
  • [ ] 디바운싱이 왜 필요한지 이해할 수 있다

💡 왜 이걸 배우나요?

지금까지 우리는 피코에게 일방적으로 명령만 내렸어. "LED 켜!", "1초 기다려!", "LED 꺼!" 이런 식으로.

그런데 생각해봐. 너희가 쓰는 모든 전자기기는 사용자의 입력을 받아서 동작하잖아?

  • 🎮 게임 컨트롤러: 버튼을 누르면 캐릭터가 점프
  • 💡 방 스위치: 누르면 불이 켜지고, 다시 누르면 꺼짐
  • 📱 스마트폰: 터치하면 앱이 실행

입력 없이는 진정한 인터랙션이 없어!

이번 장에서는 피코가 "사용자가 버튼을 눌렀네? 그럼 이렇게 해야지!"라고 스스로 판단하게 만들 거야. 이게 바로 디지털 입력의 시작이야.

flowchart LR A[👆 버튼 누름] --> B[🔍 피코가 감지] B --> C[🤔 if문으로 판단] C --> D[💡 LED 켜기] style A fill:#e3f2fd,stroke:#1976d2,stroke-width:2px style B fill:#fff3e0,stroke:#f57c00,stroke-width:2px style C fill:#fce4ec,stroke:#c2185b,stroke-width:2px style D fill:#e8f5e9,stroke:#388e3c,stroke-width:2px

📚 핵심 개념

개념 1: 디지털 입력 (Digital Input)

비유로 시작: 디지털 입력은 마치 예/아니오 질문과 같아. "버튼 눌렸어?" → "응(1)" 또는 "아니(0)". 중간은 없어!

정확한 정의: 디지털 입력이란 0(LOW) 또는 1(HIGH) 두 가지 상태만 읽어오는 것이야. 피코는 핀에 전압이 걸려있는지(1) 아닌지(0)를 판단해.

예시로 확인:

버튼 안 눌림 → 전압 없음 → 0 (LOW)
버튼 눌림    → 전압 있음 → 1 (HIGH)

쉽게 말하면: 버튼이 눌렸는지 아닌지를 0과 1로 읽어오는 것!


개념 2: Pin.IN과 Pin.OUT의 차이

비유로 시작: - Pin.OUT스피커야 - 피코가 바깥 세상에 말하는 것 (LED 켜기) - Pin.IN마이크야 - 바깥 세상의 소리를 듣는 것 (버튼 읽기)

flowchart TB subgraph 출력["📤 출력 (Pin.OUT)"] A[피코] -->|"전기 보내기"| B[💡 LED] end subgraph 입력["📥 입력 (Pin.IN)"] C[🔘 버튼] -->|"전기 받기"| D[피코] end style A fill:#e3f2fd,stroke:#1976d2 style B fill:#fff9c4,stroke:#f9a825 style C fill:#f3e5f5,stroke:#7b1fa2 style D fill:#e3f2fd,stroke:#1976d2

정확한 정의: - Pin.OUT: 피코가 핀으로 전기 신호를 내보내는 모드 - Pin.IN: 피코가 핀에서 전기 신호를 읽어오는 모드

쉽게 말하면: OUT은 말하기, IN은 듣기!


개념 3: PULL_DOWN과 PULL_UP

비유로 시작: 버튼이 안 눌렸을 때, 핀은 붕 떠있는 상태가 돼. 마치 라디오 주파수를 안 맞췄을 때 지지직거리는 것처럼, 0인지 1인지 불안정해져.

flowchart LR subgraph 문제["❓ 문제 상황"] A[버튼 안 눌림] --> B["핀 상태: ???"] end subgraph 해결["✅ PULL_DOWN 해결"] C[버튼 안 눌림] --> D["핀 상태: 0"] E[버튼 눌림] --> F["핀 상태: 1"] end style A fill:#ffcdd2,stroke:#c62828 style B fill:#ffcdd2,stroke:#c62828 style C fill:#e8f5e9,stroke:#388e3c style D fill:#e8f5e9,stroke:#388e3c style E fill:#e8f5e9,stroke:#388e3c style F fill:#e8f5e9,stroke:#388e3c

정확한 정의: - PULL_DOWN: 버튼이 안 눌렸을 때 핀을 0(LOW)으로 고정 - PULL_UP: 버튼이 안 눌렸을 때 핀을 1(HIGH)으로 고정

우리가 쓸 것: Grove 버튼은 PULL_DOWN을 써. - 안 누름 → 0 - 누름 → 1

이게 직관적이잖아! 누르면 1, 안 누르면 0.

쉽게 말하면: PULL_DOWN은 "기본값을 0으로 잡아줘"라는 설정!


개념 4: value() 메서드

비유로 시작: value()온도계를 읽는 것과 같아. 온도계를 보면 "지금 25도구나"라고 알 수 있듯이, value()를 호출하면 "지금 버튼이 눌렸구나(1)" 또는 "안 눌렸구나(0)"를 알 수 있어.

정확한 정의: value() 메서드는 핀의 현재 상태를 읽어서 0 또는 1을 반환해.

예시로 확인:

button = Pin(20, Pin.IN, Pin.PULL_DOWN)
state = button.value()  # 0 또는 1 반환
print(state)  # 버튼 안 눌림: 0, 눌림: 1

쉽게 말하면: "지금 버튼 눌렸어?" 하고 물어보는 함수!


🔨 따라하기

Step 1: Grove 버튼 연결하기

목표: Grove 버튼을 피코에 연결하기

준비물

  • 라즈베리파이 피코 2W + Grove Shield
  • Grove 버튼 모듈
  • Grove 케이블

연결 방법

flowchart LR subgraph 피코["🔌 Grove Shield"] D20["D20 포트"] end subgraph 버튼["🔘 Grove 버튼"] BTN["버튼 모듈"] end D20 <-->|"Grove 케이블"| BTN style D20 fill:#e3f2fd,stroke:#1976d2,stroke-width:2px style BTN fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
  1. Grove 케이블의 한쪽을 버튼 모듈에 연결
  2. 다른 쪽을 Grove Shield의 D20 포트에 연결
  3. 끝! Grove 시스템이라 배선 실수가 없어서 편하지? 😊

💡 왜 D20 포트? D는 Digital의 약자야. 20번 GPIO 핀에 연결된 디지털 포트라는 뜻이야.


Step 2: 버튼 상태 읽기

목표: 버튼이 눌렸는지 안 눌렸는지 확인하기

코드:

# === WHAT: 버튼의 상태를 읽어서 출력하는 코드 ===
# 버튼을 누르면 1, 떼면 0이 출력돼요

# --- WHY: 왜 필요한지 ---
# 버튼이 제대로 연결됐는지 확인하고,
# 디지털 입력이 어떻게 동작하는지 이해하기 위해서예요

# HOW: 어떻게 동작하는지
from machine import Pin  # Pin 클래스 가져오기
import time              # 시간 관련 기능

# 버튼을 입력 모드로 설정 (GP20, 입력, 풀다운)
button = Pin(20, Pin.IN, Pin.PULL_DOWN)

# 무한 반복
while True:
    state = button.value()  # 버튼 상태 읽기 (0 또는 1)
    print("버튼 상태:", state)  # 상태 출력
    time.sleep(0.3)  # 0.3초 대기 (너무 빠르면 읽기 힘들어서)

실행 결과:

버튼 상태: 0
버튼 상태: 0
버튼 상태: 1    ← 버튼 누른 순간!
버튼 상태: 1
버튼 상태: 0    ← 버튼 뗀 순간
버튼 상태: 0

여기서 잠깐! 🤔

코드를 자세히 보자:

button = Pin(20, Pin.IN, Pin.PULL_DOWN)

부분 의미
20 GPIO 20번 핀 사용 (D20 포트)
Pin.IN 입력 모드 (버튼 읽기)
Pin.PULL_DOWN 기본값을 0으로 설정

실험해보기: 버튼을 꾹 누르고 있으면 계속 1이 출력되는지 확인해봐!


Step 3: if문으로 버튼 반응하기

목표: 버튼을 누르면 "눌림!", 떼면 "안 눌림!" 출력하기

코드:

# === WHAT: 버튼 상태에 따라 다른 메시지를 출력하는 코드 ===
# if문을 사용해서 조건에 따라 다르게 반응해요

# --- WHY: 왜 필요한지 ---
# 0과 1만으로는 불친절하잖아?
# 사람이 이해하기 쉬운 메시지로 바꿔주면 좋으니까!

# HOW: 어떻게 동작하는지
from machine import Pin
import time

button = Pin(20, Pin.IN, Pin.PULL_DOWN)

while True:
    if button.value() == 1:  # 버튼이 눌렸으면
        print("🔘 버튼 눌림!")
    else:                     # 버튼이 안 눌렸으면
        print("⚪ 버튼 안 눌림")
    time.sleep(0.3)

실행 결과:

⚪ 버튼 안 눌림
⚪ 버튼 안 눌림
🔘 버튼 눌림!
🔘 버튼 눌림!
⚪ 버튼 안 눌림

여기서 잠깐! 🤔

if문의 구조를 다시 보자:

if 조건:
    # 조건이 True일 때 실행
else:
    # 조건이 False일 때 실행

button.value() == 1은 "버튼 값이 1이야?"라고 묻는 거야. - 맞으면(True): "눌림!" 출력 - 틀리면(False): "안 눌림" 출력


Step 4: 버튼으로 LED 제어하기

목표: 버튼을 누르는 동안 LED가 켜지고, 떼면 꺼지기

추가 연결

flowchart TB subgraph 피코["🔌 Grove Shield"] D20["D20 포트<br/>(버튼)"] D16["D16 포트<br/>(LED)"] end subgraph 부품들["🔧 부품"] BTN["🔘 버튼"] LED["💡 LED"] end D20 <--> BTN D16 <--> LED style D20 fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px style D16 fill:#fff9c4,stroke:#f9a825,stroke-width:2px style BTN fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px style LED fill:#fff9c4,stroke:#f9a825,stroke-width:2px
  • Grove 버튼 → D20 포트
  • Grove LED → D16 포트

코드:

# === WHAT: 버튼을 누르면 LED가 켜지는 코드 ===
# 버튼을 누르고 있는 동안만 LED가 켜져요

# --- WHY: 왜 필요한지 ---
# 입력(버튼)과 출력(LED)을 연결하는 가장 기본적인 예제예요
# 이게 모든 인터랙티브 시스템의 기초야!

# HOW: 어떻게 동작하는지
from machine import Pin
import time

# 버튼 설정 (입력)
button = Pin(20, Pin.IN, Pin.PULL_DOWN)

# LED 설정 (출력)
led = Pin(16, Pin.OUT)

while True:
    if button.value() == 1:  # 버튼 눌림
        led.on()              # LED 켜기
        print("💡 LED ON")
    else:                     # 버튼 안 눌림
        led.off()             # LED 끄기
        print("⬛ LED OFF")
    time.sleep(0.1)

실행 결과:

⬛ LED OFF
⬛ LED OFF
💡 LED ON     ← 버튼 누르는 순간, LED도 켜짐!
💡 LED ON
⬛ LED OFF    ← 버튼 떼는 순간, LED도 꺼짐!

여기서 잠깐! 🤔

지금 만든 건 손전등 같은 거야! 버튼 누르고 있어야 불이 켜지지.

그런데 실제 방 스위치는 어때? 한 번 누르면 켜지고, 다시 누르면 꺼지잖아? 이걸 토글(Toggle) 기능이라고 해. 다음 단계에서 만들어보자!


Step 5: 토글 기능 만들기

목표: 버튼을 한 번 누르면 LED가 켜지고, 다시 누르면 꺼지기

핵심 아이디어:

flowchart TB A["🔘 버튼 누름"] --> B{"LED 상태?"} B -->|"꺼져 있음"| C["💡 켜기"] B -->|"켜져 있음"| D["⬛ 끄기"] C --> E["상태 기억"] D --> E E --> F["다음 버튼 누름 대기"] style A fill:#e3f2fd,stroke:#1976d2,stroke-width:2px style B fill:#fff3e0,stroke:#f57c00,stroke-width:2px style C fill:#e8f5e9,stroke:#388e3c,stroke-width:2px style D fill:#ffebee,stroke:#c62828,stroke-width:2px style E fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px style F fill:#e0f2f1,stroke:#00695c,stroke-width:2px

코드:

# === WHAT: 버튼 토글로 LED를 제어하는 코드 ===
# 버튼을 누를 때마다 LED가 켜졌다 꺼졌다 해요

# --- WHY: 왜 필요한지 ---
# 실제 스위치처럼 동작하게 만들려면
# '상태'를 기억하고 있어야 해요

# HOW: 어떻게 동작하는지
from machine import Pin
import time

button = Pin(20, Pin.IN, Pin.PULL_DOWN)
led = Pin(16, Pin.OUT)

# LED 상태를 저장할 변수 (False = 꺼짐, True = 켜짐)
led_on = False

# 이전 버튼 상태 (버튼을 "새로 눌렀는지" 확인용)
last_button = 0

while True:
    current_button = button.value()  # 현재 버튼 상태

    # 버튼이 "방금" 눌렸을 때만 반응 (0→1로 바뀔 때)
    if current_button == 1 and last_button == 0:
        led_on = not led_on  # 상태 뒤집기 (True↔False)

        if led_on:
            led.on()
            print("💡 LED 켜짐!")
        else:
            led.off()
            print("⬛ LED 꺼짐!")

    last_button = current_button  # 현재 상태를 '이전 상태'로 저장
    time.sleep(0.05)  # 짧은 대기

실행 결과:

💡 LED 켜짐!     ← 첫 번째 버튼 누름
⬛ LED 꺼짐!     ← 두 번째 버튼 누름
💡 LED 켜짐!     ← 세 번째 버튼 누름
⬛ LED 꺼짐!     ← 네 번째 버튼 누름

여기서 잠깐! 🤔

이 코드의 핵심은 "버튼이 방금 눌렸는지" 감지하는 거야!

if current_button == 1 and last_button == 0:
current_button last_button 의미
0 0 계속 안 누르고 있음
1 0 방금 눌렸다!
1 1 계속 누르고 있음
0 1 방금 뗐다

우리가 원하는 건 "방금 눌렸을 때"만 반응하는 거니까, 1 and 0일 때만 토글해!

not 연산자:

led_on = not led_on
- not TrueFalse - not FalseTrue

즉, 상태를 뒤집어주는 거야!


Step 6: 디바운싱 이해하기

목표: 버튼 채터링 문제를 이해하고 해결하기

문제 상황

버튼을 한 번만 눌렀는데, LED가 여러 번 깜빡이는 경우가 있어. 왜 그럴까?

flowchart TB subgraph 이상적["🎯 이상적인 경우"] A1["버튼 누름"] --> A2["1"] A2 --> A3["버튼 뗌"] A3 --> A4["0"] end subgraph 현실["😵 현실 (채터링)"] B1["버튼 누름"] --> B2["1→0→1→0→1"] B2 --> B3["버튼 뗌"] B3 --> B4["0→1→0→1→0"] end style A1 fill:#e8f5e9,stroke:#388e3c style A2 fill:#e8f5e9,stroke:#388e3c style A3 fill:#e8f5e9,stroke:#388e3c style A4 fill:#e8f5e9,stroke:#388e3c style B1 fill:#ffcdd2,stroke:#c62828 style B2 fill:#ffcdd2,stroke:#c62828 style B3 fill:#ffcdd2,stroke:#c62828 style B4 fill:#ffcdd2,stroke:#c62828

원인: 버튼 내부의 금속 접점이 닿을 때 바운싱(튕김) 현상이 발생해. 아주 짧은 시간(수 밀리초) 동안 접촉과 분리가 여러 번 반복돼.

해결 방법 (디바운싱): 버튼 상태가 바뀐 후 잠깐 대기했다가 다시 확인하면 돼!

코드:

# === WHAT: 디바운싱이 적용된 버튼 토글 코드 ===
# 채터링 문제를 해결해서 안정적으로 동작해요

# --- WHY: 왜 필요한지 ---
# 버튼을 눌렀을 때 한 번만 정확히 인식하려면
# 디바운싱이 필수예요!

# HOW: 어떻게 동작하는지
from machine import Pin
import time

button = Pin(20, Pin.IN, Pin.PULL_DOWN)
led = Pin(16, Pin.OUT)

led_on = False
last_button = 0

while True:
    current_button = button.value()

    if current_button == 1 and last_button == 0:
        time.sleep(0.05)  # ⭐ 50ms 대기 (디바운싱)

        # 대기 후에도 여전히 눌려있는지 확인
        if button.value() == 1:
            led_on = not led_on

            if led_on:
                led.on()
                print("💡 LED 켜짐!")
            else:
                led.off()
                print("⬛ LED 꺼짐!")

            # 버튼을 뗄 때까지 대기
            while button.value() == 1:
                time.sleep(0.01)

    last_button = current_button
    time.sleep(0.01)

여기서 잠깐! 🤔

디바운싱의 핵심은: 1. 버튼이 눌렸다고 감지되면 50ms 대기 2. 대기 후에도 여전히 눌려있으면 진짜 눌린 거로 판단 3. 버튼을 뗄 때까지 대기해서 중복 인식 방지

💡 50ms는 어떻게 정한 거야? 대부분의 버튼 바운싱은 10~50ms 내에 끝나. 50ms면 거의 모든 버튼에서 안정적이야!


📝 전체 코드

기본 버튼-LED 제어 (step2_button_led.py)

# === 버튼으로 LED 제어하기 ===
# 버튼을 누르고 있으면 LED가 켜지고, 떼면 꺼집니다.
# 
# 연결:
#   - Grove 버튼 → D20 포트
#   - Grove LED  → D16 포트

from machine import Pin
import time

# --- 핀 설정 ---
button = Pin(20, Pin.IN, Pin.PULL_DOWN)  # 버튼: 입력, 풀다운
led = Pin(16, Pin.OUT)                    # LED: 출력

# --- 메인 루프 ---
while True:
    if button.value() == 1:  # 버튼 눌림
        led.on()
    else:                     # 버튼 안 눌림
        led.off()
    time.sleep(0.05)

토글 기능 + 디바운싱 (step4_debounce.py)

# === 디바운싱이 적용된 버튼 토글 ===
# 버튼을 누를 때마다 LED가 켜졌다 꺼졌다 합니다.
# 채터링 문제를 해결해서 안정적으로 동작합니다.
#
# 연결:
#   - Grove 버튼 → D20 포트
#   - Grove LED  → D16 포트

from machine import Pin
import time

# --- 핀 설정 ---
button = Pin(20, Pin.IN, Pin.PULL_DOWN)
led = Pin(16, Pin.OUT)

# --- 상태 변수 ---
led_on = False      # LED 상태 (False=꺼짐, True=켜짐)
last_button = 0     # 이전 버튼 상태

# --- 메인 루프 ---
while True:
    current_button = button.value()

    # 버튼이 방금 눌렸을 때 (0→1)
    if current_button == 1 and last_button == 0:
        time.sleep(0.05)  # 디바운싱 대기

        # 여전히 눌려있으면 진짜 눌린 것
        if button.value() == 1:
            led_on = not led_on  # 상태 토글

            if led_on:
                led.on()
                print("💡 LED 켜짐!")
            else:
                led.off()
                print("⬛ LED 꺼짐!")

            # 버튼 뗄 때까지 대기
            while button.value() == 1:
                time.sleep(0.01)

    last_button = current_button
    time.sleep(0.01)

⚠️ 자주 하는 실수

실수 1: Pin.OUT으로 버튼 설정하기

증상: 버튼을 눌러도 아무 반응이 없음

원인: 버튼은 입력 장치인데 출력 모드로 설정함

해결:

# ❌ 잘못된 코드
button = Pin(20, Pin.OUT)  # 출력 모드 - 틀림!

# ✅ 올바른 코드
button = Pin(20, Pin.IN, Pin.PULL_DOWN)  # 입력 모드 + 풀다운


실수 2: PULL_DOWN 빼먹기

증상: 버튼을 안 눌러도 값이 불안정하게 바뀜 (0과 1이 랜덤하게 출력)

원인: 풀업/풀다운 없이 핀이 플로팅(떠 있는) 상태

해결:

# ❌ 잘못된 코드
button = Pin(20, Pin.IN)  # PULL_DOWN 없음!

# ✅ 올바른 코드
button = Pin(20, Pin.IN, Pin.PULL_DOWN)  # 풀다운으로 안정화


실수 3: value() 괄호 빼먹기

증상: <bound_method> 같은 이상한 메시지가 출력됨

원인: value는 메서드(함수)인데 괄호 없이 호출함

해결:

# ❌ 잘못된 코드
state = button.value  # 괄호 없음!
print(state)  # <bound_method> 출력됨

# ✅ 올바른 코드
state = button.value()  # 괄호 필수!
print(state)  # 0 또는 1 출력됨


실수 4: 토글에서 이전 상태 업데이트 안 하기

증상: 버튼을 누르고 있으면 계속 토글됨 (깜빡깜빡)

원인: last_button을 업데이트하지 않아서 매 루프마다 "새로 눌림"으로 인식

해결:

# ❌ 잘못된 코드
while True:
    if button.value() == 1 and last_button == 0:
        led_on = not led_on
        # last_button 업데이트 빼먹음!
    time.sleep(0.05)

# ✅ 올바른 코드
while True:
    current_button = button.value()
    if current_button == 1 and last_button == 0:
        led_on = not led_on
    last_button = current_button  # 반드시 업데이트!
    time.sleep(0.05)


실수 5: GPIO 번호 vs 물리적 핀 번호 혼동

증상: 연결은 제대로 했는데 동작 안 함

원인: Grove Shield의 D20은 GPIO 20번을 의미해. 피코 보드의 물리적 핀 번호와 다름!

해결:

# Grove Shield D20 포트 사용 시
button = Pin(20, Pin.IN, Pin.PULL_DOWN)  # GPIO 20

# Grove Shield D16 포트 사용 시
led = Pin(16, Pin.OUT)  # GPIO 16

💡 기억하기: Grove Shield를 쓰면 포트 번호 = GPIO 번호야!


✅ 스스로 점검하기

질문 1: Pin.IN과 Pin.OUT의 차이는?

정답 확인 - **Pin.IN**: 외부 장치(버튼, 센서)에서 **신호를 읽어오는** 입력 모드 - **Pin.OUT**: 외부 장치(LED, 모터)에 **신호를 보내는** 출력 모드 버튼처럼 "눌렀는지 아닌지" 확인할 때는 `Pin.IN`, LED처럼 "켜라/꺼라" 명령할 때는 `Pin.OUT`을 써!

질문 2: PULL_DOWN을 쓰면 버튼을 안 눌렀을 때 value()는?

정답 확인 **0**을 반환해! PULL_DOWN은 "기본값을 0(LOW)으로 고정"하는 설정이야. - 버튼 안 누름 → 0 - 버튼 누름 → 1 직관적이라서 기억하기 쉽지?

질문 3: 토글 기능에서 last_button 변수는 왜 필요해?

정답 확인 버튼이 **"방금 눌렸는지"** 알기 위해서야! 버튼을 꾹 누르고 있으면 `value()`는 계속 1을 반환해. 만약 `last_button` 없이 "값이 1이면 토글"로 만들면, 누르고 있는 동안 계속 토글돼서 LED가 미친 듯이 깜빡여. `last_button`으로 **이전 상태**를 기억해서: - 이전: 0, 현재: 1 → 방금 눌렸다! ✅ 토글 - 이전: 1, 현재: 1 → 계속 누르고 있음, 무시

질문 4: 디바운싱이 필요한 이유는?

정답 확인 버튼의 물리적인 **바운싱(채터링)** 현상 때문이야! 버튼 내부의 금속 접점이 닿을 때 **미세하게 튕기면서** 아주 짧은 시간 동안 여러 번 접촉/분리가 반복돼. 이걸 피코는 "여러 번 눌렸다"고 인식할 수 있어. **해결**: 버튼이 눌렸다고 감지되면 50ms 정도 기다렸다가 다시 확인!

🚀 더 해보기

도전 1: 두 개의 버튼으로 LED 밝기 조절 (쉬움)

요구사항: 버튼 A를 누르면 밝아지고, 버튼 B를 누르면 어두워지는 LED - 힌트: PWM 사용 (2장 복습!) - 추가 연결: Grove 버튼 하나 더 (D18 포트)

# 힌트 코드
from machine import Pin, PWM

button_up = Pin(20, Pin.IN, Pin.PULL_DOWN)
button_down = Pin(18, Pin.IN, Pin.PULL_DOWN)
led_pwm = PWM(Pin(16))
led_pwm.freq(1000)

brightness = 32768  # 중간값으로 시작

도전 2: 버튼 길게 누르기 감지 (중간)

요구사항: - 짧게 누르면(0.5초 미만): LED 토글 - 길게 누르면(0.5초 이상): LED 깜빡이기 모드

# 힌트 코드
import time

press_start = 0  # 버튼 누른 시각

# 버튼 눌렸을 때 시작 시간 기록
if current_button == 1 and last_button == 0:
    press_start = time.ticks_ms()

# 버튼 뗐을 때 얼마나 눌렸는지 계산
if current_button == 0 and last_button == 1:
    duration = time.ticks_diff(time.ticks_ms(), press_start)
    if duration < 500:
        # 짧게 누름
    else:
        # 길게 누름

도전 3: 모스 부호 입력기 ⭐ (어려움)

요구사항: 버튼으로 모스 부호를 입력하면 알파벳으로 변환! - 짧게 누름: 점(.) - 길게 누름: 선(-) - 오래 안 누름: 문자 구분

모스 부호 예시:
A = .-
B = -...
S = ...
O = ---
SOS = ... --- ...

힌트:

morse_dict = {
    '.-': 'A',
    '-...': 'B',
    '...': 'S',
    '---': 'O',
    # ... 더 추가
}

current_morse = ""  # 현재 입력 중인 모스 부호


🔗 다음 장으로

이번 장에서 배운 것 ✅

  • Pin.IN: 외부 신호를 읽어오는 입력 모드
  • PULL_DOWN: 기본값을 0으로 고정하는 설정
  • value(): 핀의 현재 상태(0 또는 1) 읽기
  • if문: 조건에 따라 다른 동작 실행
  • 토글: 상태를 뒤집는 기능 구현
  • 디바운싱: 버튼 채터링 문제 해결

다음 장 미리보기 👀

Chapter 04: 센서 입문 - 세상을 느끼다

버튼은 0 또는 1, 두 가지 상태만 있었어. 하지만 세상의 대부분은 그렇게 딱 떨어지지 않아.

"지금 얼마나 밝아?" → 50? 1000? 30000? "온도가 몇 도야?" → 25.5도

이런 연속적인 값을 읽으려면 아날로그 입력이 필요해. 다음 장에서 조도 센서와 온습도 센서로 세상을 느껴보자! 🌡️💡