TinyMatrix | HUB75接口LED点阵控制器的设计

0. 前言

工具箱里有块闲置的Led点阵板,于是便想折腾起来让其绽放色彩。HUB75是全彩LED显示屏最常见的接口,但很难找到标准通信协议。经历一番探索调试,将其记录于此文。

在这里插入图片描述

1. 硬件篇

1.1. HUB75接口定义

Led点阵板的HUB75接口,一般以DC3-16P牛角座封装形式接入。通常Led点阵板的左右两侧各有一个HUB75接口IN、OUT,以实现多块Led点阵板的组合扩展。HUB75接口中:R1、G1、B1分别为上半屏的红、绿、蓝控制信号,R2、G2、B2分别为下半屏的红、绿、蓝控制信号,A、B、C、D、E为行选择信号,CLK为数据时钟信号,LAT为数据锁存信号,OE为输出使能信号,GND为信号地。

在这里插入图片描述

1.2. HUB75扫描方式

那么Led点阵板是怎样通过HUB75接口实现行扫描信号、行选择信号的输入和锁存的呢?

我们来复习下数字电路中的D型锁存器:CLK=1时,Q端将置为D端输入电平状态;CLK=0时,Q端将保持Q端输出电平状态。如果将8个D型锁存器串联就构成了一个8位串入并出移位寄存器,74HC595是一个8位串行输入、并行输出移位寄存器的集成电路。如果将8个74HC595集成电路级联,通过CLK数据时钟、LAT数据锁存、OE输出使能控制便能实现64位行扫描信号的输出。


Led点阵板通常被设计成上下两个部分进行显示,这样就能够降低扫描频率、减少地址线,代价是需要增加数据线。所以对于32扫的Led点阵板,需要6根数据线(上半屏R1、G1、B1,下半屏R2、G2、B2),5根地址线(A、B、C、D、E)。

我们来复习下数字电路中的3线-8线译码器:当E1=0、E2=0、E3=1时,输入端A0、A1、A2的二进制编码被译码成相应的十进制信号至输出端Yn。74HC138是一个3线-8线译码器的集成电路。如果将4个74HC138集成电路和一个非门电路进行连接,就构成了一个5线-32线译码器,便能实现5位-32行行选择信号的输出。


将行扫描信号、行选择信号进行组合控制,就实现了整个Led点阵板的扫描显示。其具体实现过程如下:

在这里插入图片描述

  1. 从DATA_IN引脚(R1、G1、B1、R2、G2、B2)写入1 bit数据,将CLK引脚拉高产生上升沿将数据写入移位寄存器。如此循环m次将一行m bit数据传输至移位寄存器。
  2. 将LATCH、OE引脚拉高,m bit数据被从移位寄存器传输至缓存寄存器。同时缓存寄存器中数据被保持禁止从输出驱动器中输出,以使得在行选择信号切换时没有Led被点亮。
  3. 切换并输出行选择信号。(初始状态时,第0行、第32行被选中。)
  4. 将LATCH、OE引脚拉低,m bit数据被从缓存寄存器传输至输出驱动器。同时移位寄存器中数据被锁存禁止从缓存寄存器中移出,此时对应选中行Led被点亮。

将以上步骤执行n/2次,便能实现m x n像素Led点阵板整个画面的扫描显示。如果扫描频率足够低,我们能看到逐行扫描显示的全过程:

在这里插入图片描述

基于人眼视觉暂留效应(余晖效应),我们无法分辨刷新率在24Hz以上的动态画面。如果将扫描频率设置在60Hz,我们就能看到一幅完整的静态画面。而这也就是常见的显示器的基本原理。

最后,将Led点阵板上下两个部分的R1、G1、B1、R2、G2、B2控制信号进行组合,便能基于光学RGB模型实现全彩显示。

1.3. Led Matrix控制板设计

了解了HUB75接口的控制原理,接下来进行Led Matrix控制板设计。

Led Matrix控制板设计思路如下:

在这里插入图片描述

Led Matrix控制板的核心选择的是一款尺寸为 22.86mm x 53.34mm 的STM32最小系统板。其通过2 x 20Pin GPIO排针将板载STM32F103C8T6 MCU内集成的2x SPI、3x USART、2x I2C、1x CAN、37x I/O、2x ADC、4x Timer等硬件资源引出,以便外围扩展板调用。固件程序可通过SWD接口进行烧录和调试,可通过Reset键复位。板载2路Led灯,一路用于电源状态指示,一路用于程序状态指示。

