Arduino 处理大量数组和内存耗尽

Arduino 处理大量数组和内存耗尽,arduino,arduino-uno,Arduino,Arduino Uno,第一:我从一个由于时间限制而无法完成的人那里继承了这个项目 代码包含100多个声明的数组,每个数组包含一组int。阵列都是唯一的 byte arr_foo[] = {2, 5, 6, 8, 3}; byte arr_bar[] = {1, 7}; byte arr_baz[] = {6, 10, 9, 11, 7, 8, 3}; 这些INT与电路板上的特定LED相关-总共有11个。这些阵列表示这些LED应该点亮的特定顺序 他们试图做的是编写一个例程,当给定一个数组名时,该例程将获取该数组的内容

第一:我从一个由于时间限制而无法完成的人那里继承了这个项目

代码包含100多个声明的数组,每个数组包含一组int。阵列都是唯一的

byte arr_foo[] = {2, 5, 6, 8, 3};
byte arr_bar[] = {1, 7};
byte arr_baz[] = {6, 10, 9, 11, 7, 8, 3};
这些INT与电路板上的特定LED相关-总共有11个。这些阵列表示这些LED应该点亮的特定顺序


他们试图做的是编写一个例程,当给定一个数组名时,该例程将获取该数组的内容并处理int。嗯,将数组名作为字符串传递,然后与变量匹配是行不通的。这就是他们传递信息的地方,说他们没有时间去弄清楚

所以我看着这个,想,为什么不是一个二维数组呢?我很快就在那里遇到了麻烦

byte seqs[][7] = {
  {2, 5, 6, 8, 3},
  {1, 7},
  {6, 10, 9, 11, 7, 8, 3}
}
虽然原则上这是可行的,但这里的问题是它用尾随零填充每个数组,因为我告诉它每个数组都有[7]个元素。这会导致大量内存被浪费,并且内存不足

所以我被卡住了。我不知道如何处理100多个单独的数组,除了编写100多个单独的例程供以后调用。我也不知道如何提高效率

还有一个问题是,随着更多序列的添加,我可能在以后的某个时间内存不足。那又怎样?添加一个外部i2c闪存,然后把东西放进去?由于从未处理过这个问题,我不知道如何实现它,以何种格式存储值,以及如何实现。我说得对吗?首先要编写一个程序,加载内存中的所有数据,上传并运行它,然后将要处理这些数据的实际程序放在微控制器上


所以我想我要问两件事:处理大量(小)数组并能够在调用它们的例程中使用它们的更好方法是什么?如果我最好将这些数据放入外部闪存,它们应该以什么格式存储?

将数据放入2D数组根本不会节省任何空间

现在,您正在将这些值存储到2k的SRAM中。将这些声明更改为使用关键字,以便将它们存储在空间更大的位置

使用PROGMEM指示编译器将此数据加载到内存的闪存部分:

const PROGMEM uint8_t arr_foo[] = { 2, 5, 6, 8, 3 };
然而,数据需要通过函数调用来访问,您不能直接使用它

for (byte k = 0; k < 5; k++) 
{
    uint8_t next_led = pgm_read_byte_near( arr_foo + k );
    // Do something with next_led
}
for(字节k=0;k<5;k++)
{
uint8\u t next\u led=pgm\u read\u byte\u near(arr\u foo+k);
//用下一个led做点什么
}

将数据放入2D数组根本不会节省任何空间

现在,您正在将这些值存储到2k的SRAM中。将这些声明更改为使用关键字,以便将它们存储在空间更大的位置

使用PROGMEM指示编译器将此数据加载到内存的闪存部分:

const PROGMEM uint8_t arr_foo[] = { 2, 5, 6, 8, 3 };
然而,数据需要通过函数调用来访问,您不能直接使用它

for (byte k = 0; k < 5; k++) 
{
    uint8_t next_led = pgm_read_byte_near( arr_foo + k );
    // Do something with next_led
}
for(字节k=0;k<5;k++)
{
uint8\u t next\u led=pgm\u read\u byte\u near(arr\u foo+k);
//用下一个led做点什么
}

如果这些阵列形成了一个应该点亮的LED阵列,而其他阵列则关闭,那么您可以将所有LED的状态存储在
uint16\t
中,并在
PROGMEM
中创建一个LED阵列。(如金斯利的回答)

如果您不熟悉十六进制表示法,可以使用二进制格式

const PROGMEM uint_16_t patterns[] = {
// BA9876543210  Led Pins
 0b000101101100, //foo: 2, 5, 6, 8, 3
 0b000010000010, //bar: 1, 7
 0b111111001000, //baz: 6, 10, 9, 11, 7, 8, 3
// ... 
};

我想知道你的数字顺序,所以我不确定这个猜测是否正确。因此,现在不再详细说明如何使用这种方法了

如果这些阵列形成了一种应该点亮的LED模式,而其他阵列则关闭,那么您可以将所有LED的状态存储在
uint16\t
中,并在
程序中设置一个LED阵列。(如金斯利的回答)

如果您不熟悉十六进制表示法,可以使用二进制格式

const PROGMEM uint_16_t patterns[] = {
// BA9876543210  Led Pins
 0b000101101100, //foo: 2, 5, 6, 8, 3
 0b000010000010, //bar: 1, 7
 0b111111001000, //baz: 6, 10, 9, 11, 7, 8, 3
// ... 
};
我想知道你的数字顺序,所以我不确定这个猜测是否正确。因此,现在不再详细说明如何使用此方法 对我来说,你的评论完全改变了你问题的意图

正如我现在读到的,不需要特殊类型的“名称”数据来标识数组。您想要的似乎只是将不同的数组作为函数参数传递

这通常通过指针完成,需要注意两件事:

  • 大多数情况下,数组会自动“衰减”到指针。这意味着在大多数情况下,可以使用数组变量代替指针。指针可以像数组一样使用
  • C中的数组在运行时不携带任何长度信息。数组的长度需要单独保持/传递。或者,您可以定义一个结构(或C++中的类),其中包含数组及其长度作为成员
  • 例如:

    如果要将
    T
    类型的元素数组传递给函数,可以声明函数接受指向
    T
    的指针:

    void somefunc(uint8_t* arr, uint8_t arrLength) {
    
      for ( uint8_t i = 0; i < arrLength; i++ ) {
        uint8_t value = arr[i];
        value = *(arr+i); // equivalent to arr[i]
      }
    
    }
    
    然后通过简单地传递数组变量和相应数组的长度来调用该函数,如

    uint8_t arr_foo[] = { 1,2,3,4,5 };
    uint8_t arr_bar[] = { 1,2 };
    
    somefunc(arr_foo,5);
    somefunc(arr_bar,2);
    

    数组的常量数据可以放入PrimeMy/Cuth>中保存RAM,但是,正如其他人所指出的,读访问有点复杂,需要C++中的代码> PGMYRead……())/Cudio>调用。(AVR GCC只支持C中的数据,而不是C++) 还有一个问题,我可能在以后的某个时间内存不足 随着更多序列的添加,时间也随之增加

    请注意,“Arduino”AVR有32kb的闪存。如果每个序列占用15个字节,那么它可能仍然可以在程序中保存1000或2000个这些项目

    然后呢?添加一个外部i2c闪存,然后把东西放进去 那里由于从未处理过这个问题,我不知道如何实施 即,以何种格式存储值,以及如何执行<