14

Arduino(C语言)解析带分隔符的字符串(通过串行接口输入)

在这里没有找到答案:/

我想通过串行接口 (Serial.read()) 向我的 arduino 发送一个简单的由逗号分隔的三个数字的字符串。这三个数字的范围可以是 0-255。

例如。 255,255,255 0,0,0 1,20,100 90,200,3

我需要做的是将这个发送到 arduino 的字符串解析为三个整数(比如说 r、g 和 b)。

所以当我发送 100,50,30 时,arduino 会将其翻译为

int r = 100
int g = 50
int b = 30

我尝试了很多代码,但没有一个有效。主要问题是将字符串(一堆字符)转换为整数。我发现可能会有 strtok_r 用于分隔符,但仅此而已。

感谢您的任何建议:)

4

9 回答 9

27

要回答您实际提出的问题,String 对象非常强大,它们可以完全按照您的要求进行操作。如果您直接从输入中限制解析规则,您的代码将变得不那么灵活、可重用性降低并且略微复杂。

字符串有一个名为 indexOf() 的方法,它允许您在字符串的字符数组中搜索特定字符的索引。如果未找到该字符,该方法应返回 -1。可以将第二个参数添加到函数调用以指示搜索的起点。在您的情况下,由于您的分隔符是逗号,您可以调用:

int commaIndex = myString.indexOf(',');
//  Search for the next comma just after the first
int secondCommaIndex = myString.indexOf(',', commaIndex + 1);

然后,您可以使用该索引使用 String 类的 substring() 方法创建子字符串。这将返回一个从特定起始索引开始的新字符串,并在第二个索引之前结束(或者如果没有给出文件的结尾)。所以你会输入类似于:

String firstValue = myString.substring(0, commaIndex);
String secondValue = myString.substring(commaIndex + 1, secondCommaIndex);
String thirdValue = myString.substring(secondCommaIndex + 1); // To the end of the string

最后,可以使用 String 类的未记录方法 toInt() 检索整数值:

int r = firstValue.toInt();
int g = secondValue.toInt();
int b = thirdValue.toInt();

可以在Arduino 文档中找到有关 String 对象及其各种方法的更多信息。

于 2013-01-13T18:57:10.737 回答
11

使用sscanf

const char *str = "1,20,100"; // assume this string is result read from serial
int r, g, b;

if (sscanf(str, "%d,%d,%d", &r, &g, &b) == 3) {
    // do something with r, g, b
}

如果要解析字符串流,请在此处使用我的代码:255,255,255 0,0,0 1,20,100 90,200,3解析逗号分隔字符串的函数

于 2016-02-03T04:41:27.120 回答
2

我认为最简单的是parseInt()用来完成这项任务:

void loop(){
    if (Serial.available() > 0){
        int r = Serial.parseInt();
        int g = Serial.parseInt();
        int b = Serial.parseInt();
    }
}

成功了。

于 2014-11-12T03:10:00.793 回答
1

我想你想做这样的事情来读入数据:

String serialDataIn;
String data[3];
int counter;


int inbyte;

void setup(){
  Serial.begin(9600);
  counter = 0;
  serialDataIn = String("");
}

void loop()
{
    if(serial.available){
        inbyte = Serial.read();
        if(inbyte >= '0' & inbyte <= '9')
            serialDataIn += inbyte;
        if (inbyte == ','){  // Handle delimiter
            data[counter] = String(serialDataIn);
            serialDataIn = String("");
            counter = counter + 1;
        }
        if(inbyte ==  '\r'){  // end of line
                handle end of line a do something with data
        }        
    }
}

然后使用 atoi() 将数据转换为整数并使用它们。

于 2012-06-17T06:35:07.747 回答
1

这很棒!

从@dsnettleton 最受好评的响应中给出的代码中,关于“thirdvalue = 0”的最后一条评论是正确的。但是,不要使用“lastIndexOf(',');” , 代码应该像@dsnettleton 正确地为 commaIndex+1 添加一个“+1”到“secondCommaIndex”(缺少 +1 可能只是那个人的错字)。

这是更新的代码

int commaIndex = myString.indexOf(',');
int secondCommaIndex = myString.indexOf(',', commaIndex+1);
String firstValue = myString.substring(0, commaIndex);
String secondValue = myString.substring(commaIndex+1, secondCommaIndex);
String thirdValue = myString.substring(secondCommaIndex+1); //To the end of the string  

例子)

对于 myString = "1,2,3"

  • commaIndex = 1(从索引 0(字符 1 的位置)搜索到第一个逗号的位置)
  • secondCommaIndex = 3(从索引 2(字符 2 所占据的位置)搜索到下一个逗号的位置)
  • firstValue 从索引 0-1 = "1" 读取
  • secondValue 从索引 2-3 = "2" 读取
  • 第三个值从索引 4-4(字符串的最后一个索引点)读取 = "3"

注意:不要将 INDEX 与字符串的 LENGTH 混淆。字符串的长度为 5。由于 String indexOf 从 0 开始计数,所以最后一个索引为 4。

