利用W55MH32L-EVB构建一个实时UDP像素显示屏及舞台可视化器
迄今为止,我所创建的所有项目都使用了TCP(传输控制协议)。该协议属于所谓的TCP/IP模型的一部分,这一模型提供了分层框架,使我们的电脑和微控制器能够无缝协商数据包的传输。
以下是该模型的示意图:
TCP属于传输层,负责确保设备间数据可靠且高效地传输。使用TCP的优势在于能保证数据按原样准确送达。然而,本周我想尝试另一种传输层协议——UDP(用户数据报协议)。UDP适用于对速度要求高于精确性的情况。
在之前的一篇帖子中,我尝试过LED矩阵,并思考如何通过一个无输入延迟的模块来控制LED的某些方面。这正是本项目的灵感来源。在此项目中,我利用W55MH32L-EVB构建了一个实时UDP像素显示屏及舞台可视化器。系统通过W5500控制器以以太网方式接收RGB动画帧,并驱动一个5V 8×32柔性RGB LED矩阵。
它使用SSD1306 OLED显示屏,用于显示板卡的IP地址、测量帧率、丢帧次数以及旋转编码器值。此外,还配备了一个物理旋转编码器,可实时将控制遥测数据发送回主机PC,其数值可用于调节动画速度和亮度等参数。
硬件概览与接线
以下是本项目所用硬件的一些图片:
在开始编写代码之前,先来看看各组件如何连接到W55MH32L板:
8×32 WS2812B LED矩阵:
•数据输入(DIN):PA7(或任意GPIO)
•电源与地:5V引脚和GND引脚
旋转编码器:
•通道A(CLK):PA0(配置为内部上拉)
•通道B(DT):PA1(配置为内部上拉)
•电源与地:3.3V引脚和GND引脚
SSD1306 OLED显示屏(I2C):
•SCL:I2C1 SCL(PB6)
•SDA:I2C1 SDA(PB7)
•电源与地:3.3V引脚和GND引脚
•地址:0x3D(可通过i2c.scan()方法查找)
W5500以太网控制器(内置SPI):
•片选(CS):PB12
•复位(RST):PD9
•接口:专用硬件SPI2总线
我们还需要用网线将电路板连接到路由器或以太网交换机,以便它能接入网络。
现在开始逐步分析代码!
你可以跳过部分说明,因为内容比较长。
最重要的设计思路包括:
- 使用UDP是因为LED动画需要高速度和低延迟。
- 帧ID功能使控制器能够检测丢失或过时的帧。
- LED索引映射隐藏了矩阵蛇形布线的复杂性。
- 编码器中断用于快速记录运动状态,而主循环则更新应用程序的状态。
- OLED屏幕定期刷新,避免干扰实时帧处理。
- 在可能的情况下,程序会优雅地处理硬件故障,确保控制器其余部分仍能正常运行。
这个MicroPython LED控制器的工作原理
该程序将微控制器转变为一个由网络控制的LED矩阵控制器。计算机通过UDP协议以太网发送动画帧,微控制器则在32×8的NeoPixel矩阵上显示这些帧。
同时,旋转编码器允许用户调整一个从0到100的数值,该数值通过UDP回传至计算机。OLED显示屏会显示主板的IP地址、帧率、丢包数量以及编码器数值。
计算机与板之间的通信使用UDP端口6454,板与计算机之间的通信使用UDP端口6455。
模块与初始化变量
1. 模块
这些模块提供了程序所需的功能:
•socket 提供 UDP 网络功能。
•struct 将值转换为紧凑的二进制数据包。
•time 提供延迟和毫秒计时器。
•machine 提供硬件功能,例如禁用中断。
•network 控制以太网接口。
•neopixel 控制 RGB LED 灯阵列。
•ssd1306 控制 OLED 显示屏。
•Pin 控制 GPIO 引脚。
•I2C 与 OLED 进行通信。
•SPI 与 W5500 以太网控制器进行通信。
我将使用这些行来分隔不同部分,以提高可读性。
2. 配置常量
LED矩阵宽32列,高8行:
每个NeoPixel需要三个颜色值:
每个颜色值通常在0到255之间,因此一个LED需要三个字节。
本项目中:
其余常量用于标识硬件引脚和通信设置:
LED矩阵使用PA7引脚。
旋转编码器使用两个信号引脚:
•PA0:编码器通道A
•PA1:编码器通道B
W5500以太网控制器通过SPI总线2(8 MHz)与微控制器通信。它还使用以下引脚:
•PB12作为片选
•PD9作为复位
UDP端口定义如下:
该板通过端口6454接收LED帧,并通过端口6455将编码器数据发送回计算机。
3. UDP帧格式
计算机发送的每个LED帧具有以下结构:
头部为:
这是一个两字节的标记,用于标识有效帧。
完整帧的大小为:
由于有效载荷包含768字节:
帧号为16位值,可使板卡检测到重复、过时或跳过的帧。
4. 全局应用状态
编码器值从50%开始。
编码器中断使用了多个变量:
中断例程不会直接修改encoder_value,而是将运动信息记录在encoder_delta中。主循环随后应用该变化。
这种分离很重要,因为中断处理程序应保持简短,并避免执行复杂操作。
其他变量用于跟踪网络连接和性能:
它们的用途如下:
•pc_ip:发送帧的计算机IP地址。
•frame_count:当前统计周期内处理的帧数量。
•dropped_frames:看似被跳过的帧数量。
•last_frame_id:最近接受的帧编号。
•last_stats_time:用于计算每秒帧数的时间戳。
启动序列
程序首先打印以下内容:
然后按以下顺序初始化硬件:
顺序是逻辑上的:
•初始化LED矩阵。
•尝试初始化OLED。
•配置编码器。
•构建LED接线图。
•初始化以太网。
然后检查以太网连接:
如果以太网初始化失败,程序会打印错误但继续运行。
最后,创建UDP套接字:
如果创建套接字失败,两个变量都将被设置为 None,从而使程序其余部分在不进行网络通信的情况下继续运行。
完整系统行为
在正常运行时,流程如下:
- 板子通电。
- 初始化 NeoPixel 矩阵、OLED、编码器和 W5500。
- 板子通过 DHCP 请求 IP 地址。
- 板子监听 UDP 端口 6454 上的 LED 数据帧。
- 计算机发送一个包含以下内容的数据帧:
- 两字节的头部
- 帧号
- 256 个 RGB 像素
- 计算机发送另一个包含以下内容的数据帧:
- 两字节的头部
- 帧号
- 256 个 RGB 像素
- 板子验证该数据帧。
- 板子将逻辑像素位置转换为物理矩阵位置。
- NeoPixel 矩阵显示该帧。
- 旋转编码器通过中断检测旋钮移动。
- 主循环将该移动转换为 0 到 100 之间的数值。
- 板子将修改后的数值通过 UDP 端口 6455 发送回计算机。
- OLED 显示网络和性能信息。
本文编译自hackster.io





