处理大量数组和内存耗尽

问题描述 投票:0回答:3

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

该代码包含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闪存,并在那里推送东西?从来没有处理过这个问题,我不知道如何实现它,以什么格式存储值,以及如何实现它。我是否正确,必须首先编写一个程序,将所有数据加载到内存中,上传并运行它,然后将实际程序放在微控制器上处理该数据?

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

arduino arduino-uno
3个回答
1
投票

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

现在,您将这些值存储到2k的SRAM中。更改这些声明以使用PROGMEM关键字,因此它们存储在有更多空间的地方。

使用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
}

1
投票

如果这些阵列形成一个应该点亮的LED模式,而其他阵列被关闭,你可以将所有LED的状态存储在uint16_t中,并在PROGMEM中有一个数组。 (如Kingsley的回答)

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

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
// ... 
};

我想知道你的数字的顺序,所以我不确定这个猜测是否正确。所以现在没有更多细节如何使用这种方法


0
投票

更新

对我而言,您的意见完全改变了您的问题的意图。

正如我现在读到的那样,不需要一种特殊的“名称”数据来识别数组。你想要的似乎只是将不同的数组作为函数参数传递。

这通常是通过指针完成的,有两点需要注意:

  1. 大多数情况下,数组会自动“衰减”到指针。这意味着在大多数地方可以使用数组变量代替指针。指针可以像数组一样使用。
  2. 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]
  }

}

或者等价的

void somefunc(uint8_t arr[], uint8_t arrLength) {
...
}

然后通过简单地传递数组变量和相应的数组长度来调用该函数

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

somefunc(arr_foo,5);
somefunc(arr_bar,2);

数组的常量数据可以放入PROGMEM以节省RAM,但正如其他人所说,读取访问稍微复杂一些,需要用C ++调用pgm_read_...()。 (AVR gcc仅支持C中的__flash-qualified数据,而不支持C ++。)

然后是问题,随着更多序列的添加,我可能会在以后耗尽内存。

请注意,“Arduino”AVR具有32kb的闪存。如果每个序列消耗15个字节,它可能仍然可以保存1000或2000个这些项目以及您的程序。

什么呢?添加一个外部i2c闪存,并在那里推送东西?从来没有处理过这个问题,我不知道如何实现它,以什么格式存储值,以及如何实现它。

如果在某些时候实际上用完了闪存,你仍然可以使用任何形式的外部存储。

一种常见的解决方案是SPI闪存,它可以在兆位范围内使用。 Winbond是一家知名供应商。只需搜索“Arduino SPI flash”模块和库。

更复杂的方法是支持SD卡作为外部存储器。但除非你真的想存储千兆字节的数据,否则可能不值得。

我是否正确,必须首先编写一个程序,将所有数据加载到内存中,上传并运行它,然后将实际程序放在微控制器上处理该数据?

这绝对是一种方法。如果您的代码空间允许,您可以选择在应用程序中包含写入外部闪存的例程,例如某种引导加载程序,这样您就可以切换到“上传外部闪存数据”模式而无需重新刷新微控制器。

© www.soinside.com 2019 - 2024. All rights reserved.