Raspberry 树莓派 gpio libgpiod C++ API 使用指南

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)路径,实际上是非常危险的。

上一篇:树莓派5 Raspberry Pi5 c++ 访问GPIO:控制小灯

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值