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()

这段代码做了几件事:

  1. 导入必要的库
  2. 设置GPIO的编号模式——我建议用BCM模式,因为它直接对应芯片的引脚编号,不容易搞混
  3. 把引脚设置为输出模式
  4. 输出高电平点亮LED,然后等待2秒
  5. 输出低电平熄灭LED
  6. 最后清理GPIO资源
小提示:GPIO.cleanup()这一步很重要。如果不调用,下次运行程序时可能会报错,说引脚已经被占用。我刚开始学的时候经常忘记这步,结果每次都要重启树莓派才能重新运行程序。

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点亮、熄灭、闪烁、呼吸,都玩一遍。只有亲手做过,才能真正理解这些概念。