Chapter 4. 기본 디지털 입출력 (LED, 스위치, 부저)

브레드보드를 활용해 외부 소자들을 연결해 봅시다. 전기를 내보내는 출력(Output)과 외부 상태를 읽어들이는 입력(Input)의 기초를 다집니다.

Pico 2 스위치 (Input) GP14 LED (Output) GP15

디지털 입출력의 흐름: 스위치 신호 입력 → 보드 판단 → LED 전기 출력

4.1 스위치 입력을 받아 외장 LED 제어하기

스위치가 눌렸을 때 발생하는 전류 신호를 읽어 외부 LED를 켜는 조건문 실습입니다. 안정적인 입력을 위해 내부 풀다운(Pull-Down) 저항을 활성화합니다.

스위치는 평소에 회로가 끊겨 있다가, 사람이 누르는 순간에만 회로를 연결해 전류가 흐르게 하는 부품입니다. 그런데 스위치를 누르지 않은 상태에서 GPIO 핀을 그냥 두면 전압이 정해지지 않고 공중에 떠 있는(floating) 상태가 되어, 노이즈로 인해 값이 0과 1 사이를 무작위로 오갈 수 있습니다. 이를 막기 위해 Pin.PULL_DOWN 옵션으로 내부 풀다운 저항을 활성화하면, 스위치를 누르지 않았을 때는 핀이 확실하게 GND(0)로 끌어당겨지고, 스위치를 눌러 3.3V가 연결되는 순간에만 1(High)로 값이 바뀝니다.

Pico 2 3V3 GP14 GP15 GND 스위치 330Ω LED ← 읽기(INPUT) → 출력(OUTPUT) 3.3V (전원) GP14 (입력) GP15 (출력) GND

스위치 한쪽 → GP14, 반대쪽 → 3.3V. LED는 330Ω 저항과 직렬로 GP15 → 저항 → LED(+) → LED(−) → GND 순으로 연결합니다.

from machine import Pin
import time

# GPIO 15번에 외장 LED 연결 (출력 모드)
external_led = Pin(15, Pin.OUT)

# GPIO 14번에 푸시 스위치 연결 (입력 모드 및 내부 풀다운 저항 활성화)
# 버튼을 누르면 1(High), 떼면 0(Low)이 입력됩니다.
switch = Pin(14, Pin.IN, Pin.PULL_DOWN)

print("스위치 감지 시스템 가동...")

while True:
    if switch.value() == 1:       # 스위치가 눌렸다면
        external_led.value(1)     # 외장 LED 켜기
        print("버튼 클릭 -> LED ON")
    else:                         # 스위치가 떨어졌다면
        external_led.value(0)     # 외장 LED 끄기

    time.sleep(0.05)              # 채터링(흔들림) 방지를 위한 짧은 대기

4.2 능동 부저 vs 수동 부저 제어

능동 부저(Active Buzzer)는 전원만 주면 단일 경고음이 나고, 수동 부저(Passive Buzzer)는 주파수 신호(PWM)를 주어야 원하는 음계(도레미파)를 연주할 수 있습니다.

능동 부저 내부에는 발진 회로가 이미 내장되어 있어서, 전기가 흐르기만 하면 정해진 하나의 음(삐- 소리)이 자동으로 납니다. 그래서 능동 부저는 LED처럼 Pin.OUT으로 설정하고 on() / off()만으로 제어할 수 있습니다. 반면 수동 부저는 발진 회로가 없어서, 우리가 직접 PWM(Pulse Width Modulation) 신호로 주파수(Hz)를 만들어 보내주어야만 소리가 나며, 주파수를 바꾸면 음높이도 바뀌기 때문에 멜로디 연주가 가능합니다.

[실습] 능동 부저로 단일음 울리기

능동 부저는 아래처럼 LED와 동일한 방식으로 간단하게 제어할 수 있습니다.

from machine import Pin
import time

# GPIO 16번에 능동 부저 연결 (출력 모드)
active_buzzer = Pin(16, Pin.OUT)

print("능동 부저 테스트를 시작합니다.")

active_buzzer.on()     # 부저 울리기
time.sleep(0.5)
active_buzzer.off()    # 부저 끄기
time.sleep(0.5)
Pico 2 GP16 GND 부저 (Buzzer) + (Signal) − (GND) → PWM 신호(OUT)

부저 + 단자(S 핀)→GP16, − 단자→GND. 능동 부저도 동일 배선이며, 수동 부저와 달리 GP16을 ON/OFF하는 것만으로 소리가 납니다.

[실습] 수동 부저를 이용한 도레미파 멜로디 연주

from machine import Pin, PWM
import time

# GPIO 16번에 수동 부저 연결 후 PWM 인스턴스 생성
buzzer = PWM(Pin(16))

# 음계별 주파수 정의 (도, 레, 미, 파)
tones = {
    'DO': 262,
    'RE': 294,
    'MI': 330,
    'FA': 349
}

