GPIO的使用
最近又要做嵌入式了,发现这块还是非常非常重要,再补一下吧。
在日常的工作中,其实要做的就是两点。1 查看GPIO的状态。2 修改GPIO的状态。
1 查看GPIO状态
命令有很多种,甚至不同的平台也有自己的命令,这里就用最通用命令gpiod来看吧。
首先还是安装:
sudo apt update sudo apt install -y gpiod基本查看:
tom@tom:~$ gpiodetect gpiochip0 [pinctrl-rp1] (54 lines) gpiochip10 [gpio-brcmstb@107d508500] (32 lines) gpiochip11 [gpio-brcmstb@107d517c00] (17 lines) gpiochip12 [gpio-brcmstb@107d517c20] (6 lines) gpiochip13 [gpio-brcmstb@107d508520] (4 lines)可以看到,这里分了5组,对应了5个GPIO控制器,也就是chip0,chip1...。一般我们用chip0就可以了,作用如下:
piochip0 [pinctrl-rp1] (54 lines) → 40 针排针全部在这里(外接 LCD、传感器、串口 IO 唯一要用的)
gpiochip10/11/12/13 [gpio-brcmstb@xxx] → 主芯片 BCM2712 内置内部 GPIO,不引出到 40 针插座,gpio-brcmstb = Broadcom STB 架构 GPIO,属于主芯片 BCM2712 本体,无物理排针引出,作用全是板载内置功能。用户一般完全不用碰。gpiochip10 32 路,主要负责:PCIe、SDIO (Wifi / 蓝牙 SD 总线)、USB 电源使能、USB 过流检测、蓝牙串口控制脚
gpiochip11 17 路,AON(始终上电不掉电)电源域 GPIO:PMIC 中断、HDMI I2C 复位、系统电源控制、2712 休眠唤醒
gpiochip12 6 路,辅助低速电源 / 状态信号
gpiochip13 4 路,SD 卡电源、卡检测、核心电源门控
具体看某一路的状态:
tom@tom:~$ gpioget --chip gpiochip0 17 "17"=inactive查看整个chip0的状态:
tom@tom:~$ gpioinfo --chip gpiochip0 gpiochip0 - 54 lines: line 0: "ID_SDA" input line 1: "ID_SCL" input line 2: "GPIO2" input line 3: "GPIO3" input line 4: "GPIO4" output consumer="dc" line 5: "GPIO5" input line 6: "GPIO6" input line 7: "GPIO7" output active-low consumer="spi0 CS1" line 8: "GPIO8" output active-low consumer="spi0 CS0" line 9: "GPIO9" input line 10: "GPIO10" input line 11: "GPIO11" input line 12: "GPIO12" input line 13: "GPIO13" input line 14: "GPIO14" input line 15: "GPIO15" input line 16: "GPIO16" output consumer="reset" line 17: "GPIO17" input line 18: "GPIO18" input line 19: "GPIO19" input line 20: "GPIO20" input line 21: "GPIO21" input line 22: "GPIO22" input line 23: "GPIO23" input line 24: "GPIO24" input line 25: "GPIO25" input line 26: "GPIO26" input line 27: "GPIO27" input line 28: "PCIE_RP1_WAKE" input line 29: "FAN_TACH" input line 30: "HOST_SDA" input line 31: "HOST_SCL" input line 32: "ETH_RST_N" output active-low consumer="phy-reset" line 33: "-" input line 34: "CD0_IO0_MICCLK" output consumer="cam0_reg" line 35: "CD0_IO0_MICDAT0" input line 36: "RP1_PCIE_CLKREQ_N" input line 37: "-" input line 38: "CD0_SDA" input line 39: "CD0_SCL" input line 40: "CD1_SDA" input line 41: "CD1_SCL" input line 42: "USB_VBUS_EN" output line 43: "USB_OC_N" input line 44: "RP1_STAT_LED" output active-low consumer="PWR" line 45: "FAN_PWM" output line 46: "CD1_IO0_MICCLK" output consumer="cam1_reg" line 47: "2712_WAKE" input line 48: "CD1_IO1_MICDAT1" input line 49: "EN_MAX_USB_CUR" output line 50: "-" input line 51: "-" input line 52: "-" input line 53: "-" input这里也就是0~27是可以控制的,可以连接到40Pin的引脚,其余的内部板载硬件专用引脚,最好不要动。
第二列的ID_SDA这个就是端口在设备树里面的名字。其余的状态解释如下:
| 状态类别 | gpiod 状态文本 / 属性 | 物理含义 | 典型应用场景 / 固件工程师视角 |
| 方向 (Direction) | input | 输入状态,高阻抗,只读电平。 | 读中断、按键、传感器状态采样。 |
output | 输出状态,主动驱动外设电平。 | 控制 LED、控制电源开关(EN)、RESET 信号。 | |
| 极性 (Polarity) | active-high | 高电平有效(默认值,通常不显式打印)。 | 标准的正逻辑控制。 |
active-low | 低电平有效。软件逻辑与物理电平反转。 | 常见于RESET_N、CS_N或低电平触发的 LED。 | |
| 内部偏置 (Bias) | pull-up | 开启 SoC 内部上拉电阻(通常为几K到几十K欧姆)。 | 物理引脚悬空时,强行让其稳定在高电平,防止噪声干扰引发误中断。 |
pull-down | 开启 SoC 内部下拉电阻。 | 物理引脚悬空时,强行让其稳定在低电平(0V)。 | |
bias-disable | 关闭内部上下拉(Floating/浮空)。 | 当外部电路已经焊接了强上拉/下拉电阻时使用,避免电阻并联改变阻值。 | |
| 驱动模式 (Drive) | push-pull | 推挽输出(默认)。引脚能主动拉高,也能主动拉低。 | 绝大多数高低电平控制的标准配置,驱动能力强。 |
open-drain | 开漏输出。引脚只能主动拉低(GND),释放时呈高阻态。 | 常见于 I2C 总线(SDA/SCL)或多个设备共享一条中断线的场景(线与逻辑),需外接上拉电阻。 | |
open-source | 开源输出(极少用)。引脚只能主动拉高,释放时呈高阻态。 | 与开漏相反,需外接下拉电阻。 | |
| 占用状态 (Usage) | used/kernel | 该引脚已经被内核中的某个驱动程序(Driver)申请占用了。 | 如果你在用户态通过gpioset去控这个引脚,会直接报错Device or resource busy。 |
unused | 引脚闲置。 | 用户态可以随时通过gpiod工具接管并控制。 |
一般来说,要隔绝某个GPIO,直接设置成Input就可以了。
树莓派自己的命令结果如下:
tom@tom:~$ pinctrl 0: ip pu | hi // ID_SDA/GPIO0 = input 1: ip pu | hi // ID_SCL/GPIO1 = input 2: a3 pu | hi // GPIO2 = SDA1 3: a3 pu | hi // GPIO3 = SCL1 4: op dh pu | hi // GPIO4 = output 5: no pu | -- // GPIO5 = none 6: no pu | -- // GPIO6 = none 7: op dh pu | hi // GPIO7 = output 8: op dh pu | hi // GPIO8 = output 9: a0 pn | lo // GPIO9 = SPI0_MISO 10: a0 pn | lo // GPIO10 = SPI0_MOSI 11: a0 pn | lo // GPIO11 = SPI0_SCLK 12: no pd | -- // GPIO12 = none 13: no pd | -- // GPIO13 = none 14: a4 pn | hi // GPIO14 = TXD0 15: a4 pu | hi // GPIO15 = RXD0 16: op dl pd | lo // GPIO16 = output 17: no pd | -- // GPIO17 = none 18: no pd | -- // GPIO18 = none 19: no pd | -- // GPIO19 = none 20: no pd | -- // GPIO20 = none 21: no pd | -- // GPIO21 = none 22: no pd | -- // GPIO22 = none 23: no pd | -- // GPIO23 = none 24: no pd | -- // GPIO24 = none 25: no pd | -- // GPIO25 = none 26: no pd | -- // GPIO26 = none 27: no pd | -- // GPIO27 = none 28: no pd | lo // PCIE_RP1_WAKE/GPIO28 = none 29: no pu | lo // FAN_TACH/GPIO29 = none 30: no pu | -- // HOST_SDA/GPIO30 = none 31: no pu | -- // HOST_SCL/GPIO31 = none 32: op dh pd | hi // ETH_RST_N/GPIO32 = output 33: no pd | lo // GPIO33 = none 34: op dl pd | lo // CD0_IO0_MICCLK/GPIO34 = output 35: no pd | lo // CD0_IO0_MICDAT0/GPIO35 = none 36: no pd | lo // RP1_PCIE_CLKREQ_N/GPIO36 = none 37: no pd | lo // GPIO37 = none 38: ip pd | hi // CD0_SDA/GPIO38 = input 39: ip pd | hi // CD0_SCL/GPIO39 = input 40: ip pd | hi // CD1_SDA/GPIO40 = input 41: ip pd | hi // CD1_SCL/GPIO41 = input 42: a2 pd | hi // USB_VBUS_EN/GPIO42 = VBUS_EN1 43: a2 pu | hi // USB_OC_N/GPIO43 = VBUS_OC1 44: op dh pd | hi // RP1_STAT_LED/GPIO44 = output 45: a0 pd | hi // FAN_PWM/GPIO45 = PWM1_CHAN3 46: op dl pd | lo // CD1_IO0_MICCLK/GPIO46 = output 47: no pd | lo // 2712_WAKE/GPIO47 = none 48: no pd | lo // CD1_IO1_MICDAT1/GPIO48 = none 49: op dl pd | lo // EN_MAX_USB_CUR/GPIO49 = output 50: no pd | -- // GPIO50 = none 51: no pd | -- // GPIO51 = none 52: no pu | -- // GPIO52 = none 53: no pu | hi // GPIO53 = none 100: ip pd | lo // GPIO0 = input 101: op dh pu | hi // 2712_BOOT_CS_N/GPIO1 = output 102: a6 pn | hi // 2712_BOOT_MISO/GPIO2 = VC_SPI0_MISO 103: a5 pn | hi // 2712_BOOT_MOSI/GPIO3 = VC_SPI0_MOSI 104: a6 pn | lo // 2712_BOOT_SCLK/GPIO4 = VC_SPI0_SCLK 105: ip pd | lo // GPIO5 = input 106: ip pd | lo // GPIO6 = input 107: ip pd | lo // GPIO7 = input 108: ip pd | lo // GPIO8 = input 109: ip pd | lo // GPIO9 = input 110: ip pd | lo // GPIO10 = input 111: ip pd | lo // GPIO11 = input 112: ip pd | lo // GPIO12 = input 113: ip pd | lo // GPIO13 = input 114: a1 pd | lo // PCIE_SDA/GPIO14 = SPI_S_MOSI_OR_BSC_S_SDA 115: a1 pd | lo // PCIE_SCL/GPIO15 = SPI_S_SCK_OR_BSC_S_SCL 116: ip pd | lo // GPIO16 = input 117: ip pd | lo // GPIO17 = input 118: ip pd | lo // GPIO18 = input 119: ip pd | lo // GPIO19 = input 120: ip pu | hi // PWR_GPIO/GPIO20 = input 121: ip pd | lo // 2712_G21_FS/GPIO21 = input 122: ip pd | lo // GPIO22 = input 123: ip pd | lo // GPIO23 = input 124: a3 pn | lo // BT_RTS/GPIO24 = UART_RTS_0 125: a4 pu | lo // BT_CTS/GPIO25 = UART_CTS_0 126: a4 pn | hi // BT_TXD/GPIO26 = UART_TXD_0 127: a4 pu | hi // BT_RXD/GPIO27 = UART_RXD_0 128: op dh pd | hi // WL_ON/GPIO28 = output 129: op dh pd | hi // BT_ON/GPIO29 = output 130: a4 pn | hi // WIFI_SDIO_CLK/GPIO30 = SD2_CLK 131: a4 pu | hi // WIFI_SDIO_CMD/GPIO31 = SD2_CMD 132: a4 pu | hi // WIFI_SDIO_D0/GPIO32 = SD2_DAT0 133: a3 pu | hi // WIFI_SDIO_D1/GPIO33 = SD2_DAT1 134: a4 pu | hi // WIFI_SDIO_D2/GPIO34 = SD2_DAT2 135: a3 pu | hi // WIFI_SDIO_D3/GPIO35 = SD2_DAT3 200: a6 pd | hi // RP1_SDA/AON_GPIO0 = VC_SDA0 201: a7 pd | hi // RP1_SCL/AON_GPIO1 = VC_SCL0 202: op dh pd | hi // RP1_RUN/AON_GPIO2 = output 203: op dl pd | lo // SD_IOVDD_SEL/AON_GPIO3 = output 204: op dh pd | hi // SD_PWR_ON/AON_GPIO4 = output 205: a6 pu | lo // SD_CDET_N/AON_GPIO5 = SD_CARD_PRES_G 206: ip pu | hi // SD_FLG_N/AON_GPIO6 = input 207: ip pd | lo // AON_GPIO7 = input 208: ip pd | lo // 2712_WAKE/AON_GPIO8 = input 209: op dh pd | hi // 2712_STAT_LED/AON_GPIO9 = output 210: ip pd | lo // AON_GPIO10 = input 211: ip pd | lo // AON_GPIO11 = input 212: ip pd | lo // PMIC_INT/AON_GPIO12 = input 213: a3 pu | lo // UART_TX_FS/AON_GPIO13 = VC_TXD0 214: a3 pu | hi // UART_RX_FS/AON_GPIO14 = VC_RXD0 215: ip pd | lo // AON_GPIO15 = input 216: ip pu | hi // AON_GPIO16 = input 232: a1 -- | hi // HDMI0_SCL/AON_SGPIO0 = HDMI_TX0_BSC_SCL 233: a1 -- | hi // HDMI0_SDA/AON_SGPIO1 = HDMI_TX0_BSC_SDA 234: a1 -- | hi // HDMI1_SCL/AON_SGPIO2 = HDMI_TX1_BSC_SCL 235: a1 -- | hi // HDMI1_SDA/AON_SGPIO3 = HDMI_TX1_BSC_SDA 236: a2 -- | hi // PMIC_SCL/AON_SGPIO4 = BSC_M2_SCL 237: a2 -- | hi // PMIC_SDA/AON_SGPIO5 = BSC_M2_SDA可以看到的状态如下:
op输出 /ip输入 /no未分配pu上拉、pd下拉、pn浮空hi高电平、lo低电平
具体解读:
1. 复用功能字段(ip /op/a0/a3/a4 /no)
- ip= input 普通 GPIO 输入模式
- op= output 普通 GPIO 输出模式
- a0/a3/a4= alt0/alt3/alt4 复用外设功能(SPI/I2C/UART 等)
- no= none 未分配功能,浮空闲置
2. 驱动类型(dh /dl,只输出 op 才有)
- dh:drive-high 推挽高驱动//这里大电流可以用来驱动LED,长距离传输,高速信号等。
- dl:drive-low 低驱动强度
3. 偏置 bias(pu /pd/pn)
- pu:pull-up 内部上拉
- pd:pull-down 内部下拉
- pn:pull-none 无上下拉(浮空)
4. 右侧电平(hi /lo/--)
- hi:当前物理引脚高电平
- lo:当前物理引脚低电平
- --:无有效电平(闲置 no 脚读不出稳定值)
2 设置GPIO状态
对于设置,主要是以下一个可以设置。
方向,输出的值(输出有限),上下拉偏置,中断边缘 edge(输入有限)。
1) Direction (core feature)
- Input
- Output (with initial value)
Yes, this is the most basic thing:
GPIOD_LINE_REQUEST_DIRECTION_INPUTGPIOD_LINE_REQUEST_DIRECTION_OUTPUT
2) Output value (if output mode)
- Set HIGH / LOW
- e.g.
gpiod_line_set_value()
So direction + state are separate concepts:
- direction = configuration
- value = logic level
3) Bias (pull-up / pull-down / none)
Modern gpiod supports internal resistors:
- pull-up 外部悬空时,引脚稳定读到高电平 1,外部接 GND 才会变 0。
- pull-down 外部悬空稳定读到低电平 0;外部接 VDD 才变 1。
- disabled 内部电阻断开,完全靠外部电路决定电平。此时悬空时电平飘忽不定,高低乱跳,极易误触发。
This is hardware-dependent.
4) Edge detection (interrupt behavior)
For input GPIOs:
- rising edge 0→1 跳变时触发中断
- falling edge 1→0 跳变时触发中断
- both edges 0↔1 任意跳变都触发
Used for:
- buttons
- sensors
- interrupts
老式写法如下:
# 导出gpio0 echo 0 > /sys/class/gpio/export # 设方向输出 echo out > /sys/class/gpio/gpio0/direction # 输出高电平 echo 1 > /sys/class/gpio/gpio0/value # 输入配置:上拉+上升沿中断 echo in > /sys/class/gpio/gpio1/direction echo pull-up > /sys/class/gpio/gpio1/bias echo rising > /sys/class/gpio/gpio1/edge现在一般也用gpiod
# gpiochip0, pin2 设输出高 gpioset gpiochip0 2=1 # 输入、上拉、双边沿监听 gpiodctl set gpiochip0 3 direction=in bias=pull-up edge=both好了,差不多,感觉知识点都复习到了。
