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

如何为基于libgpiod的GPIO关机监控代码添加LED心跳闪烁功能

为libgpiod GPIO关机监听程序添加LED心跳闪烁功能

需求背景

现有代码通过libgpiod监听GPIO按钮长按事件触发系统关机,需新增LED心跳闪烁功能(如每隔1秒亮灭一次),同时保留原按钮监听的低CPU占用特性。

实现思路

利用gpiod_line_event_wait的超时参数打破原无限阻塞循环,每次超时后切换LED状态实现心跳效果,同时不影响按钮事件的实时响应。

修改后的完整代码

/*
 * Monitor external button on GPIO pin, shutdown machine if pressed
 * Adds LED heartbeat blink functionality using libgpiod timeout
 */

#define SHUTDOWN_CHIP 2
#define SHUTDOWN_LINE 21     // NEO3 pin 23
#define SHUTDOWN_HOLD 3      // seconds to hold down button
#define LED_CHIP 2           // LED所在GPIO芯片编号,可与关机按钮复用同一片芯片
#define LED_LINE 24          // LED对应的GPIO引脚编号
#define HEARTBEAT_INTERVAL 1 // 心跳间隔(秒)

#include <gpiod.h>          // sudo apt install libgpiod-dev
#include <stdio.h>
#include <unistd.h>
#include <syslog.h>
#include <stdbool.h>

void shut_down(struct gpiod_line *led_line) {
    syslog(LOG_NOTICE, "Safe shutdown triggered from GPIO button");
    // 关机前熄灭LED
    gpiod_line_set_value(led_line, 0);
    system("/usr/bin/sudo /bin/shutdown -h now");
    exit(EXIT_SUCCESS);
};

int main(int argc, char *argv[]) {
    struct gpiod_chip *chip;
    struct gpiod_line *button;
    struct gpiod_line *led_line;
    bool led_state = false; // LED初始状态为熄灭

    // 资源清理函数
    void cleanup_resources() {
        if (led_line) {
            gpiod_line_set_value(led_line, 0);
            gpiod_line_release(led_line);
        }
        if (button)
            gpiod_line_release(button);
        if (chip)
            gpiod_chip_close(chip);
    }

    // 打开GPIO芯片
    chip = gpiod_chip_open_by_number(SHUTDOWN_CHIP);
    if (!chip) {
        perror("Failed to open GPIO chip");
        exit(EXIT_FAILURE);
    }

    // 初始化关机按钮引脚
    button = gpiod_chip_get_line(chip, SHUTDOWN_LINE);
    if (!button) {
        perror("Failed to get shutdown button line");
        cleanup_resources();
        exit(EXIT_FAILURE);
    }
    // 若硬件无默认上拉电阻,可启用下方带flags的请求函数(libgpiod v1.5+支持)
    // if (gpiod_line_request_both_edges_events_flags(button, "gpio-shutdown", GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP) < 0) {
    if (gpiod_line_request_both_edges_events(button, "gpio-shutdown") < 0) {
        perror("Can't claim shutdown button GPIO pin");
        cleanup_resources();
        exit(EXIT_FAILURE);
    }

    // 初始化LED引脚为输出模式
    led_line = gpiod_chip_get_line(chip, LED_LINE);
    if (!led_line) {
        perror("Failed to get LED line");
        cleanup_resources();
        exit(EXIT_FAILURE);
    }
    if (gpiod_line_request_output(led_line, "gpio-heartbeat", 0) < 0) {
        perror("Can't claim LED GPIO pin");
        cleanup_resources();
        exit(EXIT_FAILURE);
    }

    syslog(LOG_INFO, "Monitoring GPIO button for shutdown requests, LED heartbeat active");
    atexit(cleanup_resources);

    struct timespec heartbeat_timeout = {HEARTBEAT_INTERVAL, 0};

    while (true) {
        // 等待按钮事件或心跳超时
        int wait_result = gpiod_line_event_wait(button, &heartbeat_timeout);
        if (wait_result == 1) {
            // 捕获到按钮边缘事件
            struct gpiod_line_event ev;
            struct timespec t_held = {SHUTDOWN_HOLD, 0};
            if (gpiod_line_event_read(button, &ev) == 0) {
                if (ev.event_type == GPIOD_LINE_EVENT_FALLING_EDGE) {
                    // 若按钮长按超时未释放,触发关机
                    if (!gpiod_line_event_wait(button, &t_held)) {
                        shut_down(led_line);
                    }
                }
            }
        } else if (wait_result == 0) {
            // 心跳超时,切换LED状态
            led_state = !led_state;
            gpiod_line_set_value(led_line, led_state ? 1 : 0);
        } else {
            // GPIO事件等待出错
            perror("Error waiting for GPIO event");
            cleanup_resources();
            exit(EXIT_FAILURE);
        }
    };

    return EXIT_SUCCESS;
}

关键修改说明

  • LED资源初始化:新增LED引脚的定义与输出模式配置,初始状态设为熄灭。
  • 超时机制应用:给gpiod_line_event_wait设置心跳间隔超时,让循环定期执行LED状态切换逻辑。
  • 资源清理扩展:在退出函数中添加LED熄灭与资源释放逻辑,避免设备残留异常状态。
  • 关机逻辑优化:触发关机前先熄灭LED,明确设备即将关机的状态。

编译与运行

编译时需链接libgpiod库:

gcc gpio-shutdown-led.c -o gpio-shutdown-led -lgpiod

以root权限运行程序:

sudo ./gpio-shutdown-led

可将程序配置为系统服务,实现开机自动启动。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 10:17:14