结论:libgpiod是当前最稳妥、内核原生支持且无维护风险的C++ GPIO方案;wiringPi自2021年停更,不兼容Pi 5及新内核(5.10+),依赖/dev/mem易报错,编号混乱且无多线程安全与中断支持;bcm2835虽可用但绕过内核,仅适用于裸机或精确时序场景,有硬件冲突风险。

直接上结论:用 libgpiod 是当前最稳妥、内核原生支持、且不再维护风险的 C++ GPIO 方案;wiringPi 已停更,bcm2835 仍可用但绕过内核驱动,不推荐新项目。
为什么别碰 wiringPi?
它从 2021 年起就停止维护,最后一次更新是 v2.73(对应 Pi 4B),后续没适配 Raspberry Pi 5 的 GPIO 控制器。更关键的是:wiringPi 使用 /dev/mem 直接映射寄存器,在较新内核(5.10+)默认禁用该访问,即使加 sudo 也常报 Permission denied 或 segfault。你写的代码可能在旧镜像能跑,换一张 Raspberry Pi OS 2024/2025 版本就直接挂。
- 它用自定义编号(0–30),和 BCM 编号、物理引脚完全不一致,查表容易错
- 没有线程安全保证,多线程调用
digitalWrite()可能竞争写寄存器 - 不支持 edge-triggered event,想监听按钮按下得轮询或自己加中断模拟
libgpiod C++ API 怎么开一个输出口?
核心是三步:打开 chip → 获取 line → request + set output。注意所有操作都需 root 权限(sudo),因为 /dev/gpiochip* 设备节点默认只对 gpio 组可读。
- 用
chip("/dev/gpiochip0", OPEN_BY_PATH)打开主芯片(树莓派通常只有 1 个) - 用
line = chip.get_line(23)获取 BCM GPIO23 对应的 line(不是 WiringPi 编号!) - 调用
line.request({.consumer="led", .request_type=DIRECTION_OUTPUT}, 0)请求为输出,默认低电平 - 之后用
line.set_value(1)点亮 LED,line.set_value(0)熄灭
示例片段:
立即学习“C++免费学习笔记(深入)”;
#include <gpiod.hpp>
#include <chrono>
#include <thread>
int main() {
gpiod::chip chip("/dev/gpiochip0", gpiod::chip::OPEN_BY_PATH);
auto line = chip.get_line(23); // BCM GPIO23
line.request({.consumer="myapp", .request_type=gpiod::line_request::DIRECTION_OUTPUT}, 0);
for (int i = 0; i < 5; ++i) {
line.set_value(1);
std::this_thread::sleep_for(std::chrono::milliseconds(200));
line.set_value(0);
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
line.release(); // 必须释放,否则下次运行会报 BUSY
}
bcm2835 还能用吗?什么情况下必须用?
能用,但仅限两类场景:裸机(Circle)、或需要精确时序控制(比如 bit-banging 1-Wire)。它直接操作内存寄存器,绕过内核 GPIO 子系统,所以不受 libgpiod 的权限/设备节点限制,也不依赖 udev 规则。
- 初始化只需
bcm2835_init(),之后bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_OUTP)即可设为输出 - 注意:
pin参数必须是 BCM 编号(如 23),不是物理引脚号;RPI_BPLUS_GPIO_J8_31这类宏本质也是转成 BCM 编号 - 最大风险是:如果系统已加载
gpio-pwm或其他驱动占用了某引脚,bcm2835仍会强行写寄存器,可能引发硬件冲突 - 编译要链接
-lbcm2835,且头文件路径需正确(通常/usr/local/include/bcm2835.h)
真正麻烦的从来不是“怎么点亮”,而是“点亮后能不能稳定保持、会不会被其他进程抢走、重启后还生效吗”。libgpiod 把这些都交给了内核管理,而 bcm2835 和 wiringPi 把责任全甩给开发者——后者在调试阶段看不出区别,上线跑三天后突然失灵,才最头疼。


















