4. LED控制基础:从点亮到熄灭,迈出硬件控制第一步
各位同学,今天我们进入一个非常实在的环节——用Python控制单个LED的亮灭。
说实话,我刚开始学嵌入式那会儿,觉得控制一个灯太简单了。不就是给个高电平、低电平嘛?但后来在实际项目中,我发现很多看似简单的问题,恰恰是后面复杂功能的基础。你想想看,尾灯的流水效果,本质上就是多个LED按照特定时序亮灭的组合。所以,把单个LED玩透了,后面的流水效果就是水到渠成的事。
4.1 硬件连接:先让灯能亮起来
在写代码之前,我们得先把硬件搭好。这里我用的是树莓派 + 一个普通的5mm LED灯珠 + 一个220Ω电阻。
为什么一定要加电阻?我踩过这个坑。有一次我图省事,直接把LED接到了3.3V上,结果LED瞬间烧了,还冒了一股青烟。嗯,LED是电流型器件,不加限流电阻,电流会大到让它直接报废。
连接方式很简单:
- LED的正极(长脚)通过220Ω电阻连接到树莓派的GPIO引脚(比如GPIO17)
- LED的负极(短脚)连接到树莓派的GND
这里有个小细节:树莓派的GPIO输出高电平时是3.3V,驱动一个LED绰绰有余。但如果你用的是5V的单片机,记得调整电阻值,不然LED会太亮甚至烧掉。
4.2 Python代码:让灯听你的话
硬件接好了,接下来就是写代码。我个人习惯用RPi.GPIO这个库,它是最常用的树莓派GPIO控制库。
先看一个最简单的例子:
import RPi.GPIO as GPIO
import time
# 设置GPIO模式为BCM编号方式
GPIO.setmode(GPIO.BCM)
# 定义LED引脚
LED_PIN = 17
# 设置引脚为输出模式
GPIO.setup(LED_PIN, GPIO.OUT)
# 点亮LED
GPIO.output(LED_PIN, GPIO.HIGH)
print("LED已点亮")
# 等待2秒
time.sleep(2)
# 熄灭LED
GPIO.output(LED_PIN, GPIO.LOW)
print("LED已熄灭")
# 清理GPIO资源
GPIO.cleanup()
这段代码做了几件事:
- 导入必要的库
- 设置GPIO的编号模式——我建议用BCM模式,因为它直接对应芯片的引脚编号,不容易搞混
- 把引脚设置为输出模式
- 输出高电平点亮LED,然后等待2秒
- 输出低电平熄灭LED
- 最后清理GPIO资源
4.3 让灯闪烁起来:循环控制
单个亮灭太单调了,我们让LED闪烁起来。说白了就是让它在亮和灭之间来回切换。
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
LED_PIN = 17
GPIO.setup(LED_PIN, GPIO.OUT)
try:
while True:
GPIO.output(LED_PIN, GPIO.HIGH)
time.sleep(0.5)
GPIO.output(LED_PIN, GPIO.LOW)
time.sleep(0.5)
except KeyboardInterrupt:
print("程序被用户中断")
finally:
GPIO.cleanup()
这里用了try-except-finally结构。为什么要这么写?因为如果程序在运行中你按了Ctrl+C中断,GPIO.cleanup()可能不会被执行。用finally可以保证无论程序怎么退出,GPIO资源都会被释放。
我曾经在一个项目中,因为没处理好异常退出,导致GPIO引脚一直保持高电平,LED亮了一整夜。第二天发现电池都快耗光了。从那以后,我写GPIO控制代码一定会加上异常处理。
4.4 控制亮度的秘密:PWM调光
你可能觉得LED只能要么亮要么灭,其实不然。通过PWM(脉冲宽度调制),我们可以让LED呈现出不同的亮度。
PWM的原理很简单:快速地在高电平和低电平之间切换。如果高电平占的时间比例大,LED就亮一些;反之就暗一些。人眼有视觉暂留效应,只要切换频率够快(通常100Hz以上),我们就感觉不到闪烁,只看到稳定的亮度。
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
LED_PIN = 17
GPIO.setup(LED_PIN, GPIO.OUT)
# 创建PWM对象,频率设为1000Hz
pwm = GPIO.PWM(LED_PIN, 1000)
pwm.start(0) # 初始占空比为0,LED熄灭
try:
while True:
# 从暗到亮
for duty in range(0, 101, 5):
pwm.ChangeDutyCycle(duty)
time.sleep(0.1)
# 从亮到暗
for duty in range(100, -1, -5):
pwm.ChangeDutyCycle(duty)
time.sleep(0.1)
except KeyboardInterrupt:
print("程序被用户中断")
finally:
pwm.stop()
GPIO.cleanup()
这段代码让LED像呼吸一样,从暗到亮再回到暗。你想想看,汽车尾灯在刹车时那种渐亮的效果,其实就是用PWM实现的。
- PWM的频率决定了人眼是否感觉到闪烁,一般100Hz以上就够用了
- 占空比(0-100%)决定了LED的亮度
- ChangeDutyCycle()可以在程序运行中动态调整亮度
4.5 避坑指南:我踩过的那些坑
做LED控制这么多年,有些坑我是一定要告诉你的:
- 引脚电压不匹配:树莓派的GPIO是3.3V逻辑,不要直接接5V设备。我曾经把一个5V的LED灯带直接接到树莓派上,结果GPIO引脚烧了,那个引脚再也不能用了。
- 电流超限:每个GPIO引脚最大输出电流约16mA,不要直接驱动大功率LED。如果需要驱动大功率LED,要用三极管或MOS管做开关。
- 忘记上拉/下拉:有些场景下,GPIO引脚在未初始化时可能是高阻态,LED可能会微亮。我建议在硬件上加一个10kΩ的下拉电阻,或者用GPIO.setup()时设置内部下拉。
4.6 小结:从点亮到掌控
今天我们学了三个层次的控制:
| 控制方式 | 实现方法 | 应用场景 |
|---|---|---|
| 开关控制 | GPIO.output()设置高/低电平 | 尾灯的基本亮灭、转向灯闪烁 |
| 闪烁控制 | 循环 + time.sleep() | 双闪警示灯、频率控制 |
| 亮度控制 | PWM调光 | 刹车灯渐亮、氛围灯效果 |
说白了,LED控制就是「给电就亮,断电就灭」这么简单。但如何精准地控制这个「给电」和「断电」的时机和比例,才是我们后面做流水效果的关键。
下一章,我们会把多个LED组合起来,让它们按照一定的顺序亮灭——没错,就是流水灯效果。到时候你会发现,今天学的这些基础操作,就是搭建整个系统的积木。
好了,去动手试试吧。把LED点亮、熄灭、闪烁、呼吸,都玩一遍。只有亲手做过,才能真正理解这些概念。