处理大量阵列和内存耗尽

时间:2019-04-29 04:04:15

标签: 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应该点亮的特定顺序。

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

所以我正在研究这个问题,为什么不使用二维数组呢?我在那里很快遇到了麻烦。

byte seqs[][7] = {
  {2, 5, 6, 8, 3},
  {1, 7},
  {6, 10, 9, 11, 7, 8, 3}
}

虽然从原理上讲这是可行的,但是这里的问题是它用尾随的零填充数组,因为我告诉过每个数组都有[7]个元素。这会导致大量内存浪费,内存不足。

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

这是一个问题,随着添加更多的序列,我可能在以后仍然会用完内存。那又如何呢?添加外部i2c闪存,然后将东西推到那里?从来没有处理过,我不确定如何实现,以什么格式存储值以及如何实现。我是否正确,必须首先编写一个程序,将所有数据加载到内存中,然后上传并运行它,然后将要处理该数据的实际程序放在微控制器上?

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

3 个答案:

答案 0 :(得分: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 :(得分:1)

如果这些阵列形成了应点亮的led模式,而其他的LED均已关闭,则可以将所有led的状态存储在uint16_t中,并在{{1} }。 (如金斯利的回答)

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

PROGMEM

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

答案 2 :(得分: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闪存”模块和库。

更复杂的方法是将SD卡用作外部存储器。但可能不值得,除非您实际上想要存储千兆字节的数据。

  

我是不是必须先编写一个程序来加载所有   数据存储在内存中,将其上传并运行,然后将实际程序放入   将要在微控制器上处理这些数据?

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