Led Matrix控制板设计1 x 4按键用于点阵控制器的参数设置。MCU相关GPIO经由74HC245连接至HUB75接口,以增加驱动电流并将驱动电压从3.3v转换至5.0v。外挂的W25Qxx系列SPI Flash用于存储系统参数和字库数据。UART串口可用于下载系统参数和字库数据,TTL-蓝牙模块、TTL-WiFi模块通过UART串口建立与MCU间的通讯以实现控制指令、显示数据的无线透传。Led Matrix控制板由外接电源适配器或内置锂离子电池提供系统电源,直流降压电路实现系统电源从12v-> 5v-> 3.3v电压转换以给各功能单元供电。

基于以上硬件需求,将Led Matrix控制板通过Eagle PCB设计如下。选择使用Eagle PCB,是因为其小巧精悍、简单易用,丰富的元件库、精美的原理图、标准vector字体,无不透露着严谨精致。可惜的是,被Autodesk收购后的Eagle 9.6.2对于3D模型的预览编辑需要通过Fusion 360来实现。

在这里插入图片描述

在这里插入图片描述

预计Eagle PCB的功能将被全部整合入Fusion 360,一款优秀的EDA工具将走向终点。

2. 结构篇

Eagle 9.6.2不支持直接编辑3D封装,而只能通过Fusion 360以云托管元件库的方式导入。不想从Fusion 360中重构元件库,但又追求项目完整性,这怎么解决呢?那就选择KiCad,不仅支持3D封装的直接编辑,还能将Eagle的.sch原理图文件、.brd电路板文件转换成对应的KiCad格式文件。

使用KiCad将Led Matrix控制板的Eagle格式文件转换成KiCad格式文件,基于此添加编辑3D封装,导出Led Matrix控制板3D Step模型文件。

在这里插入图片描述

使用KiCad对MCU核心板重新进行layout,添加编辑3D封装,导出MCU核心板3D Step模型文件。

在这里插入图片描述

在Fusion 360中将Led Matrix控制板和MCU核心板进行零件装配、干涉检查。

在这里插入图片描述

在Fusion 360中将Led Matrix控制板设置为固定零件,以此为基准依据Led Matrix控制板的空间尺寸设计Led Matrix控制器的整体结构。选择亚克力板材作为外壳材质。顶部和底部亚克力板通过双通螺母柱进行连接,Led Matrix控制板和Led点阵板与底部亚克力板连接固定,四侧亚克力板与顶部和底部亚克力板通过卡扣扣合进行连接。

在这里插入图片描述

3. 软件篇

3.1. RGB LED全彩显示

控制RGB LED实现全彩显示的传统方式是脉宽调制(Pulse Width Modulation),简称PWM。通过脉宽调制控制LED开关时间占比,进而实现RGB LED的亮度调节。如果对RGB模块中的三个LED进行此操作,则可以将红绿蓝三色按比例混合成对应的RGB全彩输出。对于Led Matrix Panel的全彩显示,PWM方式却不适用:这需要足够多的GPIO和定时器独立控制,需要消耗太多的硬件资源。那么我们如何通过软件方式予以解决呢?

二进制编码调制(Binary Code Modulation),简称BCM。BCM利用二进制编码性质控制开关信号占空比。假设有一个位宽为4的二进制数:从其最低位向左移动至最高位依次表示1个时间切片、2个时间切片、4个时间切片、8个时间切片。将这4种时间切片混合,可产生分辨率为1/15的任意占空比。如此,位宽越大分辨率越高色彩越丰富。位宽为8的二进制数,可表示分辨率为1/255的任意占空比。但位宽越大,时间切片越小,意味着更高的CPU占用率。为更好地平衡系统性能和硬件资源,本项目中BCM位宽为4。例如,4位二进制数0101表示5/15或33.3%的占空比。

在这里插入图片描述

Led Matrix Panel是逐行扫描显示的,所以需要预先将图像像素色彩转换成BCM值保存至图像缓冲区。创建4个图像缓冲区,以表示BCM位宽为4情况下的4种长度的时间切片中在扫描时间范围内哪些时间切片需要点亮LED。将这4个图像缓冲区构成的4个颜色通道Plane,进行图像融合就构成了一幅完整的静态图像。

在这里插入图片描述

