Chapter 02: LED의 세계 - 빛으로 말하기¶
🎯 이 장에서 배우는 것¶
- [ ] Pin 클래스를 사용하여 GPIO를 제어할 수 있다
- [ ] 내장 LED와 Grove LED를 제어할 수 있다
- [ ] time.sleep()으로 LED 패턴을 만들 수 있다
- [ ] for문을 활용해 반복적인 LED 동작을 구현할 수 있다
💡 왜 이걸 배우나요?¶
LED 제어는 피지컬 컴퓨팅의 "Hello World"야. 프로그래밍을 처음 배울 때 화면에 글자를 출력하는 것처럼, 하드웨어를 다룰 때는 LED를 켜는 것부터 시작해.
왜 LED일까? 🤔
- 즉각적인 피드백: 코드가 제대로 작동하는지 눈으로 바로 확인할 수 있어
- 단순하지만 강력: 켜고 끄는 것만으로도 신호등, 알림등, 상태 표시기를 만들 수 있어
- 기초가 탄탄해야: LED를 제어하는 원리를 알면 모터, 스피커 등 모든 출력 장치를 다룰 수 있어
실생활에서 LED는 어디에 쓰일까? - 📱 스마트폰 알림등 (문자가 오면 깜빡!) - 🚦 교통 신호등 - 🎄 크리스마스 트리 조명 - 🖥️ 컴퓨터 전원 표시등
오늘 배우는 Pin 클래스는 앞으로 센서를 읽고, 모터를 돌리고, 모든 하드웨어를 제어하는 기본 도구가 돼. 제대로 익혀두자!
📚 핵심 개념¶
개념 1: GPIO와 Pin 클래스¶
비유로 시작: GPIO는 마치 벽에 있는 전기 콘센트와 같아. 콘센트에 플러그를 꽂으면 전기가 흐르고, 빼면 전기가 끊기지? GPIO 핀도 마찬가지로 전기 신호를 내보내거나(출력) 받아들일 수(입력) 있어.
정확한 정의: GPIO(General Purpose Input/Output)는 범용 입출력 핀이야. 프로그래밍으로 이 핀들을 자유롭게 제어할 수 있어. MicroPython에서는 Pin 클래스를 사용해서 GPIO 핀을 제어해.
예시로 확인:
from machine import Pin
# GP16번 핀을 출력 모드로 설정
led = Pin(16, Pin.OUT)
# 핀에 전기 신호 보내기 (LED 켜기)
led.value(1) # 또는 led.on()
쉽게 말하면: Pin 클래스는 전기 스위치 리모컨이야. 코드로 스위치를 올리면(1) 전기가 흐르고, 내리면(0) 끊겨.
개념 2: 출력 모드 (Pin.OUT)¶
비유로 시작: 출력 모드는 마치 확성기와 같아. 우리가 말하면(코드 실행) 확성기가 소리를 내보내듯, 출력 모드의 핀은 전기 신호를 밖으로 내보내.
정확한 정의: Pin.OUT은 핀을 출력 모드로 설정해. 이 모드에서 핀은 HIGH(1, 3.3V) 또는 LOW(0, 0V) 신호를 내보낼 수 있어.
예시로 확인:
led = Pin(16, Pin.OUT) # 16번 핀을 출력 모드로!
led.value(1) # HIGH 신호 (3.3V 출력) → LED 켜짐
led.value(0) # LOW 신호 (0V 출력) → LED 꺼짐
쉽게 말하면: 출력 모드는 "내가 전기를 줄게!"라고 선언하는 거야.
개념 3: time.sleep() - 시간 제어¶
비유로 시작: time.sleep()은 마치 알람 시계의 스누즈 버튼과 같아. 누르면 잠시 멈췄다가 다시 진행하지?
정확한 정의: time.sleep(초)는 프로그램을 지정한 초(seconds) 만큼 일시 정지시켜. 이 시간 동안 코드는 아무것도 하지 않고 기다려.
예시로 확인:
import time
print("시작!")
time.sleep(2) # 2초 대기
print("2초 지났어!")
time.sleep(0.5) # 0.5초(500ms) 대기
print("0.5초 더 지났어!")
쉽게 말하면: 코드에게 "잠깐 쉬어!"라고 명령하는 거야.
개념 4: 내장 LED vs 외부 LED¶
피코에는 두 종류의 LED를 사용할 수 있어:
| 구분 | 내장 LED | Grove LED |
|---|---|---|
| 위치 | 피코 보드 위에 내장 | 별도 모듈로 연결 |
| 핀 번호 | "LED" 또는 25 |
연결한 포트 번호 (예: 16, 18) |
| 색상 | 초록색 | 빨강, 파랑 등 다양 |
| 특징 | 추가 연결 불필요 | 케이블로 연결 필요 |
🔨 따라하기¶
Step 1: 내장 LED 켜기¶
목표: 피코의 내장 LED를 코드로 켜보자!
코드:
# === WHAT: 피코 내장 LED 켜기 ===
# 피코 보드에 내장된 LED를 켜는 첫 번째 하드웨어 제어!
# --- WHY: 왜 이걸 먼저 할까? ---
# 1. 추가 부품 연결 없이 바로 테스트 가능
# 2. 피코가 제대로 연결됐는지 확인 가능
# 3. Pin 클래스 사용법을 가장 간단하게 배울 수 있어
# HOW: 어떻게 동작하는지
from machine import Pin # Pin 클래스를 machine 모듈에서 가져와
led = Pin("LED", Pin.OUT) # 내장 LED를 출력 모드로 설정
# "LED"는 피코 내장 LED의 특별한 이름
led.on() # LED 켜기! (led.value(1)과 같아)
실행 결과:
(아무 메시지 없음 - 하지만 피코 보드의 초록색 LED가 켜짐! ✨)
실행 방법: 1. Thonny에서 위 코드 입력 2. 초록색 ▶️ 실행 버튼 클릭 3. 피코 보드를 봐! 작은 초록불이 켜졌어? 🎉
여기서 잠깐! 🤔
"LED"라는 이름이 신기하지? 피코 2W에서는 내장 LED를 이렇게 문자열로 지정할 수 있어. 숫자 25를 써도 똑같이 작동해:
led = Pin(25, Pin.OUT) # 이것도 내장 LED야!
Step 2: LED 끄기¶
목표: 켜진 LED를 끄는 법을 배우자
코드:
# === WHAT: LED 끄기 ===
# 켜진 LED를 끄는 방법
# --- WHY: 왜 끄는 법도 배워야 할까? ---
# 켜기만 하면 무슨 소용? 깜빡이려면 끄기도 알아야지!
# HOW: 두 가지 방법이 있어
from machine import Pin
led = Pin("LED", Pin.OUT)
# 방법 1: off() 메서드
led.off() # 직관적이야!
# 방법 2: value(0) 메서드
led.value(0) # 0 = 끄기, 1 = 켜기
여기서 잠깐! 🤔
on()/off() vs value(0)/value(1) 뭘 써야 할까?
- on()/off(): 읽기 쉽고 직관적! 처음 배울 때 추천 👍
- value(0/1): 변수로 제어할 때 편해. 나중에 더 활용하게 돼
# value()의 장점 예시
상태 = 1
led.value(상태) # 변수로 제어 가능!
Step 3: LED 깜빡이기 (Blink!)¶
목표: LED를 반복해서 껐다 켰다 해보자 - 피지컬 컴퓨팅의 진짜 "Hello World"!
코드:
# === WHAT: LED 깜빡이기 (Blink) ===
# LED를 1초 간격으로 껐다 켰다 반복!
# --- WHY: 왜 이게 중요할까? ---
# 1. "살아있다"는 신호! (프로그램이 동작 중임을 보여줌)
# 2. time.sleep()으로 타이밍 제어하는 법을 배워
# 3. 무한 반복(while True)의 기본을 익혀
# HOW: 켜고 → 기다리고 → 끄고 → 기다리고 → 반복!
from machine import Pin
import time # 시간 관련 함수들이 들어있어
led = Pin("LED", Pin.OUT)
# 무한 반복 시작!
while True: # True인 동안 = 영원히!
led.on() # 1. LED 켜기
time.sleep(1) # 2. 1초 기다리기
led.off() # 3. LED 끄기
time.sleep(1) # 4. 1초 기다리기
# → 다시 처음으로 돌아가서 반복!
실행 결과:
(LED가 1초마다 껐다 켜졌다 반복됨 - 영원히! ♾️)
멈추는 방법: Thonny에서 빨간 🛑 Stop 버튼 클릭!
여기서 잠깐! 🤔
while True는 무한 루프야. 피지컬 컴퓨팅에서 정말 자주 써. 왜냐면:
- 센서는 계속 값을 읽어야 하고
- LED는 계속 상태를 유지해야 하고
- 프로그램이 끝나면 안 되니까!
Step 4: Grove LED 연결하기¶
목표: 외부 Grove LED 모듈을 연결하고 제어하자!
준비물: - Grove LED 모듈 (빨간색 또는 다른 색) - Grove 케이블 (4핀) - Grove Shield for Pi Pico
연결 방법:
연결 순서: 1. 피코에 Grove Shield를 꽂아 (방향 주의! USB 포트 위치 맞춰서) 2. Grove LED 모듈에 Grove 케이블 연결 3. 케이블의 반대쪽을 Shield의 D18 포트에 연결 4. 딸깍! 소리가 나면 제대로 꽂힌 거야
코드:
# === WHAT: Grove LED 제어하기 ===
# 외부 LED 모듈을 D18 포트로 제어
# --- WHY: 왜 외부 LED를 쓸까? ---
# 1. 내장 LED는 하나뿐이지만, 외부는 여러 개 연결 가능
# 2. 다양한 색상의 LED 사용 가능
# 3. 위치를 자유롭게 배치할 수 있어
# HOW: D18 포트 = GPIO 18번 핀
from machine import Pin
import time
# D18 포트는 GPIO 18번에 연결되어 있어
grove_led = Pin(18, Pin.OUT)
while True:
grove_led.on()
time.sleep(0.5) # 0.5초 = 500밀리초
grove_led.off()
time.sleep(0.5)
실행 결과:
(Grove LED 모듈이 0.5초 간격으로 빠르게 깜빡임! 🔴)
여기서 잠깐! 🤔
Grove Shield의 포트 번호와 GPIO 번호가 일치해서 편해!
- D16 포트 → GPIO 16번 → Pin(16, Pin.OUT)
- D18 포트 → GPIO 18번 → Pin(18, Pin.OUT)
- D20 포트 → GPIO 20번 → Pin(20, Pin.OUT)
Step 5: 두 LED 동시 제어¶
목표: 내장 LED와 Grove LED를 동시에 제어해보자!
코드:
# === WHAT: 두 LED 교대로 깜빡이기 ===
# 내장 LED와 Grove LED가 번갈아가며 켜지는 패턴
# --- WHY: 여러 출력 장치 제어의 기초 ---
# 실제 프로젝트에서는 여러 LED, 모터 등을 동시에 다뤄야 해
# HOW: 두 개의 Pin 객체를 만들고 번갈아 제어
from machine import Pin
import time
# 두 LED 설정
builtin_led = Pin("LED", Pin.OUT) # 내장 LED
grove_led = Pin(18, Pin.OUT) # Grove LED (D18)
while True:
# 패턴: 내장 켜짐 + Grove 꺼짐
builtin_led.on()
grove_led.off()
time.sleep(0.5)
# 패턴: 내장 꺼짐 + Grove 켜짐
builtin_led.off()
grove_led.on()
time.sleep(0.5)
실행 결과:
(두 LED가 시소처럼 번갈아 깜빡임! 마치 대화하는 것 같아 💬)
Step 6: for문으로 LED 패턴 만들기¶
목표: 반복문을 사용해서 다양한 깜빡임 패턴을 만들자!
코드:
# === WHAT: for문으로 LED 깜빡이기 ===
# 정해진 횟수만큼 깜빡이는 패턴 만들기
# --- WHY: for문을 쓰면 좋은 점 ---
# 1. "5번 깜빡여"처럼 횟수 지정 가능
# 2. 점점 빨라지는 등 변화하는 패턴 가능
# 3. 코드가 더 깔끔해져
# HOW: for i in range(횟수) 사용
from machine import Pin
import time
led = Pin("LED", Pin.OUT)
print("=== 5번 깜빡이기 ===")
for i in range(5): # 0, 1, 2, 3, 4 (총 5번)
print(f"깜빡 {i+1}번째")
led.on()
time.sleep(0.3)
led.off()
time.sleep(0.3)
print("끝!")
실행 결과:
=== 5번 깜빡이기 ===
깜빡 1번째
깜빡 2번째
깜빡 3번째
깜빡 4번째
깜빡 5번째
끝!
여기서 잠깐! 🤔
range(5)는 0부터 4까지의 숫자를 만들어줘. 그래서 i+1을 출력하면 1부터 5가 나와!
Step 7: 점점 빨라지는 깜빡임¶
목표: 반복할수록 속도가 빨라지는 패턴을 만들자!
코드:
# === WHAT: 점점 빨라지는 LED ===
# 깜빡이는 속도가 점점 빨라지는 긴박한 패턴!
# --- WHY: 변화하는 패턴이 필요할 때 ---
# 알람, 카운트다운, 긴장감 표현 등에 활용
# HOW: 대기 시간을 점점 줄여나가기
from machine import Pin
import time
led = Pin("LED", Pin.OUT)
print("=== 점점 빨라지는 깜빡임 ===")
delay = 1.0 # 시작 대기 시간: 1초
for i in range(10): # 10번 반복
print(f"대기 시간: {delay}초")
led.on()
time.sleep(delay)
led.off()
time.sleep(delay)
delay = delay * 0.7 # 대기 시간을 70%로 줄여 (점점 빨라짐!)
print("끝! 💨")
실행 결과:
=== 점점 빨라지는 깜빡임 ===
대기 시간: 1.0초
대기 시간: 0.7초
대기 시간: 0.49초
대기 시간: 0.343초
... (점점 빨라지다가)
끝! 💨
📝 전체 코드¶
기본 LED 제어 (step1_led_basic.py)¶
# === 기본 LED 제어 ===
# 피코의 LED를 켜고 끄는 가장 기본적인 코드
from machine import Pin
import time
# LED 설정
led = Pin("LED", Pin.OUT)
# 켜기
print("LED 켜기!")
led.on()
time.sleep(2)
# 끄기
print("LED 끄기!")
led.off()
LED 깜빡이기 (step2_led_blink.py)¶
# === LED 깜빡이기 (Blink) ===
# 1초 간격으로 무한히 깜빡이는 코드
from machine import Pin
import time
led = Pin("LED", Pin.OUT)
print("LED 깜빡이기 시작! (멈추려면 Stop 버튼)")
while True:
led.on()
time.sleep(1)
led.off()
time.sleep(1)
두 LED 제어 (step3_two_leds.py)¶
# === 두 LED 교대 깜빡이기 ===
# 내장 LED와 Grove LED가 번갈아 깜빡임
from machine import Pin
import time
builtin_led = Pin("LED", Pin.OUT)
grove_led = Pin(18, Pin.OUT)
print("두 LED 교대 깜빡이기!")
while True:
builtin_led.on()
grove_led.off()
time.sleep(0.5)
builtin_led.off()
grove_led.on()
time.sleep(0.5)
나만의 LED 패턴 (step4_led_pattern.py)¶
# === 나만의 LED 패턴 ===
# SOS 모스 부호 패턴 (· · · — — — · · ·)
from machine import Pin
import time
led = Pin("LED", Pin.OUT)
def dot():
"""짧은 점 (·)"""
led.on()
time.sleep(0.2)
led.off()
time.sleep(0.2)
def dash():
"""긴 선 (—)"""
led.on()
time.sleep(0.6)
led.off()
time.sleep(0.2)
def letter_gap():
"""글자 사이 간격"""
time.sleep(0.4)
def word_gap():
"""단어 사이 간격"""
time.sleep(1.0)
print("=== SOS 신호 시작! ===")
while True:
# S: · · ·
dot()
dot()
dot()
letter_gap()
# O: — — —
dash()
dash()
dash()
letter_gap()
# S: · · ·
dot()
dot()
dot()
word_gap()
print("SOS!")
⚠️ 자주 하는 실수¶
실수 1: import를 빼먹음¶
증상:
NameError: name 'Pin' is not defined
원인: from machine import Pin을 안 썼어!
해결:
# 잘못된 코드
led = Pin("LED", Pin.OUT) # Pin이 뭔지 모름!
# 올바른 코드
from machine import Pin # 먼저 import!
led = Pin("LED", Pin.OUT)
실수 2: time 모듈 import 안 함¶
증상:
NameError: name 'time' is not defined
원인: import time을 빼먹었어!
해결:
# 잘못된 코드
led.on()
time.sleep(1) # time이 뭔지 모름!
# 올바른 코드
import time # 먼저 import!
led.on()
time.sleep(1)
실수 3: 핀 번호 vs 핀 이름 혼동¶
증상:
ValueError: invalid pin
원인: 내장 LED는 "LED" (문자열) 또는 25 (숫자)인데, 다른 값을 썼어
해결:
# 잘못된 코드
led = Pin(LED, Pin.OUT) # 따옴표 없으면 변수로 인식!
led = Pin("25", Pin.OUT) # 숫자를 문자열로 쓰면 안 돼!
# 올바른 코드
led = Pin("LED", Pin.OUT) # 문자열 "LED"
led = Pin(25, Pin.OUT) # 숫자 25
실수 4: Grove 케이블 방향 틀림¶
증상: 코드는 에러 없이 실행되는데 LED가 안 켜짐
원인: Grove 케이블의 색상 방향이 맞지 않거나, 포트를 잘못 연결함
해결:
✅ 체크리스트:
1. 케이블이 딸깍 소리 나게 꽂혔나?
2. D18 포트에 연결했나? (코드에서 Pin(18) 사용 시)
3. LED 모듈에 불량은 없나? (다른 포트로 테스트)
실수 5: while True 들여쓰기 오류¶
증상:
IndentationError: expected an indented block
원인: while True: 다음 줄의 들여쓰기가 없거나 잘못됨
해결:
# 잘못된 코드
while True:
led.on() # 들여쓰기가 없어!
# 올바른 코드
while True:
led.on() # 스페이스 4칸 또는 Tab
time.sleep(1)
led.off()
time.sleep(1)
✅ 스스로 점검하기¶
-
Pin 클래스를 사용하여 GPIO 핀을 출력 모드로 설정하려면 어떻게 써야 할까?
-
time.sleep(0.5)는 프로그램을 몇 초 동안 멈추게 할까? -
내장 LED와 Grove LED를 동시에 사용할 때, 왜 두 개의 Pin 객체를 따로 만들어야 할까?
-
while True를 사용하는 이유는 무엇일까? -
led.on()과led.value(1)의 차이점은?
정답 확인
1. `led = Pin(핀번호, Pin.OUT)` - Pin.OUT이 출력 모드를 의미해 2. **0.5초** (500밀리초) - sleep()의 단위는 초(second)야 3. 각 LED가 **다른 GPIO 핀**에 연결되어 있어서, 각각 독립적으로 제어해야 하기 때문이야. 하나의 Pin 객체는 하나의 핀만 제어할 수 있어. 4. 피지컬 컴퓨팅에서는 프로그램이 **계속 실행**되어야 해. 한 번 실행하고 끝나면 LED가 바로 꺼지거나, 센서 값을 한 번만 읽고 말아버리니까! 5. **기능은 똑같아!** `on()`/`off()`는 더 직관적이고, `value(0/1)`은 변수로 제어할 때 편해.# 같은 결과
led.on()
led.value(1)
# value()의 장점
상태 = 1
led.value(상태) # 변수 사용 가능!
🚀 더 해보기¶
도전 1: 하트비트 LED 🫀¶
난이도: ⭐
심장이 뛰는 것처럼 "두근두근" 패턴을 만들어봐! - 빠르게 두 번 깜빡이고 - 잠시 쉬고 - 반복!
힌트
# 두근(빠르게 2번) + 쉬기 패턴
while True:
# 두근
led.on()
time.sleep(0.1)
led.off()
time.sleep(0.1)
# 두근
led.on()
time.sleep(0.1)
led.off()
# 쉬기
time.sleep(0.6)
도전 2: 신호등 만들기 🚦¶
난이도: ⭐⭐
Grove LED 3개를 연결해서 신호등을 만들어봐! (또는 1개 LED로 타이밍만 구현) - 초록: 3초 - 노랑: 1초 - 빨강: 3초
힌트
# D16, D18, D20 포트에 각각 LED 연결
red = Pin(16, Pin.OUT)
yellow = Pin(18, Pin.OUT)
green = Pin(20, Pin.OUT)
while True:
# 초록불
green.on()
red.off()
time.sleep(3)
green.off()
# 노란불
yellow.on()
time.sleep(1)
yellow.off()
# 빨간불
red.on()
time.sleep(3)
도전 3: 이진수 카운터 ⭐¶
난이도: ⭐⭐⭐
LED 4개로 0부터 15까지 이진수로 표시해봐! - 0 = 모두 꺼짐 - 1 = 0001 (첫 번째만 켜짐) - 2 = 0010 - 3 = 0011 - ... - 15 = 1111 (모두 켜짐)
힌트
leds = [Pin(16, Pin.OUT), Pin(17, Pin.OUT),
Pin(18, Pin.OUT), Pin(19, Pin.OUT)]
for number in range(16): # 0부터 15까지
# 이진수로 변환해서 각 LED 제어
for i in range(4):
bit = (number >> i) & 1 # i번째 비트 추출
leds[i].value(bit)
time.sleep(1)
🔗 다음 장으로¶
축하해! 🎉 이번 장에서 정말 많은 걸 배웠어:
- Pin 클래스로 GPIO 핀을 제어하는 법
- 내장 LED와 Grove LED를 켜고 끄는 법
- time.sleep()으로 타이밍 제어하는 법
- for문으로 반복 패턴 만드는 법
다음 장에서는 버튼과 대화를 배워볼 거야!
지금까지는 피코가 일방적으로 LED를 제어했지? 다음에는 버튼을 눌러서 피코에게 명령을 내려볼 거야. 버튼을 누르면 LED가 켜지고, 다시 누르면 꺼지는 인터랙티브한 프로그램을 만들어보자!
출력(LED)에서 입력(버튼)으로 한 걸음 더 나아가는 거야! 👉