You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于libgpiod与C++实现多GPIO线路变化监听及值获取问询

问题描述

在树莓派4上使用C++结合libgpiod库开发时,编写了monitor函数监听GPIO线路变化,但调用event_wait等待事件触发后,无法确定具体哪条线路发生了变化,也无法获取线路的当前值和事件时间戳。同时想确认遍历所有线路的方案是否可行。

初始代码:

void monitor()
{
    const std::string chipname = "gpiochip0";
    const std::vector<int> offsets = {4, 5}; // Lines 4 and 5 for testing
    try
    {
        gpiod::chip chip(chipname);
        gpiod::line_bulk lines;

        for (int offset : offsets)
        {
            auto line = chip.get_line(offset);
            line.request({"monitor", gpiod::line_request::EVENT_BOTH_EDGES, 0});
            lines.append(line);
        }

        while (true)
        {
            // Infinite waiting on all lines
            auto signals = lines.event_wait(std::chrono::nanoseconds(0));

            // STUCK HERE - How can I find out which line has changed and get its value and timestamp.
        }
    }
    catch (const std::exception &e)
    {
        std::cerr << "Error: " << e.what() << std::endl;
    }
}

尝试的版本1代码:

void monitor()
{
    const std::string chipname = "gpiochip0";
    const std::vector<int> offsets = {4, 5}; // Lines 4 and 5 for testing
    try
    {
        gpiod::chip chip(chipname);
        gpiod::line_bulk lines;

        for (int offset : offsets)
        {
            auto line = chip.get_line(offset);
            line.request({"monitor", gpiod::line_request::EVENT_BOTH_EDGES, 0});
            lines.append(line);
        }

        while (true)
        {
            // Infinite waiting on all lines
            auto signals = lines.event_wait(std::chrono::nanoseconds(0));

            for (unsigned int i = 0; i < lines.size(); ++i)
            {
                if (lines[i].event_wait(std::chrono::seconds(0)))
                {
                    std::cout << "Change detected on GPIO line " << offsets[i] << std::endl;
                }
            }
        }
    }
    catch (const std::exception &e)
    {
        std::cerr << "Error: " << e.what() << std::endl;
    }
}
解决方案

1. 直接定位触发事件的线路

line_bulk::event_wait返回的signals对象已经包含了所有触发事件的GPIO线路,不需要遍历全部线路。直接遍历这个返回的line_bulk就能精准定位发生变化的线路。

2. 获取事件时间戳与线路当前值

对每个触发事件的线路,调用line::event_read()可获取gpiod::line_event对象:

  • timestamp字段是事件发生的纳秒级时间戳
  • type字段标记事件为上升沿(gpiod::line_event::EVENT_RISING_EDGE)或下降沿(gpiod::line_event::EVENT_FALLING_EDGE)
    再调用line::get_value()就能获取线路当前的电平值。

3. 遍历方案的可行性

你尝试的遍历所有线路的方案是可行的,但效率不如直接使用event_wait返回的signals。因为返回的signals已经明确告知触发事件的线路,逐个检查全部线路属于冗余操作。如果监听的线路数量很少,两者差异不大,但推荐用返回的signals处理,代码更简洁高效。

修改后的完整代码
void monitor()
{
    const std::string chipname = "gpiochip0";
    const std::vector<int> offsets = {4, 5}; // Lines 4 and 5 for testing
    try
    {
        gpiod::chip chip(chipname);
        gpiod::line_bulk lines;

        for (int offset : offsets)
        {
            auto line = chip.get_line(offset);
            line.request({"monitor", gpiod::line_request::EVENT_BOTH_EDGES, 0});
            lines.append(line);
        }

        while (true)
        {
            // 无限等待事件触发
            auto signals = lines.event_wait(std::chrono::nanoseconds(0));

            // 遍历所有触发事件的线路
            for (const auto& line : signals)
            {
                // 读取事件信息
                auto event = line.event_read();
                // 获取当前线路电平值
                int value = line.get_value();

                // 输出事件详情
                std::cout << "GPIO线路 " << line.offset() << " 发生变化: ";
                if (event.type == gpiod::line_event::EVENT_RISING_EDGE)
                    std::cout << "上升沿";
                else
                    std::cout << "下降沿";
                std::cout << " | 当前值: " << value 
                          << " | 时间戳: " << event.timestamp.count() << "ns" << std::endl;
            }
        }
    }
    catch (const std::exception &e)
    {
        std::cerr << "Error: " << e.what() << std::endl;
    }
}

内容的提问来源于stack exchange,提问作者Mendes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 16:57:08