最近又要做嵌入式了,发现这块还是非常非常重要,再补一下吧。

在日常的工作中,其实要做的就是两点。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_NCS_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_INPUT
    • GPIOD_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

    好了,差不多,感觉知识点都复习到了。

    Logo

    智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

    更多推荐