하드웨어 환경: 라즈베리 파이 4 모델 B 리비전 1.5 · Debian 12 북웜 · 커널 6.12.25
테스트 날짜: 2026년 4월
작성자: zeruns (https://blog.zeruns.com/)
본문은 AI가 작성하였으며 참고용임 (Hermes Agent + DeepSeek V4 Flash)
목차
1. GPIO 기초 개념
1.1 GPIO란 무엇인가
GPIO(General Purpose Input/Output, 범용 입력/출력)는 마이크로프로세서의 프로그래밍 가능한 핀 그룹입니다. 소프트웨어 제어를 통해 각 핀을 다음 모드 중 하나로 설정할 수 있습니다:
- 출력 모드: 높은 전압(3.3V) 또는 낮은 전압(0V)을 출력하여 LED, 릴레이, 부저 등을 제어합니다.
- 입력 모드: 외부 전압 상태(고/저)를 읽어 버튼, 센서 신호 등을 검출합니다.
- 다중 기능(Multiplexing): I2C, SPI, UART, PWM 등의 전용 통신 프로토콜로 사용합니다.
1.2 라즈베리 파이 4B 핀 배열
라즈베리 파이 4B는 40핀 확장 핀 헤더를 사용하며, 핀 번호 지정 방식은 3가지가 있습니다:
| 번호 방식 | 설명 | 일반적인 라이브러리 |
|---|---|---|
| 물리 핀(Board) | 1에서 40까지 번호 매기며 왼쪽 상단이 1번 | RPi.GPIO setmode(GPIO.BOARD) |
| BCM 번호(Broadcom) | 칩의 GPIO 번호를 사용, 예: GPIO17 | RPi.GPIO setmode(GPIO.BCM), libgpiod |
| wiringPi 번호 | wiringPi 라이브러리의 사용자 정의 번호 (현재 사용 중단됨) | wiringPi 라이브러리 |
40핀 핀 기능표
┌─────────────────────────────┐
│ 🥝 라즈베리 파이 4B 40핀 핀 순서도 │
3.3V (01) ──● ●── (02) 5V │
GPIO2 (03) ──● ●── (04) 5V │
GPIO3 (05) ──● ●── (06) GND │
GPIO4 (07) ──● ●── (08) GPIO14 (UART TX) │
GND (09) ──● ●── (10) GPIO15 (UART RX) │
GPIO17 (11) ──● ●── (12) GPIO18 (PWM0) │
GPIO27 (13) ──● ●── (14) GND │
GPIO22 (15) ──● ●── (16) GPIO23 │
3.3V (17) ──● ●── (18) GPIO24 │
GPIO10 (19) ──● ●── (20) GND (SPI_MOSI) │
GPIO9 (21) ──● ●── (22) GPIO25 (SPI_MISO) │
GPIO11 (23) ──● ●── (24) GPIO8 (SPI_SCLK) │
GND (25) ──● ●── (26) GPIO7 (SPI_CE0) │
GPIO0 (27) ──● ●── (28) GPIO1 (ID_SDA / I2C) │
GPIO5 (29) ──● ●── (30) GND │
GPIO6 (31) ──● ●── (32) GPIO12 (PWM0) │
GPIO13 (33) ──● ●── (34) GND │
GPIO19 (35) ──● ●── (36) GPIO16 │
GPIO26 (37) ──● ●── (38) GPIO20 │
GND (39) ──● ●── (40) GPIO21 │
└─────────────────────────────┘
라즈베리 파이 4B 주요 핀 기능표
| 물리 핀 | BCM 번호 | 기능 | 물리 핀 | BCM 번호 | 기능 |
|---|---|---|---|---|---|
| 1 | — | 3.3V | 2 | — | 5V |
| 3 | GPIO2 | I2C1 SDA | 4 | — | 5V |
| 5 | GPIO3 | I2C1 SCL | 6 | — | GND |
| 7 | GPIO4 | — | 8 | GPIO14 | UART TX |
| 9 | — | GND | 10 | GPIO15 | UART RX |
| 11 | GPIO17 | — | 12 | GPIO18 | PCM_CLK / PWM0 |
| 13 | GPIO27 | — | 14 | — | GND |
| 15 | GPIO22 | — | 16 | GPIO23 | — |
| 17 | — | 3.3V | 18 | GPIO24 | — |
| 19 | GPIO10 | SPI0 MOSI | 20 | — | GND |
| 21 | GPIO9 | SPI0 MISO | 22 | GPIO25 | — |
| 23 | GPIO11 | SPI0 SCLK | 24 | GPIO8 | SPI0 CE0 |
| 25 | — | GND | 26 | GPIO7 | SPI0 CE1 |
| 27 | GPIO0 | ID_SDA (EEPROM) | 28 | GPIO1 | ID_SCL (EEPROM) |
| 29 | GPIO5 | — | 30 | — | GND |
| 31 | GPIO6 | — | 32 | GPIO12 | PWM0 |
| 33 | GPIO13 | PWM1 | 34 | — | GND |
| 35 | GPIO19 | PCM_FS / PWM1 | 36 | GPIO16 | — |
| 37 | GPIO26 | — | 38 | GPIO20 | PCM_DIN |
| 39 | — | GND | 40 | GPIO21 | PCM_DOUT |
1.3 주요 참고 사항
- 논리 레벨: 라즈베리 파이 GPIO는 3.3V 논리 레벨이며 5V 신호를 직접 연결하면 안 됩니다.
- 전류 제한: 각 GPIO 최대 출력 전류는 약 16mA, 전체 핀 합계는 50mA를 초과하지 않아야 합니다.
- 기본 상태: 대부분의 GPIO 핀은 기본적으로 입력 모드이며 일부는 내부 풀업/풀다운 저항을 가지고 있습니다.
- 3.3V 핀 (01/17): 최대 약 500mA 출력 가능
- 5V 핀 (02/04): USB-C 전원에서 직접 공급되며 공급 전류는 전원 어댑터 사양에 따라 다릅니다.
2. 환경 준비 및 도구
2.1 설치된 도구 목록
이 튜토리얼은 Debian 12 북웜 기반 시스템에서 테스트 되었으며 다음 도구가 사전 설치되어 있습니다:
| 도구/라이브러리 | 버전 | 용도 |
|---|---|---|
| libgpiod / gpioset / gpioget | 1.6.3 | 쉘 명령어 방식 GPIO 제어 |
| python3-libgpiod | 1.6.3 | Python libgpiod 바인딩 |
| RPi.GPIO | 0.7.2 | 고전적인 Python GPIO 라이브러리 |
| smbus2 | 설치됨 | Python I2C 통신 |
| spidev | 설치됨 | Python SPI 통신 |
| pigpiod | 1.79 | GPIO 데몬 (PWM/원격 제어) |
| i2c-tools | 4.3 | I2C 장치 스캔 도구 |
2.2 필요한 도구 설치
도구가 설치되지 않은 경우 아래 명령어로 설치할 수 있습니다.
# 기본 GPIO 도구 설치
sudo apt install gpiod libgpiod-dev python3-libgpiod
# I2C 도구 설치
sudo apt install i2c-tools
# Python 라이브러리 설치
pip install RPi.GPIO smbus2 spidev gpiozero
# pigpio 데몬 설치 (하드웨어 PWM, 권장)
sudo apt install pigpio pigpiod
sudo systemctl enable pigpiod --now
2.3 I2C / SPI 인터페이스 활성화
raspi-config를 사용하여 활성화:
sudo raspi-config
메뉴 경로:
Interface Options → I2C → Enable → Yes
Interface Options → SPI → Enable → Yes
또는 터미널에서 직접 /boot/firmware/config.txt(Debian 12) 파일을 편집합니다:
# 수동으로 추가
sudo tee -a /boot/firmware/config.txt <<EOF
dtparam=i2c_arm=on
dtparam=spi=on
EOF
# 다시 시작하여 적용
sudo reboot
활성화 성공 확인:
# I2C 확인
ls /dev/i2c*
# 출력: /dev/i2c-20 /dev/i2c-21
# SPI 확인 (활성화 후)
ls /dev/spi*
# 출력: /dev/spidev0.0 /dev/spidev0.1
2.4 모든 gpiochip 보기
$ gpioinfo
gpiochip0 - 58 lines:
line 0: "ID_SDA" unused input active-high
line 1: "ID_SCL" unused input active-high
line 2: "GPIO2" unused input active-high
...
라즈베리 파이 4B의 BCM2711 칩은 하나의 gpiochip0을 제공하며 총 58개의 GPIO를 가지지만, GPIO0~GPIO27까지만 40핀 헤더를 통해 외부로 빠져나옵니다.
3. GPIO 입력/출력 (Shell 방식)
3.1 libgpiod 도구 모음
wiringPi에 의존하지 않는 libgpiod 도구 사용을 권장합니다. 현재 주류로 쓰이는 방법입니다.
주요 명령어:
| 명령 | 기능 | 예시 |
|---|---|---|
gpioinfo |
모든 GPIO 상태 보기 | gpioinfo |
gpioset |
GPIO 출력 레벨 설정 | gpioset 0 17=1 |
gpioget |
GPIO 입력 레벨 읽기 | gpioget 0 17 |
gpiomon |
GPIO 이벤트 감시 | gpiomon 0 17 |
형식 설명:
gpioset <chip> <pin>=<va>chip`는 일반적으로 0(gpiochip0)이며, 핀 번호는 BCM 번호를 사용합니다.
3.2 출력: LED 켜기
LED의 양극(긴 핀)을 330Ω 저항을 통해 GPIO17(물리 핀 11)에 연결하고, 음극(짧은 핀)은 GND(물리 핀 9)에 연결하세요.
# GPIO17에 고전압 출력 설정 → LED 켜짐
gpioset 0 17=1
# GPIO17에 저전압 출력 설정 → LED 꺼짐
gpioset 0 17=0
3.3 입력: 버튼 상태 읽기
버튼 한쪽을 GPIO18(물리 핀 12)에 연결하고, 다른 쪽을 GND(물리 핀 14)에 연결하세요.
# GPIO18의 전압 레벨 읽기 (외부 풀업 혹은 내부 풀업 필요)
gpioget 0 18
# 출력: 1 (버튼 미누름, 고전압)
# 출력: 0 (버튼 누름, 저전압)
3.4 모든 핀 상태 보기
# 전체 핀 상태 보기
gpioinfo
# 특정 핀 보기 (BCM 17번)
gpioinfo | grep "GPIO17"
# 출력: line 17: "GPIO17" "myapp" output active-high
3.5 gpioset으로 풀업/풀다운 설정
libgpiod 1.6 버전부터는 요청 시 바이어스를 설정할 수 있습니다.
# GPIO17을 출력으로 설정하고 초기 전압을 고로 설정하며 풀업 적용
gpioset --bias=enable 0 17=1
4. GPIO 입출력 (파이썬 방식)
4.1 RPi.GPIO 사용 (전통적인 라이브러리)
RPi.GPIO는 가장 일반적으로 사용하는 파이썬 GPIO 라이브러리로, 간단하고 직관적입니다.
4.1.1 출력: LED 깜박이기
import RPi.GPIO as GPIO
import time
# BCM 핀 번호 방식 사용
GPIO.setmode(GPIO.BCM)
# GPIO17을 출력으로 설정
GPIO.setup(17, GPIO.OUT)
# LED를 5번 깜박임
for _ in range(5):
GPIO.output(17, GPIO.HIGH) # LED 켬
time.sleep(0.5)
GPIO.output(17, GPIO.LOW) # LED 끔
time.sleep(0.5)
# 자원 정리
GPIO.cleanup()
4.1.2 입력: 버튼 읽기
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
# GPIO18을 입력으로 설정하고 내부 풀업 저항 활성화
GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_UP)
try:
while True:
if GPIO.input(18) == GPIO.LOW:
print("버튼 누름")
else:
print("버튼 뗌")
time.sleep(0.1)
except KeyboardInterrupt:
GPIO.cleanup()
GPIO.PUD_UP= 내부 풀업 (기본 고전압, 눌렀을 때 저전압)
GPIO.PUD_DOWN= 내부 풀다운 (기본 저전압, 눌렀을 때 고전압)
4.1.3 PWM 출력: 호흡등 효과
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.OUT) # GPIO18은 하드웨어 PWM 지원
pwm = GPIO.PWM(18, 1000) # 주파수 1kHz
pwm.start(0) # 초기 듀티 사이클 0%
try:
while True:
# 서서히 밝아짐
for duty in range(0, 101, 5):
pwm.ChangeDutyCycle(duty)
time.sleep(0.05)
# 서서히 어두워짐
for duty in range(100, -1, -5):
pwm.ChangeDutyCycle(duty)
time.sleep(0.05)
except KeyboardInterrupt:
pwm.stop()
GPIO.cleanup()
4.1.4 이벤트 감지: 인터럽트 방식으로 버튼 읽기
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_UP)
def button_callback(channel):
print(f"버튼 누름! (핀: {channel})")
# 하강 에지에서 트리거 (눌렀을 때)
GPIO.add_event_detect(18, GPIO.FALLING,
callback=button_callback,
bouncetime=200)
try:
print("버튼 입력 대기...")
time.sleep(60)
except KeyboardInterrupt:
GPIO.cleanup()
4.2 gpiozero 사용 (고수준 래핑)
gpiozero는 더 고수준의 객체 지향 인터페이스를 제공하며, 빠른 개발에 적합합니다:
# 설치
pip install gpiozero
from gpiozero import LED, Button, Buzzer
from signal import pause
# LED: 자동 깜빡임
led = LED(17)
led.blink()
# 버튼: 누르면 LED 켜짐
btn = Button(18, pull_up=True)
# 방법 1: 직접 대입
btn.when_pressed = led.on
btn.when_released = led.off
# 방법 2: 사용자 정의 콜백
btn.when_pressed = lambda: print("누름!")
# 계속 실행
pause()
gpiozero에서 제공하는 주요 컴포넌트:
| 컴포넌트 | 클래스명 | 설명 |
|---|---|---|
| LED | LED(pin) |
LED 켜기/끄기, 깜빡임, 호흡등 제어 |
| 버튼 | Button(pin, pull_up=True) |
버튼 입력, 길게 누름 감지 |
| 부저 | Buzzer(pin) |
능동형 부저 제어 |
| 거리 센서 | DistanceSensor(echo, trigger) |
HC-SR04 초음파 거리 측정 |
| 서보모터 | Servo(pin) |
서보모터 각도 제어 |
| 모터 | Motor(forward, backward) |
DC 모터 제어 |
4.3 libgpiod 파이썬 바인딩 사용 (저수준 조작)
import gpiod
import time
# gpiochip0 열기
chip = gpiod.Chip('gpiochip0')
# GPIO17을 가져와 출력으로 요청
line = chip.get_line(17)
line.request(consumer='myapp', type=gpiod.LINE_REQ_DIR_OUT)
# 고전압 출력
line.set_value(1)
time.sleep(1)
# 저전압 출력
line.set_value(0)
# 해제
line.release()
입력 모드 예시:
import gpiod
chip = gpiod.Chip('gpiochip0')
line = chip.get_line(18)
# 입력으로 요청, 내부 풀업 사용
line.request(consumer='myapp',
type=gpiod.LINE_REQ_DIR_IN,
flags=gpiod.LINE_REQ_FLAG_BIAS_PULL_UP)
value = line.get_value() # 0 또는 1
print(f"GPIO18 = {value}")
line.release()
5. I2C 통신
5.1 I2C 기본 원리
I2C(Inter-Integrated Circuit)는 두 개의 선을 사용하는 직렬 통신 버스입니다:
| 신호 | 핀 | 기능 |
|---|---|---|
| SCL | GPIO3 (물리 핀 5) | 클럭라인 |
| SDA | GPIO2 (물리 핀 3) | 데이터라인 |
특징:
- 마스터-슬레이브 아키텍처: 라즈베리파이는 마스터, 센서 등이 슬레이브
- 7비트 주소: 각 슬레이브는 고유한 주소를 가짐 (예: 0x44)
- 다중 장치 공유: 하나의 I2C 버스에 여러 장치 연결 가능
- 속도: 표준 100kHz, 빠른 모드 400kHz
5.2 I2C 버스 확인
# I2C 버스 목록 보기
$ i2cdetect -l
i2c-20 i2c bcm2711_i2c1 I2C adapter
i2c-21 i2c bcm2711_i2c0 I2C adapter
i2c-20: 물리 핀 3(SDA)/5(SCL)에 해당 — 주 I2C 버스i2c-21: ID_EEPROM(핀 27/28)에 연결, 일반적으로 외부 장치 연결 없음
5.3 I2C 장치 스캔
# i2c-20 버스에 연결된 장치 스캔
$ i2cdetect -y 20
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- 44 -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
주소
0x44에 장치 발견 — 이는 SHT30 온습도 센서(I2C 주소 0x44)입니다.
만약 아무 장치도 보이지 않고 전부 --이라면, 버스에 장치가 연결되지 않았음을 의미합니다.
5.4 smbus2를 사용한 I2C 읽기/쓰기
smbus2는 가장 일반적인 파이썬 I2C 라이브러리입니다.
5.4.1 SHT30 온습도 센서 읽기
import smbus2
import time
# SHT30 I2C 주소
SHT30_ADDR = 0x44
# I2C 버스 20 열기
bus = smbus2.SMBus(20)
# 측정 명령 전송: 고정밀도 모드
bus.write_i2c_block_data(SHT30_ADDR, 0x2C, [0x06])
time.sleep(0.015) # 측정 완료 대기 (15ms)
# 6바이트 데이터 읽기
data = bus.read_i2c_block_data(SHT30_ADDR, 0x00, 6)
# 온도 및 습도 계산
temp_raw = ((data[0] << 8) | data[1])
temp = -45 + 175 * temp_raw / 65535.0
hum_raw = ((data[3] << 8) | data[4])
hum = 100 * hum_raw / 65535.0
print(f"온도: {temp:.2f}°C")
print(f"습도: {hum:.2f}%")
5.4.2 함수로 패키징하기
import smbus2
import time
class SHT30:
def __init__(self, bus_id=20, addr=0x44):
self.bus = smbus2.SMBus(bus_id)
self.addr = addr
def read(self):
"""온습도 측정, 형식: (온도°C, 습도%)"""
self.bus.write_i2c_block_data(self.addr, 0x2C, [0x06])
time.sleep(0.015)
data = self.bus.read_i2c_block_data(self.addr, 0x00, 6)
temp_raw = (data[0] << 8) | data[1]
temp = -45 + 175 * temp_raw / 65535.0
hum_raw = (data[3] << 8) | data[4]
hum = 100 * hum_raw / 65535.0
return round(temp, 2), round(hum, 2)
# 사용 예
sensor = SHT30()
t, h = sensor.read()
print(f"{t}°C, {h}%RH")
5.4.3 일반적인 I2C 입출력 작업
import smbus2
bus = smbus2.SMBus(20)
addr = 0x44 # 디바이스 I2C 주소
# 레지스터에 한 바이트 쓰기
bus.write_byte_data(addr, 0x2C, 0x06)
# 한 바이트 읽기
value = bus.read_byte_data(addr, 0x00)
# 여러 바이트 읽기
data = bus.read_i2c_block_data(addr, 0x00, 6)
# 여러 바이트 쓰기
bus.write_i2c_block_data(addr, 0x2C, [0x06])
# 레지스터 없이 한 바이트 쓰기
bus.write_byte(addr, 0x06)
# 레지스터 없이 한 바이트 읽기
value = bus.read_byte(addr)
bus.close()
5.5 명령줄 도구 i2cget / i2cset 사용
# SHT30 상태 레지스터 읽기 (1바이트)
$ i2cget -y 20 0x44 0x00
0x65
# 6바이트 원시 데이터 읽기
$ i2cget -y 20 0x44 0x00 b 6
6. SPI 통신
6.1 SPI 기본 원리
SPI Serial Peripheral Interface는 전이중 동기 직렬 버스로 4개의 선을 사용:
| 신호 | 라즈베리파이 핀 | 기능 |
|---|---|---|
| MOSI | GPIO10 (물리 핀 19) | 마스터 출력, 슬레이브 입력 |
| MISO | GPIO9 (물리 핀 21) | 마스터 입력, 슬레이브 출력 |
| SCLK | GPIO11 (물리 핀 23) | 클럭 신호 |
| CE0 | GPIO8 (물리 핀 24) | 칩 선택 0 |
| CE1 | GPIO7 (물리 핀 26) | 칩 선택 1 |
특징:
- 전이중: 송신과 수신을 동시에 가능
- 마스터-슬레이브: 라즈베리파이는 마스터, 여러 슬레이브 장
6.3.2 일반 SPI 데이터 송수신
import spidev
spi = spidev.SpiDev()
spi.open(0, 0)
spi.max_speed_hz = 500000
spi.mode = 0
# 전송 및 수신(전이중, 0xFF 전송하면서 동시에 수신)
data_out = [0xFF, 0x00, 0x55]
data_in = spi.xfer2(data_out) # 3바이트 전송, 3바이트 수신
print(f"전송: {[hex(x) for x in data_out]}")
print(f"수신: {[hex(x) for x in data_in]}")
# 전송만(수신 결과 무시)
spi.writebytes([0x01, 0x02, 0x03])
spi.close()
7. 종합 예제
7.1 예제 1: LED 브리딩 + 버튼 제어
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
LED_PIN = 17 # BCM 17
BTN_PIN = 18 # BCM 18
GPIO.setup(LED_PIN, GPIO.OUT)
GPIO.setup(BTN_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
pwm = GPIO.PWM(LED_PIN, 500)
pwm.start(0)
running = True # LED 상태
try:
while True:
if GPIO.input(BTN_PIN) == GPIO.LOW:
running = not running
time.sleep(0.3) # 디바운싱
if running:
# 브리딩 효과
for duty in range(0, 101, 2):
pwm.ChangeDutyCycle(duty)
time.sleep(0.01)
for duty in range(100, -1, -2):
pwm.ChangeDutyCycle(duty)
time.sleep(0.01)
else:
pwm.ChangeDutyCycle(0)
except KeyboardInterrupt:
pwm.stop()
GPIO.cleanup()
7.2 예제 2: SHT30 온습도 측정 + 자동 기록
import smbus2
import time
import csv
from datetime import datetime
class SHT30:
def __init__(self, bus_id=20, addr=0x44):
self.bus = smbus2.SMBus(bus_id)
self.addr = addr
def read(self):
self.bus.write_i2c_block_data(self.addr, 0x2C, [0x06])
time.sleep(0.015)
data = self.bus.read_i2c_block_data(self.addr, 0x00, 6)
t = -45 + 175 * ((data[0] << 8) | data[1]) / 65535.0
h = 100 * ((data[3] << 8) | data[4]) / 65535.0
return round(t, 2), round(h, 2)
sensor = SHT30()
# 측정 테스트
t, h = sensor.read()
print(f"[{datetime.now()}] 온도: {t}°C, 습도: {h}%")
# CSV에 지속 기록(매분 1회)
with open('sensor_log.csv', 'w', newline='') as f:
writer = csv.writer(f)
writer.writerow(['시간', '온도(C)', '습도(%)'])
for i in range(10): # 10회 기록
t, h = sensor.read()
now = datetime.now().strftime('%H:%M:%S')
writer.writerow([now, t, h])
print(f"[{now}] {t}°C, {h}%")
time.sleep(60)
7.3 예제 3: gpiozero로 한 번에 완성
from gpiozero import LED, Button
from signal import pause
import time
led = LED(17)
btn = Button(18, pull_up=True)
# 눌렀을 때 켜지고, 뗐을 때 꺼짐
btn.when_pressed = led.on
btn.when_released = led.off
# 더블 클릭 시 깜빡임 모드 전환
press_count = 0
def double_click():
global press_count
press_count += 1
time.sleep(0.3)
if press_count == 2:
led.blink()
print("더블 클릭! LED 깜빡임 모드")
press_count = 0
btn.when_pressed = double_click
pause()
8. 주의사항과 오류 해결
8.1 전압 레벨 변환 (3.3V vs 5V)
라즈베리파이 GPIO는 3.3V 로직이며, 절대 5V 장치에 직접 연결하지 마세요!
| 상황 | 방법 |
|---|---|
| 5V 센서 출력 → 라즈베리파이 입력 | 레벨 쉬프터 모듈(예: TXS0108E) 또는 저항 분압 방식 사용 |
| 라즈베리파이 출력 → 5V 장치 입력 | 일부 5V 장치는 3.3V를 고레벨로 인식함(예: WS2812B) |
| 3.3V 센서 → 라즈베리파이 | 바로 연결 가능 |
저항 분압 (5V → 3.3V):
5V ──┬── R1 (1.8kΩ) ──┬── 라즈베리파이 GPIO
│ │
GND ── R2 (3.3kΩ) ─┘
8.2 풀업/풀다운 저항
- 내부 풀업: RPi.GPIO에서는
pull_up_down=GPIO.PUD_UP - 내부 풀다운: RPi.GPIO에서는
pull_up_down=GPIO.PUD_DOWN - libgpiod:
gpiod.LINE_REQ_FLAG_BIAS_PULL_UP - 외부 풀업: 4.7kΩ ~ 10kΩ 저항을 3.3V에 연결
8.3 전류 제한
| 항목 | 제한 |
|---|---|
| 개별 GPIO 최대 출력 전류 | 16mA |
| 전체 GPIO 합산 | 50mA |
| 3.3V 핀 총 전류 | 약 500mA |
| 5V 핀 총 전류 | 전원 공급에 따라 다름 |
LED 직접 구동 시 반드시 220Ω ~ 330Ω 제한 저항을 직렬로 연결하세요!
8.4 흔한 오류
| 오류 | 원인 | 해결 방법 |
|---|---|---|
RuntimeError: No access to /dev/mem |
권한 부족 | sudo python3 script.py 실행 |
RuntimeError: Pin already in use |
핀이 다른 프로그램에 의해 사용 중 | /sys/class/gpio/ 확인 후 해제 또는 재시작 |
[Errno 13] Permission denied + i2c |
I2C 미활성 또는 권한 부족 | 사용자를 i2c 그룹에 추가 |
Could not open /dev/spidev0.0 |
SPI 미활성 | /boot/config.txt 확인 |
| LED 역접속으로 켜지지 않음 | 양극/음극 거꾸로 연결 | LED 긴 다리는 GPIO, 짧은 다리는 GND에 연결 |
| 버튼 오작동 | 디바운싱 미처리 | 코드에 bouncetime 또는 디바운스 지연 추가 |
8.5 권한 설정
# 현재 사용자를 i2c, gpio 그룹에 추가
sudo usermod -aG i2c,gpio $USER
# 다시 로그인하여 적용
exec su - $USER
8.6 빠른 온라인 참고 자료
작성자: zeruns
이 튜토리얼은 라즈베리파이 4B + Debian 12 Bookworm에서 직접 테스트하여 작성됨