每1个颜色通道需要6位二进制数表示1个像素(每一个时钟周期内同时扫描Led Matrix Panel上半部分、下半部分)。4个颜色通道需要4x 6= 24位二进制数,即3个Byte来表示一幅完整的静态图像中的1个像素。Byte 1的高6位表示Plane 1,Byte 2的高6位表示Plane 2,Byte 3的高6位表示Plane 3,Byte 1的低2位、Byte 2的低2位、Byte 3的低2位表示Plane 0。

在这里插入图片描述

将图像中全部像素从左至右、从上至下逐一转换成对应的3 Byte缓冲数据。这时有两种扫描方式:

  1. 先选择Row 0,将Plane 0至Plane 3数据依次输出,再切换至Row 1,直至Row 31。
  2. 先选择Plane 0,将Row 0至Row 31数据依次输出,再切换至Plane 1,直至Plane 3。

那么,哪一种扫描方式效果更好呢?可以料想方式2需要更多的Row行切换,不仅消耗更多的硬件资源,而且在显示动态图像时更易产生闪烁现象。所以,先将一行像素的Plane 0至Plane 3数据依次输出,此行扫描显示完成。

在这里插入图片描述

切换行选择信号,选中下一行。再将一行像素的Plane 0至Plane 3数据依次输出,此行扫描显示完成。如此,循环切换行选择信号,再将Plane数据依次输出,一幅完整的静态图像扫描显示完成。

在这里插入图片描述

缓冲区数据和行Row地址对应关系如下:

在这里插入图片描述

需要注意的是,BCM调制实现Led Matrix Panel的全彩显示需要高速时钟信号。以BCM位宽为4为例,如果1个时间切片内完成一行LED扫描,那么实现一行LED全彩显示需要15个时间切片。设置帧频率FPS= 60Hz,则行扫描频率LPS= 60x (n/2)x 15= 60x 32x 15= 28800Hz。本项目板载STM32F103C8T6 MCU主频为72MHz,程序内有多个任务分时调度处理,经调试发现将行扫描任务定时器频率设置为LPS= 28800Hz后,在1个时间切片内无法完成一行LED扫描。

如果选用更高时钟频率的MCU、减少调度任务数量,确保行扫描任务在任务时间切片内执行完毕,便能通过BCM调制实现Led Matrix Panel的全彩显示。而在实际应用中需要将多个Led Matrix Panel组合成大型LED显示屏,这就需要更高的扫描频率,通常设计采用高速FPGA输出扫描信号。

现在集成有MBI5153/ICN2053这类LED驱动芯片的Led点阵板,可通过写入参数至配置寄存器选择1~32扫任意扫描行数、配置输出电流增益等,可通过写入16bit灰阶数据以PWM调制实现LED全彩显示。

其扫描显示序列如下,即每显示1个像素之前切换一次当前行和列。这种扫描方式能较好地解决开路十字架和残影显示问题。

在这里插入图片描述

