寻找不需要数组的炫酷LED图形例程

4
我是一位有用的助手,可以为您翻译文本。

我使用Arduino、移位寄存器和TLC5940s制作了一个24 x 15的LED矩阵。

Arduino Uno只有32KB的内存,因此图形没有预先存储到数组中。相反,我编写算法使用数学方程生成艺术动画。

彩虹正弦波的示例代码如下:

for (int iterations = 0; iterations < times; iterations++)
{
    val += PI/500;

    for (int col = 0; col < NUM_COLS; col++)
    {
        digitalWrite(layerLatchPin, LOW);
        shiftOut(layerDataPin, layerClockPin, MSBFIRST, colMasks[col] >> 16 );
        shiftOut(layerDataPin, layerClockPin, MSBFIRST, colMasks[col] >> 8 );
        shiftOut(layerDataPin, layerClockPin, MSBFIRST, colMasks[col] );
        digitalWrite(layerLatchPin, HIGH);

        Tlc.clear();
        int rainbow1 = 7 + 7*sin(2*PI*col/NUM_COLS_TOTAL + val);
        setRainbowSinkValue(rainbow1, k);
        Tlc.update();
    }
}

setRainbowSinkValue函数将LED的值从1到15设置为特定颜色,val在每次迭代中将波向右移动。

因此,我正在寻找像这样的简单图形例程,以获得酷炫的动画效果,而无需将所有内容存储在数组中,因为15 x 24 x RGB很快就会用完32KB的RAM。

我将尝试获取Arduino Mega,但现在假设这不是一个选项。

我该怎么做?

4个回答

2

如果您开始叠加简单的函数,如sin或cos,您可以获得许多效果。 这个人创建了“等离子”效果,我认为这总是一件很酷的事情 :)

另一种方法是使用噪声函数来计算像素的颜色。如果您搜索“Arduino Perlin noise”,则会获得许多示例(取决于您的Arduino模型,您可能无法获得高帧速率,因为Perlin噪声需要一些CPU功率)。


我看到有人发布了一些Perlin噪声Arduino代码。我会阅读你的链接并尝试它。谢谢! - djb

2

我一直在使用Arduino进行类似的图形项目,考虑了许多应对有限的策略。个人认为,除非结合其他事物或以某种方式指导,否则算法动画相当平凡和通用。

无论如何,我一直在探索两种方法:

  • 定义自定义格式将数据打包为位,然后使用位移来解包它

  • 将简单的SVG图形存储在PROGMEM中,然后使用精灵技术在屏幕上移动它们(例如屏幕环绕等)。通过使用布尔运算将多个图形合并在一起,可以获得动画层效果并构建复杂性/多样性。

我只使用单色LED,因此在概念和数据方面更加简单。


有趣的,那么如何将SVG绘制到LED上呢?你有什么提示吗? - djb
@djb:SVG只是一种存储路径点或基本图形(矩形、圆形等)的XML格式。对于(非常)简单的形状,我存储数据点(x/y),并使用线性例程(Bresenham、DDA)在它们之间进行插值 - 以执行精灵动画:从PROGMEM中提取形状数据,根据插值该数据打开LED,等待一段时间,将形状数据移动一些x/y,重新绘制到新位置。要点是仅存储简单的形状数据 - 而不是每个动画帧 - 并通过代码执行动画。 - spring

1
一个好问题,但由于平台的本质,你可能找不到任何东西。
您已经有了使用算法生成效果的一般想法,因此您应该继续编写更多疯狂的功能。
您可以打包您的功能并使它们对每个人都可用。
此外,如果允许,请使用串行端口与具有更多资源并且可以提供无尽模式流的主机进行通信。
使用发射器和接收器也适用于连接到另一台计算机。

我在沙漠里用汽车电池运行它,所以不幸的是我不能使用电脑。但是,如果我想到了什么特别好的东西,我会在某个地方发布代码。 - djb
确实,非洲燃烧:)它就像燃烧人一样,但只有十分之一的规模。 - djb
天啊!希望我能去! - zaf

1

我会回答相关的问题,但不会完全回答你所问的问题,因为我不是一个图形专家...

首先,请不要忘记PROGMEM,它允许你将数据存储在flash内存中。实际上,flash比SRAM有更多的存储空间,通常的做法是将额外的数据存储在flash中。

其次,现有的压缩技术可以减少你的内存消耗。这些“压缩”技术与你所做的任务自然相符,所以“压缩”一词有点误导。

首先,我们观察到由于人类对光强度的感知是指数级的(关于这个话题,我很无耻地链接了我的答案),取决于您如何使用LED驱动器,您不需要存储精确的强度。看起来您只在TLC5940上使用了8位强度,而不是全部12位。对于8位LED驱动器强度,您只有8或9个不同的强度值(因为您告诉LED驱动器使用的强度是2^perceptible_intensity)。8个不同的值只能存储在三位中。将三位块存储在字节中可能有点麻烦,但您仍然可以将数组中的每个“像素”视为uint16_t,但存储整个颜色信息。因此,您将内存消耗减少了三分之二。此外,您可以将图像调色板化:每个像素是一个字节(uint8_t),并索引调色板中的位置,如果需要,调色板可以是三个字节。调色板不需要很大,实际上,您甚至不必拥有调色板,这意味着在代码中拥有调色板:您的代码知道如何将一个字节转换为一组强度。然后,在移位之前生成TLC5940实际需要的强度值。

1
当我编译时,它会显示“二进制草图大小:14,234字节(32,256字节最大)”,例如。那么,它不是已经使用了32KB的闪存内存吗?SRAM仅为2KB。感谢压缩建议;我不确定如何将24位颜色压缩为16位。我使用3个无符号字符来保存R/G/B;所以它是否索引调色板?您能详细说明一下吗?对于彩虹代码的强度,k只是递增,并进入sin()函数以获取1-256之间的值,该值向上移动到1-4096之间。我认为在强度值压缩上不会节省太多空间。 - djb
啊,好的,那么像 Philipp 链接中描述的那样,使用 HSBtoRGB 创建一个调色板...只需要大约256种颜色,不会有不连续性。 - djb
不,您正在使用15K(32K中的一部分),因此您的闪存超过一半是空闲的。 - angelatlarge
有没有办法以非静态/非常量的方式加载PROGMEM?我想用调色板颜色初始化一个PROGMEM int[360][3],但是如果我尝试说palette[i][j] = 0,它会说我不能使用只读内存。 - djb
不幸的是,PROGMEM 几乎完全是只读的。虽然可以对 PROGMEM 进行写操作,但每次只能写一页。 - angelatlarge

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接