跳到主要内容

GPIO

GPIO(General Purpose Input/Output)就是芯片上可以 “自己决定当输入还是当输出” 的通用管脚。

  • 输出 → 输出高/低电平,点灯、继电器、蜂鸣器。
  • 输入 → 读取高/低电平,按键、红外、传感器信号。
  • 可编程 → 通过寄存器或库函数随时切换方向、电平、中断。

每个 SoC/单片机都有几十个甚至上百个 GPIO,是硬件世界与软件世界最直接的“握手口”。

1.命名规则

Rockchip 采用 “bank + port + index” 三段式命名: GPIO<bank>_<port><index>

  • bank:0~4 → 对应 gpio0~4
  • port:A=0, B=1, C=2, D=3
  • index:0~7

1.把名字换成全局编号(sysfs 或 kernel 用),公式:

global = bank × 32 + port × 8 + index

举例:GPIO0_B6

0 × 32 + 1 × 8 + 6 = 14 --> /sys/class/gpio/gpio14

2.把名字换成 libgpiod库中 的 line offset定义:

libgpiod 以 每个控制器为 1 个 chip,因此:

  • chip 名称:gpio0
  • line offset:就是 port × 8 + index = 1 × 8 + 6 = 14

2.引脚分布

在板子上拥有40Pin的拓展引脚,你可以通过下图所示的硬件接口图进行确定,更多详细功能可以通过硬件原理图确定。

注意:如果模块的接收电压是3V3请接入3V3,如果模块的接收电压是1V8请接入1V8。禁止将1V8的模块接入3V3的引脚,会导致模块烧毁!

image-20250829173326706

3.使用GPIO sysfs控制

下面以拓展排针上的GPIO0_B6为例。

image-20250829175401141

1.将GPIO导出到用户空间

#使用root权限
sudo su
#这里以GPIO0_B6为例
echo 14 > /sys/class/gpio/export

导出完成后即可执行以下命令,进入对应gpio的设备目录:

cd /sys/class/gpio/gpio14

对于其他的IO设备,可按照 /sys/class/gpio/gpioN(N=1,2,3,5,...)格式访问。

2.查看目录:

root@dshanpi-a1:/sys/class/gpio/gpio14# ls
active_low device direction edge power subsystem uevent value

作用如下:

名称类型作用说明
active_low文件极性控制。
device符号链接指向 /sys/devices/... 下的真实设备节点,内核内部用,用户一般不用管。
direction文件设置引脚方向。
edge文件中断触发方式(仅输入有效)。
power目录电源管理属性,通常为空;挂起/唤醒相关,用户很少改。
subsystem符号链接指向 /sys/class/gpio 自身,方便脚本快速定位。
uevent文件内核热插拔事件属性,udev 规则用;普通用户无需操作。
value文件读写引脚电平。

3.控制GPIO引脚

1.设置GPIO的方向,选择方向指南(二选一)

# 设置 GPIO 为输入
echo in > direction
# 设置 GPIO 为输出
echo out > direction

2.控制GPIO电平

# 获取引脚输入
cat value
# 设置引脚输出
echo 1 > value
echo 0 > value

注意:如果是1V8的引脚高电平为1V8,如果是3V3的引脚高电平为3V3。

运行完成后取消占用,可执行

echo 14 > /sys/class/gpio/unexport  

4.使用Python程序控制

安装python3 libgpiod库

sudo apt update
sudo apt install python3-libgpiod

4.1 输出控制示例

#!/usr/bin/env python3
import gpiod
import time

CHIP_NAME = "gpio0" # /dev/gpiochip0
LINE_OFFSET = 14 # GPIO0_B6

chip = gpiod.Chip(CHIP_NAME)
line = chip.get_line(LINE_OFFSET)

# 申请为输出,默认低电平
line.request(consumer="rk3576-gpio", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0])

try:
while True:
line.set_value(1)
time.sleep(0.5)
line.set_value(0)
time.sleep(0.5)
except KeyboardInterrupt:
pass
finally:
line.release()

运行方式:

sudo python gpio-out.py

运行效果:可使用万用表测量GPIO0_B6,可观察到其电压值在0和3.3V之间循环。

4.2 输入控制示例

#!/usr/bin/env python3
import gpiod
import time

# gpio0 芯片
chip = gpiod.Chip("gpio0")
# 输出脚:GPIO0_B6 (offset 14)
led = chip.get_line(14)
# 输入脚:GPIO0_A0 (offset 0)
btn = chip.get_line(0)

# 申请输出,默认高
led.request(consumer="led",
type=gpiod.LINE_REQ_DIR_OUT,
default_vals=[1])

# 申请输入,启用下降沿中断
btn.request(consumer="btn",
type=gpiod.LINE_REQ_EV_FALLING_EDGE)

print("上电:GPIO0_B6 = 高")
print("按下 GPIO0_A0 后:GPIO0_B6 拉低,松开恢复高")
print("Ctrl+C 退出")

try:
while True:
ev = btn.event_wait(sec=1) # 阻塞等 1 秒
if ev and btn.event_read().event_type == gpiod.LineEvent.FALLING_EDGE:
led.set_value(0) # 按下 -> 低
print("按键按下 → GPIO0_B6 = 低")
# 简单消抖:等待按钮松开
while btn.get_value() == 0:
time.sleep(0.01)
led.set_value(1) # 松开 -> 高
print("按键松开 → GPIO0_B6 = 高")
except KeyboardInterrupt:
pass
finally:
led.release()
btn.release()

