树莓派CharliePlex LED矩阵驱动:从I2C通信到Python动画实战
1. 项目概述与硬件解析如果你手头有一块树莓派想给它加个能显示点动态信息、甚至能播放小动画的“眼睛”那Adafruit的CharliePlex LED矩阵Bonnet绝对是个好玩又实用的选择。这东西本质上是一个直接插在树莓派GPIO排针上的扩展板Bonnet上面集成了一个8x16的LED点阵总共128颗LED以及一颗负责驱动这些LED的专用芯片IS31FL3731。它的核心魅力在于你不需要像驱动传统的8x8点阵那样自己写复杂的行列扫描代码去“人肉”刷新也不用担心电流不够烧坏GPIO口。这颗驱动芯片通过I2C总线接收你的指令然后默默地在后台完成所有繁重的PWM调光和刷新工作让你能用几行简单的Python代码就轻松点亮任意一颗LED控制它的亮度甚至玩出多帧动画。我最初接触这个板子是想给一个放在角落的树莓派服务器做个状态指示灯显示CPU负载或者网络流量。传统方法要么是接几个独立的LED信息量有限要么是用OLED屏成本又上去了。这块Bonnet正好在信息密度、可视距离和编程复杂度之间找到了一个不错的平衡点。128个像素点足够显示两行简短文字或者一些自定义的图标动画而且LED本身亮度很高在环境光下也清晰可见。整个系统的核心是I2C通信和Charlieplexing查理复用技术。I2C的好处是接线极其简单只需要SDA数据、SCL时钟、电源和地四根线而且树莓派上原生支持。Charlieplexing则是一种聪明的电路设计技巧它允许你用N个GPIO引脚驱动多达 N*(N-1) 个LED。我们这个板子上的8x16矩阵其底层就是靠这种技术实现的而IS31FL3731芯片内部已经完美封装了所有复杂的Charlieplexing逻辑和PWM生成电路。对我们开发者来说完全不需要关心底层硬件是如何扫描的只需要通过I2C告诉芯片“把坐标X, Y的LED亮度设为127”剩下的脏活累活芯片全包了。这种将复杂硬件逻辑抽象成简单API的思想正是现代开源硬件生态比如Adafruit、Arduino能快速普及的关键。注意虽然板子从树莓派的5V引脚取电但其I2C通信电平仍然是3.3V与树莓派GPIO的逻辑电平完美兼容无需任何电平转换电路直接插上就能用非常省心。1.1 核心硬件IS31FL3731驱动芯片深度剖析IS31FL3731这颗芯片是项目的“大脑”理解它的特性才能更好地发挥Bonnet的潜力。它不仅仅是一个简单的LED开关而是一个具备独立帧缓冲区的图形控制器。首先它支持每颗LED独立的8位PWM调光。这意味着每颗LED都有256级0-255灰度可调而不仅仅是亮或灭。你可以实现平滑的淡入淡出效果或者用不同的亮度来表现图像的灰度层次。这在显示文字或简单图形时能有效改善边缘的锯齿感让视觉效果更柔和。其次芯片内部集成了8个独立的显示帧缓冲区Frame Buffer。这是实现无闪烁动画的关键。你可以把动画的每一帧画面预先绘制到不同的帧缓冲区里比如帧0画个圆圈帧1画个方块。当需要播放动画时你只需要通过一条I2C指令告诉芯片“现在切换到帧1显示”显示内容就会瞬间切换没有任何刷新的黑屏间隙。这比你在代码里逐像素擦除再重绘要高效和稳定得多。芯片甚至支持硬件自动循环播放这些帧Autoplay模式进一步解放了主控CPU。芯片的I2C地址默认为0x74。板子上设计了一个地址选择跳线。如果你需要连接多个同款Bonnet或者与其他I2C设备地址冲突了可以通过焊接这个跳线将地址改为0x70。这个设计考虑得很周到为项目扩展留下了空间。关于功耗需要留意当所有128颗LED都以最高亮度255点亮时总电流可能会超过500mA。虽然树莓派本身的5V电源能力足够但如果你是通过Micro USB口供电特别是使用一些输出能力不足的电源适配器时可能会引起电压跌落导致树莓派重启。我的经验是在开发调试阶段尤其是点亮大面积LED时最好将全局亮度限制在150以下或者使用能提供2A以上电流的优质电源为树莓派供电。1.2 硬件连接与准备工作硬件连接简单到几乎“傻瓜式”。Bonnet的排针孔位与树莓派40针GPIO排母完全对应你只需要像戴帽子一样将Bonnet对准树莓派的排针轻轻按下去确保方向正确通常Bonnet上会有“Raspberry Pi”字样朝向树莓派板子中央就完成了物理连接。它同时兼容树莓派3B/3B/4B/Zero等所有拥有40针GPIO的型号。连接好后首先需要确保树莓派的I2C接口已启用。因为默认情况下Raspberry Pi OS可能禁用了I2C。打开终端运行sudo raspi-config。选择Interface Options-I5 I2C。当询问是否启用ARM I2C接口时选择Yes。退出raspi-config并重启树莓派。重启后可以通过命令sudo i2cdetect -y 1来验证。如果一切正常你应该能在输出列表中看到地址0x74或0x70如果你改了跳线被检测到。这个步骤是后续所有软件工作的基础务必先确认通过。2. Python驱动环境搭建与基础库使用驱动这块Bonnet我们主要使用Adafruit提供的Python库生态。这里有两个略有区别但同源的选择CircuitPython和Blinka Python。理解它们的区别能帮你选对路径。CircuitPython通常用于微控制器如Adafruit自家的Feather、ItsyBitsy等。你需要将代码文件code.py和库文件复制到微控制器识别出的CIRCUITPY磁盘里它会上电自动运行。这种方式脱离操作系统更接近硬件底层。Blinka Python这是用于像树莓派这样的单板计算机SBC或任何运行Linux的电脑的方案。Adafruit-Blinka是一个兼容层库它让CircuitPython的硬件控制API如board、busio能在标准Python 3环境下运行。对于树莓派上的Bonnet项目我们毫无疑问选择这个方案。2.1 安装Python驱动库确保你的树莓派系统已更新并且使用的是Python 3Raspberry Pi OS默认就是。然后通过pip安装必要的库。我强烈建议在虚拟环境venv中进行以避免污染系统Python环境。# 更新系统包列表和pip sudo apt update sudo apt upgrade -y sudo pip3 install --upgrade pip setuptools wheel # 安装Adafruit BlinkaCircuitPython兼容层和IS31FL3731驱动库 sudo pip3 install adafruit-blinka adafruit-circuitpython-is31fl3731 # 安装framebuf库用于高级图形和文本操作如后面的滚动文字示例 sudo pip3 install adafruit-circuitpython-framebuf安装完成后可以创建一个简单的测试脚本test_bonnet.py来验证硬件和库是否工作正常。import board import busio import time # 导入适用于Bonnet的显示类 from adafruit_is31fl3731.charlie_bonnet import CharlieBonnet as Display # 初始化I2C和显示对象 i2c busio.I2C(board.SCL, board.SDA) display Display(i2c) print(CharliePlex Bonnet测试开始...) # 测试1全屏半亮 display.fill(127) # 亮度值127约50% time.sleep(1) # 测试2清屏 display.fill(0) time.sleep(0.5) # 测试3逐行点亮 for y in range(display.height): # height8 for x in range(display.width): # width16 display.pixel(x, y, 100) time.sleep(0.01) time.sleep(1) # 测试4对角线闪烁 display.fill(0) for i in range(min(display.width, display.height)): display.pixel(i, i, 255, blinkTrue) # 开启闪烁 time.sleep(3) # 测试5关闭闪烁并清屏 display.fill(0, blinkFalse) # 关闭所有LED的闪烁 print(测试完成)运行这个脚本python3 test_bonnet.py。如果能看到LED矩阵依次执行全亮、清屏、逐行扫描、对角线闪烁最后熄灭那么恭喜你硬件和基础驱动环境已经完美就绪。2.2 核心API详解与避坑指南Adafruit的库封装得非常友好主要操作通过display对象完成。下面结合我的使用经验深入讲讲几个核心函数和容易踩的坑。1.display.fill(brightness, blinkFalse)这是最常用的函数之一用于设置所有LED的亮度。brightness: 0全灭到255最亮。注意brightness控制的是PWM占空比并非线性感知亮度。人眼对低亮度更敏感所以设置brightness50看起来可能比一半亮度亮得多。如果需要均匀的亮度渐变可能需要一个亮度-占空比映射表Gamma校正。blink: 布尔值。设为True时所有LED会以通过display.blink()设置的频率闪烁。一个关键细节blink参数只控制“是否启用闪烁模式”而brightness参数则决定了在“亮”的阶段LED的亮度是多少。你可以让LED以半亮127的状态闪烁。2.display.pixel(x, y, brightness, blinkFalse)控制单个像素。坐标原点(0,0)在矩阵的左上角。X轴向右增长Y轴向下增长。这是计算机图形学的惯例但如果你习惯数学坐标系原点在左下角需要适应一下。边界检查库内部应该做了边界检查但自己写循环时最好也确认一下避免传入x16或y8的值导致程序异常。性能考量在快速动画中频繁调用pixel()设置单个点效率较低。更优的做法是先在内存中构建好一整帧的图像数据比如用一个二维列表然后一次性更新或者利用后面提到的多帧缓冲功能。3.display.blink(period_ms)设置全局闪烁周期。芯片支持的周期是270ms的整数倍。如果你设置display.blink(500)实际生效的周期可能是540ms2*270。这不是bug而是硬件限制。如果你的动画对闪烁节奏要求精确需要以270ms为基准进行计算。4. 多帧缓冲操作display.frame(frame_number, showTrue)这是实现流畅动画的灵魂函数。frame_number: 0到7选择8个帧缓冲区中的一个作为当前“绘图”目标。show: 默认为True即切换到该帧并立即显示。如果设为False则只是切换到该帧进行“幕后”绘制画面仍显示之前的那一帧。典型工作流# 准备帧1的内容但不显示 display.frame(1, showFalse) display.fill(0) # 清空帧1 # ... 在帧1上绘制你的图形 ... display.pixel(5, 3, 200) # 准备帧2的内容 display.frame(2, showFalse) display.fill(0) # ... 在帧2上绘制 ... # 快速切换显示形成动画 while True: display.frame(1, showTrue) # 显示帧1 time.sleep(0.2) display.frame(2, showTrue) # 显示帧2 time.sleep(0.2)这种方式完全避免了在单帧上擦除-重绘带来的闪烁感。实操心得在初始化display对象后芯片会自动清空所有8个帧缓冲区。但如果你在程序运行中途动态切换帧最好养成先display.fill(0)清空目标帧的习惯因为之前可能残留数据。特别是当你复用帧来显示不同内容时。3. 高级应用实战文本滚动与动画播放基础的点亮和闪烁玩熟了之后就可以尝试更酷的应用了。Adafruit库的示例提供了两个经典案例文本滚动和GIF动画播放。它们都依赖额外的Python图像库PIL/Pillow让我们能处理字体和图片。3.1 实现流畅的文本滚动显示单纯的pixel()画字符太痛苦了。我们需要借助adafruit_framebuf库它提供了一个简单的帧缓冲区Framebuffer对象支持text()等高级绘图函数。首先确保你有字体文件。示例中使用了一个内置的5x8像素位图字体font5x8.bin。你可以直接下载wget https://raw.githubusercontent.com/adafruit/Adafruit_CircuitPython_framebuf/master/examples/font5x8.bin将下载的font5x8.bin文件放在与你的Python脚本相同的目录下。下面是文本滚动示例的核心代码解读与优化import board import busio import adafruit_framebuf from adafruit_is31fl3731.charlie_bonnet import CharlieBonnet as Display i2c busio.I2C(board.SCL, board.SDA) display Display(i2c) text_to_show Hello, World! # 1. 创建缓冲区我们的显示是16x8但framebuf需要按字节对齐。 # 16像素宽 * 8像素高 / 8 bits per byte 16字节不对。 # 实际上framebuf的MVLSB模式要求每行像素按字节打包8像素高正好是1字节宽。 # 所以对于16x8的显示缓冲区大小是 16 * 1 16字节这里示例用了32字节可能是历史或兼容性原因。 # 我们遵循示例创建一个32字节的缓冲区。 buf bytearray(32) fb adafruit_framebuf.FrameBuffer(buf, display.width, display.height, adafruit_framebuf.MVLSB) frame 0 # 使用双帧缓冲来减少闪烁 while True: text_width len(text_to_show) * 6 # 5x8字体每个字符宽约6像素含1像素间距 for i in range(text_width display.width): # 2. 清空framebuffer fb.fill(0) # 3. 在framebuffer上绘制文本。文本的X坐标是负的偏移量使其从右侧移入。 fb.text(text_to_show, -i display.width, 0, color1) # 4. 使用双帧缓冲技术在“后台”帧绘制 display.frame(frame, showFalse) display.fill(0) # 清空显示器的该帧 # 5. 将framebuffer中的位数据“翻译”到LED矩阵 for x in range(display.width): # 获取当前列对应的字节 byte_value buf[x] # 注意这里索引取决于framebuf的布局示例中是buf[x] for y in range(display.height): # 检查字节中对应的位是否为1 if byte_value (1 y): display.pixel(x, y, 50) # 点亮该像素亮度50 # 6. 切换显示到绘制好的这一帧 display.frame(frame, showTrue) # 7. 切换帧索引为下一轮绘制准备 frame 0 if frame else 1 time.sleep(0.05) # 控制滚动速度关键点与优化双帧缓冲代码中frame在0和1之间切换。当一帧比如帧0正在前台显示时我们在后台帧帧1上准备下一幅画面。准备完成后瞬间切换显示帧。这能有效消除绘制过程中的闪烁。性能瓶颈最内层的双层循环for x in range... for y in range...在Python中执行效率不高尤其是每次滚动都要执行16*8128次pixel()调用和位运算。对于16x8这种小规模矩阵尚可接受但如果追求极致的滚动流畅度可以考虑预渲染所有滚动位置的帧到8个硬件帧中然后用芯片的autoplay功能播放。字体局限font5x8.bin是固定大小的位图字体不支持缩放和抗锯齿。如果需要显示更漂亮的字体必须使用下面介绍的Pillow方案。3.2 使用Pillow显示自定义字体与GIF动画PillowPIL是Python强大的图像处理库。通过它我们可以渲染任意TrueType字体甚至播放GIF动画。第一步安装系统依赖和Pillow# 安装字体通常系统已自带 sudo apt-get install ttf-dejavu # 安装Pillow的Python库 sudo pip3 install pillow第二步TrueType字体滚动示例精讲这个例子比之前的framebuf文本滚动强大得多也更具实用性。它允许你使用电脑里的任何字体文件。import board import time from PIL import Image, ImageDraw, ImageFont from adafruit_is31fl3731.charlie_bonnet import CharlieBonnet as Display i2c board.I2C() display Display(i2c) SCROLLING_TEXT 树莓派状态正常 BRIGHTNESS 80 # 建议亮度避免过亮 # 1. 加载字体。注意指定正确的字体路径。 # DejaVu是常用开源字体路径如下。你也可以指定其他TTF字体文件。 try: font ImageFont.truetype(/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf, 8) except IOError: # 如果找不到尝试其他路径或使用默认字体 font ImageFont.load_default() print(警告未找到DejaVu字体使用默认字体。) # 2. 测量文本尺寸 # 注意Pillow 9.2.0 移除了getsize需要使用textbbox try: # 新版本Pillow bbox font.getbbox(SCROLLING_TEXT) text_width, text_height bbox[2] - bbox[0], bbox[3] - bbox[1] except AttributeError: # 旧版本Pillow text_width, text_height font.getsize(SCROLLING_TEXT) # 3. 创建文本图像虚拟的足够大以容纳整个文本 # 模式L代表8位灰度图亮度值0-255直接对应我们的LED亮度。 text_image Image.new(L, (text_width, text_height)) text_draw ImageDraw.Draw(text_image) # 在文本图像上绘制白色文字亮度为BRIGHTNESS text_draw.text((0, 0), SCROLLING_TEXT, fontfont, fillBRIGHTNESS) # 4. 创建与显示区域同样大小的画布 image Image.new(L, (display.width, display.height)) draw ImageDraw.Draw(image) print(f文本宽度{text_width}像素开始滚动...) while True: # 5. 主滚动循环 for x_offset in range(text_width display.width): # 清空画布 draw.rectangle((0, 0, display.width, display.height), fill0) # 计算文本图像在画布上的粘贴位置实现从右向左滚动 # 当x_offset0时文本的右边缘对齐显示区域右边缘文本在屏幕外右侧 # 随着x_offset增大文本向左移动 paste_x display.width - x_offset # 垂直居中 paste_y (display.height - text_height) // 2 # 将文本图像粘贴到画布上 image.paste(text_image, (paste_x, paste_y)) # 6. 将PIL图像对象直接发送给显示器 # 这是最简洁的一步库内部会处理好图像数据到LED亮度的转换。 display.image(image) time.sleep(0.05) # 控制滚动速度这个方案的巨大优势display.image(image)函数接收一个PIL的Image对象并自动将其缩放如果尺寸不对和转换为亮度信息驱动LED。你完全不用关心底层像素是如何映射的。这使得显示复杂的渲染结果比如用Pillow画出的图形、图标变得极其简单。第三步播放GIF动画播放GIF是另一个炫酷功能。你需要一个GIF文件最好其尺寸不超过16x8或者是你希望显示的区域大小。import sys import board from PIL import Image import adafruit_is31fl3731 i2c board.I2C() display adafruit_is31fl3731.CharlieBonnet(i2c) # 检查命令行参数 if len(sys.argv) 2: print(用法: python3 play_gif.py 你的动画.gif) sys.exit(1) gif_path sys.argv[1] try: gif Image.open(gif_path) except FileNotFoundError: print(f错误找不到文件 {gif_path}) sys.exit(1) # 检查是否为动态GIF if not gif.is_animated: print(错误该文件不是动态GIF。) sys.exit(1) # 获取GIF信息 frame_delay gif.info.get(duration, 100) # 默认100毫秒 loop_count gif.info.get(loop, 0) # 0表示无限循环 # IS31FL3731最多支持8帧硬件缓冲 max_frames min(gif.n_frames, 8) print(f加载GIF: {gif_path}, 帧数: {gif.n_frames}, 循环: {loop_count}, 使用前{max_frames}帧) # 将GIF的每一帧加载到驱动芯片的帧缓冲区 for frame_index in range(max_frames): gif.seek(frame_index) # 跳转到指定帧 # 将当前帧转换为灰度图(L模式) frame_converted gif.convert(L) # 创建一个与显示区域大小相同的黑色背景图 display_frame Image.new(L, (display.width, display.height), color0) # 计算位置将GIF帧居中粘贴 paste_x (display.width - frame_converted.width) // 2 paste_y (display.height - frame_converted.height) // 2 display_frame.paste(frame_converted, (paste_x, paste_y)) # 将该帧图像数据上传到芯片的指定帧缓冲区 display.image(display_frame, frameframe_index) # 使用芯片的硬件自动播放功能 # delay: 每帧显示时长毫秒 # loop: 循环次数0为无限循环1播放一次2播放两次... # 注意芯片的loop参数和GIF的loop含义略有不同这里做了简单转换。 # GIF中loop0表示无限loopN表示播放N1次。 hardware_loop 0 if loop_count 0 else loop_count display.autoplay(delayframe_delay, loopshardware_loop) print(动画开始播放按CtrlC停止。) try: # 主循环什么都不用做动画由芯片硬件控制 while True: time.sleep(1) except KeyboardInterrupt: print(\n停止播放。) display.fill(0) # 清屏核心技巧硬件自动播放display.autoplay()是神器。它配置芯片自动在多个帧缓冲区之间循环无需CPU持续干预。这大大降低了系统负载并且播放时序由硬件保证极其稳定流畅。居中显示通过计算paste_x和paste_y可以将尺寸不一的GIF完美居中显示在16x8的点阵上。资源管理对于帧数多于8帧的GIF此示例只加载前8帧。如果你需要播放更长的动画就需要软件配合动态加载后续帧到硬件缓冲区实现“流式”播放这会复杂一些。4. 性能优化与常见问题排查在实际项目中你可能会遇到刷新率不够、动画卡顿、或者I2C通信错误等问题。下面分享一些优化和排查经验。4.1 提升I2C总线速度关键优化树莓派上I2C的默认速度可能是100kHz或400kHz。对于需要快速更新128个LED亮度数据的应用这个速度可能成为瓶颈导致动画帧率低下。我们可以将I2C时钟提升到1MHz1000kHz。操作步骤编辑启动配置文件sudo nano /boot/config.txt在文件末尾添加一行dtparami2c_baudrate1000000按CtrlX然后按Y再按Enter保存退出。重启树莓派sudo reboot重启后可以通过命令sudo cat /sys/module/i2c_bcm2708/parameters/baudrate对于旧内核或检查dmesg | grep i2c来确认新的速率是否生效。这项优化对于使用Pillow渲染复杂图形或快速滚动的文本效果提升非常明显。警告提高I2C速率可能会影响总线上其他对时序要求严格的设备。如果系统中还有其他I2C设备如某些传感器开始工作不正常可能需要将其调整到另一条I2C总线如树莓派4的/dev/i2c-0和/dev/i2c-1或者将速率调回400kHz。4.2 常见问题与解决方案速查表以下是我在开发过程中遇到的一些典型问题及解决方法问题现象可能原因排查步骤与解决方案运行脚本无任何反应LED不亮1. I2C未启用2. 库未正确安装3. 硬件连接松动4. I2C地址错误1. 运行sudo i2cdetect -y 1检查是否能看到0x74或0x70设备。2. 运行python3 -c “import adafruit_is31fl3731; print(‘OK’)”测试库导入。3. 重新插拔Bonnet确保接触良好。4. 检查代码中初始化的类是否为CharlieBonnet并确认是否修改过地址跳线。LED显示混乱错位或部分不亮1. 坐标系统理解错误2. 缓冲区操作错误3. 多帧缓冲切换逻辑错误1. 确认原点(0,0)在左上角X向右Y向下。写个简单脚本点亮四个角测试。2. 在使用framebuf时确保缓冲区大小和模式(MVLSB)设置正确。3. 检查frame()函数调用时show参数的使用确保绘图和显示帧的切换逻辑正确。动画闪烁严重不流畅1. 单帧缓冲绘制2. Python循环效率低3. I2C速度太慢1.务必使用双帧或多帧缓冲技术在后台帧绘制完成后瞬间切换。2. 优化Python代码避免在动画主循环中进行大量计算或IO操作。考虑预渲染。3.实施I2C提速优化见4.1节将速率提升至1MHz。显示内容有残影或“鬼影”1. 切换帧前未清空缓冲区2. PWM干扰或电源噪声1. 在绘制新内容到某一帧之前先调用display.fill(0)清空该帧。2. 这是Charlieplexing和PWM驱动的固有特性在低亮度下更明显。尝试适当提高全局亮度或调整PWM频率但该芯片频率不可调。使用优质电源。Pillow示例报错ImportError或IOError1. Pillow未安装2. 字体文件路径错误3. 图像文件不存在或格式不支持1. 运行sudo pip3 install pillow确保已安装。2. 检查ImageFont.truetype()中的字体路径是否存在。可使用fc-list命令查看系统字体。3. 检查GIF文件路径并用其他软件确认GIF文件有效。树莓派运行大型脚本时卡顿或重启1. USB电源供电不足2. CPU负载过高3. 内存不足1.这是最常见原因点亮全屏高亮LED时功耗激增。换用足额5V/2.5A以上的电源适配器并避免使用长或细的USB线。2. 使用htop查看CPU占用。优化Python脚本利用硬件自动播放(autoplay)减少CPU干预。3. 对于树莓派Zero等内存较小的型号关闭不必要的后台服务。4.3 项目扩展思路与进阶玩法掌握了基础之后你可以将这个Bonnet集成到更有趣的项目中系统状态监视器写一个Python脚本定期读取树莓派的CPU温度、负载、内存使用率、IP地址等信息并将其转换为简单的柱状图、滚动文字或图标动画显示在LED矩阵上。网络信息展示结合requests库显示天气信息、股票价格、下一个日历事件等。例如用不同的LED图案代表晴天、多云、下雨。简易游戏利用8x16的点阵可以制作极简版的贪吃蛇、俄罗斯方块或Flappy Bird。需要处理按钮输入可以连接USB手柄或通过GPIO连接几个按钮。音乐可视化通过树莓派的音频输入接口或USB声卡结合pyaudio库分析音频频谱将音量或频率信息实时映射成LED矩阵上的动态波浪图。多设备同步如果你有多个树莓派和Bonnet可以通过网络Socket通信让所有LED矩阵显示相同的内容打造一面简单的分布式显示墙。最后一点个人体会Adafruit CharliePlex Bonnet的魅力在于它极大地降低了硬件图形显示的门槛。它把复杂的Charlieplexing电路、PWM驱动、帧缓冲管理都封装在了一个小小的芯片和友好的Python库后面。作为开发者我们可以更专注于应用逻辑和创意本身而不是纠缠于底层的时序和扫描算法。从点亮第一个像素到让自定义的文字滚动起来再到播放自己设计的动画这个过程充满了即时的成就感。希望这篇详细的解析能帮你绕过我当初踩过的一些坑更快地把这个有趣的小设备玩起来。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2614525.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!