现有的互联网资源很难找到IC厂商提供的驱动程序,感谢bitbucket大神 @nadyrshin_ryu 贡献的源码。(https://bitbucket.org/nadyrshin_ryu/icn2053_esp32_demo/)

3.2. GBK中文字库

Led Matrix点阵控制器可控制GBK编码的中文字符显示。GBK字库存储在板载的SPI Flash,存储空间为8MB。

GBK全称《汉字内码扩展规范》,GBK编码是在GB2312-80标准基础上的内码扩展规范,使用了双字节编码方案,其编码范围从8140至FEFE(剔除xx7F),共23940个码位,共收录了21003个汉字,完全兼容GB2312-80标准。

3.3. 菜单显示控制

Led Matrix点阵控制器板载1 x 4按键,通过按键控制和菜单显示实现Led Matrix Panel模式和参数的设置。

1 x 4按键从左往右依次为上翻、下翻、确认、取消。确认/取消按键的长按和短按,可以实现不同的操作。

控制逻辑和菜单结构如下:

#mermaid-svg-Ejt8czwiQqwsZi7N .label{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);fill:#333;color:#333}#mermaid-svg-Ejt8czwiQqwsZi7N .label text{fill:#333}#mermaid-svg-Ejt8czwiQqwsZi7N .node rect,#mermaid-svg-Ejt8czwiQqwsZi7N .node circle,#mermaid-svg-Ejt8czwiQqwsZi7N .node ellipse,#mermaid-svg-Ejt8czwiQqwsZi7N .node polygon,#mermaid-svg-Ejt8czwiQqwsZi7N .node path{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-Ejt8czwiQqwsZi7N .node .label{text-align:center;fill:#333}#mermaid-svg-Ejt8czwiQqwsZi7N .node.clickable{cursor:pointer}#mermaid-svg-Ejt8czwiQqwsZi7N .arrowheadPath{fill:#333}#mermaid-svg-Ejt8czwiQqwsZi7N .edgePath .path{stroke:#333;stroke-width:1.5px}#mermaid-svg-Ejt8czwiQqwsZi7N .flowchart-link{stroke:#333;fill:none}#mermaid-svg-Ejt8czwiQqwsZi7N .edgeLabel{background-color:#e8e8e8;text-align:center}#mermaid-svg-Ejt8czwiQqwsZi7N .edgeLabel rect{opacity:0.9}#mermaid-svg-Ejt8czwiQqwsZi7N .edgeLabel span{color:#333}#mermaid-svg-Ejt8czwiQqwsZi7N .cluster rect{fill:#ffffde;stroke:#aa3;stroke-width:1px}#mermaid-svg-Ejt8czwiQqwsZi7N .cluster text{fill:#333}#mermaid-svg-Ejt8czwiQqwsZi7N div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:12px;background:#ffffde;border:1px solid #aa3;border-radius:2px;pointer-events:none;z-index:100}#mermaid-svg-Ejt8czwiQqwsZi7N .actor{stroke:#ccf;fill:#ECECFF}#mermaid-svg-Ejt8czwiQqwsZi7N text.actor>tspan{fill:#000;stroke:none}#mermaid-svg-Ejt8czwiQqwsZi7N .actor-line{stroke:grey}#mermaid-svg-Ejt8czwiQqwsZi7N .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333}#mermaid-svg-Ejt8czwiQqwsZi7N .messageLine1{stroke-width:1.5;stroke-dasharray:2, 2;stroke:#333}#mermaid-svg-Ejt8czwiQqwsZi7N #arrowhead path{fill:#333;stroke:#333}#mermaid-svg-Ejt8czwiQqwsZi7N .sequenceNumber{fill:#fff}#mermaid-svg-Ejt8czwiQqwsZi7N #sequencenumber{fill:#333}#mermaid-svg-Ejt8czwiQqwsZi7N #crosshead path{fill:#333;stroke:#333}#mermaid-svg-Ejt8czwiQqwsZi7N .messageText{fill:#333;stroke:#333}#mermaid-svg-Ejt8czwiQqwsZi7N .labelBox{stroke:#ccf;fill:#ECECFF}#mermaid-svg-Ejt8czwiQqwsZi7N .labelText,#mermaid-svg-Ejt8czwiQqwsZi7N .labelText>tspan{fill:#000;stroke:none}#mermaid-svg-Ejt8czwiQqwsZi7N .loopText,#mermaid-svg-Ejt8czwiQqwsZi7N .loopText>tspan{fill:#000;stroke:none}#mermaid-svg-Ejt8czwiQqwsZi7N .loopLine{stroke-width:2px;stroke-dasharray:2, 2;stroke:#ccf;fill:#ccf}#mermaid-svg-Ejt8czwiQqwsZi7N .note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-Ejt8czwiQqwsZi7N .noteText,#mermaid-svg-Ejt8czwiQqwsZi7N .noteText>tspan{fill:#000;stroke:none}#mermaid-svg-Ejt8czwiQqwsZi7N .activation0{fill:#f4f4f4;stroke:#666}#mermaid-svg-Ejt8czwiQqwsZi7N .activation1{fill:#f4f4f4;stroke:#666}#mermaid-svg-Ejt8czwiQqwsZi7N .activation2{fill:#f4f4f4;stroke:#666}#mermaid-svg-Ejt8czwiQqwsZi7N .mermaid-main-font{font-family:"trebuchet ms", verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-Ejt8czwiQqwsZi7N .section{stroke:none;opacity:0.2}#mermaid-svg-Ejt8czwiQqwsZi7N .section0{fill:rgba(102,102,255,0.49)}#mermaid-svg-Ejt8czwiQqwsZi7N .section2{fill:#fff400}#mermaid-svg-Ejt8czwiQqwsZi7N .section1,#mermaid-svg-Ejt8czwiQqwsZi7N .section3{fill:#fff;opacity:0.2}#mermaid-svg-Ejt8czwiQqwsZi7N .sectionTitle0{fill:#333}#mermaid-svg-Ejt8czwiQqwsZi7N .sectionTitle1{fill:#333}#mermaid-svg-Ejt8czwiQqwsZi7N .sectionTitle2{fill:#333}#mermaid-svg-Ejt8czwiQqwsZi7N .sectionTitle3{fill:#333}#mermaid-svg-Ejt8czwiQqwsZi7N .sectionTitle{text-anchor:start;font-size:11px;text-height:14px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-Ejt8czwiQqwsZi7N .grid .tick{stroke:#d3d3d3;opacity:0.8;shape-rendering:crispEdges}#mermaid-svg-Ejt8czwiQqwsZi7N .grid .tick text{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-Ejt8czwiQqwsZi7N .grid path{stroke-width:0}#mermaid-svg-Ejt8czwiQqwsZi7N .today{fill:none;stroke:red;stroke-width:2px}#mermaid-svg-Ejt8czwiQqwsZi7N .task{stroke-width:2}#mermaid-svg-Ejt8czwiQqwsZi7N .taskText{text-anchor:middle;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-Ejt8czwiQqwsZi7N .taskText:not([font-size]){font-size:11px}#mermaid-svg-Ejt8czwiQqwsZi7N .taskTextOutsideRight{fill:#000;text-anchor:start;font-size:11px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-Ejt8czwiQqwsZi7N .taskTextOutsideLeft{fill:#000;text-anchor:end;font-size:11px}#mermaid-svg-Ejt8czwiQqwsZi7N .task.clickable{cursor:pointer}#mermaid-svg-Ejt8czwiQqwsZi7N .taskText.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-Ejt8czwiQqwsZi7N .taskTextOutsideLeft.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-Ejt8czwiQqwsZi7N .taskTextOutsideRight.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-Ejt8czwiQqwsZi7N .taskText0,#mermaid-svg-Ejt8czwiQqwsZi7N .taskText1,#mermaid-svg-Ejt8czwiQqwsZi7N .taskText2,#mermaid-svg-Ejt8czwiQqwsZi7N .taskText3{fill:#fff}#mermaid-svg-Ejt8czwiQqwsZi7N .task0,#mermaid-svg-Ejt8czwiQqwsZi7N .task1,#mermaid-svg-Ejt8czwiQqwsZi7N .task2,#mermaid-svg-Ejt8czwiQqwsZi7N .task3{fill:#8a90dd;stroke:#534fbc}#mermaid-svg-Ejt8czwiQqwsZi7N .taskTextOutside0,#mermaid-svg-Ejt8czwiQqwsZi7N .taskTextOutside2{fill:#000}#mermaid-svg-Ejt8czwiQqwsZi7N .taskTextOutside1,#mermaid-svg-Ejt8czwiQqwsZi7N .taskTextOutside3{fill:#000}#mermaid-svg-Ejt8czwiQqwsZi7N .active0,#mermaid-svg-Ejt8czwiQqwsZi7N .active1,#mermaid-svg-Ejt8czwiQqwsZi7N .active2,#mermaid-svg-Ejt8czwiQqwsZi7N .active3{fill:#bfc7ff;stroke:#534fbc}#mermaid-svg-Ejt8czwiQqwsZi7N .activeText0,#mermaid-svg-Ejt8czwiQqwsZi7N .activeText1,#mermaid-svg-Ejt8czwiQqwsZi7N .activeText2,#mermaid-svg-Ejt8czwiQqwsZi7N .activeText3{fill:#000 !important}#mermaid-svg-Ejt8czwiQqwsZi7N .done0,#mermaid-svg-Ejt8czwiQqwsZi7N .done1,#mermaid-svg-Ejt8czwiQqwsZi7N .done2,#mermaid-svg-Ejt8czwiQqwsZi7N .done3{stroke:grey;fill:#d3d3d3;stroke-width:2}#mermaid-svg-Ejt8czwiQqwsZi7N .doneText0,#mermaid-svg-Ejt8czwiQqwsZi7N .doneText1,#mermaid-svg-Ejt8czwiQqwsZi7N .doneText2,#mermaid-svg-Ejt8czwiQqwsZi7N .doneText3{fill:#000 !important}#mermaid-svg-Ejt8czwiQqwsZi7N .crit0,#mermaid-svg-Ejt8czwiQqwsZi7N .crit1,#mermaid-svg-Ejt8czwiQqwsZi7N .crit2,#mermaid-svg-Ejt8czwiQqwsZi7N .crit3{stroke:#f88;fill:red;stroke-width:2}#mermaid-svg-Ejt8czwiQqwsZi7N .activeCrit0,#mermaid-svg-Ejt8czwiQqwsZi7N .activeCrit1,#mermaid-svg-Ejt8czwiQqwsZi7N .activeCrit2,#mermaid-svg-Ejt8czwiQqwsZi7N .activeCrit3{stroke:#f88;fill:#bfc7ff;stroke-width:2}#mermaid-svg-Ejt8czwiQqwsZi7N .doneCrit0,#mermaid-svg-Ejt8czwiQqwsZi7N .doneCrit1,#mermaid-svg-Ejt8czwiQqwsZi7N .doneCrit2,#mermaid-svg-Ejt8czwiQqwsZi7N .doneCrit3{stroke:#f88;fill:#d3d3d3;stroke-width:2;cursor:pointer;shape-rendering:crispEdges}#mermaid-svg-Ejt8czwiQqwsZi7N .milestone{transform:rotate(45deg) scale(0.8, 0.8)}#mermaid-svg-Ejt8czwiQqwsZi7N .milestoneText{font-style:italic}#mermaid-svg-Ejt8czwiQqwsZi7N .doneCritText0,#mermaid-svg-Ejt8czwiQqwsZi7N .doneCritText1,#mermaid-svg-Ejt8czwiQqwsZi7N .doneCritText2,#mermaid-svg-Ejt8czwiQqwsZi7N .doneCritText3{fill:#000 !important}#mermaid-svg-Ejt8czwiQqwsZi7N .activeCritText0,#mermaid-svg-Ejt8czwiQqwsZi7N .activeCritText1,#mermaid-svg-Ejt8czwiQqwsZi7N .activeCritText2,#mermaid-svg-Ejt8czwiQqwsZi7N .activeCritText3{fill:#000 !important}#mermaid-svg-Ejt8czwiQqwsZi7N .titleText{text-anchor:middle;font-size:18px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-Ejt8czwiQqwsZi7N g.classGroup text{fill:#9370db;stroke:none;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:10px}#mermaid-svg-Ejt8czwiQqwsZi7N g.classGroup text .title{font-weight:bolder}#mermaid-svg-Ejt8czwiQqwsZi7N g.clickable{cursor:pointer}#mermaid-svg-Ejt8czwiQqwsZi7N g.classGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-Ejt8czwiQqwsZi7N g.classGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-Ejt8czwiQqwsZi7N .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5}#mermaid-svg-Ejt8czwiQqwsZi7N .classLabel .label{fill:#9370db;font-size:10px}#mermaid-svg-Ejt8czwiQqwsZi7N .relation{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-Ejt8czwiQqwsZi7N .dashed-line{stroke-dasharray:3}#mermaid-svg-Ejt8czwiQqwsZi7N #compositionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-Ejt8czwiQqwsZi7N #compositionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-Ejt8czwiQqwsZi7N #aggregationStart{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-Ejt8czwiQqwsZi7N #aggregationEnd{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-Ejt8czwiQqwsZi7N #dependencyStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-Ejt8czwiQqwsZi7N #dependencyEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-Ejt8czwiQqwsZi7N #extensionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-Ejt8czwiQqwsZi7N #extensionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-Ejt8czwiQqwsZi7N .commit-id,#mermaid-svg-Ejt8czwiQqwsZi7N .commit-msg,#mermaid-svg-Ejt8czwiQqwsZi7N .branch-label{fill:lightgrey;color:lightgrey;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-Ejt8czwiQqwsZi7N .pieTitleText{text-anchor:middle;font-size:25px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-Ejt8czwiQqwsZi7N .slice{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-Ejt8czwiQqwsZi7N g.stateGroup text{fill:#9370db;stroke:none;font-size:10px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-Ejt8czwiQqwsZi7N g.stateGroup text{fill:#9370db;fill:#333;stroke:none;font-size:10px}#mermaid-svg-Ejt8czwiQqwsZi7N g.statediagram-cluster .cluster-label text{fill:#333}#mermaid-svg-Ejt8czwiQqwsZi7N g.stateGroup .state-title{font-weight:bolder;fill:#000}#mermaid-svg-Ejt8czwiQqwsZi7N g.stateGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-Ejt8czwiQqwsZi7N g.stateGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-Ejt8czwiQqwsZi7N .transition{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-Ejt8czwiQqwsZi7N .stateGroup .composit{fill:white;border-bottom:1px}#mermaid-svg-Ejt8czwiQqwsZi7N .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px}#mermaid-svg-Ejt8czwiQqwsZi7N .state-note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-Ejt8czwiQqwsZi7N .state-note text{fill:black;stroke:none;font-size:10px}#mermaid-svg-Ejt8czwiQqwsZi7N .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.7}#mermaid-svg-Ejt8czwiQqwsZi7N .edgeLabel text{fill:#333}#mermaid-svg-Ejt8czwiQqwsZi7N .stateLabel text{fill:#000;font-size:10px;font-weight:bold;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-Ejt8czwiQqwsZi7N .node circle.state-start{fill:black;stroke:black}#mermaid-svg-Ejt8czwiQqwsZi7N .node circle.state-end{fill:black;stroke:white;stroke-width:1.5}#mermaid-svg-Ejt8czwiQqwsZi7N #statediagram-barbEnd{fill:#9370db}#mermaid-svg-Ejt8czwiQqwsZi7N .statediagram-cluster rect{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-Ejt8czwiQqwsZi7N .statediagram-cluster rect.outer{rx:5px;ry:5px}#mermaid-svg-Ejt8czwiQqwsZi7N .statediagram-state .divider{stroke:#9370db}#mermaid-svg-Ejt8czwiQqwsZi7N .statediagram-state .title-state{rx:5px;ry:5px}#mermaid-svg-Ejt8czwiQqwsZi7N .statediagram-cluster.statediagram-cluster .inner{fill:white}#mermaid-svg-Ejt8czwiQqwsZi7N .statediagram-cluster.statediagram-cluster-alt .inner{fill:#e0e0e0}#mermaid-svg-Ejt8czwiQqwsZi7N .statediagram-cluster .inner{rx:0;ry:0}#mermaid-svg-Ejt8czwiQqwsZi7N .statediagram-state rect.basic{rx:5px;ry:5px}#mermaid-svg-Ejt8czwiQqwsZi7N .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#efefef}#mermaid-svg-Ejt8czwiQqwsZi7N .note-edge{stroke-dasharray:5}#mermaid-svg-Ejt8czwiQqwsZi7N .statediagram-note rect{fill:#fff5ad;stroke:#aa3;stroke-width:1px;rx:0;ry:0}:root{--mermaid-font-family: '"trebuchet ms", verdana, arial';--mermaid-font-family: "Comic Sans MS", "Comic Sans", cursive}#mermaid-svg-Ejt8czwiQqwsZi7N .error-icon{fill:#522}#mermaid-svg-Ejt8czwiQqwsZi7N .error-text{fill:#522;stroke:#522}#mermaid-svg-Ejt8czwiQqwsZi7N .edge-thickness-normal{stroke-width:2px}#mermaid-svg-Ejt8czwiQqwsZi7N .edge-thickness-thick{stroke-width:3.5px}#mermaid-svg-Ejt8czwiQqwsZi7N .edge-pattern-solid{stroke-dasharray:0}#mermaid-svg-Ejt8czwiQqwsZi7N .edge-pattern-dashed{stroke-dasharray:3}#mermaid-svg-Ejt8czwiQqwsZi7N .edge-pattern-dotted{stroke-dasharray:2}#mermaid-svg-Ejt8czwiQqwsZi7N .marker{fill:#333}#mermaid-svg-Ejt8czwiQqwsZi7N .marker.cross{stroke:#333}

:root { --mermaid-font-family: "trebuchet ms", verdana, arial;}
#mermaid-svg-Ejt8czwiQqwsZi7N {
color: rgba(0, 0, 0, 0.75);
font: ;
}

