CircuitPython驱动NeoPixel与DotStar实现彩虹动画:从原理到实践
1. 项目概述:用代码点亮彩虹
玩嵌入式开发或者物联网项目,灯光效果几乎是绕不开的一环。从简单的状态指示,到复杂的氛围渲染,LED都是最直观、最有效的交互媒介。但如果你还停留在用digitalWrite控制单个LED亮灭的阶段,那可就错过了太多乐趣。今天,我们要聊的是如何用CircuitPython,驱动两种业界“顶流”的可编程LED——NeoPixel和DotStar,来实现丝滑流畅、色彩绚丽的彩虹动画效果。
这不仅仅是让灯带“跑个马灯”那么简单。我们将深入底层,理解colorwheel函数背后的色彩空间转换数学,搞懂如何通过一行行代码,让数百颗LED像被施了魔法一样,同步上演一场光的华尔兹。无论你是想为自己的桌面增添一抹动态色彩,还是为机器人项目打造酷炫的指示灯,亦或是创作一个大型的光影艺术装置,掌握NeoPixel和DotStar的驱动技巧都是至关重要的第一步。CircuitPython的出现,让这一切变得异常简单——它用我们最熟悉的Python语法,屏蔽了底层硬件的复杂细节,让你可以专注于创意和逻辑本身。
2. 核心硬件解析:NeoPixel与DotStar的异同
在开始写代码之前,我们必须先搞清楚手头的“画笔”是什么。NeoPixel(WS2812系列)和DotStar(APA102系列)是目前最流行的两种智能RGB LED,它们内部都集成了驱动芯片,但通信协议和电气特性截然不同,这直接影响了我们的选型和编程方式。
2.1 NeoPixel:单线奇迹与它的局限
NeoPixel,或者说WS2812,最大的特点就是“单线制”。它只需要一根数据线(Din)就能串联起成百上千颗LED,每个LED都会读取数据、提取属于自己的颜色信息,然后将剩余数据转发给下一颗。这种设计极大地简化了布线,你只需要接上电源、地线和一根数据线,就能控制一条长长的灯带。
它的工作原理可以想象成一条流水线:微控制器发出一个很长的数据序列,序列被分割成许多小段,每段对应一颗LED的RGB值。第一颗LED“吃掉”开头的第一段数据,把剩下的整条序列推给下一颗,如此接力下去。因此,数据刷新率(帧率)会随着LED数量增加而线性下降。当你点亮100颗LED时,发送一整帧数据的时间可能长达数毫秒,对于需要快速变化的动画(比如音乐可视化)来说,这可能成为瓶颈。
另一个关键点是PWM(脉冲宽度调制)频率。NeoPixel的PWM频率通常在400Hz到800Hz左右。这个频率不算高,在摄像头或高速运动的物体下,可能会观察到明显的闪烁现象。此外,由于它的时序要求非常严格,数据信号必须精准,在长距离传输或受到干扰时容易出错。
2.2 DotStar:双线高速与硬件加持
DotStar(APA102)则采用了完全不同的思路:它使用标准的SPI(串行外设接口)协议进行通信。这意味着它需要两根线:数据线(DI)和时钟线(CI)。时钟线由主控制器(我们的开发板)提供,用于同步每一位数据的传输。
这带来了两个巨大的优势:
- 极高的速度:SPI的时钟频率可以轻松达到几兆赫兹(MHz)。这意味着刷新一整条LED灯带的时间极短,几乎可以做到实时更新,非常适合需要高速、流畅动画的场景。
- 更强的抗干扰能力:有时钟线同步,数据传输更可靠,不易受环境噪声影响。
DotStar的PWM频率也远高于NeoPixel,通常能达到20kHz以上,彻底消除了肉眼可见的闪烁,在专业摄影或视频录制下也能稳定工作。
那么,该如何选择?
- 选NeoPixel:当你的项目对引脚数量非常敏感(比如只用一块很小的开发板),布线要求极其简单,或者成本是第一考量因素时。
- 选DotStar:当你需要极致的动画流畅度、更高的刷新率、更好的抗干扰性,或者计划驱动超长灯带(数百颗以上)时。虽然多了一根线,但带来的性能提升是质的飞跃。
注意:市面上有些LED模组虽然外观一样,但芯片方案不同。购买时务必确认型号是WS2812(NeoPixel)还是APA102(DotStar),它们的驱动库和接线方式不兼容。
3. 环境搭建与库安装
CircuitPython项目离不开库文件。Adafruit为NeoPixel和DotStar提供了官方维护的、高度优化的库,我们需要将它们部署到开发板上。
3.1 获取CircuitPython库 Bundle
最省事的方法是下载完整的“库捆绑包”(Library Bundle)。你可以访问Adafruit的CircuitPython库页面,找到与你的CircuitPython版本号匹配的捆绑包进行下载。下载后解压,你会看到一个lib文件夹。
3.2 部署库文件到开发板
将你的开发板通过USB连接到电脑,它会显示为一个名为CIRCUITPY的U盘(驱动器)。
- 打开这个驱动器。
- 如果里面没有
lib文件夹,就新建一个。 - 从刚才解压的库捆绑包的
lib文件夹中,找到以下两个.mpy文件(它们是针对MicroPython编译的优化版库):adafruit_pixelbuf.mpy(NeoPixel和DotStar都依赖的基础库)neopixel.mpy(用于驱动NeoPixel)adafruit_dotstar.mpy(用于驱动DotStar)
- 将这三个文件复制到你的
CIRCUITPY驱动器下的lib文件夹中。
为什么是.mpy文件?.mpy是MicroPython/CircuitPython的预编译字节码文件。相比原始的.py文件,它们加载更快、占用内存更少,这对于资源紧张的微控制器来说非常重要。直接使用.mpy文件能让你获得最佳性能。
3.3 创建并编辑code.py
在CIRCUITPY驱动器的根目录下,你会看到一个code.py文件。这是CircuitPython板子上电后自动执行的主程序文件。用任何文本编辑器(如VS Code、Thonny、甚至记事本)打开它,清空原有内容,准备写入我们的彩虹代码。
4. 彩虹的核心:colorwheel函数原理解析
所有炫酷的彩虹效果,都源于一个优雅的数学函数——colorwheel。它接受一个0-255的整数输入,输出一个对应的RGB颜色元组(R, G, B)。理解它,你就掌握了色彩循环的钥匙。
colorwheel函数将0-255的色相值(Hue)均匀地映射到RGB色彩空间的一个完整循环上。其核心逻辑是将255等分为三段,分别对应红色到绿色、绿色到蓝色、蓝色回红色的渐变过渡。
def colorwheel(pos): # 输入一个0到255的值,返回一个颜色值。 # 颜色在红-绿-蓝-红之间过渡。 if pos < 0 or pos > 255: return (0, 0, 0) # 输入越界返回黑色 if pos < 85: # 第一段:红 -> 绿。红递减,绿递增。 return (255 - pos * 3, pos * 3, 0) if pos < 170: pos -= 85 # 第二段:绿 -> 蓝。绿递减,蓝递增。 return (0, 255 - pos * 3, pos * 3) pos -= 170 # 第三段:蓝 -> 红。蓝递减,红递增。 return (pos * 3, 0, 255 - pos * 3)数学拆解:
pos * 3和255 - pos * 3:因为每段长度是85,pos * 3的取值范围是0-255,恰好用于线性插值。一个颜色分量从255线性下降到0,另一个从0线性上升到255。& 255操作:在后续的动画循环中,我们可能会让索引值j不断累加超过255。rc_index & 255是一个高效的位操作,等同于rc_index % 256,它能确保索引值始终在0-255的循环范围内,这是实现无缝色彩循环的关键。
在CircuitPython 6.0及以上版本,这个函数已经被内置在rainbowio模块中,我们可以直接from rainbowio import colorwheel来使用这个优化过的版本。
5. 驱动单个内置LED的彩虹动画
让我们从最简单的开始:许多CircuitPython开发板(如Circuit Playground Express、QT Py等)都板载了一颗可编程的RGB LED。我们可以用它来测试我们的colorwheel逻辑。
5.1 硬件抽象与自动检测
不同的开发板,这颗内置LED的驱动芯片可能不同。幸运的是,CircuitPython的board模块提供了硬件抽象。我们可以写一段兼容性代码,让它自动判断该用哪个库。
import time import board from rainbowio import colorwheel # 自动检测板载LED类型并初始化 if hasattr(board, "APA102_SCK"): # 如果板子定义了APA102_SCK引脚,说明是DotStar LED import adafruit_dotstar led = adafruit_dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1) else: # 否则,默认为NeoPixel LED import neopixel led = neopixel.NeoPixel(board.NEOPIXEL, 1) led.brightness = 0.3 # 设置亮度为30%,防止过亮刺眼这段代码的精妙之处在于hasattr(board, “APA102_SCK”)。它检查board模块是否有这个属性,从而在运行时决定使用哪套驱动方案,实现了代码的跨平台兼容。
5.2 主循环与动画逻辑
初始化完成后,彩虹动画的逻辑其实非常简洁:
i = 0 while True: i = (i + 1) % 256 # i在0到255之间循环 led.fill(colorwheel(i)) # 用colorwheel计算的颜色填充LED time.sleep(0.01) # 控制变化速度i = (i + 1) % 256:这是实现循环递增的标准写法。每次循环i加1,当达到256时,取模运算使其归零,从而实现永无止境的循环。led.fill():对LED对象进行填充。即使我们只控制一颗LED,使用fill()也是一个好习惯,因为它同样适用于多颗LED的场景,代码更具通用性。time.sleep(0.01):这行代码决定了彩虹颜色变化的速度。0.01秒(10毫秒)的间隔意味着每秒变化100次,看起来非常流畅。你可以通过调整这个值来加速或减速动画。试试改成time.sleep(0.1),你会看到彩虹缓慢流淌;改成time.sleep(0.001),则会看到色彩飞速变换。
实操心得:在驱动板载LED时,务必注意亮度设置。很多板载LED的驱动能力有限,且没有限流电阻,全亮度(
brightness=1.0)长时间工作可能导致LED过早老化或损坏。通常从0.2到0.5的亮度开始测试是比较安全的。
6. 驱动多颗NeoPixel LED
当我们需要驱动灯带或灯环时,就需要创建控制多个像素的LED对象。
6.1 初始化与参数详解
import board import neopixel pixel_pin = board.A1 # 数据线连接的引脚 num_pixels = 8 # LED的数量 pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.3, auto_write=False)pixel_pin:数据输入(DIN)线连接的GPIO引脚。NeoPixel对时序要求高,理论上任何数字引脚都可以,但最好避免使用那些有特殊复用功能的引脚(如I2C、SPI的默认引脚)。num_pixels:你串联的LED总数。务必准确设置,否则多出的LED不会被控制,而设置少了则无法控制全部LED。brightness=0.3:全局亮度,范围0.0到1.0。这是一个非常重要的保护性参数。NeoPixel在5V电压下,单颗LED全白(R=255,G=255,B=255)时,电流可能高达60mA。8颗就是480mA!许多微控制器的3.3V稳压器无法提供如此大的电流。设置亮度为0.3,不仅保护了你的眼睛,也保护了你的开发板和电源。auto_write=False:这是性能优化的关键。当设置为False时,你对pixels数组的所有颜色修改(如pixels[0] = (255,0,0))都不会立即发送到LED上,而是缓存在内存中。只有当你调用pixels.show()时,所有更改才会被一次性打包并发送出去。这避免了频繁、低效的单次数据发送,能极大提升动画的流畅度,尤其是在驱动较多LED时。
6.2 高级视觉效果函数
单纯的填充太单调了,我们来编写几个更酷的效果函数。
颜色追逐(Color Chase)效果:
def color_chase(color, wait): for i in range(num_pixels): pixels[i] = color # 将第i颗LED设置为目标颜色 pixels.show() # 更新LED显示 time.sleep(wait) # 等待一段时间,产生追逐感 time.sleep(0.5) # 一轮追逐完成后的停顿这个函数让颜色像水流一样依次流过每一颗LED。wait参数控制“水流”的速度。
彩虹循环(Rainbow Cycle)效果:
def rainbow_cycle(wait): for j in range(255): # j是彩虹的相位,循环0-254 for i in range(num_pixels): # i是第几颗LED # 核心算法:为每颗LED计算不同的色相偏移 rc_index = (i * 256 // num_pixels) + j pixels[i] = colorwheel(rc_index & 255) pixels.show() time.sleep(wait)这是最经典的彩虹动画。(i * 256 // num_pixels)确保了在任一时刻,整条灯带上的LED都均匀分布着彩虹上的所有颜色。随着j的增加,这个彩虹谱会整体向前移动,形成循环流动的效果。rc_index & 255确保了索引值不会溢出。
6.3 主程序与效果组合
# 预定义一些常用颜色,方便调用 RED = (255, 0, 0) YELLOW = (255, 150, 0) GREEN = (0, 255, 0) CYAN = (0, 255, 255) BLUE = (0, 0, 255) PURPLE = (180, 0, 255) while True: # 1. 纯色填充展示 pixels.fill(RED) pixels.show() time.sleep(1) # ... 其他颜色填充 # 2. 颜色追逐序列 color_chase(RED, 0.1) color_chase(YELLOW, 0.1) # ... 其他颜色追逐 # 3. 彩虹循环 rainbow_cycle(0) # 参数为0,表示以最快速度运行在主循环中,我们将不同的效果组合起来,形成一个丰富的灯光秀。通过调整time.sleep和各个效果函数的wait参数,你可以创造出快慢交替、动静结合的复杂节奏。
6.4 电源与接线的严峻考验
驱动多颗NeoPixel是对电源系统的严峻考验。绝对不能忽视供电问题。
- 计算功耗:一颗NeoPixel在显示纯白色(255,255,255)时,典型电流约为60mA。那么10颗就是600mA,50颗就是3A!你电脑USB口的500mA输出远远不够。
- 供电方案:
- 少量LED(<10颗):可以尝试从开发板的3.3V或5V引脚取电。但务必监控开发板稳压芯片的温度,如果烫手,必须立刻停止。
- 中量LED(10-50颗):必须使用外部独立电源。一个5V/2A以上的手机充电器或专用的LED电源是必要的。将外部电源的正极(5V)同时接到LED灯带的5V和开发板的VIN/USB(如果支持5V输入),将负极(GND)同时接到LED灯带的GND和开发板的GND。这是最关键的一步,共地!
- 大量LED(>50颗):除了大功率独立电源,还需要在灯带沿线进行“电源注入”,即在灯带中段额外并联电源线,以补偿长距离导线的电压降。
- 数据信号衰减:对于很长的灯带(如5米以上),数据信号在末端可能会衰减到无法识别。解决方法是在数据线中串联一个100-500欧姆的电阻(靠近微控制器输出端),或者在末端并联一个100-220欧姆的电阻到地,这有助于消除信号反射。
血的教训:我曾因贪图方便,试图用Feather M0的3.3V引脚驱动一条20颗的NeoPixel灯带显示白色。结果芯片瞬间过热保护,整个项目宕机,还差点烧了芯片。从此牢记:先算电流,再供电。
7. 处理RGBW NeoPixel
RGBW NeoPixel在红、绿、蓝之外增加了一个独立的白色LED。这带来了更纯正、更高效的白色光,但也需要不同的代码来处理。
7.1 对象初始化的关键区别
初始化RGBW NeoPixel时,必须指定pixel_order参数:
pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.3, auto_write=False, pixel_order=(1, 0, 2, 3)) # 注意这个元组这里的pixel_order=(1, 0, 2, 3)是一个四元素元组,它定义了数据流中四个颜色分量的顺序。这个顺序因LED制造商而异!(1, 0, 2, 3)是Adafruit常见的RGBW灯带顺序,分别代表:红、绿、蓝、白的偏移量。如果你的灯带颜色错乱,尝试将其改为(0, 1, 2, 3)(GRBW)或(2, 1, 0, 3)(BRGW)等。最可靠的方法是查阅你的LED灯带的数据手册。
7.2 颜色元组的改变
所有颜色值现在都需要是四元组(R, G, B, W),其中W是白色分量值(0-255)。
RED = (255, 0, 0, 0) # 纯红,白色LED不亮 WHITE = (0, 0, 0, 255) # 仅白色LED亮 WARM_WHITE = (50, 30, 0, 200) # 混合白光,略带暖色调重要提示:如果你错误地给RGBW灯带发送RGB三元组(255,0,0),库通常会默认将白色分量补0,你可能会发现红色比预期暗,因为只有三分之二的LED(红、绿、蓝中的红色)被点亮了。
7.3 适配的colorwheel函数
内置的rainbowio.colorwheel函数返回的是RGB三元组。对于RGBW,我们需要一个返回四元组的版本:
def colorwheel(pos): if pos < 0 or pos > 255: return (0, 0, 0, 0) if pos < 85: return (255 - pos * 3, pos * 3, 0, 0) if pos < 170: pos -= 85 return (0, 255 - pos * 3, pos * 3, 0) pos -= 170 return (pos * 3, 0, 255 - pos * 3, 0)注意,这个函数在彩虹循环中没有使用白色分量(W始终为0)。如果你想在彩虹中也融入白光,需要更复杂的色彩空间转换算法(如从HSV到RGBW),这超出了基础教程的范围。
8. 驱动DotStar LED并启用硬件SPI
DotStar的驱动与NeoPixel类似,但因其采用SPI协议,在速度和接线方式上有所不同。
8.1 初始化与引脚选择
import board import adafruit_dotstar num_pixels = 30 pixels = adafruit_dotstar.DotStar(board.A1, board.A2, num_pixels, brightness=0.1, auto_write=False)这里DotStar构造函数的前两个参数分别是时钟引脚(clock_pin)和数据引脚(data_pin)。顺序很重要!
性能关键点:硬件SPI vs 软件SPI
- 硬件SPI:如果你的开发板有专用的SPI硬件模块,并且你恰好将时钟和数据线接到了该模块对应的硬件引脚上(例如,在Many boards上,硬件SPI的SCK和MOSI是固定引脚),那么
adafruit_dotstar库会自动使用硬件SPI。这将带来数量级的速度提升(MHz级别时钟 vs KHz级别)。 - 软件SPI(位碰撞):如果你使用了任意两个GPIO引脚,库将使用软件模拟SPI时序。这虽然灵活,但速度慢,CPU占用率高。
如何检查引脚是否支持硬件SPI?Adafruit提供了一个非常实用的脚本:
import board import busio def is_hardware_spi(clock_pin, data_pin): try: p = busio.SPI(clock_pin, data_pin) # 尝试创建硬件SPI对象 p.deinit() # 释放资源 return True except ValueError: # 如果引脚不支持硬件SPI,会抛出ValueError return False if is_hardware_spi(board.A1, board.A2): print("恭喜!这个引脚组合支持硬件SPI,性能爆表!") else: print("这是软件SPI,性能会差一些。")强烈建议:在项目规划阶段,就查阅你的开发板原理图,找到硬件SPI引脚(通常是board.SCK和board.MOSI)并优先使用它们。
8.2 DotStar专属的高级效果
得益于其高速刷新,DotStar非常适合实现一些需要快速切换的复杂效果。
交替切片(Slice Alternating)效果:
def slice_alternating(wait): # 点亮所有偶数索引的LED(0, 2, 4...) pixels[::2] = [RED] * (num_pixels // 2) pixels.show() time.sleep(wait) # 点亮所有奇数索引的LED(1, 3, 5...) pixels[1::2] = [GREEN] * (num_pixels // 2) pixels.show() time.sleep(wait)这里用到了Python列表的切片赋值和列表乘法,是批量设置LED颜色的高效写法。pixels[::2]获取了所有偶数索引的LED,然后我们用[RED] * (num_pixels // 2)生成一个包含一半数量红色元组的列表,一次性赋值过去。这比用for循环逐个设置要简洁高效得多。
彩虹切片(Slice Rainbow)效果:
def slice_rainbow(wait): # 每6颗LED为一组,分别设置不同的彩虹色 pixels[::6] = [RED] * (num_pixels // 6) pixels.show() time.sleep(wait) pixels[1::6] = [ORANGE] * (num_pixels // 6) pixels.show() time.sleep(wait) # ... 以此类推这个效果要求LED总数能被6整除(因为用了6种颜色)。Adafruit常见的DotStar灯带是30、60、72颗,都满足条件。如果你的灯带被剪过,数量不匹配,这个函数就需要调整。
8.3 DotStar的供电考量
DotStar的功耗特性与NeoPixel类似,但由于其更高的刷新率和可能更亮的LED,供电不足的问题会更加凸显。前述关于NeoPixel的供电警告(计算电流、使用外部电源、共地)全部适用于DotStar,且要求更严格。在驱动长串DotStar做高速动画时,一个纹波小、电流足的5V电源是必须的。
9. 常见问题与深度排查指南
即使按照教程一步步来,你也可能会遇到灯光不亮、颜色不对、闪烁、乱码等问题。别慌,我们来系统性地排查。
9.1 LED完全不亮
| 可能原因 | 排查步骤 | 解决方案 |
|---|---|---|
| 电源问题 | 1. 用万用表测量LED灯带5V和GND之间的电压。 2. 检查电源是否开启,电流是否足够(参考第6.4节计算)。 | 确保电压在4.5-5.5V之间。使用额定电流足够的电源。 |
| 接线错误 | 1. 确认5V、GND、数据线(Din/DI)是否接对。 2.重点:数据线是否接在了LED灯带的**数据输入(DIN/DI)**端?接在输出端(DO/DOUT)是无效的。 | 仔细对照灯带上的箭头或文字标识(DIN输入,DOUT输出),确保数据流向正确。 |
| 代码未运行 | 1. 检查开发板是否成功进入CircuitPython模式(出现CIRCUITPY驱动器)。 2. 检查 code.py文件是否在根目录,且代码无语法错误。 | 连接串口监视器(如Mu编辑器),查看是否有错误信息输出。 |
| 亮度设置为0 | 检查代码中brightness参数是否被意外设为0.0。 | 将亮度调整为0.1以上再测试。 |
9.2 只有第一颗LED亮,或颜色异常
| 可能原因 | 排查步骤 | 解决方案 |
|---|---|---|
| 数据线接触不良 | 晃动数据线连接处,观察LED是否闪烁。 | 重新焊接或压接数据线接头,确保连接牢固。 |
num_pixels设置错误 | 检查代码中num_pixels变量是否等于你实际连接的LED数量。 | 修改num_pixels为正确值。 |
| 电平不匹配 | NeoPixel/DotStar是5V器件,而很多开发板GPIO是3.3V。长线传输时,3.3V可能被认作低电平。 | 在数据线上(靠近开发板端)串联一个300-500欧姆的电阻。对于长距离或干扰环境,使用74AHCT125之类的3.3V转5V电平转换器是最可靠的。 |
| 电源地线环路 | 如果使用外部电源,开发板的GND和外部电源的GND没有连接在一起。 | 必须将两个电源的“地”(GND)连接在一起,形成共同的参考零电位。 |
9.3 灯光闪烁、乱码或部分LED不受控
| 可能原因 | 排查步骤 | 解决方案 |
|---|---|---|
| 电源功率不足 | 测量电源在LED全白时的输出电压,如果远低于5V(如降到4V),说明功率不足。 | 换用功率更大、线径更粗的电源。对于长灯带,考虑多点供电。 |
| 电源纹波过大 | 使用劣质电源或电源距离灯带过远,导致电压不稳。 | 在LED灯带的电源输入端并联一个1000μF 6.3V以上的电解电容,可以很好地平滑电压。 |
| 代码逻辑过慢 | 动画效果计算太复杂,导致pixels.show()调用间隔过长。 | 优化代码,减少循环内的计算量。对于复杂效果,可以考虑使用_thread模块(如果板子支持)或将计算提前。 |
| 软件SPI速度瓶颈 | DotStar使用了非硬件SPI引脚,刷新速度跟不上。 | 换用硬件SPI引脚(如board.SCK和board.MOSI)。 |
9.4 RGBW灯带显示颜色不正确
| 可能原因 | 排查步骤 | 解决方案 |
|---|---|---|
pixel_order错误 | 观察显示的颜色与预期颜色的关系。例如,设置红色(255,0,0,0)却显示绿色。 | 调整pixel_order参数。常见组合有(1,0,2,3)(RGBW),(0,1,2,3)(GRBW),(2,1,0,3)(BRGW)。需要逐一测试或查数据手册。 |
| 使用了RGB三元组 | 检查颜色赋值是否为(R,G,B,W)四元组。 | 将所有颜色定义和colorwheel函数改为支持四元组。 |
一个终极调试技巧:当你一筹莫展时,写一个最简单的测试程序:
import time import board import neopixel pixels = neopixel.NeoPixel(board.A1, 1, brightness=0.1) while True: pixels[0] = (255,0,0) # 红 time.sleep(1) pixels[0] = (0,255,0) # 绿 time.sleep(1) pixels[0] = (0,0,255) # 蓝 time.sleep(1)只接一颗LED,用最简短的代码测试。如果这个能工作,再逐步增加LED数量、引入效果函数,从而定位问题是在基础驱动、电源还是效果逻辑本身。
灯光项目的调试,三分靠代码,七分靠硬件。耐心和细致的排查,是成功点亮彩虹的最后一步,也是最关键的一步。当你看到自己编写的代码驱动起第一串流光溢彩的LED时,那种成就感,就是嵌入式开发最纯粹的乐趣。