运行方式:

sudo python3 gpio-in.py

运行效果:默认GPIO0_B6为高电平,当您按下用户按键USER1时会变为低电平。

baiwen@dshanpi-a1:~$ sudo python3 gpio-in.py
扩展排针 GPIO0_B6 默认为高
按下 GPIO0_A0 时 GPIO0_B6 拉低,松开恢复高
Ctrl+C 退出
按键按下 → GPIO0_B6 = 低
按键松开 → GPIO0_B6 = 高
按键按下 → GPIO0_B6 = 低
按键松开 → GPIO0_B6 = 高
按键按下 → GPIO0_B6 = 低
按键松开 → GPIO0_B6 = 高
按键按下 → GPIO0_B6 = 低
按键松开 → GPIO0_B6 = 高

按键位置如下图所示:

image-20250829190550796

5.使用C语言控制

安装c libgpiod库

sudo apt update
sudo apt install libgpiod-dev gpiod

5.1 输出控制示例

GPIO的高低电平循环示例:

#include <gpiod.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>

static volatile int running = 1;
void handle_sig(int sig) { running = 0; }

int main(void)
{
const char *chip_name = "gpiochip0";
const unsigned int line_offset = 14; /* GPIO0_B6 */

struct gpiod_chip *chip;
struct gpiod_line *line;

chip = gpiod_chip_open_by_name(chip_name);
if (!chip) { perror("open chip"); return 1; }

line = gpiod_chip_get_line(chip, line_offset);
if (!line) { perror("get line"); gpiod_chip_close(chip); return 1; }

/* 申请输出,默认低电平 */
if (gpiod_line_request_output(line, "rk3576-gpio", 0) < 0) {
perror("request output"); gpiod_chip_close(chip); return 1;
}

signal(SIGINT, handle_sig); /* Ctrl+C 退出 */

while (running) {
gpiod_line_set_value(line, 1);
usleep(500000); /* 0.5 s */
gpiod_line_set_value(line, 0);
usleep(500000);
}

gpiod_line_release(line);
gpiod_chip_close(chip);
puts("\n结束");
return 0;
}

编译程序

gcc gpio-out.c -o gpio-out -lgpiod

运行:

sudo ./gpio-out

运行效果:可使用万用表测量GPIO0_B6,可观察到其电压值在0和3.3V之间循环。

5.2 输入控制示例

#include <gpiod.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdbool.h>

static volatile sig_atomic_t running = 1;
void sig_handler(int sig) { running = 0; }

int main(void)
{
const char *chip_name = "gpiochip0";
const unsigned int ext_offset = 14; /* GPIO0_B6 扩展排针 */
const unsigned int key_offset = 0; /* GPIO0_A0 按键 */

struct gpiod_chip *chip;
struct gpiod_line *ext, *key;

/* 捕获 Ctrl+C */
signal(SIGINT, sig_handler);

/* 打开 gpiochip0 */
chip = gpiod_chip_open_by_name(chip_name);
if (!chip) { perror("open chip"); return 1; }

/* 排针:输出,默认高 */
ext = gpiod_chip_get_line(chip, ext_offset);
if (!ext || gpiod_line_request_output(ext, "ext_pin", 1) < 0) {
perror("request ext"); gpiod_chip_close(chip); return 1;
}

/* 按键:输入,下降沿中断 */
key = gpiod_chip_get_line(chip, key_offset);
if (!key || gpiod_line_request_falling_edge_events(key, "btn") < 0) {
perror("request key"); gpiod_chip_close(chip); return 1;
}

puts("扩展排针 GPIO0_B6 默认为高");
puts("按下 GPIO0_A0 时 GPIO0_B6 拉低,松开恢复高");
puts("Ctrl+C 退出");

while (running) {
if (gpiod_line_event_wait(key, NULL) == 0) { /* 等到下降沿 */
struct gpiod_line_event ev;
gpiod_line_event_read(key, &ev); /* 清事件 */

gpiod_line_set_value(ext, 0); /* 拉低 */
puts("按键按下 → GPIO0_B6 = 低");

/* 等待松开(防抖) */
while (gpiod_line_get_value(key) == 0 && running)
usleep(10000); /* 10 ms */

gpiod_line_set_value(ext, 1); /* 恢复高 */
puts("按键松开 → GPIO0_B6 = 高");
}
}

/* 释放资源 */
gpiod_line_release(ext);
gpiod_line_release(key);
gpiod_chip_close(chip);
puts("结束");
return 0;
}

编译程序

gcc gpio-in.c -o gpio-in -lgpiod

运行:

sudo ./gpio-in

运行效果:默认GPIO0_B6为高电平,当您按下用户按键USER1时会变为低电平。


baiwen@dshanpi-a1:~$ sudo ./gpio-in
扩展排针 GPIO0_B6 默认为高
按下 GPIO0_A0 时 GPIO0_B6 拉低,松开恢复高
Ctrl+C 退出
按键按下 → GPIO0_B6 = 低
按键松开 → GPIO0_B6 = 高
按键按下 → GPIO0_B6 = 低
按键松开 → GPIO0_B6 = 高
按键按下 → GPIO0_B6 = 低
按键松开 → GPIO0_B6 = 高

按键位置如下图所示:

image-20250829190550796