Преобразовать serial.read() в полезную строку с помощью Arduino?

Я использую два Arduinos для отправки текстовых строк друг другу с помощью newsoftserial и приемопередатчика RF.

Каждая строка длиной 20-30 символов. Как преобразовать Serial.read() в строку, чтобы я мог делать if x == "testing statements" и т.д.?

Ответ 1

Из Справка с Serial.Read() Получение строки:

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

Ответ 2

Неограниченное количество строк

  String content = "";
  char character;

  while(Serial.available()) {
      character = Serial.read();
      content.concat(character);
  }

  if (content != "") {
    Serial.println(content);
  }

Ответ 3

Вы можете использовать Serial.readString() и Serial.readStringUntil() для разбора строк из Serial на Arduino.

Вы также можете использовать 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

Ответ 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

Лучшим и наиболее интуитивным способом является использование обратного вызова 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();
}

Ответ 7

Если вы хотите читать сообщения из последовательного порта, и вам нужно иметь дело с каждым отдельным сообщением отдельно, я предлагаю разделить сообщения на части с помощью разделителя следующим образом:

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

Таким образом вы получите одно сообщение каждый раз, когда используете эту функцию.

Ответ 8

Вот более надежная реализация, которая обрабатывает ненормальные условия ввода и гонки.

  • Он обнаруживает необычно длинные входные значения и безопасно их отбрасывает. Например, если источник имел ошибку и генерировал ввод без ожидаемого терминатора; или был злонамерен.
  • Он гарантирует, что строковое значение всегда заканчивается на нуль (даже если размер буфера полностью заполнен).
  • Ожидает, пока не будет зафиксировано полное значение. Например, задержки передачи могут привести к тому, что 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\")");
  }
}

Ответ 9

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

Ответ 10

Если вы используете метод concatenate, не забудьте обрезать строку, если вы работаете с методом if else.

Ответ 11

Используйте оператор добавления строки на serial.read(). Он работает лучше, чем string.concat()

char r;
string mystring = "";

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

После того, как вы закончите сохранение потока в строке (в этом случае, в качестве параметра mystring), используйте функции SubString для извлечения того, что вы ищете.

Ответ 12

Кредит для этого идет на магму. Отличный ответ, но здесь он использует строки стиля С++ вместо строк стиля 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");
    }
}

Ответ 13

Это всегда работает для меня:)

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

Ответ 14

Я мог бы уйти от этого:

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

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

Ответ 15

Много отличных ответов, вот мои 2 цента с точной функциональностью, как было задано в вопросе.

Плюс это должно быть немного легче читать и отлаживать.

Код проверен до 128 символов ввода.

Протестировано на Arduino uno r3 (Arduino IDE 1.6.8)

Функциональность:

  • Включает или выключает Arduino на выводе (контакт 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());
  } 
}