微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Arduino 非常随机地冻结通过 String 和 sprintf

如何解决Arduino 非常随机地冻结通过 String 和 sprintf

TLDR:通过 arduinos String 类将浮点数打印到字符串时,我得到了一致的冻结。以前,我在使用 sprintf 和 %f 时遇到了同样的冻结。我已经使用 PString 类解决了这个问题,但我想了解这个问题。

全文:我有一个相当大的用于 arduino SAMD 架构(一个 MKRZero)的 C++ 代码库,它最近开始冻结在我很久没有接触过的代码行上。这是对 sprintf%f调用,它奇怪地按预期工作。在对 SO 和 google 进行了一些研究之后,我意识到 Arduino 不支持通过 sprintf 进行浮点格式化,在排除 dtostr(由于不在 AVR 上)之后,我尝试使用 Arduinos String 类。这暂时解决了问题,但是在使用一些不同的外部外围设备(可以连接和断开连接的 I2C 从设备)测试系统后,冻结再次出现。所以完全相同的代码,但由于不同的外围设备,它的部分代码有所不同。

代码库非常大(有 1000 行),我无法用一个简单的例子来重现。不幸的是,没有太多上下文,这些是失败的行:

for (int fieldindex = 0; fieldindex < totalFullDataPoints; fieldindex++) {
      char buffer[14];
      Serial.println("foo");
      // String floatString = String((float)data[fieldindex],2); // causes system to freeze
      // String floatString = String((float)1024.46,2); // causes system to freeze
      String floatString = String((float)1024.46); // causes system to freeze      
      // String floatString = String("1024.46"); // works
      Serial.println("bar"); // freezes before this
}

错误非常不稳​​定,因为我可以通过修改代码中其他地方的无关内容或从我的 arduino 断开传感器(I2C 从设备)来导致它无法触发。但是当它出现时,它是一致的,因为它每次运行都会发生。我什至有一个有效的代码版本 - 但是删除三行会导致它再次冻结:

String floatString = "14123.123";
Serial.println("Float String: ");
Serial.println(floatString);

我很确定这不是内存问题,据我所知,这不是指针或非终止字符串爆炸的情况。

由于这篇文章https://github.com/boseji/PString-Arduino-lib,我最终使用了 PStrings (https://forum.arduino.cc/t/use-pstring-to-avoid-crashes-due-to-string-sprintf-or-dtostrf-float-issues/230946),但我很沮丧和好奇,为什么它在创建浮动时以这种看似随机的方式冻结应该支持通过 String

解决方法

经过大量调试后,似乎问题确实与 Arduino 将浮点数打印为字符串的能力有关,而不是我的代码中的指针或未终止的字符串问题。

它似乎在 String 构造函数的 dtostrf() 调用中停滞:

// ~/.platformio/packages/framework-arduino-samd/cores/arduino/api/String.cpp
String::String(float value,unsigned char decimalPlaces)
{
    static size_t const FLOAT_BUF_SIZE = FLT_MAX_10_EXP + FLT_MAX_DECIMAL_PLACES + 1 /* '-' */ + 1 /* '.' */ + 1 /* '\0' */;
    init();
    char buf[FLOAT_BUF_SIZE];
    decimalPlaces = min(decimalPlaces,FLT_MAX_DECIMAL_PLACES);
    *this = dtostrf(value,(decimalPlaces + 2),decimalPlaces,buf);     // <-- HERE
}

它似乎与 _print_float 函数中对 dtostrf() 的汇编调用有关:

// ~/.platformio/packages/framework-arduino-samd/cores/arduino/api/deprecated-avr-comp/avr/dtostrf.c.impl
char *dtostrf (double val,signed char width,unsigned char prec,char *sout) {
  asm(".global _printf_float");   // If this line is uncommented,the stall wont happen
  char fmt[20];
  sprintf(fmt,"%%%d.%df",width,prec);
  sprintf(sout,fmt,val);   // If the above line is not commented out,the system will freeze here
  return sout;
}

我意识到对于遇到此线程的任何人来说,这可能是一个非常不令人满意的答案......但是对于它的价值,我们的解决方案是使用 PString (https://github.com/boseji/PString-Arduino-lib),因为他们在到目前为止似乎最不稳定。

如果问题再次出现,尽管使用了 PStrings

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。