【问题标题】:Arduino crash and reboot at "random points"Arduino 在“随机点”崩溃并重启
【发布时间】:2016-04-13 10:06:23
【问题描述】:

我正在做一个非常重要的学校项目,它是一个带有网络界面的 MP3 播放器和一个使用 arduino mega 的网络服务器。 当我想使用以太网库的任何功能时,我必须暂停音乐,因为以太网屏蔽和 mp3 播放器屏蔽使用相同的 spi 总线。但是当我改变音量时,这会导致音乐冻结 1 秒。为了避免我创建了暂停音乐的新函数,请调用以太网库和恢复的函数。

bool clientAvailable(EthernetClient &client){
  MP3player.pauseDataStream ();
  bool a = client.connected();
  MP3player.resumeDataStream ();
  return a;
}
int clientConnected(EthernetClient &client){
  MP3player.pauseDataStream ();
  int a = client.available();
  MP3player.resumeDataStream ();
  return a;
}
void stopClient(EthernetClient &client){
  MP3player.pauseDataStream ();
  client.stop();
  MP3player.resumeDataStream ();
}

void checkForClient(int loading){
  String firstLine;
  MP3player.pauseDataStream ();
  EthernetClient client = server.available();
  MP3player.resumeDataStream();
  if (client) {
    if(!loading){
      Serial.println(F("new client")); // CRASH HERE
      bool endLn(false);
      char chr;
      int i(0);
      while (clientConnected(client)) {
        char received[clientAvailable(client)+2];
        while (clientAvailable(client)) {
          MP3player.pauseDataStream ();
          char c = client.read();
          MP3player.resumeDataStream ();
           received[i] = c;
          Serial.print(c); // OR HERE
          if(!endLn){
            firstLine += c;
            if (c == '\n'){
            endLn = true;
            }
          }
          ++i;
        }
        received[i+1] = '\0';
        i = 0;
        if(endLn){
          Serial.println();
          endLn = false;
          Serial.print(F("first line : "));
          Serial.println(firstLine);
        }

我在输出中得到什么:

new û192.168.0.123

最后有一个 IP,因为这是 arduino 重新启动的地方,这是我显示的第一件事。 如果我删除 "client.println(F("new client")) 行,client.print(c) 行会出现错误(显示 3 或 4 个字符后)。如果我也删除这个,它会在某处坠毁,但我不知道在哪里。

我检查了内存,程序此时还剩下大约 600 个字节。

有什么想法吗?

谢谢。

【问题讨论】:

  • 您的看门狗是如何配置的?它被禁用了吗?如果没有,服务看门狗的代码在哪里?
  • 我不知道代码,但是仅仅阅读问题文本就让我感到深深的不安和不祥之感......问如何使用创可贴:(我希望我错了,但我认为你的设计正在流血。
  • @Lundin 不是,所以我尝试禁用它,但如果我启用它并配置它,没有任何改变?
  • @MartinJames 那只是因为我试图用 6 来解释大约 430 行的代码,而且我的英语不是很熟练......如果你想要更多细节,有这个 1s延迟,因为我必须从客户端获取数据并从中提取信息。之前,我有类似的东西:暂停 - 以太网功能 - 导致 1 秒延迟的东西 - 以太网功能 - 恢复。现在我想要暂停 - 以太网功能 - 恢复 - 导致 1 秒延迟的东西 - 暂停 - 以太网功能 - 恢复 - 所以我每次更改音量时都不会冻结。
  • 运行经过充分测试的库函数时代码崩溃,这反过来又表现为缓慢的数据传输,听起来很像看门狗。

标签: c++ c crash arduino reboot


【解决方案1】:

您的 RAM 可能不足。

此外,您不应将String 类用于firstLine。它会导致很多问题,其中一些问题可能会随机发生。

只需像 received 那样使用字符数组。将每个字符存储在数组中,直到换行符到达,并增加每个字符的长度:

void checkForClient(int loading){
  char    firstLine[60];
  uint8_t firstLineLen = 0;

  MP3player.pauseDataStream ();
  EthernetClient client = server.available();
  MP3player.resumeDataStream();
  if (client) {
    if(!loading){
      Serial.println(F("new client")); // CRASH HERE
      bool endLn(false);
      char chr;
      int i(0);
      while (clientConnected(client)) {
        char received[clientAvailable(client)+2];
        while (clientAvailable(client)) {
          MP3player.pauseDataStream ();
          char c = client.read();
          MP3player.resumeDataStream ();
          received[i] = c;
          Serial.print(c); // OR HERE
          if (!endLn) {
            if (firstLineLength < sizeof(firstLine)-2)
              firstLine[ firstLineLength++ ] = c;
            if (c == '\n') {
              endLn = true;
              firstLine[ firstLineLength ] = '\0'; // NUL-terminate
            }
          }
          ++i;
        }
        received[i+1] = '\0';
        i = 0;
        if(endLn){
          Serial.println();
          endLn = false;
          Serial.print(F("first line : "));
          Serial.println(firstLine);
        }

这也将节省大约 1600 字节的程序空间。避免使用 String 的原因有很多,而且很多人都写过关于这些陷阱的文章。如果您在程序的其他地方使用String,您应该使用类似的方法来消除它。

另一个减少 RAM 的技术是避免在数据进入时存储它,然后再使用它。相反,立即使用它:

void checkForClient(int loading){

  MP3player.pauseDataStream ();
  EthernetClient client = server.available();
  MP3player.resumeDataStream();
  if (client) {
    if(!loading){
      Serial.println(F("new client")); // CRASH HERE

      Serial.print(F("first line : "));
      bool endLn(false);

      char chr;
      int i(0);
      while (clientConnected(client)) {
        char received[clientAvailable(client)+2];
        while (clientAvailable(client)) {
          MP3player.pauseDataStream ();
          char c = client.read();
          MP3player.resumeDataStream ();
          received[i] = c;
          if (!endLn) {
            Serial.print(c); // printed now instead of saved for later
            if (c == '\n') {
              endLn = true;
            }
          }
          ++i;
        }
        received[i+1] = '\0';
        i = 0;
        if (endLn) {
          Serial.println();
          endLn = false;
          //Serial.println(firstLine); // NOT NEEDED, already printed!
        }

这样可以节省您用于firstLine 的所有 RAM。

您没有发布您的整个程序供我们审查,因此您必须寻找其他太大的变量,或者可以在内部声明的例程(即本地变量)而不是在文件范围内(即,全局变量,在任何例程之外声明)。

【讨论】:

  • 感谢这些建议,但不幸的是,它没有奏效......仍然有一些改进,这就是我得到的:new client GET / HTTP¯192.168.0.123 它只是在我添加了这些功能后才这样做,但我不明白为什么。这是完整的代码:pastebin.com/BWFqVGEv
  • 我还将更改我的 mp3 结构中的字符串
  • @RedSkidy,我很高兴它更好。顺便说一句,您可以编辑原始问题并包含您的草图。大多数人不会下载东西来回答问题……除了图书馆。如果您使用图书馆,请发布您正在使用的图书馆的链接,不要在您的帖子中包含它。
  • 我不认为库在这种情况下很重要。即使有一个小的改进,它仍然会发生同样的崩溃。随着使用 char 数组而不是字符串变得更好,我猜这个问题来自内存不足,但它只是因为我添加了这些函数,所以它们有什么理由会消耗内存吗?
  • @RedSkidy,您不认为库或您的其余代码非常重要吗?听起来你已经知道答案了。
猜你喜欢
  • 2015-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-17
相关资源
最近更新 更多