initialize
long ENTER
long ESC
power on
Menu:R
Menu:M
Menu:1.Font

1.Font12

2.Font16

3.Font24
Menu:2.Color

1.Red

2.Green

3.Yellow

4.Blue

5.Pink

6.Cyan

7.White

8.Auto
Menu:3.Lang

1.EN

2.CN
Menu:4.Freq

1.D_freq

2.S_peri
Menu:1.1.FONT12

1.SEL. *

2.UPG. *

3.EAU. !
Menu:1.1.Dis_Freq

60Hz
Menu:1.2.Shi_Peri

100ms

系统上电初始化后,Led点阵板将按照设置的模式和参数,滚动显示保存的文本字符。长按按键[确认],系统将从显示模式(Menu:R)切换到设置模式(Menu:M)。进入设置模式(Menu:M)后,通过按键[上翻]、[下翻]选择对应设置项。

Menu:1.Font设置显示模式的字体,目前可选择宋体12号、16号、24号。进入子菜单后,"1.SEL"选中当前字体,"2.UPG"准备写入字体,"3.EAU"擦除当前字体。目前字库是通过UART串口通讯方式传输至Flash的。

Menu:2.Color设置显示字体的颜色,目前可选择红、绿、黄、蓝、紫、青、白和7色循环显示。进入此菜单后,选中颜色并[确认]后,字体的颜色被切换并保存。

