Convert serial.read() into a useable string using Arduino?

后端 未结 15 1049
盖世英雄少女心
盖世英雄少女心 2020-11-29 15:27

I\'m using two Arduinos to sent plain text strings to each other using newsoftserial and an RF transceiver.

Each string is perhaps 20-30 characters in length. How do

相关标签:
15条回答
  • 2020-11-29 16:07

    If you want to read messages from the serial port and you need to deal with every single message separately I suggest separating messages into parts using a separator like this:

    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;
    }
    

    This way you will get a single message every time you use the function.

    0 讨论(0)
  • 2020-11-29 16:09

    I could get away with this:

    void setup() {
      Serial.begin(9600);
    }
    
    void loop() {
      String message = "";
      while (Serial.available())
        message.concat((char) Serial.read());
      if (message != "")
        Serial.println(message);
    }
    
    0 讨论(0)
  • 2020-11-29 16:11

    This always works for me :)

    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
        }
      }
    }
    
    0 讨论(0)
  • 2020-11-29 16:14

    Here is a more robust implementation that handles abnormal input and race conditions.

    • It detects unusually long input values and safely discards them. For example, if the source had an error and generated input without the expected terminator; or was malicious.
    • It ensures the string value is always null terminated (even when buffer size is completely filled).
    • It waits until the complete value is captured. For example, transmission delays could cause Serial.available() to return zero before the rest of the value finishes arriving.
    • Does not skip values when multiple values arrive quicker than they can be processed (subject to the limitations of the serial input buffer).
    • Can handle values that are a prefix of another value (e.g. "abc" and "abcd" can both be read in).

    It deliberately uses character arrays instead of the String type, to be more efficient and to avoid memory problems. It also avoids using the readStringUntil() function, to not timeout before the input arrives.

    The original question did not say how the variable length strings are defined, but I'll assume they are terminated by a single newline character - which turns this into a line reading problem.

    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
    }
    

    Here is an example of it being used to read commands from the serial monitor:

    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\")");
      }
    }
    
    0 讨论(0)
  • 2020-11-29 16:16

    The best and most intuitive way is to use serialEvent() callback Arduino defines along with loop() and setup().

    I've built a small library a while back that handles message reception, but never had time to opensource it. This library receives \n terminated lines that represent a command and arbitrary payload, space-separated. You can tweak it to use your own protocol easily.

    First of all, a library, 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__
    

    To use it, in your project do this:

    #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;
      }
    }
    

    To use the received commands:

    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();
    }
    
    0 讨论(0)
  • 2020-11-29 16:17

    I was asking the same question myself and after some research I found something like that.

    It works like a charm for me. I use it to remote control my 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
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题