Arduino 似乎在 45 uint32_t >崩溃

Arduino seems to crash when uint32_t > 45

本文关键字:gt 崩溃 uint32 Arduino      更新时间:2023-10-16

我在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":  }

对可能导致此问题的任何见解都非常感谢。

每次调用loop时,分配了32个字节。Arduino Uno的内存不多,因此很快就用完了。完成后,您需要处理内存。这是一个类比。

RAM是一条字符串。该字符串的长度固定。您可以切断一块字符串并将其用于您喜欢的任何东西。这是分配。如果您不断从字符串中切割32个字节,最终将用完。完成使用后,您需要将一块字符串胶带回到主字符串中。这是DealLocation。

那是一个非常糟糕的类比,但我希望你明白了!要解决直接问题,您可以简单地将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去向。

malloc(),但在非常有限的RAM的Arduino上不太有用。

Arduino没有操作系统,如果没有足够的内存可以分配,它可能会干扰。(无论如何,保持Arduino永远运行该怎么办?)

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

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

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

为什么不使用String(),例如代码Bellow:

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++;
}