Menu:3.Lang设置菜单显示的语言,目前可选择英文、中文2种语言显示。

Menu:4.Freq设置滚动显示的频率。进入子菜单后,"1.D_freq"可设置Led Matrix Panel的扫描频率即帧速率,"2.S_peri"可设置Led Matrix Panel的滚动字幕显示速率( :ms/pixel)。

3.4. 通讯协议格式

Led Matrix点阵控制器可通过板载UART串口,实现系统参数、字库数据的传输和菜单的显示控制。
数据帧格式如下:

在这里插入图片描述

已实现和可扩展的通讯协议:

目标地址 功能码 帧索引 数据长度 数据域 帧校验 描述
0x01 0x00 (reserved)
0x01 0x01 N 字库数据包 字库数据传输
0x01 0x02 0x01 按键键值 远程控制菜单[上翻]、[下翻]、[确认]、[取消]
0x01 0x03 0x01 系统参数 修改并保存系统参数#1
0x01 0x04 0x01 系统参数 修改并保存系统参数#2
0x01 0x05 0x01 系统参数 修改并保存系统参数#3
0x01 0x06 0x01 系统参数 修改并保存系统参数#4
0x01 0x07 0x01 系统参数 修改并保存系统参数#5
0x01 0x08 0x01 系统参数 修改并保存系统参数#6
0x01 0x09 0x01 系统参数 修改并保存系统参数#7
0x01 0x0A 0x01 系统参数 修改并保存系统参数#8
0x01 0x0B 0x01 系统参数 修改并保存系统参数#9
0x01 0x10 N 滚动字符串 修改并保存滚动字幕行#1
0x01 0x11 N 滚动字符串 修改并保存滚动字幕行#2
0x01 0x12 N 滚动字符串 修改并保存滚动字幕行#3
0x01 0x13 N 滚动字符串 修改并保存滚动字幕行#4
0x01 0x14 N 滚动字符串 修改并保存滚动字幕行#5

