亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

适用于 WS2812 RGB LED 阵列动画的 Excel

组件和用品

Arduino UNO
× 1
ws2812 8x8 RGB LED 矩阵
× 1
公/母跳线
我的三个是 Black-Gnd、Red-5v 和 Green-Data
× 3
9V 电池(通用)
× 1
9V to Barrel Jack Connector
× 1
Male-Header 5 Position- 1 Row- Long (0.1" )
只需要三个图钉
× 1

必要的工具和机器

烙铁(通用)
焊锡丝,无铅

关于这个项目

检查是否有在线支持后,我订购了一个 WS2812 8x8 RGB LED 矩阵,希望它可以作为 XY 坐标结构进行寻址,而不是 64 个 LED 的菊花链(带)包裹成 8 行,每行 8 行!

“WS2812 Led 动画”搜索结果很少,我可以立即轻松理解。当我发现由 Kevin Darrah 制作的 YouTube 视频时,他正在处理一个 16 x 16 矩阵(256 个 LED 菊花链),好像它是一个 XY 坐标系。

他的 Excel 实用程序编译了用于复制/粘贴到他的草图中的文本代码,其中包含所有必要的功能;无需导入库。

当他在他的效用范围内选择单元格并添加 RGB 值时,它们会毫无区别地应用于那些选定的单元格;不是我想要的,所以我重新设计并重建了它。这也意味着我不得不修改他的草图以兼容 8x8。

随着我对 WS2812 的要求越来越高,我不得不不断修改我的 Excel 应用程序 LED_Utility.xlsm。

Excel 工作簿现在提供:

  • 要单独处理的 LED RGB 属性。
  • 通过编程动态改变这些属性。
  • 这些属性的 XY 重定位以模拟运动。
  • 要处理的 RGB 值以及更改 XY 位置。
  • 8x8 和 16x16 LED 寻址。
  • 用于快速参考的一小部分 RGB 值集合。

具体来说,我的目标是:

  • 开发一个红色的空心方块并打开和关闭它。
  • 用不同颜色的图层覆盖另一个正方形并在它们之间交替。
  • 种植红色方块并使用它。
  • 考虑使用函数来保存显示元素;我将建立一个逐渐消失的螺旋。
  • 创建一个颜色淡入淡出的设计。
  • 在设计中加入动感。
  • 寻址 16x16 数组。

我确实认识到编程知识会产生问题。我提供了一些指导,但建议进行研究或询问可能会亲自为您提供建议的人。

开始

组装硬件

如果您的矩阵没有排针,则将排针排焊接到矩阵背面较低位置(DIN、+5V、GND)。将 DIN 引脚连接到 Arduino 右侧的引脚 8,将另外两个连接到电路板另一侧的匹配位置。

对于此板和实用程序,XY (0, 0) 是左上角。

Excel 实用程序

打开 LED_Utility.xlsm 文件。您将看到三个工作表,“八”、“十六”和“ColMap”。

最后是一小部分 RGB 代码示例,供参考。

我已将 LED_Utility.xlsm 设置为只读以防止覆盖,同时也鼓励使用“另存为”来保留文件以供可能的重用。还内置了其他一些“错误陷阱”。

选择“八”工作表。

请注意,右侧网格填充了零。这很重要,因为草图不接受“空”值。

如上所示,有四个按钮(在“十六”上,它们可能会在屏幕右侧,一个在另一个下方,但功能如下所述)。

生成文本代码:

“显示”在左侧网格中显示值的 RGB。它只处理 0-255 之间的值。它将提醒高于 255 的值或任何变量。

“Var Map”接受数字和变量但不提供显示。

“Wrap Map”是两层的。它接受通常为“显示”显示输入的 RGB 值。然后它为草图编码添加一个模函数,以允许矩阵溢出。其次,可以添加变量,但必须稍后在草图中编程。我不是在这里解决这个问题。

每个都在网格下方(在两个工作表中)生成与设计为接受它的草图兼容的“红色”文本。

“清除”显然使两个网格都无效。

这些都将在后面描述。

当您使用 Excel 实用程序,我建议您在使用后使用 File/SaveAs... 生成您的代码,这样您就不必在某些时候重新创建您的设计 另外一点,特别是如果设计相当复杂。另外,您的 原始 LED_Utility.xlsm 已设置为只读以防止其被破坏 被覆盖。

草图

提供代码 下方 注意事项 使用只读属性保存。

打开 Arduino IDE 并加载“LED_Arduino.ino”草图。

你会看到:

  • 第 3 行定义了正在使用的 Arduino 引脚。此设置为 Pin 8。
  • 第 4 行定义了板上的 LED 单元。这些是 64。
  • 然而,第 5 行将该数字乘以 3 以考虑 RBG 计数,即 192。
  • 第 8、10 和 25 行定义了正在使用的函数。

在第 3 行和第 19 行之间,原始文本已更改,但您可以编辑以寻址 16x16 矩阵。也就是说,我在软件中提供了 LED_Ardino16.ino 并且 LED_Utility.xlsm 将容纳它。

我经常会建议你打开“LED_Arduino.ino”,然后用一些名字“另存为”。如果您没有将适当的属性设置为“只读”,这将确保“LED_Arduino.ino”不变。 [我发现我新创建的文件仍然设置了只读属性;发布以确保未来的编辑和保存]。

同时,新创建的草图可能需要重新定义端口和电路板中的一个或两个;会出现错误消息,但可能不会立即清除。

项目 1

将 LED_Arduino.ino 加载到 Arduino IDE 中并保存为 Red_Square(ino 会自动添加)。

最初我提议建立一个 3x3 红色方块 并将该代码放在草图的第 40 行。单元格 N8、O8、P8、N11、P11、N14、O14 和 P14 将保持 255 的值。

当 LED_Utility 红色文字时,

mapLEDXY(2,2,255,0,0);mapLEDXY(2,3,255,0,0);mapLEDXY(2,4,255,0,0);mapLEDXY(3,2,255,0,0); mapLEDXY(3,4,255,0,0);mapLEDXY(4,2,255,0,0);mapLEDXY(4,3,255,0,0);mapLEDXY(4,4,255,0,0); 

复制到第40行,下面的文字自然会下移。

当您将草图上传到 Arduino 时,您的矩阵将打开和关闭该方块。

在继续之前,您需要考虑:

  • 清除两个网格。
  • 更改该方块内的一些颜色。
  • 在原件周围添加一个不同颜色的正方形。

项目2

建议您打开草图Red_Square.ino 并保存为Colour_Sq('.ino' 会自动添加)以防止覆盖Red_Square.ino。

将 Colour_Sq.ino 加载到 IDE 中后,转到实用程序中的 Red_Square 并修改中间方块。 MakeO8、O10、O14 和 O16 ‘255’。 N11 和 P11 为“0”,但 N12 和 P12 为“255”。按“显示”。

添加新代码后,我预计 IDE 中的第 47 行,您需要使用以下代码块:

RGB_update(-1, 0, 0, 0);delay(1000);clearLEDs();RGB_update(-1, 0, 0, 0);延迟(1000); 

请注意,您可以更改延迟值以适合自己; 1000 等于 1 秒。

项目3

重新加载 Red_Square.ino 并将其另存为 Grow。

在实用程序中重新创建红色方块。在该方块周围添加您选择的值以创建边框,它们可以是 0 到 255 之间的任何值,但低于 32 可能会非常暗淡。这是我在“LED_Utility.xlsm”中的创作:

现在删除那个内部红色方块的值,然后按“显示”。将生成的代码复制到 IDE 中的第 47 行,然后复制/粘贴第 42 至 46 行。上传到 Arduino 以交替使用一个内部红色方块,然后一个被各种颜色包围的方块。

如果您愿意,请尝试扩展到另一个边界。

项目4

您可能已经意识到,当我们将代码添加到“循环”中时,它会变得冗长,并且可能会导致以后难以编辑。

在这里,我正在构建一个螺旋。

图片来自工作簿“spir5.xlsm”。这是 4 个早期工作簿的高潮。

“spir1.xlsm”是中心有明亮的(255)块,“spir2.xlsm”使用内部4x4方块的值,“spir3.xlsm”是27个方块,等等。在每个阶段我复制了代码到我的草图但不是“循环”。

相反,我在“loop”下面创建了 5 个 void 函数并在“loop”中引用它们:

Void loop(){Sp1();Sp2();Sp3();Sp4();Sp5();clearLEDs();delay(1000);} 

我的第一个函数 void Sp1() 是:

 void Sp1(){mapLEDXY(3,3,255,0,0);mapLEDXY(3,4,255,0,0);mapLEDXY(4,3,255,0,0);mapLEDXY(4,4,255, 0,0);RGB_update(-1, 0, 0, 0);delay(100);clearLEDs();RGB_update(-1, 0, 0, 0);delay(10);} 

除了“mapLEDXY…”的两行外,每个连续的函数都是相同的。

从这个例子来看,建议打开“spir4.xlsm”来编辑外部提示的颜色来编辑专用函数而不是在“循环”内编辑似乎微不足道。

与荒谬的接壤,假设您想一次一个地连续显示单词“MISSISSIPPI”的字母。有 11 个字符,这意味着要处理 77 行代码来处理“void loop()”。如果您决定更改“S”,则必须进行 4 次编辑。这个词只使用了4个字符。因此,为它们中的每一个创建一个函数并从“循环”中适当地调用它们是有意义的。

项目5

该项目考虑了 LED_Utility 的另一个功能“Var Map”。这里将介绍变量,因此需要一些基本的编程知识。

将使用“For 循环”语法以及“If”条件。

“for”将用于增加或减少 RGB 值,例如:

for (int r=0; r<=256; r++) {} orfor (int r=255; r>=0; r--) {}  

“如果”将根据需要修改程序。

让我们从简单开始,我的意思是简单。

在 LED_utility 和“Show”中间创建一个 2x2 的红色方块,代码如下:

mapLEDXY(3,3,255,0,0);mapLEDXY(3,4,255,0,0);mapLEDXY(4,3,255,0,0);mapLEDXY(4,4,255,0,0);  

现在将所有 255 个值更改为“r”。按“显示”...。哎哟!它不喜欢那样。没关系,是我加的保护。按“Var Map”并检查生成的代码:

mapLEDXY(3,3,r,0,0);mapLEDXY(3,4,r,0,0);mapLEDXY(4,3,r,0,0);mapLEDXY(4,4) ,r,0,0); 

