대상: Raspberry Pi 5에서 C++로 GPIO 입출력을 직접 다뤄보고 싶은 임베디드 개발자
환경: Raspberry Pi 5 + Raspberry Pi OS (Bookworm, 64-bit), GCC 11 이상
1. 문제/주제 요약
Raspberry Pi에서 LED를 켜거나 버튼 입력을 읽는 것은 임베디드 입문자의 첫걸음이다.
Python으로는 gpiozero나 RPi.GPIO로 쉽게 할 수 있지만,
C++에서는 직접 GPIO 파일 인터페이스(/sys/class/gpio)를 다루거나
**라이브러리(wiringPi, libgpiod)**를 이용해야 한다.
Pi 5에서는 기존 wiringPi가 공식적으로 deprecated 되었기 때문에,libgpiod 기반 제어 방법을 사용하는 것이 최신 방식이다.
2. 배경 설명
✅ GPIO 제어의 두 가지 방식
| 방식 | 설명 | 비고 |
|---|---|---|
/sys/class/gpio | 오래된 커널 인터페이스. 단순하지만 비추천 (deprecated) | 느림 |
libgpiod | 최신 Linux GPIO 커널 인터페이스 (/dev/gpiochip*) 기반 | 빠르고 안정적 |
Raspberry Pi 5 (Bookworm OS 기준)에서는 /sys/class/gpio 방식이 기본 비활성화되어 있다.
따라서 C++에서는 **libgpiod**를 사용하는 것이 표준이다.
3. 설치 및 준비
1️⃣ 라이브러리 설치
sudo apt update
sudo apt install libgpiod-dev gpiod
2️⃣ 연결 회로 (예시)
| 역할 | GPIO 핀 번호 | BCM 번호 | 연결 |
|---|---|---|---|
| LED | Physical 11 | GPIO17 | 저항(220Ω) → GND |
| Button | Physical 13 | GPIO27 | GND와 풀업 구성 |
⚠️ Pi의 물리적 핀 번호(BOARD) 와 BCM 번호는 다르다.
예제에서는 BCM 기준(GPIO17,GPIO27)으로 제어한다.
4. C++ 코드 예제 (led_button.cpp)
#include <gpiod.h>
#include <iostream>
#include <thread>
#include <chrono>
#define CONSUMER "rpi5-gpio-demo"
// GPIO 번호 (BCM 기준)
constexpr int LED_PIN = 17;
constexpr int BUTTON_PIN = 27;
int main() {
const char* chipname = "gpiochip4"; // Raspberry Pi 5: 일반 GPIO는 gpiochip4부터 시작
gpiod_chip* chip = gpiod_chip_open_by_name(chipname);
if (!chip) {
std::cerr << "Failed to open GPIO chip: " << chipname << std::endl;
return 1;
}
// LED 출력 핀 설정
gpiod_line* led = gpiod_chip_get_line(chip, LED_PIN);
if (gpiod_line_request_output(led, CONSUMER, 0) < 0) {
std::cerr << "Failed to request LED line" << std::endl;
return 1;
}
// 버튼 입력 핀 설정 (풀업 입력)
gpiod_line* button = gpiod_chip_get_line(chip, BUTTON_PIN);
if (gpiod_line_request_input_flags(button, CONSUMER, GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP) < 0) {
std::cerr << "Failed to request button line" << std::endl;
return 1;
}
std::cout << "Press the button (GPIO27) to toggle LED (GPIO17)." << std::endl;
bool led_state = false;
while (true) {
int value = gpiod_line_get_value(button);
if (value == 0) { // 눌림 (풀업 기준)
led_state = !led_state;
gpiod_line_set_value(led, led_state ? 1 : 0);
std::cout << (led_state ? "LED ON" : "LED OFF") << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(300)); // 디바운스
}
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
gpiod_line_release(led);
gpiod_line_release(button);
gpiod_chip_close(chip);
return 0;
}
5. 빌드 및 실행
g++ led_button.cpp -o led_button -lgpiod
sudo ./led_button
- 버튼을 누를 때마다 LED가 ON/OFF 토글된다.
- 실행 중
Ctrl+C로 종료 가능.
6. 추가 팁 / 자주 하는 실수
- gpiochip 번호 확인 필수
gpiodetect출력 예:gpiochip0 [pinctrl-bcm2712] (58 lines) gpiochip4 [pinctrl-rp1] (36 lines)→ Raspberry Pi 5의 일반 GPIO는 대부분gpiochip4에 연결되어 있다. - 루트 권한 필요
→ GPIO 접근은 일반 유저 권한으로 불가능할 수 있음.sudo로 실행하거나gpio그룹에 사용자를 추가.sudo usermod -aG gpio $USER - 디바운싱 중요
→ 버튼은 노이즈로 인해 여러 번 눌림이 감지될 수 있다.
코드에서sleep_for(300ms)로 디바운스 처리. - LED 극성 반전 확인
→ LED가 “공통 GND”인지 “공통 VCC”인지에 따라 on/off 값 반대로 줄 수 있다.
7. 정리
- Raspberry Pi 5에서는
/sys/class/gpio대신libgpiodAPI를 사용해야 한다. gpiochip4는 일반 GPIO 핀을 제어하는 주요 디바이스이다.- LED 제어는
gpiod_line_set_value()로, 버튼 입력은gpiod_line_get_value()로 처리. - 전원, 풀업 설정, 디바운스 등 실제 하드웨어 연결 시 안정성을 고려해야 한다.
실무 요약: “Pi 5의 GPIO는 libgpiod로 다루자. gpiochip만 제대로 잡으면 LED/버튼은 금방 된다.”