[树莓派 PICO(基于MicroPython)]基础教程02-玩转板载LED:从呼吸灯到SOS摩尔斯电码

张开发
2026/6/25 23:41:22 15 分钟阅读
[树莓派 PICO(基于MicroPython)]基础教程02-玩转板载LED:从呼吸灯到SOS摩尔斯电码
1. 从基础点亮到呼吸灯效果如果你已经跟着上一期教程成功点亮了树莓派PICO的板载LED甚至实现了简单的闪烁效果那么今天我们要玩点更酷的——让LED像呼吸一样渐变明暗。这个效果在电子产品中很常见比如笔记本的睡眠指示灯、手机的呼吸通知灯等。实现呼吸灯的核心技术叫做PWM脉宽调制。简单来说就是通过快速开关LED来控制它的平均亮度。开关速度足够快时人眼就看不到闪烁只会感觉到亮度变化。这就像用风扇调速器控制风扇转速一样虽然电源本身只有开和关两种状态但通过调节开关时间的比例就能实现无级变速。在MicroPython中PWM功能已经封装得非常友好。我们先来看基础代码框架from machine import Pin, PWM import time led PWM(Pin(25)) # 注意这里和普通点灯的区别 led.freq(1000) # 设置PWM频率为1000Hz这里有几个关键参数需要注意PWM(Pin(25))将GPIO25初始化为PWM模式freq(1000)设置PWM频率为1000Hz1秒内开关1000次duty_u16()这是控制亮度的核心方法取值范围0-65535实际制作呼吸灯时我们需要让亮度从0逐渐增加到最大再逐渐减小。这可以通过一个循环来实现while True: # 渐亮过程 for duty in range(0, 65535, 50): led.duty_u16(duty) time.sleep(0.001) # 渐暗过程 for duty in range(65535, 0, -50): led.duty_u16(duty) time.sleep(0.001)我实测时发现几个实用技巧步长值代码中的50影响呼吸速度值越大呼吸越快sleep时间0.001秒影响平滑度时间越短越平滑频率不宜设太低否则会看到闪烁建议保持在500Hz以上2. 深入理解PWM参数调节很多新手在实现呼吸灯时容易遇到两个问题要么呼吸效果不平滑要么LED亮度变化范围不够大。这通常是因为没有正确理解PWM的参数设置。2.1 PWM频率的选择频率设置对呼吸灯效果影响很大。频率太低比如100Hz以下人眼会察觉到LED在闪烁频率太高比如超过10kHz虽然看不到闪烁但可能会遇到硬件限制。经过多次测试我发现1kHz是个比较理想的中间值。频率对功耗也有影响。这是我的实测数据频率(Hz)功耗(mA)肉眼观察效果1003.2明显闪烁5003.5轻微闪烁10003.8平滑50004.2非常平滑2.2 亮度变化的非线性处理人眼对光强的感知是对数关系而不是线性关系。这意味着如果我们简单地线性增加duty值人眼会觉得亮度变化不均匀。解决方法是对duty值做指数变换import math def gamma_correction(value): return int(math.pow(value / 100, 2.8) * 65535) while True: for i in range(100): led.duty_u16(gamma_correction(i)) time.sleep(0.02) for i in range(100, 0, -1): led.duty_u16(gamma_correction(i)) time.sleep(0.02)这个改进版呼吸灯看起来会更加自然因为亮度变化更符合人眼的感知特性。3. 实现SOS摩尔斯电码掌握了呼吸灯后我们再来挑战一个更有实际意义的项目——用LED发送SOS求救信号。SOS的国际摩尔斯电码是三短· · ·、三长— — —、三短· · ·每个字母间间隔一个单位时间单词间间隔三个单位时间。3.1 基础实现方案首先定义短闪和长闪的基本函数def short_flash(): led.value(1) time.sleep(0.2) led.value(0) time.sleep(0.2) def long_flash(): led.value(1) time.sleep(0.6) led.value(0) time.sleep(0.2)然后组合成SOS信号while True: # 三个短闪 for _ in range(3): short_flash() time.sleep(0.4) # 字母间间隔 # 三个长闪 for _ in range(3): long_flash() time.sleep(0.4) # 字母间间隔 # 三个短闪 for _ in range(3): short_flash() time.sleep(1.4) # 单词间间隔3.2 进阶优化版本基础版本虽然能用但代码重复较多。我们可以用更优雅的方式实现MORSE_CODE { S: [1,1,1], # 短短短 O: [3,3,3] # 长长长 } def send_morse(code, unit_time0.2): for duration in code: led.value(1) time.sleep(unit_time * duration) led.value(0) time.sleep(unit_time) # 符号间间隔 while True: # 发送SOS for char in [S, O, S]: send_morse(MORSE_CODE[char]) time.sleep(unit_time * 2) # 字母间间隔 time.sleep(unit_time * 4) # 单词间间隔这种实现方式有几个优点可扩展性强容易添加其他摩尔斯电码通过unit_time参数可以整体调节发送速度代码结构更清晰逻辑更明确4. 创意扩展与实用技巧掌握了基础功能后我们可以尝试一些更有创意的应用。这里分享几个我实践过的有趣项目。4.1 呼吸灯SOS二合一结合前面两个功能我们可以制作一个平时是呼吸灯紧急情况下切换为SOS信号的智能LEDfrom machine import Pin, PWM import time led PWM(Pin(25)) button Pin(16, Pin.IN, Pin.PULL_UP) # 接一个按钮到GP16 def breathing_led(): while True: for duty in range(0, 65535, 512): if not button.value(): # 检测按钮是否按下 return led.duty_u16(duty) time.sleep(0.005) for duty in range(65535, 0, -512): if not button.value(): return led.duty_u16(duty) time.sleep(0.005) def sos_signal(): # 之前的SOS实现代码 pass while True: breathing_led() sos_signal()4.2 通过串口控制LED模式更高级的玩法是通过串口接收指令动态切换LED模式import uasyncio as asyncio async def led_controller(): mode breathing while True: if mode breathing: # 呼吸灯代码 pass elif mode sos: # SOS代码 pass await asyncio.sleep(0) async def uart_receiver(): while True: if uart.any(): cmd uart.read().decode().strip() if cmd in [breathing, sos, blink]: mode cmd await asyncio.sleep(0.1) # 启动两个协程 loop asyncio.get_event_loop() loop.create_task(led_controller()) loop.create_task(uart_receiver()) loop.run_forever()这个方案使用了MicroPython的异步编程功能可以同时处理LED控制和串口通信非常适合需要远程控制的场景。

更多文章