4. GPIO 输出控制实战:用 Python 控制树莓派点亮 LED 与呼吸灯
这一章我们终于要动手了。说实话,我每次带新人入门嵌入式,第一件事就是让他们点亮一颗 LED。为什么?因为这是最直观的反馈——代码写对了,灯就亮;写错了,灯不亮。没有比这更实在的调试手段了。
咱们这一章的目标很明确:用 Python 控制树莓派的 GPIO 引脚,先让 LED 亮起来,再让它呼吸起来。你想想看,一个呼吸灯效果,其实就涵盖了 PWM 的核心原理。
4.1 硬件准备与电路连接
先看看我们需要什么。别小看这些物料,我在项目里吃过亏——有一次就是因为用了劣质面包板,接触不良,查了整整一下午的 bug。
| 元件 | 规格 | 数量 | 备注 |
|---|---|---|---|
| 树莓派 | 3B+/4B/Zero 2W | 1 | GPIO 引脚需完好 |
| LED | 5mm,颜色任意 | 1 | 推荐红色或蓝色 |
| 电阻 | 220Ω ~ 330Ω | 1 | 限流用,不可省略 |
| 杜邦线 | 母对母 | 2 | 长度 10-20cm |
| 面包板 | 半尺寸 | 1 | 方便搭建 |
连接方式很简单:LED 长脚(阳极)通过电阻接到树莓派的 GPIO 引脚,短脚(阴极)接到 GND。我个人习惯用 GPIO 18(物理引脚 12),因为这个引脚支持硬件 PWM,后面做呼吸灯会方便很多。
4.2 软件环境准备
树莓派上做 Python GPIO 控制,主流方案有两个:RPi.GPIO 和 gpiozero。我个人更推荐 gpiozero,因为它封装得更高级,代码写起来更简洁。但 RPi.GPIO 更底层,适合理解原理。这一章我们两个都用,你感受一下区别。
先安装库:
# 更新系统
sudo apt update
sudo apt upgrade -y
# 安装 RPi.GPIO(通常系统自带)
sudo apt install python3-rpi.gpio -y
# 安装 gpiozero
sudo apt install python3-gpiozero -y
4.3 点亮 LED:最简单的 GPIO 输出
先来一个最基础的——让 LED 常亮。这其实就是把 GPIO 引脚拉高,输出 3.3V 电平。
用 RPi.GPIO 实现:
import RPi.GPIO as GPIO
import time
# 设置引脚编号模式为 BCM
GPIO.setmode(GPIO.BCM)
# 定义 LED 引脚
LED_PIN = 18
# 设置引脚为输出模式
GPIO.setup(LED_PIN, GPIO.OUT)
# 输出高电平,点亮 LED
GPIO.output(LED_PIN, GPIO.HIGH)
# 保持 5 秒
time.sleep(5)
# 关闭 LED
GPIO.output(LED_PIN, GPIO.LOW)
# 清理 GPIO 资源
GPIO.cleanup()
用 gpiozero 实现:
from gpiozero import LED
from time import sleep
# 创建 LED 对象,指定引脚
led = LED(18)
# 点亮
led.on()
sleep(5)
# 熄灭
led.off()
看到了吗?gpiozero 的代码量少了一半。但 RPi.GPIO 让你更清楚地看到每一步在做什么——设置模式、配置引脚、输出电平。我个人建议初学者先用 RPi.GPIO 跑一遍,理解底层逻辑,再用 gpiozero 提高效率。
4.4 闪烁 LED:理解时间控制
闪烁其实就是亮灭交替,中间加延时。这个看似简单,但延时精度在实际项目中很关键。
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
LED_PIN = 18
GPIO.setup(LED_PIN, GPIO.OUT)
try:
while True:
GPIO.output(LED_PIN, GPIO.HIGH)
time.sleep(0.5) # 亮 0.5 秒
GPIO.output(LED_PIN, GPIO.LOW)
time.sleep(0.5) # 灭 0.5 秒
except KeyboardInterrupt:
pass
finally:
GPIO.cleanup()
time.sleep() 是阻塞的,也就是说在延时期间程序做不了其他事。如果你需要同时处理多个任务(比如一边闪灯一边读传感器),就得用多线程或异步。这个我们后面章节会讲。
4.5 呼吸灯效果:PWM 原理与实现
呼吸灯,说白了就是让 LED 从暗到亮、再从亮到暗,循环往复。这靠单纯的开关做不到,需要调节亮度。怎么调?用 PWM(脉冲宽度调制)。
PWM 的原理很简单:在一个周期内,让引脚快速地在高电平和低电平之间切换。高电平占的时间比例(占空比)决定了 LED 的亮度。占空比 0% 就是全灭,100% 就是全亮,50% 就是半亮。
我画了一张图,帮你理解 PWM 的核心逻辑:
树莓派的硬件 PWM 在 GPIO 12、13、18、19 上。我们用 GPIO 18,因为它正好支持硬件 PWM,频率和占空比控制都很精准。
用 RPi.GPIO 实现呼吸灯:
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.OUT)
# 创建 PWM 实例,频率 1000Hz
pwm = GPIO.PWM(18, 1000)
pwm.start(0) # 初始占空比 0%
try:
while True:
# 从暗到亮
for duty in range(0, 101, 1):
pwm.ChangeDutyCycle(duty)
time.sleep(0.01)
# 从亮到暗
for duty in range(100, -1, -1):
pwm.ChangeDutyCycle(duty)
time.sleep(0.01)
except KeyboardInterrupt:
pass
finally:
pwm.stop()
GPIO.cleanup()
用 gpiozero 实现更简洁:
from gpiozero import PWMLED
from time import sleep
led = PWMLED(18)
while True:
# 从暗到亮,步进 0.01
for brightness in range(0, 101, 1):
led.value = brightness / 100.0
sleep(0.01)
# 从亮到暗
for brightness in range(100, -1, -1):
led.value = brightness / 100.0
sleep(0.01)
time.sleep(0.01) 控制呼吸速度。数值越小,呼吸越快。我一般用 0.005 到 0.02 之间,效果比较自然。另外,频率 1000Hz 是人眼感觉不到闪烁的下限,如果你觉得有频闪,可以提高到 2000Hz。
4.6 常见问题与避坑指南
做这个实验,我见过的问题比成功的案例还多。挑几个典型的说说:
- LED 不亮: 先检查接线,特别是电阻有没有接对位置。然后用万用表测 GPIO 引脚电压,看是不是 3.3V。如果电压正常,换一颗 LED 试试——LED 也有坏的。
- 呼吸灯闪烁不均匀: 大概率是
time.sleep()的值太大或太小。我建议从 0.01 开始调,步进 1% 或 0.01 的亮度变化。 - 程序报错 "RuntimeError: No access to /dev/mem": 权限问题。用
sudo运行脚本,或者把用户加入gpio组。 - GPIO.cleanup() 没执行: 程序异常退出时,GPIO 引脚可能保持高电平。下次运行前手动拉低,或者重启树莓派。
4.7 本章小结
这一章我们做了三件事:点亮 LED、让 LED 闪烁、实现呼吸灯效果。你其实已经掌握了 GPIO 输出的核心操作——数字输出和 PWM 输出。数字输出就是简单的 0 和 1,PWM 输出则是用高速开关模拟模拟量。
呼吸灯看起来是个小实验,但它背后的 PWM 原理在电机控制、舵机驱动、电源调压中都会用到。你想想看,一个呼吸灯搞明白了,后面做直流电机调速也就是改几行代码的事。