【问题标题】:Convert serial.read() into a useable string using Arduino?使用 Arduino 将 serial.read() 转换为可用字符串?
【发布时间】:2023-03-17 23:34:01
【问题描述】:

我正在使用两个 Arduino 使用 newsoftserial 和 RF 收发器相互发送纯文本字符串。

每个字符串的长度可能为 20-30 个字符。如何将Serial.read() 转换为字符串,以便进行if x == "testing statements" 等操作?

【问题讨论】:

  • 请在下面查看我的答案,它比您选择的答案更直接/简单

标签: arduino


【解决方案1】:

无限字符串读取:

String content = "";
char character;
    
while(Serial.available()) {
     character = Serial.read();
     content.concat(character);
}
      
if (content != "") {
     Serial.println(content);
}

【讨论】:

  • 在 Arduino Leonardo 上比任何其他阅读方法都更可靠。由于 concat 可能是 RAM 使用问题,但如果草图可以接受,它看起来是最好的方法。
  • 非常有用和简单。虽然,我发现我必须在串行读取每个字符之间设置一个小的延迟 - 否则它将每个字符打印在单独的行上,而不是连接在一起。 void setup() { Serial.begin(9600); // Initialize serial port } void loop() { String content = ""; char character; while(Serial.available()) { character = Serial.read(); content.concat(character); delay (10); } if (content != "") { Serial.println(content); } }
  • 如果您想将此代码移动到从loop() 调用的单独函数中,请务必使用return(content); 而不是Serial.println()-ing 它。否则,您将陷入无限循环,因为它将捕获函数打印到 Serial 的任何内容,并尝试重新处理它。
  • 如果还是不行,试试content.trim()方法
  • 打印后必须清除内容,否则即使新的串口数据还没有到达,if块也会再次执行。
【解决方案2】:

来自Help with Serial.Read() getting string

char inData[20]; // Allocate some space for the string
char inChar=-1; // Where to store the character read
byte index = 0; // Index into array; where to store the character

void setup() {
    Serial.begin(9600);
    Serial.write("Power On");
}

char Comp(char* This) {
    while (Serial.available() > 0) // Don't read unless
                                       // there you know there is data
    {
       if(index < 19) // One less than the size of the array
       {
           inChar = Serial.read(); // Read a character
           inData[index] = inChar; // Store it
           index++; // Increment where to write next
           inData[index] = '\0'; // Null terminate the string
       }
    }

    if (strcmp(inData,This)  == 0) {
       for (int i=0;i<19;i++) {
            inData[i]=0;
       }
       index=0;
       return(0);
    }
    else {
       return(1);
    }
}

void loop()
{
    if (Comp("m1 on")==0) {
        Serial.write("Motor 1 -> Online\n");
    }
    if (Comp("m1 off")==0) {
       Serial.write("Motor 1 -> Offline\n");
    }
}

【讨论】:

  • 如果这不起作用,请尝试添加 inData.trim() 以防我们使用 arduino 控制台,会有换行符。这个stackoverflow.com/questions/24961402/… 为我工作
  • 这应该行不通。循环中的第二个“if”语句永远不会触发,因为您已经从第一个“if”比较中读取了串行数据。
【解决方案3】:

您可以在 Arduino 上使用 Serial.readString()Serial.readStringUntil() 解析来自 Serial 的字符串。

您也可以使用Serial.parseInt() 从串口读取整数值。

int x;
String str;
    
void loop() 
{
     if(Serial.available() > 0)
     {
        str = Serial.readStringUntil('\n');
        x = Serial.parseInt();
     }
}

通过串口发送的值是my string\n5,结果是str = "my string"x = 5

【讨论】:

  • 我在尝试手动将串行输入读入字符缓冲区时遇到了奇怪的电压波动,但使用Serial.readStringUntil() 为我解决了所有问题,并使代码更具可读性!谢谢!
  • 我测试过,是的,它更容易。但是与字符缓冲区相比,此操作需要更多的时间和延迟。
  • 有趣,你能分享更多关于你的发现的细节吗?我们在这里谈论的时间差异有多大?如果你有详细的数字,如果你能与我们分享,我会很高兴。谢谢!
【解决方案4】:

我自己也问过同样的问题,经过一些研究,我发现了类似的问题。

它对我来说就像一个魅力。我用它来远程控制我的 Arduino。

// Buffer to store incoming commands from serial port
String inData;
    
void setup() {
    Serial.begin(9600);
    Serial.println("Serial conection started, waiting for instructions...");
}
    
void loop() {
    while (Serial.available() > 0)
    {
        char recieved = Serial.read();
        inData += recieved; 
    
        // Process message when new line character is recieved
        if (recieved == '\n')
        {
            Serial.print("Arduino Received: ");
            Serial.print(inData);
                
            // You can put some if and else here to process the message juste like that:

            if(inData == "+++\n"){ // DON'T forget to add "\n" at the end of the string.
              Serial.println("OK. Press h for help.");
            }   

    
            inData = ""; // Clear recieved buffer
        }
    }
}

【讨论】:

  • 最好的比更好的:-)
