DF 创客周刊 Vol.182 的三件作品——赛博朋克风格的“全息时钟”、树莓派 Pico 加个转盘“转”出的小电视、用垃圾桶改出的联网空气净化器——第一眼都像“带点赛博味的玩具”。但如果你把它们拆到元器件层面,会发现它们共享同一套非常成熟的硬件范式:输入信息采集 + 树莓派 Pico 控制 + 执行器输出反馈。
真正值得写的,不是“照着三步复刻一个同名作品”,而是这三件作品背后的通用能力:时间显示类的视觉暂留怎么做?旋转扫描显示为什么难在同步而不是难在 LED?空气净化器的“净化”逻辑和“联网”逻辑如何拆成两个独立模块来调试?树莓派 Pico 在这些项目里到底负责什么,又在哪里会被电机电流干扰导致重启?
这篇文章会把三件作品逐一拆解,需要的读者可以直接拿去当项目设计参考。
读完之后,你能获得三层信息:
- 第一层,了解树莓派 Pico 的 GPIO、PWM、ADC、Wi-Fi 这些基础外设到底怎么配合真实项目。
- 第二层,理解三种最常见创客输出形式的实现骨架:伪全息显示、旋转 POV 显示、传感器闭环控制。
- 第三层,发现从“复刻别人的项目”到“自己改成原创作品”之间,真正要掌握的是哪套工程方法。
1. 这三件作品,真正的共同点在哪里
先说一个比较容易误判的地方:很多人看到“全息时钟”“小电视”“空气净化器”,第一反应是这三个项目需要的技术完全不同。
其实从硬件控制的角度看,它们高度相似。任何一个交互硬件项目,本质都是“输入—处理—输出”的闭环。
做一个最简单的抽象:
| 项目 | 输入 | 处理核心 | 输出/执行 |
|---|---|---|---|
| 全息时钟 | 时间源、按键设置 | 树莓派 Pico | LED、显示屏、旋转电机 |
| 转盘小电视 | 旋转角度、场景选择 | 树莓派 Pico | 柱状 LED、直流电机 |
| 联网空气净化器 | 空气质量传感器、远程指令 | 树莓派 Pico W | 风机 PWM、状态灯、网络请求 |
看这张表,你会发现所谓“三件作品”,其实是在同一个骨架上换了三种传感器和执行器。
- 全息时钟的难点在于显示方式,要制造“悬浮感”或“旋转成像”的视错觉。
- 转盘小电视的难点在于执行器,要让旋转体和显示内容严格同步,否则画面会漂移。
- 联网空气净化器的难点在输入与执行的闭环,还多了一层网络通信。
树莓派 Pico 之所以频繁出现在这类项目中,不是因为它性能强,而是因为它的硬件接口非常“正直”。GPIO、PWM、ADC、I2C、SPI、UART 都直接可用,MicroPython 下用几行代码就能操作一个外设。对于创客项目来说,最大的成本不是芯片价格,而是“从想法到看得见物理效果”的距离。Pico 把这个距离压缩到了几十分钟内。
理解了这条骨架,再去逐个拆解三件作品,你就不会只看表面,而是能看到每一件作品在“输入—处理—输出”链路的哪个环节做了创新。
2. 树莓派 Pico 开发基础与环境准备
既然三件作品都以 Pico 为控制核心,先把通用环境搭好。下面的步骤对三个项目都适用。
2.1 树莓派 Pico 能做什么
树莓派 Pico 的本质是一块微控制器开发板,不是一台微型 Linux 电脑。它和树莓派 4B 这类“卡片电脑”有本质区别:
- Pico 运行 MicroPython 或 C/C++,没有操作系统。
- 程序直接跑在芯片上,上电即执行。
- 它适合做“实时控制”,不适合跑数据库、容器这类任务。
- 它拥有大量可编程 GPIO,可以读取传感器、控制电机、驱动 LED。
从硬件配置看,Pico 的核心是 RP2040 芯片,双核 Arm Cortex-M0+ 处理器,主频常见为 133MHz,自带 26 个 GPIO、多路 PWM、ADC 和常用通信接口。对于 DIY 时钟、LED 旋转显示、传感器采集这类任务,性能是够用的。
需要注意,普通树莓派 Pico 不带 Wi-Fi 功能。如果要做“联网空气净化器”,建议直接选树莓派 Pico W,它在板子尺寸和引脚兼容的前提下增加了 Wi-Fi 模组,省去外挂 ESP8266 的麻烦。
2.2 MicroPython 固件烧录
大多数 Pico 创客项目使用 MicroPython 开发,因为它不需要编译,代码修改后立即运行,方便调试。
准备材料:
- 一块树莓派 Pico 或 Pico W。
- 一根 Micro USB 或 USB-C 数据线,具体接口按板型判断。
- Thonny IDE,它内置 MicroPython 支持,适合新手。也可以使用 mpremote 命令行工具。
烧录固件时,先按住 Pico 板上的 BOOTSEL 按钮,再用数据线连接电脑。此时电脑会识别出一个名为RPI-RP2的 U 盘。然后把下载到的 MicroPython.uf2固件文件直接拖入该 U 盘即可。固件版本请以 Raspberry Pi 官方文档为准,本文不推荐特定版本号,避免绑定旧版本。
拖入完成后,Pico 会自动重启,并在 Thonny 中显示 MicroPython 交互提示符。
2.3 第一个测试程序:板载 LED 点灯
用下面的代码测试开发环境是否正常。
# 文件路径:main.py # 本示例用于验证 Pico/Pico W 的 MicroPython 环境 from machine import Pin import time # 普通 Pico 板载 LED 接 GPIO25 # Pico W 板载 LED 直接使用 Pin("LED") try: led = Pin("LED", Pin.OUT) except ValueError: led = Pin(25, Pin.OUT) while True: led.toggle() time.sleep(0.5)在 Thonny 中运行这段代码,如果板载 LED 以 0.5 秒间隔闪烁,说明环境正常。这里有一个新手容易踩的坑:普通 Pico 的板载 LED 是 GPIO25,而 Pico W 的板载 LED 连接在无线模组上,不能直接用 GPIO 编号操作。上面用try...except做了一个兼容处理,日常排查时可以留意。
3. “全息时钟”背后的显示方案:伪全息与旋转成像
先给一个判断:绝大多数 DIY“全息时钟”,包括很多视频平台上的效果,并不是真正的空间三维全息,而是利用光学反射或视觉暂留制造的“类全息”观感。这不影响作品好看,但理解原理后,你更容易判断该买什么材料、该写什么逻辑。
围绕“赛博朋克风格全息时钟”这个关键词,网上能搜到的实现通常分成两条路线。
3.1 路线一:佩珀尔幻象式“悬浮显示”
这种方案的核心不是旋转,而是光学反射。
它通常使用四片透明亚克力板,拼成一个倒金字塔形状,放置在屏幕上方。屏幕播放四个对称画面,光线经过亚克力板的反射,在金字塔中央形成“悬浮”影像。侧面看过去,画面像是立在半空中。
这种方案的优点:
- 结构简单,不需要电机。
- 显示内容由屏幕控制,可以自由切换时间、动画、天气。
- 非常适合“赛博朋克 UI”风格,霓虹色数字和扫描线效果都能直接做到。
树莓派 Pico 在这种方案里,通常负责实时生成显示内容。例如通过天气 API 拿到数据,再拼成数字和特殊字体显示在屏幕上。
缺点是:它需要一块高亮度屏幕,并且对亚克力角度、周围光线有要求。白天环境光太强,悬浮效果会明显打折。
3.2 路线二:旋转 LED POV 成像
POV 是 Persistence of Vision 的缩写,翻译为视觉暂留。人的眼睛会对消失的光影保留大约 0.1 秒的视觉印象,如果一条 LED 灯带快速旋转,并在不同角度点亮不同像素,人眼就会把一圈光影“脑补”成圆形画面。
很多“圆形时钟”“空中成像风扇”就是这个原理。
这种方案的技术链路包括:
- 一根 LED 灯条或一个 LED 点阵,固定在旋转臂上。
- 直流电机带动旋转臂持续转动。
- 霍尔传感器配合磁铁,检测旋转到起始位置的时间点。
- 控制器根据角度,输出对应列的画面数据。
树莓派 Pico 在这里的职责是“像素调度”。它需要知道当前转到哪个角度,然后在极其短的时间内把这一角度应该显示的列数据送入 LED。
如果用普通 Pico 做这种旋转 POV,要注意处理速度。一个 32×32 像素的圆形画面,如果每圈要刷新 96 列,对主频 133MHz 的 RP2040 来说仍有余量,但你的代码不能出现大段阻塞操作,比如写文件、等待网络响应。
3.3 显示内容同步时间的两种方式
全息时钟的核心任务之一,是拿到准确时间。
- 离线方式:外接 DS3231 高精度实时时钟模块,断电后仍能通过纽扣电池保持计时。
- 联网方式:使用 Pico W 通过网络时间协议获取时间,上电后自动校准。
如果只做一个纯展示模型,用离线 RTC 更稳定。如果追求“永远准确”的时钟,联网校时是更好的选择。
下面是一段简化思路代码,示意 Pico 如何从网络获取时间后,再把时间字符串交给显示层渲染。代码不处理具体屏幕驱动,只展示分层逻辑。
# 文件路径:main_clock.py # 意图:演示“联网取时间 -> 格式化 -> 准备渲染”的控制流 # 实际显示驱动需要根据硬件接入调整 import network import time import ntptime # 假设使用 Pico W wlan = network.WLAN(network.STA_IF) wlan.active(True) wlan.connect("你的WiFi名称", "你的WiFi密码") # 等待连接成功 for _ in range(30): if wlan.isconnected(): break time.sleep(0.5) # 同步网络时间 ntptime.settime() # 获取本地时间 t = time.localtime() # 注意:不同固件时区处理不同,这里仅为演示 formatted_time = "%02d:%02d:%02d" % (t[3], t[4], t[5]) print("当前时间:", formatted_time) # 实际项目这里会把 formatted_time 送给显示渲染函数这段代码最值得学习的地方不是网络部分,而是“数据获取”和“数据渲染”分离。无论最终选择佩珀尔幻象、旋转 POV,还是普通点阵屏,只要时间字符串格式固定,显示层就可以独立替换。
3.4 赛博朋克风格从哪来
很多“赛博朋克”视觉其实不是靠昂贵硬件,而是靠字体的选择、颜色搭配和动态效果堆出来的。
常见的低成本做法包括:
- 使用带辉光感的霓虹色,比如青色和品红色。
- 给数字增加扫描线或故障特效。
- 用半透明外壳配合点亮的边框。
- 加入秒级动态刷新,让数字有“流动感”。
这些效果对硬件性能要求不高,但对显示驱动代码的细节要求更高。例如用 WS2812 灯带做背景光,需要严格遵循时序;用点阵屏做数字,则需要维护好自己的字模库。
4. 树莓派 Pico 转盘小电视:旋转 POV 的核心难点
另一个项目是“树莓派 Pico 加个转盘转出一台小电视”。从项目标题看,“转出”两个字很关键。最符合直觉的实现方式,是旋转 LED 扫描成像:电机带动一个 LED 柱或 LED 条高速旋转,Pico 在合适角度点亮像素,最后人眼看到一个圆形小屏幕。
这类项目也常被叫做“LED POV 电视”“电风扇显示屏”“扫描显示”。
4.1 为什么说难点在同步,不在 LED
如果只让 LED 灯条旋转并闪烁,代码并不复杂。难点在于,要让画面稳定显示,必须保证 LED 点亮的位置和旋转角度一一对应。
举个例子,一个圆形屏幕要显示 32 列像素。电机旋转一圈,Pico 应该依次刷出第 1 列到第 32 列的数据。如果电机转速稳定,每列等待时间相同,画面会正常显示。但直流电机会受负载、电压、风阻影响,转速不可能绝对恒定。如果 Pico 只按“固定延时”来刷列,画面就会出现横向压缩、拉伸或缓慢漂移。
所以,成熟的 POV 方案都会加入一个“角度同步源”。
常用同步方式:
| 同步方式 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| 霍尔传感器 + 磁铁 | 每旋转一圈产生一个起始脉冲 | 结构简单,成本低 | 只有每圈一个基准点,中间仍依赖速度插值 |
| 光电码盘 | 旋转盘上开孔,光电对管输出多个脉冲 | 角度分辨率高 | 结构更复杂 |
| 增量编码器 | 输出多路相位差脉冲 | 能判断方向和精确角度 | 成本较高,接线多 |
对于 DIY 项目,霍尔传感器最常用。Pico 利用脉冲中断判断“旋转起点”,然后用高分辨率定时器或循环计算每个列间隔,在每一列到达正确位置时刷新 LED。
4.2 电机选择和“树莓派 Pico 控制舵机”的关系
这里必须纠正一个常见的认知误区。
很多人看到转盘项目,第一反应是“要控制角度转动,那就用舵机”。舵机确实是树莓派 Pico 里最常见的运动控制外设,搜索引擎里“树莓派 pico 控制舵机”几乎是最高频关键词。但舵机是位置伺服设备,不是持续旋转设备,它更适合用于云台、机械臂关节、转向结构。普通舵机的转动范围通常只有 0 到 180 度,即使部分支持 360 度连续旋转,也不适合长时间高速带动 LED 阵列。
如果要带动旋转 POV,优先考虑:
- 空心杯直流电机,转速高,适合轻负载。
- 无刷电机,寿命长,适合长时间旋转。
- 带减速箱的直流电机,适合直接驱动较重负载。
所以正确的判断是:先把“舵机控制”作为 Pico 外设基本功学会,但在旋转 POV 项目里不要硬套舵机。舵机适合做交互控制,比如转动一个旋钮去选择电视“频道”,而不是带整根 LED 灯条旋转。
下面给出一个标准舵机控制示例,方便你练习 Pico 的 PWM 输出。这段代码在实际项目中,可以用于控制摄像头云台或调节控制器旋钮。
# 文件路径:servo_control.py # 树莓派 Pico 控制舵机的通用示例 # 接线建议: # 舵机信号线 -> Pico GPIO0 # 舵机电源线 -> 外部 5V 电源正极(若舵机电流较大,不能由 Pico 直接供电) # 舵机地线 -> 外部电源负极 + Pico GND 共地 from machine import Pin, PWM import time servo = PWM(Pin(0)) servo.freq(50) # 典型舵机 PWM 频率为 50Hz # 常见舵机脉宽范围约 0.5ms ~ 2.5ms # 50Hz 周期为 20ms,用 duty_u16 换算: # 0.5ms / 20ms * 65535 ≈ 1638 # 2.5ms / 20ms * 65535 ≈ 8192 DUTY_MIN = 1638 DUTY_MAX = 8192 def angle_to_duty(angle): # 将 0~180 度映射到 DUTY_MIN~DUTY_MAX return int(DUTY_MIN + (angle / 180.0) * (DUTY_MAX - DUTY_MIN)) def set_angle(angle): duty = angle_to_duty(max(0, min(180, angle))) servo.duty_u16(duty) try: while True: for a in range(0, 181, 10): set_angle(a) time.sleep(0.05) for a in range(180, -1, -10): set_angle(a) time.sleep(0.05) except KeyboardInterrupt: pass finally: servo.deinit()上面代码里,最能体现经验的是DUTY_MIN和DUTY_MAX的换算。舵机不是靠持续高或低电平控制的,而是靠“PWM 周期内高电平的宽度”,也就是脉冲宽度。50Hz 频率下,1.5ms 高电平对应大约 90 度位置。如果直接照抄别人的占空比数值,而不理解周期和脉宽的关系,换成不同舵机后很容易失控。
另外要强调供电问题。常见 SG90 这类小型舵机启动瞬间电流可能到数百毫安,如果直接从 Pico 的 3.3V 引脚取电,可能造成电压跌落,轻则舵机无力,重则 Pico 重启。正确做法是外部 5V 电源供电,同时把外部电源地线和 Pico 的 GND 接到一起。
4.3 旋转 POV 的软件骨架
下面用一个简化数据流,说明旋转 POV 中 Pico 代码看起来是什么样。这里不绑定具体电路,只展示程序结构。
# 文件路径:pov_scan_demo.py # 循环过程示意:等待同步信号 -> 按列刷新 LED from machine import Pin import time # 假设 8 个 LED 行引脚接到 GPIO0~GPIO7 rows = [Pin(i, Pin.OUT) for i in range(8)] # 一帧画面:宽度 8 列,高度 8 行,0 表示灭,1 表示亮 frame = [ [0, 1, 1, 1, 0, 1, 1, 0], [1, 0, 0, 1, 0, 1, 0, 1], [1, 1, 0, 0, 0, 0, 1, 0], [0, 1, 0, 1, 0, 1, 0, 0], [1, 0, 1, 0, 1, 0, 0, 1], [0, 1, 0, 0, 1, 1, 1, 0], [1, 1, 1, 0, 0, 0, 1, 0], [0, 0, 1, 1, 1, 1, 0, 1], ] def show_column(col): # 把 frame 的第 col 列输出到 8 个行引脚 for row in range(8): rows[row].value(1 if frame[row][col] else 0) # 主循环 while True: # 真实项目中,这里要先检测霍尔传感器的起始信号 # 并精确计算每一列应该出现的时刻 for col in range(8): show_column(col) # 延时长短需要根据电机转速动态调整 time.sleep_us(200)可以看到,软件层面要做的事非常直白:把一个二维数组按列拿出来,送到发光管引脚。真实项目的复杂度全在“什么时候送”上。
如果把完整 POV 电视做出来,推荐把“画面数据管理”和“硬件刷新”切分成两个模块。一个模块负责解码视频帧、缩放图片、生成二维像素数据;另一个模块只负责按角度输出当前列。这样可以单独测试画面数据是否正确。
4.4 小电视的外观与交互
做一个“小电视”,除了画面,还得有外壳和交互。
转盘结构本身可以隐藏电机和驱动电路,外壳可以选择透明亚克力、3D 打印件,甚至用金属罐改造。标题中“转出一台小电视”的趣味感,一部分来自把“旋转机械”和“屏幕画面”两种反差元素放在一起。常见交互方式包括:
- 外接一个旋钮,切换几条不同的内置动画。
- 使用按键切换画面模式。
- 使用 Pico W 接收手机发送的图片,再转成 POV 画面。
如果使用旋钮,建议使用旋转编码器而不是普通电位器。旋转编码器输出数字脉冲信号,判断旋转方向和步数稳定,也没有机械磨损导致的阻值漂移问题。
5. 垃圾桶改装的联网空气净化器:从风道到传感器闭环
第三个项目是把垃圾桶改装成联网空气净化器。这个项目的好玩之处在于外壳成本低,但它的技术含量反而可能是三个项目里最高的。因为空气净化器不是“装个风扇就能过滤”的简单电器,它的核心是风道、滤芯和风机的匹配。
5.1 先搞清楚净化逻辑
空气净化器的工作方式很简单:让空气通过滤芯,颗粒物被拦截,洁净空气再吹出来。决定净化效果的不是风扇功率,而是风量和滤芯效率的匹配。如果滤芯过于密实,而风机功率不足,出风量会很小,净化效果反而不理想。如果风机功率过大,又会产生明显噪音。
垃圾桶在外观上是一个现成的密封容器,可以利用它做风道:
- 垃圾桶顶部或侧面开进风口。
- 内部安装滤芯。
- 底部安装风机,把过滤后的空气送出。
- 垃圾桶原来的盖子可以改造为出风结构。
从“技术拆解”角度看,树莓派 Pico 负责的不是“净化”,它负责的是“自动控制”。它要读取空气质量传感器的数据,根据浓度调整风机转速,同时把状态上传到网络。传感器、Pico、风机三部分构成一个完整的反馈链路。
5.2 空气质量传感器选型
常见的 DIY 空气质量传感器有几种,先区分清楚:
| 传感器类型 | 检测对象 | 接口形式 | 特点 |
|---|---|---|---|
| 激光粉尘传感器 | PM2.5/PM10 颗粒物浓度 | UART/PWM | 精度较高,常用型号如 PMS5003,需要风道进入传感器 |
| 红外粉尘传感器 | 颗粒物浓度 | 模拟量/PWM | 成本低,精度不如激光式 |
| 半导体气体传感器 | TVOC、烟雾等 | 模拟量 | 响应慢,需要预热,受温湿度影响大 |
| 温湿度传感器 | 温度、湿度 | I2C/单总线 | 常用作辅助判断 |
如果目标是检测室内 PM2.5,激光粉尘传感器更合适。但这种传感器输出的是串口数据,需要按照数据手册解析协议。如果只是做教学演示,也可以用带模拟电压输出的传感器,直接接 Pico 的 ADC 引脚读取。
需要注意,ADC 输入电压不能超过 3.3V。如果传感器输出是模拟电压且可能超过 3.3V,必须用分压电路或电压转换模块。
5.3 Pico 读取传感器并控制风机
下面的示例使用 Pico 的 ADC 读取一个模拟空气质量信号,然后使用 PWM 控制风机转速。为了安全,这个示例默认风机是低压直流风机,并且通过 MOSFET 驱动模块控制,不能把 Pico 的 GPIO 直接接大功率风机。
# 文件路径:air_purifier_control.py # 功能:读取空气质量传感器信号,并根据阈值自动调速 # 安全提示: # 1. 风机必须使用安全低压电源供电 # 2. GPIO 只输出 PWM 信号,不要直接驱动大功率负载 # 3. 强电改装需要专业资质,本文场景默认使用低压直流风机 from machine import Pin, ADC, PWM import time # ADC 引脚,假设传感器输出接到 GPIO26 # 注意:输入电压不能超过 3.3V sensor = ADC(Pin(26)) # 风机 PWM 控制引脚,需要外接驱动模块 fan = PWM(Pin(15)) fan.freq(25000) # 使用较高频率,减少风机啸叫 # 模拟量阈值,需要根据实际传感器校准 HIGH_LEVEL = 40000 # 严重污染 MID_LEVEL = 25000 # 轻度污染 while True: value = sensor.read_u16() print("传感器原始值:", value) if value >= HIGH_LEVEL: fan.duty_u16(65535) # 满速 elif value >= MID_LEVEL: fan.duty_u16(32768) # 半速 elif value < MID_LEVEL: fan.duty_u16(0) # 停转 time.sleep(1)这段代码的关键点有两个。
第一个关键点是 ADC 的read_u16()返回 0 到 65535 的数值,对应 0 到 3.3V 电压。阈值不可能是固定的,必须根据你实际使用的传感器标定。在空气净化器项目中,最有效的标定办法是先让设备在洁净环境下运行半小时,记录基线值,再在污染环境下观察值的变化。
第二个关键点是 PWM 频率。普通直流电机风扇在低频 PWM 下会产生明显的“嗡嗡”声,把频率提高到 20kHz 以上,超出人耳灵敏范围,噪音会明显下降。
5.4 垃圾桶改装时的结构安全
垃圾桶本身不是为电气设备设计的,改装时需要注意几点:
- 开孔切割要打磨边缘,防止金属毛刺或塑料锐边划伤电源线。
- 风机高速旋转,进风口必须加保护格栅。
- 滤芯要固定牢靠,不能因为风机震动而移位。
- 内部电源线和信号线需要固定,避免被风机叶片卷入。
- 电路部分要远离可能的进水和垃圾残渣。
推荐使用低压直流风机代替原有 220V 电器。如果一定要处理 220V 设备,请断电操作,并交由有专业资质的人完成,这不是写几行代码能规避的风险。
5.5 联网上报:让净化器“被看见”
净化器如果只做自动调速,其实不需要联网。联网的核心价值是远程查看状态、积累历史数据、远程开关机。
树莓派 Pico W 自带 Wi-Fi,可以让净化器变成一个小型物联网节点。最简单的数据传输方式是通过 HTTP 请求,把传感器值和风机状态发送到本地服务器或局域网内的其他设备。
下面的代码演示 Pico W 如何连接 Wi-Fi,并打印自己的 IP 地址。
# 文件路径:wifi_connect.py # 树莓派 Pico W 连接 Wi-Fi 示例 import network import time ssid = "你的WiFi名称" password = "你的WiFi密码" wlan = network.WLAN(network.STA_IF) wlan.active(True) # 断开已有连接并重新连接 wlan.disconnect() wlan.connect(ssid, password) # 最多等待 15 秒 for _ in range(30): if wlan.isconnected(): break time.sleep(0.5) if wlan.isconnected(): print("连接成功,网络信息:", wlan.ifconfig()) else: print("连接失败,请检查 Wi-Fi 名称和密码")这段代码不是数据上传代码,而是所有联网项目的第一步。只有先把 Wi-Fi 连通,后续才能使用 HTTP 或 MQTT 协议上报数据。
在实际物联网项目中,我更推荐使用 MQTT 而不是 HTTP。MQTT 是发布订阅模型,适合传感器数据长期上报。Pico W 可以每秒发布一条空气质量消息,局域网内的订阅端通过仪表盘实时显示曲线。HTTP 更适合低频操作,比如按一次按钮上报一次状态。
6. 三个项目可复用的外设调试技巧
把三件作品放在一起看,你会找到很多能复用的经验。
6.1 任何新外设,先用“最小测试代码”验证
不要一上来就把全部代码写完。面对一个新的传感器或显示器,先写一个最简单的测试脚本。
比如新买了一个空气质量传感器,先不要写“自动调速逻辑”,只写一行print(sensor.read_u16()),然后打开串口监视器看数值变不变。把这条链路测通,再叠加复杂的控制逻辑。
这个习惯可以帮你快速定位问题:
- 数值完全不变,说明接线或电源有问题。
- 数值乱跳,说明引脚悬空或未共地。
- 数值有规律变化,才说明传感器本身工作正常。
6.2 信号地和电源地必须共地
这是创客项目最常见的问题之一。
Pico 的 GPIO 输出高电平只有 3.3V,传感器、电机驱动模块如果要被 Pico 控制,通常需要信号线之外再有一个共同参考地。如果外部模块使用独立电源,而没有和 Pico 共地,GPIO 信号可能不稳定,甚至无法工作。
在接线时,把外部电源的负极、电机驱动模块的 GND、Pico 的 GND 接在一起。不要只靠 USB 供电来带所有外设。
6.3 电压跌落会引起“神秘的自动重启”
电机启动、LED 全亮、Wi-Fi 发射瞬间,都可能出现大电流。如果整个系统共用同一个 3.3V 或 5V 电源,电压会被瞬间拉低,导致 Pico 复位。
排查现象是:代码运行一段时间后,日志停在某一行,板载 LED 重新闪烁,说明系统已经重启。解决办法是独立供电,把控制电路、执行器电源分开,只共享地线。
6.4 用状态打印代替复杂调试
MicroPython 的一大优势是print()很方便。在实际项目中,不要只在最后打印结果,而应该在关键节点打印状态:
- 启动时打印当前配置。
- 每次采集传感器后打印原始值和换算后的值。
- 控制风机时打印 PWM 占空比。
日志会帮助你建立一个“现象到原因”的映射。比如看到风扇不转,如果日志显示占空比已经输出为 65535,问题更大概率在驱动电路或电源,而不在 Pico 代码。
7. 三件作品常见问题与排查清单
下表汇总了三个项目中的高频问题。遇到问题时,优先按“先查电源、再查接线、最后查代码”的顺序排查。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| Pico 上电后代码不运行 | 固件未正确烧录或 main.py 报错 | 连接 Thonny,查看 REPL 输出 | 重新烧录 MicroPython 固件,修复 main.py 语法错误 |
| LED 闪烁但画面乱 | POV 项目没有角度同步信号 | 确认霍尔传感器能否检测起始脉冲,打印中断次数 | 加入同步信号,按角度刷新列数据 |
| 舵机抖动或无力 | 供电不足或未共地 | 测量舵机电源电压,监听启动瞬间电压跌落 | 使用独立 5V 电源,外部电源与 Pico 共地 |
| 电机旋转时 Pico 重启 | 电机启动电流过大 | 看串口日志是否出现“软复位”特征 | 电机单独供电,不在 Pico 电源上取电 |
| 传感器数值不变 | 接线错误或输入电压超限 | 用万用表量传感器输出引脚电压 | 修正接线,超压引脚增加分压电路 |
| Wi-Fi 连接失败 | 密码错误、路由器只开 5GHz | 打印 Wi-Fi 连接状态码 | 确认使用 2.4GHz 网络,检查密码长度 |
| 风机不转但代码占空比改变 | 缺少驱动电路或驱动模块损坏 | 用示波器/万用表测 PWM 引脚,测驱动输出 | 增加 MOSFET 或电机驱动模块 |
| 风扇有明显啸叫 | PWM 频率低于人耳敏感范围 | 确认 PWM 频率设置 | 将频率提高到 20kHz 以上 |
| 显示亮度不均匀 | 供电线太细或 LED 电压跌落 | 测量 LED 供电端电压 | 加粗电源线,增加电容缓冲 |
表里看起来都是“常规问题”,但在实际制作中,大部分时间恰恰消耗在这些常规问题上。遇到问题时先不要去改算法,而是先确认电源、信号和接线这三层地基。
8. 从“仿制”到“原创”的工程建议
很多新手做完一个项目后,会有一种“学会但不会变通”的感觉。原因不是没有理解原理,而是在项目过程中跳过了设计过程,只顾着照抄接线和代码。想让这三个项目沉淀出原创能力,建议遵循下面几条原则。
8.1 把项目当作“模块拼装”而不是“整体复刻”
不要把所有代码写在一个巨大的while True死循环里。即使是个人作品,也可以按功能拆分模块。
一个比较清晰的工程划分是/drivers、/core、/app:
drivers放具体硬件的底层驱动,比如 LED 显示驱动、传感器读取。core放核心逻辑,比如“污染等级判定”“POV 列刷新”。app放业务组合,比如“空气净化器主循环”。
用文件夹或注释把模块分开,最大的好处是能在新项目里复用旧模块。全息时钟里写好的时间格式化模块,直接拿到空气净化器中用于状态屏显示,不需要重写。
8.2 先定义好“输入和输出”,再写代码
动手前用一张表格定义清楚:
- 输入信号是什么?数值范围有多大?
- 执行器通过什么接口控制?
- 系统有哪几种状态?状态之间如何切换?
例如空气净化器,可以先在纸上写清楚:
- 传感器值大于阈值 A 时,风机开满速。
- 传感器值介于 A 和 B 之间时,风机半速。
- 传感器值低于 B 时,风机停转。
把规则写清楚后,写代码会快很多。很多卡壳并不是不会写代码,而是没有想清楚状态和边界条件。
8.3 预留安全边界
Pico 输出的 GPIO 高电平是 3.3V,不能直接驱动继电器线圈、大功率 LED、无刷电机等负载。这不仅是效率问题,更是安全问题。凡是电流较大的执行器,都要经过三极管、MOSFET 或电机驱动模块。
写代码时也要为控制量设置上下限。不要出现“PWM 占空比为负”或“电机转速超过设计最大值”这类越界问题。使用舵机时,要在代码里限制角度不超过 180 度,防止舵机扫齿损坏。
8.4 为调试预留接口
如果是联网设备,最好把调试信息通过串口输出。如果是带屏幕的设备,增加一个“调试模式”页面,把传感器原始值、PWM 占空比、Wi-Fi 信号强度直接显示出来。这样你调试程序时不用把设备拆开接电脑才能看到数据。
8.5 迭代顺序:先手工,再自动,最后联网
对于空气净化器,建议不要从一开始就做传感器自动调速。先手动测试风机不同占空比下的体验,确认风量和噪音都能接受,再写自动逻辑。最后再加入 Wi-Fi 远程控制。
对于 POV 小电视,同样先让电机转起来,再点亮固定 LED 测试同步,最后才播放动图。把每一层风险单独隔离,出错时能快速定位。
8.6 使用文件保存校准数据
传感器会受到个体差异和使用环境影响。一个比较实用的做法,是把校准阈值写在单独的配置文件里,而不是硬编码在主程序里。
在 MicroPython 中可以用config.py保存配置:
# 文件路径:config.py # 项目配置文件,便于统一调整参数 WIFI_SSID = "你的WiFi名称" WIFI_PASSWORD = "你的WiFi密码" # 空气净化器阈值 SENSOR_HIGH_LEVEL = 40000 SENSOR_MID_LEVEL = 25000 # 风机 PWM 频率 FAN_PWM_FREQ = 25000在其他文件中通过import config引用,方便维护:
# 文件路径:air_purifier.py from config import FAN_PWM_FREQ import config fan.freq(FAN_PWM_FREQ) if value >= config.SENSOR_HIGH_LEVEL: fan.duty_u