基于Voronoi图与ATtiny85的PCB艺术灯设计与实现
1. 项目概述从数学之美到实体光影几年前我在研究自然界的几何形态时被一种名为Voronoi的图案深深吸引。从长颈鹿的皮肤纹理、玉米粒的排列到蜂巢的结构这种由“最近邻”原则划分空间的数学之美无处不在。当时我就萌生了一个想法能否将这种抽象的数学概念转化为一个能捧在手里、能点亮生活的实体物件于是这个基于Voronoi图与ATtiny85的PCB艺术灯项目便开始了。它的核心目标很简单用电路板作为画布用LED作为画笔让光线从精密的几何分割缝隙中透出创造一种独特的光影艺术。这个灯本质上是一个由六块PCB板拼装而成的矩形灯箱。底部的主控板搭载了一颗ATtiny85微控制器驱动着64颗WS2812B迷你RGB LED。四周的四块侧板以及顶盖则蚀刻着Voronoi图案。当LED点亮时光线只能从这些图案的缝隙即阻焊层开窗区域中透出从而在黑暗中勾勒出Voronoi的轮廓。整个项目麻雀虽小五脏俱全它串联起了数学概念理解、PCB设计、SMT焊接、微控制器编程等多个电子制作的关键环节。无论你是想深入学习PCB艺术化设计还是希望挑战一个集成度较高的创客项目这个案例都能提供一条清晰的路径和不少值得借鉴的实操细节。2. 核心设计思路与方案选型2.1 为什么选择Voronoi图作为艺术载体Voronoi图又称泰森多边形其数学定义是给定平面上一组离散的点称为种子点将平面划分为多个区域使得每个区域内的任意一点到该区域种子点的距离小于到其他任何种子点的距离。这个定义听起来有点绕但你可以把它想象成一场“地盘争夺战”每个种子点都宣称自己周围距离最近的土地归自己最终形成的势力边界就是Voronoi图。在工程和艺术领域选择它主要基于以下几点考量视觉独特性与自然感它生成的图案既规则又随机边缘是直线段但整体形态富有变化模仿了许多自然结构视觉上不会显得呆板或过于人工化。实现的确定性给定一组种子点生成的Voronoi图是唯一确定的。这非常利于数字化设计。我们可以通过编程如Python的scipy.spatial.Voronoi或利用在线工具生成图案然后导出为矢量图形文件便于导入PCB设计软件。良好的透光与遮光效果Voronoi区域单元格本身是封闭的多边形。在PCB上我们可以将单元格内部设为铜层或保留基材使其不透光将单元格之间的边界即维诺边区域做成阻焊开窗让光透出。这样就能形成“暗单元格亮边界”的负形光效对比鲜明艺术感强。2.2 硬件架构的权衡ATtiny85 WS2812B项目的硬件核心是“大脑”和“光源”。我选择了ATtiny85作为主控WS2812B作为光源这是一个在小型创客项目中非常经典且高效的组合。关于主控芯片ATtiny85 这是一颗Microchip原Atmel的8位AVR微控制器。在Arduino生态如日中天的今天为什么不用更简单的Arduino Nano原因有三极致紧凑SOIC-8封装尺寸极小非常适合这种PCB即外壳、内部空间寸土寸金的项目。成本与功耗单价仅约1美元且功耗极低在电池供电场景下优势明显。性能足够虽然只有8KB Flash、512B RAM但驱动几十颗WS2812B并运行简单的色彩变换逻辑绰绰有余。它的USI通用串行接口模块可以模拟时序要求严格的单线归零码协议完美驱动WS2812B。当然它的局限也很明显IO口稀少仅6个可用、没有硬件串口、内存有限。这就要求我们的代码必须精简且电路设计要充分利用每一个引脚。关于光源WS2812B 这是一种集成了控制电路和RGB芯片的智能LED每个像素点都可以通过单线串行协议独立寻址和控制颜色。选型原因无需为每个LED设计单独的驱动电路只需要一根信号线串联所有LED极大简化了PCB布线和程序控制逻辑。本项目使用的“2020”封装迷你型号尺寸仅为2.0x2.0mm亮度却足够非常适合在紧凑空间内实现高密度点阵。供电考量64颗LED全白最亮时理论最大电流可达64 * 60mA ≈ 3.84A。这是一个惊人的数字。在实际中我们几乎不会这样使用。通过程序限制亮度如设置BRIGHTNESS为64或更低可以将电流控制在1A以内。我选用了一个5V/2A的USB-C电源适配器留有充足余量确保长期工作稳定。2.3 结构设计与PCB规划灯体被设计为一个矩形六面体。这决定了我们需要6块PCB1块底板主控、4块侧板、1块顶板开关。功能分区底板承载ATtiny85、USB-C供电接口、LED阵列以及连接侧板的焊盘。所有核心电路集中于此。侧板纯艺术板。仅在TOP层蚀刻Voronoi图案的线条并对这些线条区域做阻焊开窗。板子中间大面积覆铜接地用于加强结构并作为LED光线的反射层提升出光均匀性。顶板仅安装一个贴片按钮和连接底板的接插件。结构最简单。连接方式摒弃了螺丝或卡扣采用最“电子”的方式——焊接。在每块板的边缘设计对应的焊盘组装时直接用焊锡将各板子的焊盘“桥接”起来。这样做的好处是结构牢固且电气连接可靠所有侧板的地线通过焊盘与主板地连通缺点是组装后不可拆卸。光路设计这是效果成败的关键。LED阵列贴在底板内表面光线向上发射。侧板内表面有铜层会反射大部分光线只有对准了阻焊开窗Voronoi线条的光线才能穿透PCB射出。因此LED的布局密度和亮度需要与开窗的宽度匹配。开窗太细光效弱开窗太粗则失去了线条的精致感。需要在打样前用渲染工具多做模拟。3. 核心实现流程详解3.1 Voronoi图案生成与PCB化处理直接从零编码生成Voronoi图对于不常编程的朋友可能有些门槛。我的实用建议是善用现有工具。获取图案我是在开源设计社区如OpenProcessing.org搜索“Voronoi”找到了许多可交互的示例。调整参数生成满意的图案后直接截图保存。更专业的方法是使用Python的matplotlib或scipy库生成并导出SVG矢量图。图像处理用Photoshop或GIMP等软件将截图转为纯黑白的BMP格式。这里有个关键点白色代表“有”黑色代表“无”。我们希望Voronoi的“边”透光所以在图像中Voronoi边应画为白色单元格内部为黑色。得到的是一张白线黑底的图片。导入EDA软件我使用的是KiCad。在PCB编辑器中通过“文件”-“导入”-“图形”功能将BMP图片导入到“用户绘图层”或“阻焊层”。这里我选择直接导入到F.Cu顶层走线层。重要技巧导入时设置合适的DPI通常300-600以确保线条宽度符合预期。导入后这些线条实际上是铜皮。接着在阻焊层F.Mask上沿着这些铜皮线条绘制完全重合的图形并设置其属性为“阻焊层开窗”。这样生产时这部分就不会覆盖绿色或其他颜色的阻焊油墨露出下面的铜箔或基材。3.2 主控板底板电路设计要点主控板的原理图并不复杂但几个细节决定了稳定性。电源与滤波USB-C口的5V电源直接接入。在VCC和GND之间紧挨着ATtiny85和WS2812B的电源引脚必须放置一个0.1uF-1uF的陶瓷去耦电容。这是为了滤除芯片高速开关产生的高频噪声防止干扰内部逻辑甚至导致复位。虽然ATtiny85很皮实但这一步不能省。WS2812B信号连接ATtiny85的PB0物理引脚5被定义为信号输出。串联的LED矩阵数据输入DIN接MCU第一个LED的数据输出DOUT接第二个LED的DIN以此类推。信号线上建议串联一个22Ω-100Ω的小电阻靠近MCU端放置可以阻尼反射提高信号完整性。尽管很多简单项目省略了它但在PCB走线较长或LED数量多时它能有效减少数据错误。按钮防抖按钮一端接地另一端接ATtiny85的PB4物理引脚3并启用内部上拉电阻代码中INPUT_PULLUP。硬件上不需要额外上拉电阻。为了软件消抖更可靠可以在按钮两端并联一个0.01uF-0.1uF的电容成本极低效果显著。PCB布局实战经验电源走线优先先用粗线如0.5mm以上规划好5V和GND的主干道确保到每个LED和MCU的路径都尽可能短而宽。信号线避免平行长距离走线数据线应避免与电源线或其他信号线长距离紧挨着平行走减少串扰。如果不可避免中间用地线隔离。LED阵列布局64颗LED8x8要均匀分布在底板中央区域。计算好LED间距使其发出的光能均匀覆盖侧板的Voronoi图案区域。可以事先在纸上画个等比例草图。3.3 焊接与组装工艺实录这次组装混合了SMT贴片和THT通孔工艺核心是主控板的SMT焊接。焊锡膏涂布我没有使用钢网因为板子不大元件不多。用的是注射器装的中温焊锡膏。要点是少量多次。用牙签或细针头在每个焊盘上点一小坨量宁少勿多。过多的焊锡膏在回流时容易导致元件移位或桥连。手工贴片使用防静电镊子。先贴小元件电阻、二极管再贴芯片最后是USB-C座虽然它稍大。贴ATtiny85时一定要对准方向芯片上的小圆点或凹槽标记对应PCB丝印上的“1”脚标识。热板回流焊接我用的是一块自制的温控热板。温度曲线是关键预热将热板升温至约150°C把PCB放上去预热60-90秒。这使焊锡膏中的溶剂缓慢挥发避免突然沸腾溅射。回流迅速升温至焊锡膏的熔点以上我用的锡膏熔点为217°C我升至约230-240°C。此时可以看到焊锡瞬间熔化变成亮银色元件会因表面张力自动“归位”对齐焊盘。保持这个温度30-60秒。冷却关闭热板或将PCB移开让其自然冷却。切勿用嘴吹或强制冷却以免产生冷焊点或应力裂纹。踩坑记录第一次预热不足直接猛加热结果焊锡膏飞溅导致两个LED焊盘桥连。返修时只能用吸锡带和烙铁一点点清理非常麻烦。所以“慢预热快回流”是DIY回流焊的黄金法则。侧板与结构焊接这是最需要耐心和手稳的步骤。先将底板与一块侧板垂直对齐用夹具或帮助手固定。用烙铁加热侧板焊盘先上一点锡。然后熔化这点锡同时将底板的对应焊盘靠上去移开烙铁待锡凝固。同样的方法焊接对角位置这样板子就被初步固定了。然后再补焊其余焊点。注意散热焊接大面积铜箔的焊盘时烙铁温度要调高一些我设到380°C并配合使用助焊剂否则很难上锡。3.4 ATtiny85的编程与调试ATtiny85不能像Arduino Uno那样直接用USB线编程需要借助编程器。搭建编程环境Arduino as ISP最经济的方式是用一块Arduino Uno作为编程器。在Arduino IDE中打开示例代码ArduinoISP并上传到Uno。关键一步上传完ArduinoISP程序后必须在Uno的RESET引脚和GND之间接一个10uF电容。这是为了在给ATtiny编程时防止Uno的串口监控器干扰复位线否则会报“进入编程模式失败”的错误。按照下图连接线缆Arduino Uno (作为编程器) - ATtiny85 10 -------- RESET (PB5, 引脚1) 11 -------- MOSI (PB0, 引脚5) 12 -------- MISO (PB1, 引脚6) 13 -------- SCK (PB2, 引脚7) 5V -------- VCC (引脚8) GND ------- GND (引脚4)在Arduino IDE中通过“工具”菜单安装ATTinyCore开发板支持包。然后选择开发板为“ATtiny25/45/85”处理器为“ATtiny85”时钟为“内部8MHz”编程器选择“Arduino as ISP”。烧录引导程序与代码点击“工具”-“烧录引导程序”。这并非传统意义上的Bootloader而是设置芯片的熔丝位配置正确的时钟源等参数是必须的一步。烧录成功后就可以像平常一样编写代码了。但上传时不是点“上传”而是点击“项目”-“使用编程器上传”。我提供的两个代码中FastLED库的示例用于测试所有LED是否正常工作色彩绚丽。第二个基于Adafruit_NeoPixel的代码是最终使用的通过按钮循环切换15种单色光效。代码精简与优化心得 ATtiny85的8KB Flash空间需要精打细算。FastLED库功能强大但体积较大。Adafruit_NeoPixel库更轻量但对于复杂动画也捉襟见肘。如果只需要静态颜色或简单渐变可以自己写最底层的WS2812B时序驱动能节省大量空间。网上有很多“极简版”驱动代码仅需几百字节。关掉未使用的功能。例如如果不用模拟输入可以在setup()里将未用的ADC关闭以省电。颜色数据尽量用uint8_t或uint16_t类型避免使用浮点数运算AVR芯片处理浮点非常慢且耗资源。4. 问题排查与效果优化实录在实际制作和调试过程中遇到了几个典型问题这里分享排查思路和解决方案。4.1 LED部分不亮或颜色错乱这是WS2812B项目中最常见的问题。症状从某个LED开始后面的灯全不亮或乱闪颜色。排查步骤检查电源首先用万用表测量问题LED处的VCC和GND电压。WS2812B对电压很敏感低于4V就可能工作异常。确保电源能提供足够电流且PCB上的电源走线足够宽压降小。检查信号连接用示波器或逻辑分析仪看数据信号。如果条件有限可以用一个简单的办法在代码中只点亮第一个LED。如果第一个正常第二个不正常问题很可能出在第一个LED的DOUT到第二个LED的DIN之间的连接虚焊、断线。补焊这两个引脚。检查时序WS2812B对数据时序要求严格。ATtiny85在8MHz内部时钟下需要精心调整延时来满足0码和1码的时序要求。如果使用了第三方库确保库是兼容ATtiny85且版本正确。可以尝试在信号线靠近MCU端加一个几十欧姆的电阻如前所述。我的案例我曾遇到中间一串LED颜色随机变化。最终发现是其中一个LED的电源引脚焊盘有细微裂纹导致接触不良。在振动或温度变化时时通时断扰乱了整个数据流。重新焊接后解决。4.2 按钮响应不灵或连击症状按一下按钮灯效跳过多格或没反应。原因与解决硬件消抖不足机械按钮在按下和弹起时触点会物理抖动产生多个脉冲。我虽然在代码中加了20ms延时消抖但在某些情况下可能不够。最佳实践是硬件消抖并联电容和软件消抖延时状态检测结合使用。我在按钮两端并联了一个0.1uF电容后问题基本消失。代码逻辑缺陷我最初的代码只在检测到按钮按下LOW时切换模式。但如果按住不放程序会循环执行快速切换。改进方法是使用“状态机”或检测“下降沿”从HIGH变LOW的瞬间确保一次按下只触发一次。我提供的最终代码已经包含了这种检测。4.3 Voronoi光效不均匀这是艺术效果上的主要挑战。症状有些线条很亮有些很暗整体斑驳。分析与优化根本原因LED是点光源且集中在底板。侧板上的Voronoi线条距离LED的远近、角度各不相同。优化方法1增加LED数量或优化布局。这是最直接但成本最高的方法。可以在底板边缘也布置一圈LED从侧面补光。优化方法2使用导光材料。在LED阵列和侧板之间加一层乳白色的亚克力板或扩散膜可以将点光源转化为面光源使光线更均匀。这是我计划在V2版本中尝试的。优化方法3软件亮度补偿。如果LED是逐个可寻址的可以写一个校准程序让每个LED单独点亮通过摄像头或光传感器测量每条Voronoi线条的亮度生成一个亮度补偿表。在显示时根据该表动态调整每个LED的亮度。这属于高阶玩法对ATtiny85的内存和算力是巨大挑战。4.4 ATtiny85无法被编程器识别症状烧录引导程序时提示“进入编程模式失败”、“无法识别芯片”等。排查清单接线错误这是最常见原因。反复检查MOSI/MISO/SCK/RESET/VCC/GND这6根线是否一一对应有无虚焊。电容未接忘记在作为编程器的Arduino Uno的RESET和GND间接10uF电容。电源问题确保ATtiny85的VCC引脚有稳定的5V电压。编程时电流需求稍大最好由编程器Arduino Uno的5V引脚供电而不是从目标板的其他电路取电。芯片损坏或熔丝位锁死如果之前误操作设置了错误的熔丝位如禁用了SPI编程可能导致芯片无法被识别。此时需要高压并行编程器来解救对于新手而言操作复杂。因此初次烧录熔丝位时要格外小心使用ATTinyCore的默认设置通常是最安全的。5. 项目总结与迭代思考回顾整个项目最大的成就感在于将抽象的数学图形通过电子工艺变成了可触摸、可交互的光影实体。ATtiny85这颗小芯片的表现令人惊喜驱动64颗LED流畅自如证明了在资源受限环境下实现复杂效果的可行性。然而不满意的地方也很明显主要集中在光效上。原设计希望光线只从精细的Voronoi线条中透出形成清晰的负形图案。但由于LED是直射且侧板内部没有做漫反射处理实际效果更像是整个侧板在发光线条的锐利感被削弱了更像一个光晕背景下的图案。这背离了最初的“镂空”设计初衷。对于想复现或改进这个项目的朋友我的核心建议是将光路设计作为重中之重来模拟和验证。在PCB投板前可以用3D建模软件如Fusion 360简单建模渲染光线追踪效果或者更简单地用纸板做一个1:1的模型用手电筒从不同角度照射观察“透光缝”的效果。这能避免我犯的错。V2版本的改进思路已经清晰第一在LED和侧板之间加入匀光层第二考虑使用侧发光LED或将LED贴在侧板边缘让光在导光板中传播再从Voronoi线条处散射出来这样线条的清晰度会极大提升。第三主控可以升级为ESP32-C3等带无线功能的芯片实现手机APP调色和动画上传让这件艺术品从静态变为动态与人产生更多互动。电子制作不仅是功能的实现更是创意的表达。这个Voronoi PCB灯就像一座桥梁一头连着严谨的数学与工程另一头连着感性的艺术与生活。每一次调试每一次改进都是在这座桥上添砖加瓦的过程。希望我的这些经验无论是成功的还是踩坑的能帮你更顺畅地建造属于你自己的那座桥。