刚刚的原因

String thirdValue = myString.substring(secondCommaIndex);

使用 .toInt() 时返回 0 是因为 thirdValue = ",3" 而不是 "3" 搞砸了 toInt()。

附言。很抱歉把所有的说明都写出来,但作为一名机械工程师,即使我有时也希望有人为我简化代码,尤其是在过去 7 年从事咨询工作的情况下。继续发布精彩的帖子!帮助像我这样的人很多!

于 2014-11-08T21:53:17.180 回答
0

对于在字符串中分隔的 n 个数字

int end;
while((end=str.indexOf(","))!=-1){
  String num = str.substring(0,end);
  str= asc.substring(end+1,str.length());
  Serial.println(num);  
}
于 2019-07-26T07:25:51.637 回答
0

新的 SafeString Arduino 库(可通过库管理器获得)提供了一个 stoken() 方法和一个 toLong() 方法来处理这种情况并避免 String 类的堆碎片问题。

有关详细教程,请参见
https://www.forward.com.au/pfod/ArduinoProgramming/SafeString/index.html

#include "SafeString.h"

void setup() {
  Serial.begin(9600);

  createSafeString(appCmd, 50);  // large enough for the largest cmd
  createSafeString(token1, 10);
  createSafeString(token2, 10);
  createSafeString(token3, 10);
  long r; 
  long g;
  long b;
  
  appCmd = "1,20a,100"; 
 
  token1.clear();token2.clear();token3.clear(); // clear any old data
  size_t nextIdx = 0; 
  nextIdx = appCmd.stoken(token1, nextIdx, ",");
  nextIdx++; //step over delimiter
  nextIdx = appCmd.stoken(token2, nextIdx, ",");
  nextIdx++; //step over delimiter
  nextIdx = appCmd.stoken(token3, nextIdx, ",");
  nextIdx++; //step over delimiter
  // now parse the numbers
  bool have3ValidNumbers = true;
  if (!token1.toLong(r)) {
    have3ValidNumbers = false;
    Serial.print("Red number invalid:");Serial.println(token1);
  }
  if (!token2.toLong(g)) {
    have3ValidNumbers = false;
    Serial.print("Green number invalid:");Serial.println(token2);
  }
  if (!token3.toLong(b)) {
    have3ValidNumbers = false;
    Serial.print("Blue number invalid:");Serial.println(token3);
  }
  if (have3ValidNumbers) {
    Serial.print("The values are ");
    Serial.print(" r:");Serial.print(r);
    Serial.print(" g:");Serial.print(g);
    Serial.print(" b:");Serial.print(b);
    Serial.println();
  }
}

void loop() {
}

此输入“1,20a,100”的输出是
绿色数字无效:20a

'标准' toInt() 方法将返回 1 20 100 作为结果。
对于像“1,a,50”这样的输入,“标准”toInt() 方法将返回 1 0 100
SafeString toLong() 方法在尝试将字符串转换为整数时会进行更多错误检查。

您还应该添加对 <0 和 >255 的检查,以确保输入是有效范围

于 2020-06-25T02:20:11.573 回答
-3

@cstrutton - 关于使用 'indexOf' 的优秀建议。它为我的项目节省了大量时间。不过,一个小指针,

我注意到第三个值没有显示(返回为零)。在稍微玩了一下并浏览了http://arduino.cc/en/Tutorial/StringIndexOf上的文档后, 我意识到,我可以使用 lastIndexOf 作为最后一个值。

这里有两行修改提供了正确的第三个值。

int lastCommaIndex = myString.lastIndexOf(',');

String thirdValue = myString.substring(lastCommaIndex+1); // To the end of the string
于 2013-04-02T03:27:51.930 回答
-3
    String myString = "dfsdfgsafhffgsdvbsdvdsvsdvsdsdfdfsdsff|date|recipt|weight|time|date|";

    // the setup routine runs once when you press reset:
    void setup() {                
        Serial.begin(9600); 
    }


// the loop routine runs over and over again forever:
void loop() {
 int Index1 = myString.indexOf('|');
int Index2 = myString.indexOf('|', Index1+1);
int Index3 = myString.indexOf('|', Index2+1);
int Index4 = myString.indexOf('|', Index3+1);
int Index5 = myString.indexOf('|', Index4+1);
int Index6 = myString.indexOf('|', Index5+1);
String secondValue = myString.substring(Index1+1, Index2);
String thirdValue = myString.substring(Index2+1, Index3);  
String fourthValue = myString.substring(Index3+1, Index4); 
String fifthValue = myString.substring(Index4+1, Index5); 
String firstValue = myString.substring(Index5+1, Index6); 
//Serial.println(Index1);
//
Serial.println(secondValue);
Serial.println(thirdValue);
Serial.println(fourthValue);
Serial.println(fifthValue);
Serial.println(firstValue);
delay(14000);
    }
于 2016-05-19T06:09:13.700 回答