5

我正在编写一个应用程序来通过蓝牙用我的 Android 手机控制我的机器人,一切顺利,数据得到回显和验证,但我在协议方面遇到了一些问题,特别是我希望我的机器人的轮子在我发送时转动一个命令,例如s,10,100or s,-30,-10...(以百分比表示的值)。

我的问题是,当我想在我的Arduino上解析我的轮速命令时,我必须从最多4 个单独解析bytes为到-100?ints,-100,-100setSpeed(left, right);leftright

我知道我可以单独分析每个字节并将它们放在一起以获得一个整数,但这不是很优雅,并且可能已经有更好的解决方案,不幸的是我还没有找到它。

编辑

这是用于解析我的命令的 Arduino 函数:

void parseCommand(char* command, int* returnValues)
{
  // parsing state machine
  byte i = 2, j = 0, sign = 0;
  int temp = 0;
  while(*(command + i) != '\0')
  {
    switch(*(command + i))
    {
      case ',':
        returnValues[j++] = sign?-temp:temp;
        sign = 0;
        temp = 0;
        break;
      case '-':
        sign = 1;
        break;
      default:
        temp = temp * 10 + *(command + i) - 48;
    }
    i++;
  }
  // set last return value
  returnValues[j] = sign?-temp:temp;
}

s,100,-100在解析类似(必须\0终止)的内容时,您可以这样称呼它:

char serialData[16];
void loop()
{
  if(Serial.available() > 0)
  {
    Serial.readBytesUntil('\0', serialData, 15);
    switch(serialData[0])
    {
      case 's':
        int speed[2];
        parseCommand(serialData, speed);
        setSpeed(speed[0], speed[1]);
        break;
    }
    // always echo
    Serial.write(serialData);
    // end of message is maked with a \0
    Serial.print('\0');

    // clear serialData array
    memset(serialData, 0, sizeof(serialData));
  }
}
4

2 回答 2

9

只需将逐个字符读入状态机即可。它简单而高效。

要逐位读取数字,请执行以下操作:从零开始。对于每个数字,将数字乘以十并添加数字的值。因此,例如,读取 97 将像这样工作:

  1. 你读入一个没有前面数字的数字,你从 0 开始。

  2. 你读入 9 并计算 (0*10)+9 -> 9

  3. 你读入 7 并计算 (9*10)+7 -> 97

  4. 你读取一个非数字,你输出 97。

这是一个更完整的例子s,10,100

  1. 您从“准备读取命令状态”开始。

  2. 你读“s”,“s”是命令。您切换到“准备阅读第一个逗号”状态。

  3. 你读了第一个逗号,你就切换到“准备找出第一个参数的符号”状态。

  4. 你读了一个数字。由于这不是“-”,因此第一个参数是正数。您将第一个数字设置为数字的值 1。您现在处于“读取第一个数字”状态。

  5. 您读取了一个数字 0。您将第一个数字设置为 1*10+0 -> 10。您仍处于“读取第一个数字”状态。

  6. 你读了一个逗号。您现在处于“准备找出第二个参数的符号”状态。

  7. 你读到了 1。第二个数字是正数(因为这不是“-”)。您将第二个数字设置为 1。您处于“读取第二个数字”状态。

  8. 您读取 0。第二个数字现在设置为 1x10+0 -> 10。您仍处于“读取第二个数字”状态。

  9. 您读取 0。第二个数字现在设置为 10x10+0 -> 100。您仍处于“读取第二个数字”状态。

  10. 你读到了行尾。你执行你的结果:命令是“s”,第一个数是正数,第一个数是10,第二个数是正数,第二个数是100。

  11. 您切换回“准备读取命令”状态。

于 2012-08-28T14:47:48.887 回答
4

我喜欢David Swartz的回答,但我想我会扮演魔鬼的拥护者。

以二进制形式读取数据可能很优雅,这取决于您需要用它做什么。

在以下示例中,从串行读取数据,直到它看到二进制分隔符0X7F。读取的字节存储在inDatachar 数组中。查看文档Serial.readBytesUntil()

char inData[16];
int bRead;
bRead = Serial.readBytesUntil(0x7F,inData,4);

然后可以将该字节转换为整数或以其他方式进行操作。请记住,最大值为 +/-126,因为这是一个有符号字符(127 是一个分隔符,不会被视为一个值)。

您可以通过以下方式访问这些值:

Serial.print("Bytes Read: ");
Serial.println(bRead);
Serial.println("First Byte");
Serial.println((int)inData[0]);
Serial.println(
            map((int)inData[0],0,126,0,1024)
);
Serial.println("Second Byte");
Serial.println((int)inData[1]);

我使用以下 bash 命令对此进行了测试(确保正确设置了串行速度之后):

echo -ne '\x01\x02\x7F' > /dev/ttyACM0

我写的一些粗略的示例代码可以在这里找到

于 2012-08-28T17:31:06.433 回答