推荐使用Ymodem协议进行文件传输,一次可传输1024字节的信息块,是一种可错误纠正、高效稳定的文件传输协议。

4. 结语

经历很多周末时间,终于将Led Matrix点阵控制器设计并制作完成,希望能给更多电子爱好者参考借鉴。本项目中还有更多优化空间:如选用更高时钟频率的MCU、高效的Ymodem协议,实时全彩动画显示等。但由于我时间所限,这些就交由您来完成吧!

最后附上TinyMatrix点阵控制器调试效果:

在这里插入图片描述

本项目设计资料已推送至 github,希望收到你的pull request。关注公众号,获取设计资料!

— END —

参考文章:
1.Everything You Didn’t Want to Know About RGB Matrix Panels
2.Adafruit RGB Matrix + Real Time Clock HAT for Raspberry Pi
3.github.com/hzeller/rpi-rgb-led-matrix
4.stm32f103-bootloader-and-programming

在这里插入图片描述

版权声明:本文为CSDN博主「槿良」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/sparkjl/article/details/121590831

生成海报
点赞 0

槿良

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

STM32学习笔记

适逢寒假,终于可以开始学习期待已久的STM32啦!其实十年前就有身边的同学在学习了,只不过我一直停留在89C51,一直没机会学习STM32。以前在公司做Linux嵌入式,其实

串口不定长接收

一、保留接收区和开启接收的语句    uint8_t buffer[5];HAL_UART_Transmit_IT(&huart1,buffer,3); 二、写入开启空闲中断的语句    __HAL_UART_ENABLE_IT(&huart