Linux 应用层 GPIO 编程指南

Linux 应用层 GPIO 编程指南

一、GPIO 基础概念与架构

1. 什么是 GPIO?

GPIO(General Purpose Input/Output)是通用输入输出端口,可以通过软件控制实现输入输出功能。

2. Linux GPIO 架构

应用层 API
    ↓
sysfs GPIO 接口
    ↓
GPIO 子系统
    ↓
GPIO 驱动
    ↓
GPIO 硬件

二、GPIO 访问方式

1. sysfs 接口

Linux 提供了 sysfs 文件系统接口,路径为 /sys/class/gpio/

/sys/class/gpio/
├── export          # 导出GPIO
├── unexport        # 取消导出
└── gpioN/          # GPIO目录
    ├── direction   # 方向控制
    ├── value       # 值读写
    └── edge        # 中断触发

2. 字符设备接口

新版本 Linux 内核推荐使用字符设备接口 /dev/gpiochipN

三、GPIO 编程实战

1. 基础 GPIO 操作

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>

// GPIO 导出函数
int gpio_export(unsigned int gpio) {
    int fd, len;
    char buf[64];

    fd = open("/sys/class/gpio/export", O_WRONLY);
    if (fd < 0) {
        perror("gpio/export");
        return fd;
    }

    len = snprintf(buf, sizeof(buf), "%d", gpio);
    write(fd, buf, len);
    close(fd);

    return 0;
}

// GPIO 方向设置
int gpio_set_dir(unsigned int gpio, const char* dir) {
    int fd;
    char buf[64];

    snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/direction", gpio);
    fd = open(buf, O_WRONLY);
    if (fd < 0) {
        perror("gpio/direction");
        return fd;
    }

    write(fd, dir, strlen(dir));
    close(fd);

    return 0;
}

// GPIO 值读取
int gpio_get_value(unsigned int gpio) {
    int fd;
    char buf[64], ch;

    snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/value", gpio);
    fd = open(buf, O_RDONLY);
    if (fd < 0) {
        perror("gpio/value");
        return fd;
    }

    read(fd, &ch, 1);
    close(fd);

    return ch == '0' ? 0 : 1;
}

// GPIO 值设置
int gpio_set_value(unsigned int gpio, int value) {
    int fd;
    char buf[64];

    snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/value", gpio);
    fd = open(buf, O_WRONLY);
    if (fd < 0) {
        perror("gpio/value");
        return fd;
    }

    write(fd, value ? "1" : "0", 1);
    close(fd);

    return 0;
}

2. 中断处理示例

#include <poll.h>

int gpio_set_edge(unsigned int gpio, const char* edge) {
    int fd;
    char buf[64];

    snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/edge", gpio);
    fd = open(buf, O_WRONLY);
    if (fd < 0) {
        perror("gpio/edge");
        return fd;
    }

    write(fd, edge, strlen(edge));
    close(fd);

    return 0;
}

// 等待 GPIO 中断
int gpio_wait_for_interrupt(unsigned int gpio, int timeout_ms) {
    int fd, ret;
    char buf[64];
    struct pollfd pfd;
    char ch;

    snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/value", gpio);
    fd = open(buf, O_RDONLY);
    if (fd < 0) {
        perror("gpio/value");
        return fd;
    }

    // 清除初始状态
    read(fd, &ch, 1);

    pfd.fd = fd;
    pfd.events = POLLPRI | POLLERR;
    pfd.revents = 0;

    ret = poll(&pfd, 1, timeout_ms);
    close(fd);

    return ret;
}

四、实际应用示例

1. LED 控制示例

int main() {
    const int LED_GPIO = 18;  // 使用GPIO18
    
    // 导出GPIO
    gpio_export(LED_GPIO);
    
    // 设置为输出模式
    gpio_set_dir(LED_GPIO, "out");
    
    // LED闪烁5次
    for (int i = 0; i < 5; i++) {
        gpio_set_value(LED_GPIO, 1);  // LED开
        sleep(1);
        gpio_set_value(LED_GPIO, 0);  // LED关
        sleep(1);
    }
    
    return 0;
}

2. 按键检测示例

int main() {
    const int BUTTON_GPIO = 17;  // 使用GPIO17
    
    // 导出GPIO
    gpio_export(BUTTON_GPIO);
    
    // 设置为输入模式
    gpio_set_dir(BUTTON_GPIO, "in");
    
    // 设置边缘触发
    gpio_set_edge(BUTTON_GPIO, "rising");
    
    printf("等待按键按下...\n");
    while (1) {
        if (gpio_wait_for_interrupt(BUTTON_GPIO, -1) > 0) {
            printf("检测到按键按下!\n");
        }
    }
    
    return 0;
}

五、注意事项

  1. 权限问题

    • GPIO 操作通常需要 root 权限
    • 可以通过 udev 规则配置访问权限
  2. 性能考虑

    • sysfs 接口性能较低
    • 对于高速操作,建议使用字符设备接口
  3. 资源管理

    • 及时关闭文件描述符
    • 程序退出时取消导出 GPIO
  4. 错误处理

    • 检查所有系统调用的返回值
    • 实现适当的错误恢复机制

六、调试技巧

  1. LED控制示例
# 1. 导出GPIO
echo 18 > /sys/class/gpio/export

# 2. 设置为输出模式
echo out > /sys/class/gpio/gpio18/direction

# 3. 控制LED
echo 1 > /sys/class/gpio/gpio18/value  # LED亮
echo 0 > /sys/class/gpio/gpio18/value  # LED灭

# 4. 使用完后取消导出
echo 18 > /sys/class/gpio/unexport
  1. 按键输入示例
# 1. 导出GPIO
echo 17 > /sys/class/gpio/export

# 2. 设置为输入模式
echo in > /sys/class/gpio/gpio17/direction

# 3. 设置中断触发方式
echo rising > /sys/class/gpio/gpio17/edge

# 4. 读取按键状态
cat /sys/class/gpio/gpio17/value

# 5. 使用完后取消导出
echo 17 > /sys/class/gpio/unexport
  1. 使用工具
    • multimeter(万用表)测量电平
    • oscilloscope(示波器)观察波形
    • logic analyzer(逻辑分析仪)分析时序
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值