Raspberry Pi 5 GPIO로 LED 제어와 버튼 입력 읽기 (C++ 예제)

대상: Raspberry Pi 5에서 C++로 GPIO 입출력을 직접 다뤄보고 싶은 임베디드 개발자
환경: Raspberry Pi 5 + Raspberry Pi OS (Bookworm, 64-bit), GCC 11 이상


1. 문제/주제 요약

Raspberry Pi에서 LED를 켜거나 버튼 입력을 읽는 것은 임베디드 입문자의 첫걸음이다.
Python으로는 gpiozeroRPi.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 번호연결
LEDPhysical 11GPIO17저항(220Ω) → GND
ButtonPhysical 13GPIO27GND와 풀업 구성

⚠️ 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 대신 libgpiod API를 사용해야 한다.
  • gpiochip4 는 일반 GPIO 핀을 제어하는 주요 디바이스이다.
  • LED 제어는 gpiod_line_set_value() 로, 버튼 입력은 gpiod_line_get_value() 로 처리.
  • 전원, 풀업 설정, 디바운스 등 실제 하드웨어 연결 시 안정성을 고려해야 한다.

실무 요약: “Pi 5의 GPIO는 libgpiod로 다루자. gpiochip만 제대로 잡으면 LED/버튼은 금방 된다.”

댓글 남기기