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

如何在Yocto中实现GPIO按键触发syslog的systemd服务?

实现GPIO按键触发Syslog日志的systemd服务(Yocto环境)

在Yocto环境中开发了一个作为systemd服务的用户态应用,需求是当连接到GPIO 193引脚的按键按下时,在syslog中生成"button pressed"日志。以下是现有代码及完善的实现建议:


现有C代码

#include <stdio.h>
#include <unistd.h>
#include <syslog.h>
#include <fcntl.h>
#include <systemd/sd-event.h>

#define GPIO_PIN "/sys/class/gpio/gpio1009/value" // 1009是GPIO193的导出编号(芯片编号816)

int button_event_callback(sd_event_source *source, int fd, uint32_t revents, void *userdata)
{
    char value;
    ssize_t bytes_read = read(fd, &value, 1); // 读取GPIO电平值

    if (bytes_read == -1) {
        perror("Error reading GPIO pin value");
        return -1;
    }

    if (value == '0') {
        syslog(LOG_INFO,"Button pressed!\n");
        printf("Button Pressed!\n");
    }

    return 0;
}

int main()
{
    sd_event *event_loop = NULL;

    sd_event_new(&event_loop);

    int button_fd = open(GPIO_PIN, O_RDONLY); // 打开GPIO值文件

    if (button_fd == -1) {
        perror("Error opening GPIO pin file");
        return 1;
    }

    sd_event_add_io(event_loop, NULL, button_fd, EPOLLIN, button_event_callback, NULL);

    syslog(LOG_INFO,"Listening for button press events.\n");

    sd_event_run(event_loop,-1);
    sd_event_unref(event_loop);

    return 0;
}

现有systemd服务文件

[Unit]
Description=Continuous Hello World Service
After=syslog.target

[Service]
ExecStart=/usr/bin/buttonser
StandardOutput=syslog
Type=simple
Restart=always

[Install]
WantedBy=multi-user.target

实现建议
  • GPIO硬件配置修正

    • 确保GPIO193已导出为gpio1009:可手动执行echo 1009 > /sys/class/gpio/export验证,或在Yocto中通过设备树、udev规则自动导出该GPIO。
    • 配置GPIO方向与上下拉:执行echo in > /sys/class/gpio/gpio1009/direction设置为输入,根据硬件电路执行echo pullup > /sys/class/gpio/gpio1009/pull(若支持)确保按键默认电平稳定。
    • 启用边沿触发:sysfs GPIO默认不触发IO事件,需设置边沿检测规则,例如按键按下时电平从高变低,执行echo falling > /sys/class/gpio/gpio1009/edge;若为低电平触发,根据实际选rising或both。
  • 代码优化

    • 添加非阻塞打开标志:修改open(GPIO_PIN, O_RDONLY | O_NONBLOCK),避免read操作阻塞,适配sd-event事件驱动模型。
    • 初始化syslog标识:在main函数开头添加openlog("buttonser", LOG_PID | LOG_CONS, LOG_DAEMON);,让日志携带进程ID和明确服务标识,方便排查。
    • 重置文件偏移量:在callback函数读取完成后添加lseek(fd, 0, SEEK_SET);,因为sysfs的value文件读取后指针会停在末尾,重置后才能正常读取下一次电平变化。
  • systemd服务文件修正

    • 修正描述信息:将Description改为GPIO Button Press Logger Service,明确服务用途。
    • 添加权限配置:若GPIO文件权限不足,添加User=root(或具有GPIO访问权限的用户),确保进程能正常读取GPIO节点。
    • 调整重启策略:将Restart=always改为Restart=on-failure,仅在服务异常退出时重启,避免无意义的重启操作。
  • Yocto编译与部署

    • 配置编译依赖:在.bb文件中添加DEPENDS += "systemd"和LDFLAGS += "-lsystemd",确保链接systemd库。
    • 安装服务文件:将服务文件放置到${D}/lib/systemd/system/buttonser.service,并添加SYSTEMD_SERVICE_${PN} = "buttonser.service",让Yocto自动处理服务安装。
    • 自动启用服务:添加SYSTEMD_AUTO_ENABLE_${PN} = "enable",部署后自动启用服务。
  • 功能验证

    • 查看服务日志:执行journalctl -u buttonser.service查看服务专属日志,确认按键按下时出现"Button pressed!"条目。
    • 检查服务状态:systemctl status buttonser.service确认服务正常运行,无启动错误。
    • 手动触发测试:按下按键,观察journalctl输出是否有对应日志生成。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 18:58:23