def play_tone(frequency, duration):
    if frequency == 0:
        buzzer.duty_u16(0) # 소리 끄기
    else:
        buzzer.freq(frequency)       # 주파수 설정
        buzzer.duty_u16(32768)       # 소리 크기 설정 (50% 듀티폭)
    time.sleep(duration)
    buzzer.duty_u16(0)               # 음과 음 사이 음소거
    time.sleep(0.05)

try:
    print("멜로디 연주를 시작합니다.")
    play_tone(tones['DO'], 0.5)
    play_tone(tones['RE'], 0.5)
    play_tone(tones['MI'], 0.5)
    play_tone(tones['FA'], 0.5)
finally:
    # 에러가 발생하거나 연주가 끝나면 안전하게 소리를 끄고 객체 해제
    buzzer.duty_u16(0)
    buzzer.deinit()
    print("시스템이 안전하게 종료되었습니다.")

🏆 과제 해결해보기!

과제 1. 스위치를 누를 때만 LED 깜빡이기

4.1절 회로를 그대로 사용해서, 스위치를 누르고 있는 동안에는 LED가 계속 켜져 있는 것이 아니라 0.2초 간격으로 깜빡이도록 코드를 수정해 봅시다. 스위치를 떼면 LED는 완전히 꺼져야 합니다.

💻 정답 코드 보기
from machine import Pin
import time

external_led = Pin(15, Pin.OUT)
switch = Pin(14, Pin.IN, Pin.PULL_DOWN)

while True:
    if switch.value() == 1:      # 스위치가 눌린 동안
        external_led.toggle()    # LED 상태를 반전시켜 깜빡이게 함
        time.sleep(0.2)
    else:                        # 스위치를 떼면
        external_led.off()       # LED를 완전히 끔

과제 2. 수동 부저로 도레미파솔라시도 연주하기

4.2절의 tones 딕셔너리에 '솔(SOL, 392Hz)', '라(LA, 440Hz)', '시(SI, 494Hz)', '높은 도(DO2, 523Hz)'를 추가하여, 도레미파솔라시도 8음계를 순서대로 연주하는 코드를 작성해 봅시다.

💻 정답 코드 보기
from machine import Pin, PWM
import time

buzzer = PWM(Pin(16))

tones = {
    'DO': 262, 'RE': 294, 'MI': 330, 'FA': 349,
    'SOL': 392, 'LA': 440, 'SI': 494, 'DO2': 523
}

def play_tone(frequency, duration):
    buzzer.freq(frequency)
    buzzer.duty_u16(32768)
    time.sleep(duration)
    buzzer.duty_u16(0)
    time.sleep(0.05)

try:
    for note in ['DO', 'RE', 'MI', 'FA', 'SOL', 'LA', 'SI', 'DO2']:
        play_tone(tones[note], 0.4)
finally:
    buzzer.duty_u16(0)
    buzzer.deinit()

4.3 Wokwi 시뮬레이션으로 실습하기

1.8절에서 소개한 Wokwi에서 이번 챕터의 스위치·LED·부저 회로를 실제 부품 없이 미리 실습해 볼 수 있습니다. 아래 diagram.json을 Wokwi 프로젝트의 회로 편집기(diagram.json)에 붙여넣고, 4.1절과 4.2절의 main.py 코드를 코드 편집기에 붙여넣은 뒤 초록색 ▶ 실행 버튼을 누르면 동작을 확인할 수 있습니다.

{
  "version": 1,
  "author": "Pico 2 IoT Guide",
  "editor": "code",
  "parts": [
    { "type": "wokwi-pi-pico", "id": "pico", "top": 0, "left": 0, "attrs": {} },
    { "type": "wokwi-pushbutton", "id": "btn1", "top": 40, "left": -120, "attrs": {} },
    { "type": "wokwi-resistor", "id": "r1", "top": 60, "left": 150, "attrs": { "value": "330" } },
    { "type": "wokwi-led", "id": "led1", "top": 60, "left": 220, "attrs": { "color": "red" } },
    { "type": "wokwi-buzzer", "id": "bz1", "top": 120, "left": 220, "attrs": { "volume": "0.1" } }
  ],
  "connections": [
    [ "pico:3V3", "btn1:1.l", "red", [] ],
    [ "btn1:2.l", "pico:GP14", "green", [] ],
    [ "pico:GP15", "r1:1", "orange", [] ],
    [ "r1:2", "led1:A", "orange", [] ],
    [ "led1:C", "pico:GND", "black", [] ],
    [ "pico:GP16", "bz1:1", "purple", [] ],
    [ "bz1:2", "pico:GND", "black", [] ]
  ],
  "dependencies": {}
}

💡 참고

Wokwi의 부품 이름(wokwi-pushbutton, wokwi-buzzer 등)이나 핀 이름은 라이브러리 버전에 따라 조금씩 달라질 수 있습니다. 부품을 추가했는데 오류가 표시된다면, 좌측 부품 라이브러리(Parts) 검색창에서 정확한 이름을 다시 확인해 보세요.