255 已被替换为“r”。

在 IDE 中打开存档的 LED_Arduino.ino 并将其保存为“更改”。

在第 40 行输入:

for (int r=0; r<256;r++){}/// 后跟:for (int r=255;r>=0;r--){}  

请注意,每个“for”语句后都有一个空行。

在第 41 行粘贴您的 Excel 代码:

mapLEDXY(3,3,r,0,0);mapLEDXY(3,4,r,0,0);mapLEDXY(4,3,r,0,0);mapLEDXY(4,4) ,r,0,0);接着是:RGB_update(-1, 0, 0, 0);delay(50); 

现在将相同的 4 行代码块复制/粘贴到第二个“for”块中。

在“for”块之后,在“}”下面添加“delay(200);”。我发现有必要让我的眼睛知道第二个街区已经关闭!

上传后,红色块增加到全亮度然后减小,关闭然后重复。

项目6

现在让我们利用“If”条件。

在 LED_utility 中重新创建之前的红色方块,但使用 255 的 G 和 B 值用“天蓝色”块围绕它。使用“显示”。

保留红色 255,但将所有 G 255 更改为“g”,将 B 255 更改为“b”,

然后按“Var Map”。

将“LED_Arduino.ino”重新加载到IDE并另存为“FadeBorder”。

现在我们将遇到一些问题。我们有两个变量,'g' 和 'b',每个变量都必须被赋予一个值。它们也必须在程序中声明。我打算在“for”语句中声明“g”,但我需要在草图中更早地声明“b”。在第 5 行的草图中是声明 BYTE RGB[192]。在下面输入‘int b=0;’。

