libgpiod C++ API 使用指南
核心类
1. chip 类
代表一个 GPIO 芯片控制器。主要方法:
// 打开 GPIO 芯片
chip(const std::string& device, int how = OPEN_LOOKUP);
// 获取 GPIO 线
line get_line(unsigned int offset);
line find_line(const std::string& name);
line_bulk get_lines(const std::vector<unsigned int>& offsets);
line_bulk get_all_lines();
// 芯片信息
std::string name();
std::string label();
unsigned int num_lines();
打开方式枚举:
OPEN_LOOKUP
- 自动查找设备OPEN_BY_PATH
- 通过路径打开OPEN_BY_NAME
- 通过名称打开OPEN_BY_LABEL
- 通过标签打开OPEN_BY_NUMBER
- 通过编号打开
2. line 类
代表单个 GPIO 线。主要方法:
// 请求控制 GPIO 线
void request(const line_request& config, int default_val = 0);
// 读写值
int get_value();
void set_value(int val);
// 设置配置
void set_config(int direction, std::bitset<32> flags, int value = 0);
void set_direction_input();
void set_direction_output(int value = 0);
// 事件相关
bool event_wait(const std::chrono::nanoseconds& timeout);
line_event event_read();
// 释放控制
void release();
3. line_request 结构体
用于配置 GPIO 线请求。
struct line_request {
std::string consumer; // 使用者名称
int request_type; // 请求类型
std::bitset<32> flags; // 标志位
};
请求类型:
- DIRECTION_AS_IS - 保持当前方向
- DIRECTION_INPUT - 输入模式
- DIRECTION_OUTPUT - 输出模式
- EVENT_FALLING_EDGE - 下降沿事件
- EVENT_RISING_EDGE - 上升沿事件
- EVENT_BOTH_EDGES - 双边沿事件
标志位:
- FLAG_ACTIVE_LOW - 低电平有效
- FLAG_OPEN_SOURCE - 开漏输出
- FLAG_OPEN_DRAIN - 开漏输出
- FLAG_BIAS_DISABLE - 禁用上下拉
- FLAG_BIAS_PULL_DOWN - 下拉
- FLAG_BIAS_PULL_UP - 上拉
4. line_bulk 类
用于批量操作多个 GPIO 线。主要方法:
// 批量请求
void request(const line_request& config, const std::vector<int> default_vals = {});
// 批量读写
std::vector<int> get_values();
void set_values(const std::vector<int>& values);
// 批量设置方向
void set_direction_input();
void set_direction_output(const std::vector<int>& values);
迭代器
1. chip_iter 类
用于遍历系统中的所有 GPIO 芯片。
// 创建迭代器
gpiod::chip_iter iter = gpiod::make_chip_iter();
// 使用方法 1: 手动迭代
for (iter; iter != gpiod::end(iter); ++iter) {
const gpiod::chip& chip = *iter;
// 使用 chip...
}
// 使用方法 2: 范围for循环
for (const auto& chip : gpiod::make_chip_iter()) {
// 使用 chip...
}
主要方法:
chip_iter& operator++(); // 前进到下一个芯片
const chip& operator*() const; // 获取当前芯片引用
const chip* operator->() const; // 获取当前芯片指针
bool operator==(const chip_iter&); // 比较迭代器
bool operator!=(const chip_iter&); // 比较迭代器
2. line_iter 类
用于遍历特定 GPIO 芯片上的所有 GPIO 线。
// 创建迭代器
gpiod::line_iter iter(chip);
// 使用方法 1: 手动迭代
for (iter; iter != gpiod::end(iter); ++iter) {
const gpiod::line& line = *iter;
// 使用 line...
}
// 使用方法 2: 范围for循环
for (const auto& line : gpiod::line_iter(chip)) {
// 使用 line...
}
主要方法:
line_iter(const chip& owner); // 构造函数,指定芯片
line_iter& operator++(); // 前进到下一条线
const line& operator*() const; // 获取当前线引用
const line* operator->() const; // 获取当前线指针
bool operator==(const line_iter&); // 比较迭代器
bool operator!=(const line_iter&); // 比较迭代器
Example
基本 GPIO 使用
#include <gpiod.hpp>
// 打开 GPIO 芯片
gpiod::chip chip("gpiochip0");
// 获取 GPIO 线
auto line = chip.get_line(4);
// 配置请求
gpiod::line_request config;
config.consumer = "my-app";
config.request_type = gpiod::line_request::DIRECTION_OUTPUT;
// 请求控制 GPIO 线
line.request(config);
// 设置输出值
line.set_value(1);
// 读取输入值
int value = line.get_value();
// 释放控制
line.release();
遍历 GPIO 资源 API使用
#include <gpiod.hpp>
#include <iostream>
// 遍历所有 GPIO 芯片
for (const auto& chip : gpiod::make_chip_iter()) {
std::cout << "Found chip: " << chip.name() << std::endl;
// 遍历该芯片的所有 GPIO 线
for (const auto& line : gpiod::line_iter(chip)) {
std::cout << " Line " << line.offset();
if (!line.name().empty()) {
std::cout << " (" << line.name() << ")";
}
std::cout << std::endl;
}
}
总结
API 总结是死的,源码是活的。直接查看ligpiod-dev头文件即可。 头文件的位置:
/usr/include/gpiod.hpp
安装gpiod
sudo apt-get install libgpiod-dev ligpiod-doc
$ dpkg -l |grep gpiod 查看安装情况
ii gpiod 1.6.3-1+b3 arm64 Tools for interacting with Linux GPIO character device - binary
ii libgpiod-dev:arm64 1.6.3-1+b3 arm64 C library for interacting with Linux GPIO device - static libraries and headers
ii libgpiod-doc 1.6.3-1 all C library for interacting with Linux GPIO device - library documentation
ii libgpiod2:arm64 1.6.3-1+b3 arm64 C library for interacting with Linux GPIO device - shared libraries
ii libpigpiod-if-dev 1.79-1+rpt1 arm64 Development headers for client libraries for Raspberry Pi GPIO control
ii libpigpiod-if1 1.79-1+rpt1 arm64 Client library for Raspberry Pi GPIO control (deprecated)
ii libpigpiod-if2-1 1.79-1+rpt1 arm64 Client library for Raspberry Pi GPIO control
ii pigpiod 1.79-1+rpt1 arm64 Client tools for Raspberry Pi GPIO control
ii python3-libgpiod:arm64 1.6.3-1+b3 arm64 Python bindings for libgpiod (Python 3)
编译实例
CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(listgpiochipinfo)
# 设置C++标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# 查找gpiod库
find_library(GPIODCXX_LIBRARY gpiodcxx REQUIRED)
# 添加可执行文件
add_executable(listgpiochipinfo main.cpp)
# 链接gpiod库
target_link_libraries(listgpiochipinfo
${GPIODCXX_LIBRARY}
)
# 包含gpiod头文件路径
target_include_directories(listgpiochipinfo PRIVATE ${GPIOD_INCLUDE_DIRS})
当然,如果嫌弃CMake麻烦,可以选择手动编译:
$ g++ main.cpp -o allChipInfos -lgpiodcxx
Testcase
#include <iostream>
#include <gpiod.hpp>
void func()
{
// int chip_num = 0;
// gpiod::chip_iter chip_iter = gpiod::make_chip_iter();
// for (gpiod::chip_iter iter = gpiod::begin(chip_iter); iter != gpiod::end(chip_iter); ++iter)
// {
// std::cout << "chip_num:" << chip_num << ",label:" << iter->label() << ",name:" << iter->name() << ",lines:" << iter->num_lines() << std::endl;
// chip_num++;
// }
for(const auto &chip : gpiod::make_chip_iter()){
std::cout << "hello,chip_num:" << chip.label() << ",label:" << chip.name() << ",lines:" << chip.num_lines() << std::endl;
}
}
int main()
{
func();
return 0;
}
结果
hello,chip_num:pinctrl-rp1,label:gpiochip0,lines:54
hello,chip_num:gpio-brcmstb@107d508500,label:gpiochip10,lines:32
hello,chip_num:gpio-brcmstb@107d508520,label:gpiochip11,lines:4
hello,chip_num:gpio-brcmstb@107d517c00,label:gpiochip12,lines:17
hello,chip_num:gpio-brcmstb@107d517c20,label:gpiochip13,lines:6
hello,chip_num:pinctrl-rp1,label:gpiochip0,lines:54
终端执行gpiodetect
$ gpiodetect
gpiochip0 [pinctrl-rp1] (54 lines)
gpiochip10 [gpio-brcmstb@107d508500] (32 lines)
gpiochip11 [gpio-brcmstb@107d508520] (4 lines)
gpiochip12 [gpio-brcmstb@107d517c00] (17 lines)
gpiochip13 [gpio-brcmstb@107d517c20] (6 lines)
gpiochip0 [pinctrl-rp1] (54 lines)
$ ls -l /dev |grep gpiochip
crw-rw----+ 1 root gpio 254, 0 Jan 19 01:31 gpiochip0
crw-rw----+ 1 root gpio 254, 10 Jan 19 01:31 gpiochip10
crw-rw----+ 1 root gpio 254, 11 Jan 19 01:31 gpiochip11
crw-rw----+ 1 root gpio 254, 12 Jan 19 01:31 gpiochip12
crw-rw----+ 1 root gpio 254, 13 Jan 19 01:31 gpiochip13
lrwxrwxrwx 1 root root 9 Jan 19 01:31 gpiochip4 -> gpiochip0
有个重定向的。
在做gpio实验前,使用pinout,gpioinfo 先确定:
- 引脚属于哪个chip
- 代码里使用chip iter 迭代器器找到gpiochip,不要直接指定
之前的一篇,控制小灯实验中,使用的固定gpiochip(/dev/gpiochip4)路径,实际上是非常危险的。