【解决方案5】:

这样会更容易:

char data [21];
int number_of_bytes_received;

if(Serial.available() > 0)
{
    number_of_bytes_received = Serial.readBytesUntil (13,data,20); // read bytes (max. 20) from buffer, untill <CR> (13). store bytes in data. count the bytes recieved.
    data[number_of_bytes_received] = 0; // add a 0 terminator to the char array
} 

bool result = strcmp (data, "whatever");
// strcmp returns 0; if inputs match.
// http://en.cppreference.com/w/c/string/byte/strcmp


if (result == 0)
{
   Serial.println("data matches whatever");
} 
else 
{
   Serial.println("data does not match whatever");
}

【讨论】:

    【解决方案6】:

    这是一个更强大的实现,可以处理异常输入和竞争条件。

    • 它检测异常长的输入值并安全地丢弃它们。例如,如果源有错误并且生成的输入没有预期的终止符;或者是恶意的。
    • 它确保字符串值始终以 null 结尾(即使缓冲区大小已完全填满)。
    • 它一直等到捕获完整的值。例如,传输延迟可能会导致 Serial.available() 在其余值完成到达之前返回零。
    • 当多个值的到达速度快于它们的处理速度时,不会跳过值(受串行输入缓冲区的限制)。
    • 可以处理作为另一个值前缀的值(例如“abc”和“abcd”都可以读入)。

    它故意使用字符数组而不是String 类型,以提高效率并避免内存问题。它还避免使用readStringUntil() 函数,在输入到达之前不超时。

    最初的问题没有说明可变长度字符串是如何定义的,但我假设它们以单个换行符终止 - 这变成了行阅读问题。

    int read_line(char* buffer, int bufsize)
    {
      for (int index = 0; index < bufsize; index++) {
        // Wait until characters are available
        while (Serial.available() == 0) {
        }
    
        char ch = Serial.read(); // read next character
        Serial.print(ch); // echo it back: useful with the serial monitor (optional)
    
        if (ch == '\n') {
          buffer[index] = 0; // end of line reached: null terminate string
          return index; // success: return length of string (zero if string is empty)
        }
    
        buffer[index] = ch; // Append character to buffer
      }
    
      // Reached end of buffer, but have not seen the end-of-line yet.
      // Discard the rest of the line (safer than returning a partial line).
    
      char ch;
      do {
        // Wait until characters are available
        while (Serial.available() == 0) {
        }
        ch = Serial.read(); // read next character (and discard it)
        Serial.print(ch); // echo it back
      } while (ch != '\n');
    
      buffer[0] = 0; // set buffer to empty string even though it should not be used
      return -1; // error: return negative one to indicate the input was too long
    }
    

    这是一个用于从串行监视器读取命令的示例:

    const int LED_PIN = 13;
    const int LINE_BUFFER_SIZE = 80; // max line length is one less than this
    
    void setup() {
      pinMode(LED_PIN, OUTPUT);
      Serial.begin(9600);
    }
    
    void loop() {
      Serial.print("> ");
    
      // Read command
    
      char line[LINE_BUFFER_SIZE];
      if (read_line(line, sizeof(line)) < 0) {
        Serial.println("Error: line too long");
        return; // skip command processing and try again on next iteration of loop
      }
    
      // Process command
    
      if (strcmp(line, "off") == 0) {
          digitalWrite(LED_PIN, LOW);
      } else if (strcmp(line, "on") == 0) {
          digitalWrite(LED_PIN, HIGH);
      } else if (strcmp(line, "") == 0) {
        // Empty line: no command
      } else {
        Serial.print("Error: unknown command: \"");
        Serial.print(line);
        Serial.println("\" (available commands: \"off\", \"on\")");
      }
    }
    

    【讨论】:

      【解决方案7】:
      String content = "";
      char character;
      
      if(Serial.available() >0){
          //reset this variable!
          content = "";
      
          //make string from chars
          while(Serial.available()>0) {
              character = Serial.read();
              content.concat(character);
      }
          //send back   
          Serial.print("#");
          Serial.print(content);
          Serial.print("#");
          Serial.flush();
      }
      

      【讨论】:

      • 警告:有时您的字符串会分成两部分或更多部分发送。放置一些“消息结束”字符来检查是否连接了按摩中的所有字符。
      【解决方案8】:

      如果您想从串口读取消息并且需要单独处理每条消息,我建议使用这样的分隔符将消息分成几部分:

      String getMessage()
      {
        String msg=""; //the message starts empty
        byte ch; // the character that you use to construct the Message 
        byte d='#';// the separating symbol 
      
        if(Serial.available())// checks if there is a new message;
        {
            while(Serial.available() && Serial.peek()!=d)// while the message did not finish
            {
                ch=Serial.read();// get the character
                msg+=(char)ch;//add the character to the message
                delay(1);//wait for the next character
            }
           ch=Serial.read();// pop the '#' from the buffer
           if(ch==d) // id finished
               return msg;
           else
               return "NA";
        }
        else
            return "NA"; // return "NA" if no message;
      }
      

      这样您每次使用该功能时都会收到一条消息。

      【讨论】:

        【解决方案9】:

        最好和最直观的方法是使用 serialEvent() 回调 Arduino 与 loop()setup() 一起定义。

        不久前我建立了一个小型库来处理消息接收,但一直没有时间开源它。 该库接收 \n 终止的行,这些行代表命令和任意有效负载,以空格分隔。 您可以轻松调整它以使用您自己的协议。

        首先是一个库,SerialReciever.h:

        #ifndef __SERIAL_RECEIVER_H__
        #define __SERIAL_RECEIVER_H__
            
        class IncomingCommand {
          private:
            static boolean hasPayload;
          public:
            static String command;
            static String payload;
            static boolean isReady;
            static void reset() {
              isReady = false;
              hasPayload = false;
              command = "";
              payload = "";
            }
            static boolean append(char c) {
              if (c == '\n') {
                isReady = true;
                return true;
              }
              if (c == ' ' && !hasPayload) {
                hasPayload = true;
                return false;
              }
              if (hasPayload)
                payload += c;
              else
                command += c;
              return false;
            }
        };
            
        boolean IncomingCommand::isReady = false;
        boolean IncomingCommand::hasPayload = false;
        String IncomingCommand::command = false;
        String IncomingCommand::payload = false;
            
        #endif // #ifndef __SERIAL_RECEIVER_H__
        

        要使用它,请在您的项目中执行以下操作:

        #include <SerialReceiver.h>
            
        void setup() {
          Serial.begin(115200);
          IncomingCommand::reset();
        }
            
        void serialEvent() {
          while (Serial.available()) {
            char inChar = (char)Serial.read();
            if (IncomingCommand::append(inChar))
              return;
          }
        }
        

        使用接收到的命令:

        void loop() {
          if (!IncomingCommand::isReady) {
            delay(10);
            return;
          }
        
        executeCommand(IncomingCommand::command, IncomingCommand::payload); // I use registry pattern to handle commands, but you are free to do whatever suits your project better.
            
        IncomingCommand::reset();
        

        【讨论】:

          【解决方案10】:

          这要归功于岩浆。很好的答案,但这里使用的是 c++ 样式字符串而不是 c 样式字符串。一些用户可能会觉得这更容易。

          String string = "";
          char ch; // Where to store the character read
          
          void setup() {
              Serial.begin(9600);
              Serial.write("Power On");
          }
              
          boolean Comp(String par) {
              while (Serial.available() > 0) // Don't read unless
                                                 // there you know there is data
              {
                  ch = Serial.read(); // Read a character
                  string += ch; // Add it
              }
              
              if (par == string) {
                 string = "";
                 return(true);
              }
              else {
                 //dont reset string
                 return(false);
              }
          }
              
          void loop()
          {
              if (Comp("m1 on")) {
                  Serial.write("Motor 1 -> Online\n");
              }
              if (Comp("m1 off")) {
                  Serial.write("Motor 1 -> Offline\n");
              }
          }
          

          【讨论】:

            【解决方案11】:

            如果您使用的是 concatenate 方法,那么如果您使用的是 if else 方法,请不要忘记修剪字符串。

            【讨论】:

              【解决方案12】:

              serial.read() 上使用字符串附加运算符。比string.concat()效果更好

              char r;
              string mystring = "";
              
              while(serial.available()){
                  r = serial.read();
                  mystring = mystring + r; 
              }
              

              将流保存为字符串(本例中为 mystring)后,使用 SubString 函数提取您要查找的内容。

              【讨论】:

                【解决方案13】:

                我可以逃脱惩罚:

                void setup() {
                  Serial.begin(9600);
                }
                
                void loop() {
                  String message = "";
                  while (Serial.available())
                    message.concat((char) Serial.read());
                  if (message != "")
                    Serial.println(message);
                }
                

                【讨论】:

                  【解决方案14】:

                  许多很好的答案,这是我的 2 美分,具有问题中要求的确切功能。

                  此外,它应该更易于阅读和调试。

                  对最多 128 个输入字符的代码进行测试。

                  在 Arduino unor3 (Arduino IDE 1.6.8) 上测试

                  功能:

                  • 使用串行命令输入打开或关闭 Arduino 板载 LED(引脚 13)。

                  命令:

                  • LED.ON
                  • LED.OFF

                  注意:请记住根据您的板速更改波特率。

                  // Turns Arduino onboard led (pin 13) on or off using serial command input.
                  
                  // Pin 13, a LED connected on most Arduino boards.
                  int const LED = 13;
                  
                  // Serial Input Variables
                  int intLoopCounter = 0;
                  String strSerialInput = "";
                  
                  // the setup routine runs once when you press reset:
                  void setup() 
                  {
                    // initialize the digital pin as an output.
                    pinMode(LED, OUTPUT);
                  
                    // initialize serial port
                    Serial.begin(250000); // CHANGE BAUD RATE based on the board speed.
                  
                    // initialized
                    Serial.println("Initialized.");
                  }
                  
                  // the loop routine runs over and over again forever:
                  void loop() 
                  {
                    // Slow down a bit. 
                    // Note: This may have to be increased for longer strings or increase the iteration in GetPossibleSerialData() function.
                    delay(1);
                    CheckAndExecuteSerialCommand();  
                  }
                  
                  void CheckAndExecuteSerialCommand()
                  {
                    //Get Data from Serial
                    String serialData = GetPossibleSerialData();
                    bool commandAccepted = false;
                  
                    if (serialData.startsWith("LED.ON"))
                    {
                      commandAccepted = true;
                      digitalWrite(LED, HIGH);   // turn the LED on (HIGH is the voltage level)
                    }
                    else if  (serialData.startsWith("LED.OFF"))
                    {
                      commandAccepted = true;
                      digitalWrite(LED, LOW);    // turn the LED off by making the voltage LOW
                    }
                    else if (serialData != "")
                    {
                      Serial.println();
                      Serial.println("*** Command Failed ***");
                      Serial.println("\t" + serialData);
                      Serial.println();
                      Serial.println();
                      Serial.println("*** Invalid Command ***");
                      Serial.println();
                      Serial.println("Try:");
                      Serial.println("\tLED.ON");
                      Serial.println("\tLED.OFF");
                      Serial.println();
                    }
                  
                    if (commandAccepted)
                    {
                      Serial.println();
                      Serial.println("*** Command Executed ***");
                      Serial.println("\t" + serialData);
                      Serial.println();
                    }
                  }
                  
                  String GetPossibleSerialData()
                  {
                    String retVal;
                    int iteration = 10; // 10 times the time it takes to do the main loop
                    if (strSerialInput.length() > 0)
                    {
                      // Print the retreived string after looping 10(iteration) ex times
                      if (intLoopCounter > strSerialInput.length() + iteration)
                      {
                          retVal = strSerialInput;
                          strSerialInput = "";
                          intLoopCounter = 0;
                      } 
                      intLoopCounter++;
                    }
                  
                    return retVal;
                  }
                  
                  void serialEvent()
                  {  
                    while (Serial.available())
                    {    
                      strSerialInput.concat((char) Serial.read());
                    } 
                  }
                  

                  【讨论】:

                    【解决方案15】:

                    这总是对我有用:)

                    String _SerialRead = "";
                        
                    void setup() {
                      Serial.begin(9600);
                    }
                        
                    void loop() {
                      while (Serial.available() > 0)        //Only run when there is data available
                     {
                        _SerialRead += char(Serial.read()); //Here every received char will be
                                                            //added to _SerialRead
                        if (_SerialRead.indexOf("S") > 0)   //Checks for the letter S
                        {
                          _SerialRead = "";                 //Do something then clear the string
                        }
                      }
                    }
                    

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2015-08-03
                      • 1970-01-01
                      • 2021-10-09
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多