作为解释的一点,不能使用两个“for”循环,稍后将需要。这里每个‘b’值必须与“for”循环生成的‘g’值相同。

我的“循环”结构如下,但没有我的地图代码:

void loop() {delay(50);for (int g=0; g<256;g++){b=g;[在此添加地图代码]RGB_update(-1, 0, 0, 0 );延迟(50);}for (int g=255;g>=0;g--){b=g; [此处添加地图代码]RGB_update(-1, 0, 0, 0);delay(50);}} 

请注意,B 值通过语句“b=g;”链接到 G 值。 R值保持不变,为255,而边框的亮度逐渐变淡。

项目7

现在是使用“if”语句的时候了。

使用 255 变量创建并“显示”以下内容,其中变量出现在右侧网格中。请注意,与红色单元格相邻的单元格中出现了一个很小的“L”。这将允许程序在适当的时候控制这些单元格。

这一次 LED 将逐渐变为绿色和红色,直到达到 64 值,然后这些中间边界单元将随着电路板的亮度继续增加而变为黄色。然后这个过程将反过来。

我将再次提供我的“循环”的基本结构。我将此草图称为“FadeColourChange.ino”。

void loop() { delay(50);for (int r=0; r<256;r++){g=r;if(g>64){ g=65; l=r;}[此处添加地图代码]RGB_update(-1, 0, 0, 0);延迟(50);}对于(int r=255;r>=0;r--){if(r<65){g=r; l=0;}[此处添加MapCode]RGB_update(-1, 0, 0, 0);delay(50);}} 

