3. Python 操作 GPIO:用 RPi.GPIO 库控制树莓派

好,咱们正式开始动手。这一章,我会带你用 Python 直接操作树莓派的 GPIO 引脚。说白了,就是让芯片的脚听你的话——输出高电平点亮 LED,或者读取按键按下时的电平变化。

我最早接触 RPi.GPIO 库时,觉得它就是个简单的开关控制。后来在项目中踩过几次坑,才发现里面的门道不少。比如中断触发抖动、引脚复用冲突,这些如果不注意,调试起来能让你怀疑人生。

咱们先搭好环境,然后一个一个功能过。

3.1 环境准备与库安装

树莓派上默认没有预装 RPi.GPIO,需要手动安装。我个人习惯用 pip3,干净利落。

sudo apt update
sudo apt install python3-pip
sudo pip3 install RPi.GPIO

装完之后,可以用 Python 交互式环境验证一下:

import RPi.GPIO as GPIO
print(GPIO.VERSION)

如果能打印出版本号,说明安装成功。嗯,这里要注意:如果你用的是树莓派 5,RPi.GPIO 可能不兼容,建议改用 gpiozero 或 librgpio。我在一次培训课上就遇到过学生拿 Pi 5 跑老代码,直接报错——硬件版本变了,库也得跟着升级。

3.2 GPIO 输出模式:点亮 LED

输出模式是最基础的操作。你想想看,控制一个 LED 亮灭,其实就是让引脚输出高电平(3.3V)或低电平(0V)。

先看电路连接:

元件树莓派引脚
LED 正极(长脚)GPIO 17(物理引脚 11)
LED 负极(短脚)GND(物理引脚 6)
限流电阻(330Ω)串联在 LED 与 GPIO 之间

代码实现:

import RPi.GPIO as GPIO
import time

# 设置引脚编号模式
GPIO.setmode(GPIO.BCM)   # 使用 BCM 编号
GPIO.setwarnings(False)  # 关闭警告

# 设置 GPIO 17 为输出模式
LED_PIN = 17
GPIO.setup(LED_PIN, GPIO.OUT)

# 循环闪烁
try:
    while True:
        GPIO.output(LED_PIN, GPIO.HIGH)   # 点亮
        time.sleep(1)
        GPIO.output(LED_PIN, GPIO.LOW)    # 熄灭
        time.sleep(1)
except KeyboardInterrupt:
    GPIO.cleanup()  # 清理 GPIO 状态
个人经验:我习惯在代码开头加 GPIO.setwarnings(False),否则如果引脚之前被占用过,会一直弹警告。另外,GPIO.cleanup() 一定要在退出时调用,不然下次运行可能报错。

3.3 GPIO 输入模式:读取按键状态

输入模式用来检测外部信号,比如按键按下。这里有个关键点:按键按下时电平会抖动,硬件上需要加一个上拉或下拉电阻。

树莓派内部自带弱上拉电阻,我们可以直接启用:

BUTTON_PIN = 18
GPIO.setup(BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)

完整代码:

import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_UP)

try:
    while True:
        if GPIO.input(18) == GPIO.LOW:   # 按键按下(低电平)
            print("按键被按下")
        else:
            print("按键未按下")
        time.sleep(0.1)
except KeyboardInterrupt:
    GPIO.cleanup()
避坑指南:我曾经在项目中直接用 GPIO.input() 检测按键,结果发现按下一次会触发好几次。原因就是机械抖动。后来加了 20ms 的软件消抖才解决。后面讲中断时,我会专门演示消抖方法。

3.4 GPIO 中断:边沿触发事件检测

轮询方式(while 循环里不断读引脚)效率低,还占 CPU。更好的做法是用中断——引脚电平变化时,自动调用回调函数。

RPi.GPIO 支持三种边沿触发:

触发方式说明适用场景
GPIO.RISING上升沿触发(低→高)检测按键释放
GPIO.FALLING下降沿触发(高→低)检测按键按下
GPIO.BOTH双边沿触发检测电平变化

代码示例:

import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_UP)

# 定义回调函数
def button_callback(channel):
    print(f"引脚 {channel} 检测到下降沿,按键被按下")

# 注册中断
GPIO.add_event_detect(18, GPIO.FALLING, 
                      callback=button_callback, 
                      bouncetime=200)  # 200ms 消抖

try:
    print("等待按键中断...")
    while True:
        time.sleep(1)  # 主程序可以干别的事
except KeyboardInterrupt:
    GPIO.cleanup()
关键参数:bouncetime 是硬件消抖时间,单位毫秒。我一般设 200ms,既能滤掉抖动,又不会让按键响应太迟钝。如果设得太小(比如 10ms),抖动还是会触发多次回调。

3.5 知识体系总览

下面这张图,把本章的核心逻辑串起来了。你可以把它当作操作 GPIO 的路线图:

Python 操作 GPIO 知识体系 RPi.GPIO 库 输出模式 输入模式 中断模式 GPIO.output() 控制电平 PWM 模拟输出(后续) GPIO.input() 读取电平 上拉/下拉电阻配置 add_event_detect() bouncetime 消抖 核心原则 先设模式 → 再操作 → 最后 cleanup。中断回调里不要做耗时操作。

3.6 常见问题与调试技巧

  • 引脚编号混淆:BCM 编号和 BOARD 编号容易搞混。我建议统一用 BCM,因为大部分教程和库都默认 BCM。
  • 中断不触发:检查回调函数是否注册成功。可以在回调里加个打印,看看到底有没有被调用。
  • LED 不亮:先测引脚电压。用万用表量 GPIO 和 GND 之间,如果输出 HIGH 时电压接近 3.3V,说明代码没问题,检查电路。
  • 按键误触发:bouncetime 设大一点。我试过 50ms 不够,200ms 基本稳。
调试小工具:我习惯在代码里加一个 GPIO.getmode() 打印当前模式,防止自己搞混。另外,用 gpio readall 命令可以查看所有引脚状态,非常直观。

好了,这一章的内容就这些。从输出到输入,再到中断,每一步都有对应的代码和电路。你可以在树莓派上直接跑一遍,看看效果。遇到问题别急,对照上面的表格和流程图,基本都能找到原因。