Linux系统编程-通过sys子系统控制gpio
重要提示:sysfs GPIO 接口自 Linux 4.8 起已被标记为已弃用,并在 Linux 5.3 之后开始逐步移除。
基本原理
sysfs 是一个虚拟文件系统,它将内核中的设备、驱动等信息映射到用户空间,以文件和目录的形式呈现。
对于 GPIO,其控制接口位于 /sys/class/gpio/。
将 gpio 写入 /sys/class/gpio/export ,就可将此 gpio 从内核空间导出到用户空间。例如:
1 | echo 12 > /sys/class/gpio/export |
导出后,在 /sys/class/gpio/ 目录下就会生成一个 gpio12 目录。其目录结构如下:
gpio12
├── active_low
├── device -> ../../../gpiochip0
├── direction
├── edge
├── power
│ ├── autosuspend_delay_ms
│ ├── control
│ ├── runtime_active_time
│ ├── runtime_status
│ └── runtime_suspended_time
├── subsystem -> ../../../../../../../class/gpio
├── uevent
└── value
GPIO Sysfs 接口文件功能详解:
value (最重要的文件)
功能:读取或设置GPIO引脚的电平状态。
读取 (
cat value):
- 返回引脚的当前电平状态。
- 0: 代表低电平。
- 1: 代表高电平。
写入 (
echo 1 > value或echo 0 > value):
- 当引脚被设置为输出模式时,向此文件写入可以控制引脚输出高电平或低电平。
- 注意:在写入之前,必须先将
direction设置为out。direction
功能:设置GPIO引脚的方向(输入或输出)。
读取 (
cat direction):
- 返回引脚当前的方向,通常是
in或out。写入:
echo in > direction: 将引脚设置为输入模式。echo out > direction: 将引脚设置为输出模式。- 注意:出于安全考虑,将方向从
in改为out时,引脚的初始输出电平是未定义的。有些系统允许使用echo low > direction或echo high > direction来同时设置方向为输出并指定初始输出电平(low为低,high为高)。edge
功能:设置引脚的中断触发模式。这个文件仅当引脚设置为输入模式时有效。
读取 (
cat edge): 返回当前设置的中断触发模式。写入:
echo none > edge: 默认值。禁止中断触发。表示忽略该引脚上的边沿变化。echo rising > edge: 设置为上升沿触发。当引脚电平从低变高时,会产生中断事件。echo falling > edge: 设置为下降沿触发。当引脚电平从高变低时,会产生中断事件。echo both > edge: 设置为双边沿触发。只要引脚电平发生变化(无论是上升还是下降),都会产生中断事件。active_low
功能:反转引脚的逻辑电平。这是一个非常有用的功能,用于处理低电平有效的设备(例如,低电平触发的LED或按键)。
读取 (
cat active_low):
- 0: 默认值。正常逻辑。
value文件中的0代表低电平,1代表高电平。- 1: 反转逻辑。
value文件中的0现在代表高电平,1代表低电平。写入:
echo 0 > active_low: 使用正常逻辑。echo 1 > active_low: 使用反转逻辑。device
功能:一个符号链接(Symbolic Link),指向这个GPIO引脚所属于的硬件设备(通常是GPIO控制器芯片)在
/sys/devices/目录下的路径。作用: 主要用于在sysfs文件系统中维护设备之间的层次关系,对于普通用户控制GPIO来说,一般不需要关心这个文件。
subsystem
功能:一个符号链接,指向包含它的子系统目录,即
/sys/class/gpio。作用: 同样用于维护sysfs的内部结构,表明这个
gpio12目录属于gpio子系统。用户通常无需操作。uevent
功能:内核事件接口。主要用于通知设备管理器(如udev)关于设备的热插拔事件。
作用: 当你向这个文件写入
add,它会强制内核发送一个“新增设备”的事件,通知用户空间的设备管理工具。对于GPIO,这个文件通常由系统自动管理,用户一般不需要手动操作。power
功能:电源管理相关目录。它包含一些与设备电源状态管理相关的接口文件,如
async,runtime_status,control等。作用: 用于高级的电源管理功能,例如挂起或恢复设备以节省功耗。对于简单的GPIO操作,完全可以忽略这个目录及其内容。
控制步骤
要控制一个GPIO,通常遵循以下步骤:
- 导出引脚:
echo 12 > /sys/class/gpio/export- 设置方向:
- 输出:
echo out > /sys/class/gpio/gpio12/direction- 输入:
echo in > /sys/class/gpio/gpio12/direction- 操作引脚:
- 如果是输出:
- 设置高电平:
echo 1 > /sys/class/gpio/gpio12/value- 设置低电平:
echo 0 > /sys/class/gpio/gpio12/value- 如果是输入:
- 读取电平:
cat /sys/class/gpio/gpio12/value- (可选)如果需要中断通知,设置中断模式:
echo rising > /sys/class/gpio/gpio12/edge- (完成后)取消导出:
echo 12 > /sys/class/gpio/unexport(这会移除gpio12目录)
GPIO 输出
操作步骤
导出 GPIO
将 GPIO 控制从内核空间导出到用户空间
1 | echo 12 > /sys/class/gpio/export |
设置成输出模式
1 | echo out > /sys/class/gpio/gpio12/direction |
设置高低电平
1 | echo 1 > /sys/class/gpio/gpio12/value |
shell 编程示例
1 |
|
C 系统编程示例
1 |
|
GPIO 输入
操作步骤
导出 GPIO
将 GPIO 控制从内核空间导出到用户空间
1 | echo 12 > /sys/class/gpio/export |
设置成输入模式
1 | echo in > /sys/class/gpio/gpio12/direction |
读取电平
1 | cat /sys/class/gpio/gpio12/value |
C 系统编程示例
1 |
|
GPIO 中断
实现步骤
导出 GPIO
首先需要导出要使用的 GPIO 引脚:
1 | # 以 GPIO 13 为例 |
设置方向为输入
1 | echo "in" > /sys/class/gpio/gpio13/direction |
设置边沿触发模式
这是关键步骤,设置中断触发方式:
1 | # 设置为下降沿触发(从高到低电平变化) |
使用 poll 监测中断
poll 函数
函数原型和头文件
1 |
|
参数详解
struct pollfd *fds
指向 pollfd 结构体数组的指针,每个结构体描述一个要监视的文件描述符。
1 | struct pollfd { |
nfds_t nfds
fds 数组中的元素数量。
int timeout
等待的超时时间(毫秒):
-1:无限期阻塞,直到有事件发生0:立即返回,不阻塞(轮询)> 0:等待指定的毫秒数
返回值
- > 0:返回就绪的文件描述符数量
- = 0:超时,没有文件描述符就绪
- -1:发生错误,并设置
errno
events 和 revents 标志
常用事件标志:
| 标志 | 描述 | 用途 |
|---|---|---|
POLLIN |
有数据可读 | 普通文件、socket、管道 |
POLLPRI |
有紧急数据可读 | 带外数据、GPIO中断 |
POLLOUT |
可写,不会阻塞 | 普通文件、socket |
POLLERR |
发生错误 | 自动设置,无需请求 |
POLLHUP |
挂起 | 对端关闭连接 |
POLLNVAL |
文件描述符未打开 | 自动设置 |
C 编程
1 |
|







