【问题标题】:Arduino C++ for loop exiting early?Arduino C++ for 循环提前退出?
【发布时间】:2021-07-12 09:32:45
【问题描述】:

我下午的大部分时间都在盯着这个看,我很难过。这个问题看起来很简单,我相信这将是一个真正的Doh!当我破解它时,面对手掌的时刻。

一些背景:

我正在创建一个小项目,使用 Arduino 从我的遥控器读取红外信号并将它们发送到我正在编写的 Python 程序。

我将示例命令作为 JSON 字符串发送到 Arduino,并使用 Arduinojson 库对其进行反序列化。这很好用。我的采样方法捕获信号并将其写入 int 数组。

我正在努力将该数组转换为 JSON 字符串。我尝试使用相同的库对其进行序列化,但它使用了大量内存,因此我尝试编写一个循环将整数转换为字符串形式并从中手动构造一个 JSON 字符串。

我的信号捕捉方法:

// Capture an IR signal
bool capture() {
  bool captured = false;
  if(myReceiver.getResults()) {
    int index = 0;
    for(bufIndex_t i = 1; i < recvGlobal.recvLength; i++){
      irBuffer[index++] = recvGlobal.recvBuffer[i];

      // Debug
      Serial.print(i);
      Serial.print(" - ");
      Serial.println(recvGlobal.recvBuffer[i]);
    }
    irBuffer[index] = 0;
    captured = true;
  }
  myReceiver.enableIRIn();
  return captured;
}

该方法的调试输出显示我正在捕获 67 个脉冲:

1 - 4400
2 - 4600
3 - 550
4 - 600
5 - 550
6 - 550
7 - 550
8 - 1650
9 - 550
10 - 1700
11 - 550
12 - 600
13 - 550
14 - 1650
15 - 600
16 - 550
17 - 550
18 - 600
19 - 500
20 - 600
21 - 550
22 - 550
23 - 550
24 - 1700
25 - 550
26 - 1650
27 - 550
28 - 600
29 - 550
30 - 1700
31 - 550
32 - 600
33 - 500
34 - 600
35 - 550
36 - 550
37 - 550
38 - 1700
39 - 550
40 - 1650
41 - 550
42 - 1700
43 - 550
44 - 1700
45 - 550
46 - 600
47 - 500
48 - 600
49 - 550
50 - 600
51 - 500
52 - 1700
53 - 550
54 - 600
55 - 550
56 - 550
57 - 550
58 - 600
59 - 500
60 - 600
61 - 500
62 - 1700
63 - 600
64 - 1650
65 - 550
66 - 1700
67 - 550

我尝试将其转换为 JSON 字符串:

#define MAX_IR 100

...


if (RETURN_IR_SIGNAL) {
    char out[MAX_IR];
    char tmp[10];
    strcpy(out, "{\"signal\":[");
    for (int i = 0; i <= MAX_IR; i++) {
      if (irBuffer[i] == 0) {
        break;
      }
      // Debug statements
      Serial.print("out = ");
      Serial.println(out);

      sprintf(tmp, "%d,", irBuffer[i]);
      strcat(out, tmp);
    }
    strcat(out, "]}");

    // Debug
    Serial.println("Finished");

    RETURN_IR_SIGNAL = false;
  }

该代码的调试输出如下:

out = {"signal":[
out = {"signal":[4400,
out = {"signal":[4400,4600,
out = {"signal":[4400,4600,550,
out = {"signal":[4400,4600,550,600,
out = {"signal":[4400,4600,550,600,550,
out = {"signal":[4400,4600,550,600,550,550,
out = {"signal":[4400,4600,550,600,550,550,550,
out = {"signal":[4400,4600,550,600,550,550,550,1650,
out = {"signal":[4400,4600,550,600,550,550,550,1650,550,
out = {"signal":[4400,4600,550,600,550,550,550,1650,550,1700,
out = {"signal":[4400,4600,550,600,550,550,550,1650,550,1700,550,
out = {"signal":[4400,4600,550,600,550,550,550,1650,550,1700,550,600,
out = {"signal":[4400,4600,550,600,550,550,550,1650,550,1700,550,600,550,
out = {"signal":[4400,4600,550,600,550,550,550,1650,550,1700,550,600,550,1650,
out = {"signal":[4400,4600,550,600,550,550,550,1650,550,1700,550,600,550,1650,600,
out = {"signal":[4400,4600,550,600,550,550,550,1650,550,1700,550,600,550,1650,600,550,
out = {"signal":[4400,4600,550,600,550,550,550,1650,550,1700,550,600,550,1650,600,550,550,
out = {"signal":[4400,4600,550,600,550,550,550,1650,550,1700,550,600,550,1650,600,550,550,600,
out = {"signal":[4400,4600,550,600,550,550,550,1650,550,1700,550,600,550,1650,600,550,550,600,500,
out = {"signal":[4400,4600,550,600,550,550,550,1650,550,1700,550,600,550,1650,600,550,550,600,500,600,
out = {"signal":[4400,4600,550,600,550,550,55�␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀␀

您可以看到,当它到达数组中的第 21 个数字时,它会将字符串截断为几个数字。此外,我没有看到最终的“已完成”消息这一事实表明我可能会抛出异常并重新启动,但我无法查看是否是这种情况。

自从我编写任何 C 或 C++ 以来,已经有 20 多年了,所以这是一场艰苦的战斗,但很有趣。所以我敢说这是一个经典的菜鸟错误,但它正在躲避我。

非常感谢任何帮助。

【问题讨论】:

  • 最后一个完整的行有 96 个字符存储在 out 中,有 100 个空间。下一个数字将写入缓冲区末尾。
  • 我猜irBufferint 的数组。因此,您期望将大小为MAX_IRint 数组转换为字符串,结果字符串将适合大小为MAX_IRchar 数组?
  • 一般来说,我不知道您使用的是哪个 arduino 板,但无论如何这些都是微控制器,它们的 RAM 以数十或数百字节为单位,因此来自 PC 的方法(创建数千字节长的字符串)可能不会在那里工作。

标签: c++ indexing arduino indexoutofboundsexception


【解决方案1】:

你的代码

strcat(out, tmp);

会导致最终的堆栈缓冲区溢出,因为out 缓冲区的大小只有 100 个字符(不是整数),但是在迭代次数(准确地说是第 20 次迭代)。

我在启用 ASAN (-fsanitize=address) 的情况下编译了您的代码 sn-p,很容易找出错误。我希望解决这个问题可以解决打印中的这种异常情况,前提是板上的串行日志记录可以容纳这么长的字符串。您可能可以使用 std::string 或使用中间的 std::vector ,再加上 std::to_string 然后将其字符串化并将其转储到控制台。

【讨论】:

  • 谢谢,一如既往,昨晚我在床上打瞌睡时,我得到了答案。增加尺寸解决了这个问题。你提到了一些我不熟悉的东西,比如 ASAN。我将阅读该内容并了解如何使用 std::strings。干杯!并感谢其他也发现错误的评论者...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-22
  • 1970-01-01
相关资源
最近更新 更多