前言
在嵌入式 Linux 開發中,控制 GPIO 引腳 是再常見不過的需求。
無論是點亮一個 LED,還是檢測一個按鍵,都離不開對 GPIO 的操作。
本文帶你從最傳統的 /sys/class/gpio 接口入門,再到現代的 libgpiod 接口。
兩者對比之後,你將清楚地知道:
哪種方式適合快速調試?哪種方式適合正式產品開發?
🧩 一、什麼是 GPIO?
GPIO(General Purpose Input/Output)是“通用輸入輸出口”的縮寫。
它是一種最基礎的硬件接口,用來:
- 輸出高低電平(控制 LED、繼電器等)
- 讀取電平狀態(檢測按鍵、傳感器信號等)
Linux 內核會把硬件 GPIO 管理起來,通過驅動暴露給用户空間使用。
而用户空間訪問 GPIO 的方式,主要有兩種:
- 舊接口:sysfs(通過
/sys/class/gpio) - 新接口:libgpiod(通過
/dev/gpiochipX)
⚙️ 二、傳統方式:Sysfs GPIO 接口
在早期的 Linux 系統中,控制 GPIO 通常通過 sysfs 文件系統來完成。
所有 GPIO 節點都位於:
/sys/class/gpio/
🔹 示例操作
cd /sys/class/gpio
# 1. 導出編號為 193 的 GPIO
echo 193 > export
# 2. 設置方向為輸出
echo out > gpio193/direction
# 3. 輸出高電平
echo 1 > gpio193/value
# 4. 輸出低電平
echo 0 > gpio193/value
# 5. 讀當前狀態
cat gpio193/value
執行這些命令後,就能在硬件上看到 LED 燈亮起或熄滅。
🧮 三、GPIO 編號的計算公式(為什麼是 193?)
在 Linux 中,每個 GPIO 控制器(gpiochip) 會負責一組引腳(通常 32 個),
每組都從一個基地址(base)開始編號。
你可以通過以下命令查看:
cat /sys/class/gpio/gpiochip0/base
cat /sys/class/gpio/gpiochip0/ngpio
例如:
base = 0
ngpio = 224
這表示:
- 第一個控制器(gpiochip0)管理 GPIO0 ~ GPIO223
- 每個 GPIO 實際編號 =
base + 引腳偏移號
🔹 計算公式
GPIO 全局編號 = GPIO 控制器基址(base) + 引腳號(offset)
🔹 舉例:以全志(Allwinner)芯片為例
在很多全志平台(如 H3/H5/F1C100s 等)中,GPIO 命名方式是:
PnX—— n 表示組號,X 表示組內編號
每組通常有 32 個引腳(編號 0~31)
因此計算公式可以寫成:
GPIO 編號 = n × 32 + X
例如:
|
引腳名稱
|
組號 (n)
|
組內編號 (X)
|
全局編號 (n×32 + X)
|
|
PA0
|
0
|
0
|
0
|
|
PA10
|
0
|
10
|
10
|
|
PB0
|
1
|
0
|
32
|
|
PC1
|
2
|
1
|
65
|
|
PD0
|
3
|
0
|
96
|
|
PG1 |
6 |
1 |
6×32 + 1 = 193 ✅ |
所以當你執行:
echo 193 > /sys/class/gpio/export
實際上就是導出了 PG1 這個物理引腳。
💡 小結:
- 不同芯片的組號不同(例如
PA、PB、PG等) - 每組佔 32 個引腳
- 編號從 0 開始
- 有些平台(如 Rockchip、NXP)命名方式略有不同,但計算原理一致
🧱 四、現代方式:Libgpiod 新接口
為了替代 sysfs,Linux 引入了更現代的接口:
/dev/gpiochipX
這是一種基於 字符設備 的設計,每個 GPIO 控制器會被映射為一個設備節點。
同時,官方提供了用户空間庫和命令行工具:libgpiod。
🔹 命令行示例
安裝(部分發行版):
apt install gpiod
使用命令行工具操作:
# 查看 GPIO 控制器信息
gpiodetect
# 查看 gpiochip0 的所有引腳
gpioinfo gpiochip0
# 設置編號為193的GPIO為高電平
gpioset gpiochip0 193=1
# 讀取編號為193的GPIO電平
gpioget gpiochip0 193
還可以設置多個引腳:
gpioset gpiochip0 193=1 194=0 195=1
🔹 C語言調用示例
#include <gpiod.h>
#include <stdio.h>
int main(void) {
struct gpiod_chip *chip;
struct gpiod_line *line;
// 打開 gpiochip0
chip = gpiod_chip_open_by_name("gpiochip0");
// 獲取編號為193的引腳
line = gpiod_chip_get_line(chip, 193);
// 設置為輸出並拉高
gpiod_line_request_output(line, "myapp", 1);
// 延時1秒後拉低
sleep(1);
gpiod_line_set_value(line, 0);
// 釋放資源
gpiod_line_release(line);
gpiod_chip_close(chip);
}
⚔️ 五、Sysfs vs Libgpiod 對比
|
對比項
|
Sysfs GPIO
|
Libgpiod
|
|
接口位置
|
|
|
|
狀態
|
已廢棄 (deprecated)
|
官方推薦
|
|
訪問方式
|
文件讀寫
|
函數/命令行工具
|
|
併發控制
|
不支持
|
支持
|
|
性能
|
較低
|
更高
|
|
適用場景
|
調試、老項目
|
新項目、正式產品
|
|
事件監聽
|
不支持
|
支持(可響應中斷)
|
🚀 六、總結:新手該怎麼選?
|
目的
|
推薦方式
|
|
想快速點亮一個燈
|
sysfs(操作簡單、幾條命令就夠) |
|
在正式項目中控制 GPIO
|
libgpiod(性能更好、未來趨勢) |
|
寫 C 代碼或腳本程序
|
libgpiod |
|
學習內核 GPIO 原理
|
從 sysfs 入門更容易理解
|
sysfs是老方法,簡單但過時;libgpiod是新標準,更強大、可維護、未來主流;- GPIO 編號的計算遵循:
GPIO編號 = 組號 × 32 + 組內偏移
例如 PG1 → 6×32 + 1 = 193。
🧭 延伸閲讀
- Linux Kernel Documentation – GPIO Sysfs Interface (deprecated)
- Libgpiod GitHub 項目