当uint32_t> 45时Arduino似乎崩溃

时间:2019-02-27 10:04:22

标签: c++ arduino

我在Uno克隆上运行以下程序。

uint32_t counter = 0;

void setup() {
    Serial.begin(9600);
    while(!Serial);
}

void loop() {
    char *result = malloc(32);
    sprintf(result, "%024u", counter);

    Serial.print("{\"n\": ");
    Serial.print(result);
    Serial.println(" }");

    delay(100);
    counter++;
}

一切正常,字符串已打印,计数器按预期增加。下面是输出示例:

{"n": 000000000000000000000000 }
{"n": 000000000000000000000001 }
{"n": 000000000000000000000002 }
{"n": 000000000000000000000003 }
....

但是,每次counter > 45时,程序都会停止通过UART打印,这是此时的输出结果:

{"n": 000000000000000000000044 }
{"n": 000000000000000000000045 }
{"n":  }

对于可能导致此问题的原因的任何见解,都将受到赞赏。

3 个答案:

答案 0 :(得分:4)

每次调用loop时,都会分配32个字节的内存。 Arduino Uno没有太多内存,因此很快就会用完。使用完毕后,您需要释放内存。这是一个比喻。

RAM是一条字符串。此字符串的长度是固定的。您可以切断该字符串的一部分,然后将其用于任何您喜欢的对象。这是分配。如果继续从字符串中删减32个字节,则最终用完。使用完毕后,您需要将这条弦带绑回到主弦上。这是释放。

这是一个非常糟糕的类比,但我希望您能想到!要解决紧迫的问题,您只需在函数的末尾附加free(result)即可在每次分配时取消分配。为了真正正确地解决问题,您应该在堆栈上分配而不是在堆上分配。在堆栈上进行分配时,内存将在作用域末尾自动释放。要在堆栈上分配32个字节,只需执行以下操作:

char result[32];

result中的内存仅在其包围范围内有效(loop函数)。上面的代码段基本上与此等效:

char result_0;
char result_1;
char result_2;
// ...
char result_29;
char result_30;
char result_31;

堆栈分配比堆分配(mallocfree)要快得多,因为编译器确切知道您正在使用多少内存。但这有其缺点。为了堆栈分配内存,编译器需要知道您正在使用多少内存!您不能这样做:

int size = get_a_number_from_somewhere();
char result[size];

因为编译器不知道要分配多少内存。但是,这是

int size = get_a_number_from_somewhere();
char *result = malloc(size);
// ...
free(result);

完全可以。

通常,当所需的内存量是编译时常量(例如32)时,应进行堆栈分配,否则应进行堆分配。每次您写malloc时,请仔细考虑相应的free应该去哪里。

答案 1 :(得分:1)

允许使用malloc(),但在内存非常有限的Arduino上不是很有用。

Arduino没有操作系统,如果没有足够的内存分配,这可能会造成干扰。 (无论如何,要使Arduino永远运行,该怎么做?)

如果您有Java背景,也请避免使用new关键字,这将导致相同的问题。

如果需要内存,请尽早获取(最好在编译时)并保留它。

当然,free(result)响应也是正确的。

答案 2 :(得分:0)

为什么不使用String(),例如下面的代码:

uint32_t counter = 0;

void setup() {
    Serial.begin(9600);
    while(!Serial);
}

void loop() {

    Serial.print("{\"n\": ");
    Serial.print(String(counter));
    Serial.println(" }");

    delay(100);
    counter++;
}