项目8

对于最后一个项目,我不会改变颜色而是引入运动;我有一个箭头,它可以在棋盘上移动,但会从左侧重新出现。

这里我只想用“Show”生成代码。

由于我希望箭头从其当前位置移动到每个下一个位置,因此我需要更改“x”值。

这是在 G29:G33 生成的代码:

mapLEDXY(0,3,0,255,255);mapLEDXY(1,1,255,128,128);mapLEDXY(1,3,0,255,255);mapLEDXY(1,5,255,128,128);mapLEDXY(2,2,832155) ,0,255,255);mapLEDXY(2,4,255,128,128);mapLEDXY(3,3,255,128,128); 

由于“1”是我对 X 坐标的最小值,因此我将其称为“x”并将所有其他值减 1。

mapLEDXY(x+0,3,0,255,255);mapLEDXY(x+1,255,128,128);mapLEDXY(x+1,3,0,255,255);mapLEDXY(x+1,5,255,128,128);mapLEDXY(x+1,3,0,255,128);mapLEDXY(x 2,255,128,128);mapLEDXY(x+2,3,0,255,255);mapLEDXY(x+2,4,255,128,128);mapLEDXY(x+3,3,255,128,128); 

我的 ‘for (int x...loop’ 做得很好,除了箭头溢出到下一行循环几次!

解决方案! 如果一个值超过“8”,我需要它的模值。这迫使我创建“Wrap Map”按钮。一个 LED 的代码现在显示为:

mapLEDXY((x +1) % 8, (y +1) %8, 255, 128, 128);

为了解决 XY 布局,我觉得最好嵌套两个“for”循环,即使一个不会被使用(是的,我找到了一个尴尬的替代方案)。

for(int x=0;x<8;x++){for(int y=0;y<8;y++){[mapcode]}} 

如果我在第二个循环中设置“y<1”,则忽略“y”。相反,将“y”更改为 8,将“x”更改为 0 会产生不同的效果。

最后,“Wrap Map”将接受 RGB 变量。见上面我引用的地方。具有基本编程的人应该能够处理这个问题。我添加了一个 INO 草图,ArrowVar.ino,作为一个小演示,箭头前面的亮度会发生变化。

16x16 矩阵使用。

上面提到的所有内容都适用于 16x16 WS2812 矩阵。但是必须使用“LED_Arduino16.ino”草图。

提供的草图是为 8x8 矩阵设计的,除了“Spiral16.ino”。它提供比“Spiral.ino”更大的显示。

这个螺旋形 16x16 矩阵有 2 张打印纸作为光漫射器。显示暂停了大约 10 秒以捕获合理的图像。

要开发您的代码,请打开 LED_Utility.xlsm 并选择页面底部的“十六”选项卡。

如果和我一样,你的显示器太大而你需要滚动,那么使用缩小选项。即便如此,也需要进行一些滚动才能复制您的代码。

扩展?

是否可以处理其他大小的矩阵?

我想知道为什么我的“LED_Arduino.ino”和“LED_Arduino16.ino”的开场白如此不同。我在第一行注释掉了某些行;两个草图都按我的意愿工作。

即使我刚刚获得了一块电路板,我也不打算为“8x32”编写工作表。我会引导你到“草图 “ 多于。有一些参数需要处理。也要特别注意第 15 行和第 18 行。

注意:我也在考虑比 UNO 类型板更小的选项。

代码

  • LED_Arduino
LED_ArduinoC/C++
该草图构成了项目的基础。保存时应将其设置为只读,进一步使用时应设为“另存为”以进行存档以防止覆盖并允许轻松重新编辑。
//此处的变量和定义 - WS2812 驱动程序代码需要#define WS2812_pin 8 // 现在只有数字引脚 8 可以工作#define numberOfLEDs 64// RGB LED 的总数 [256]byte RGB[192];//将 LED 的数量乘以 3 [768]// FUNCTIONS HEREvoid RGB_update(int LED, byte RED, byte GREEN, byte BLUE);//驱动LED的函数void mapLEDXY(int x, int y, byte RED, byte GREEN, byte BLUE) { int RGBlocation =0; //if (y % 2 ==0) { //偶数列[取消注释] RGBlocation =x + y * 8; //[16] // } else { //奇数列[取消注释] //RGBlocation =7 - x + y * 8; //[15] 和 [16] // } [取消注释] RGB[RGBlocation * 3] =BLUE; RGB[RGBlocation * 3 + 1] =红色; RGB[RGBlocation * 3 + 2] =GREEN;}void clearLEDs() { memset(RGB, 0, sizeof(RGB));}void setup() { pinMode(WS2812_pin, OUTPUT); clearLEDs(); RGB_update(-1, 0, 0, 0);}//setup0void loop() {//在下面RGB_update的正上方粘贴mapLEDXY线。RGB_update(-1, 0, 0, 0);延迟(1000); clearLEDs(); RGB_update(-1, 0, 0, 0); delay(1000);}//loop//WS2812 Driver Functionvoid RGB_update(int LED, byte RED, byte GREEN, byte BLUE) { // LED 是从 0 开始的 LED 编号 // RED, GREEN, BLUE 是亮度 0 ..255 该 LED 字节的设定点 ExistingPort, WS2812pinHIGH;//此处的局部变量以加快 pinWrites if (LED>=0) { //将 REG GREEN BLUE 值映射到 RGB[] 数组 RGB[LED * 3] =绿色; RGB[LED * 3 + 1] =红色; RGB[LED * 3 + 2] =蓝色; } noInterrupts();//在我们发送比特流的同时终止中断... ExistingPort =PORTB; // 保存整个 PORT B 的状态 - 让我们写入整个端口而不弄乱该端口上的其他引脚 WS2812pinHIGH =PORTB | 1; //这给了我们一个字节,我们可以用 WS2812 引脚设置整个 PORTB 高 int bitStream =numberOfLEDs * 3;//LED 串中的总字节数 //这个 for 循环遍历所有位(8 位)时间)设置 WS2812 引脚 ON/OFF 时间(int i =bitStream - 1; i>=0; i--){ PORTB =WS2812pinHIGH;//第 7 位,将引脚设置为高电平 - 不管0/1 //这里是棘手的部分,检查字节中的位是否为高/低,然后将该状态正确设置为引脚 // (RGB[i] &B10000000) 将去除 R​​GB[i 中的其他位],所以这里我们将剩下 B10000000 或 B00000000 // 然后很容易检查该位是高还是低,方法是使用位掩码 ""&&B10000000)"" 对它进行 AND 运算,结果为 1 或 0 //如果它是 1,我们将它与现有端口进行或运算,从而保持引脚为高电平,如果为 0,则引脚写入低电平 PORTB =((RGB[i] &B10000000) &&B10000000) |现有端口; __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");//这些是NOPS - 这些让我们延迟时钟周期更精确的计时 PORTB =ExistingPort;//好吧,这里我们知道无论 0/1 位状态如何 __asm__("nop\n\t""nop\n\t""nop\n\ t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");//不管0/1位状态如何,引脚的最小低电平时间//然后做再次为下一位,依此类推...看到最后一位虽然略有变化 PORTB =WS2812pinHIGH;//bit 6 PORTB =((RGB[i] &B01000000) &&B01000000) |现有端口; __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); PORTB =现有端口; __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t "); PORTB =WS2812pinHIGH;//bit 5 PORTB =((RGB[i] &B00100000) &&B00100000) |现有端口; __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); PORTB =现有端口; __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t "); PORTB =WS2812pinHIGH;//bit 4 PORTB =((RGB[i] &B00010000) &&B00010000) |现有端口; __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); PORTB =现有端口; __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t "); PORTB =WS2812pinHIGH;//bit 3 PORTB =((RGB[i] &B00001000) &&B00001000) |现有端口; __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); PORTB =现有端口; __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t "); PORTB =WS2812pinHIGH;//bit 2 PORTB =((RGB[i] &B00000100) &&B00000100) |现有端口; __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); PORTB =现有端口; __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t "); PORTB =WS2812pinHIGH;//bit 1 PORTB =((RGB[i] &B00000010) &&B00000010) |现有端口; __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); PORTB =现有端口; __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t "); PORTB =WS2812pinHIGH;//bit 0 __asm__("nop\n\t");//在最后一个位上,检查要快得多,所以不得不在这里添加一个NOP PORTB =((RGB[i] &B00000001) &&B00000001) |现有端口; __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); PORTB =ExistingPort;//注意在将引脚写为低电平后没有 NOP,这是因为 FOR 循环使用我们可以使用的时钟周期来代替 NOPS }//for loop interrupts();//启用中断 //全部完成!}//void RGB_update
Led_Utility.xlsm
此应用程序生成用于复制/粘贴到草图中的各种文本。https://github.com/CobraCat/LED_Utility
草图.zip
这些是开发过程中使用的一些或更多草图。它们可作为“支持”使用。https://github.com/CobraCat/LED_Utility

制造工艺

  1. 带有 Arduino 的用于飞行模拟器的 LCD 面板
  2. 用于 FS2020 的带有 Arduino 的开关/LED 面板
  3. 适用于 WS2812 RGB LED 阵列动画的 Excel
  4. 全球物联网安全的三个步骤
  5. 2020 年的三大数字化制造趋势
  6. 中小企业向海外扩张的三个秘诀
  7. 给零售商带来颠覆一年的三个教训
  8. 建立一个走开!机器人 - 儿童简易入门项目
  9. 4x3 键盘只有三个引脚
  10. 用于控制 RGB 灯的 TinyML 关键字检测
  11. 工业设备维护三招
  12. 购买重型工业设备的三个技巧