Convertir série.read () dans une chaîne utilisable en utilisant Arduino?

J'utilise deux Arduinos pour envoyer des chaînes de texte brut les unes aux autres en utilisant newsoftserial et un émetteur-récepteurRF .

Chaque chaîne a peut-être une longueur de 20 à 30 caractères. Comment puis-je convertir Serial.read() en une chaîne pour pouvoir faire if x == "testing statements", etc.?

68
demandé sur Peter Mortensen 2011-04-18 02:57:22

15 réponses

Depuis Aide avec série.Read () obtenir une chaîne:

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");
    }
}
59
répondu magma 2011-09-07 21:22:22

Chaîne illimitée lue

  String content = "";
  char character;

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

  if (content != "") {
    Serial.println(content);
  }
110
répondu user1415516 2012-09-15 18:27:55

, Vous pouvez utiliser Serial.readString() et Serial.readStringUntil() pour analyser les chaînes de Série sur l'Arduino.

Vous pouvez aussi utiliser Serial.parseInt() pour lire des valeurs entières de série.

int x;
String str;

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

, La valeur pour l'envoi de série serait my string\n5 et le résultat serait str = "my string" et x = 5

52
répondu Ihab Hajj 2014-08-13 20:59:38

Je posais moi-même la même question et après quelques recherches, j'ai trouvé quelque chose comme ça.

Ça marche comme un charme pour moi. Je l'utilise pour contrôler à distance mon 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
        }
    }
}
11
répondu ladislas 2013-06-11 19:13:09

Ce serait beaucoup plus facile:

 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");
 }
4
répondu mrv 2014-08-05 20:29:34

Le meilleur et le plus intuitif est d'utiliser serialevent () callback Arduino defines avec loop () et setup ().

J'ai construit une petite bibliothèque il y a quelque temps qui gère la réception des messages, mais je n'ai jamais eu le temps de l'ouvrir. Cette bibliothèque reçoit \N lignes terminées qui représentent une commande et une charge utile arbitraire, séparées par des espaces. Vous pouvez le modifier pour utiliser votre propre protocole facilement.

Tout d'abord, une bibliothèque, 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__

Pour l'utiliser dans votre projet ce:

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

Pour utiliser les commandes reçues:

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();
}
2
répondu Blazer 2013-09-28 11:44:06

Si vous voulez lire les messages du port série et que vous devez traiter chaque message séparément, je suggère de séparer les messages en parties en utilisant un séparateur comme ceci:

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

De cette façon, vous obtiendrez un seul message chaque fois que vous utilisez la fonction.

2
répondu Qurashi 2014-01-15 16:48:53

Voici une implémentation plus robuste qui gère les conditions d'entrée et de course anormales.

  • Il détecte des valeurs d'entrée inhabituellement longues et les rejette en toute sécurité. Par exemple, si la source a eu une erreur et a généré une entrée sans le terminateur attendu; ou était malveillant.
  • cela garantit que la valeur de la chaîne est toujours terminée par null (même lorsque la taille du tampon est complètement remplie).
  • Il attend que la valeur complète soit capturée. Par exemple, des retards de transmission pourraient Série.disponible () pour renvoyer zéro avant que le reste de la valeur ne finisse d'arriver.
  • ne saute pas les valeurs lorsque plusieurs valeurs arrivent plus rapidement qu'elles ne peuvent être traitées (sous réserve des limites du tampon d'entrée série).
  • peut gérer des valeurs qui sont un préfixe d'une autre valeur (par exemple, " abc "et" abcd " peuvent tous deux être lus).

Il utilise délibérément des tableaux de caractères au lieu du type String, pour être plus efficace et éviter les problèmes de mémoire. Il évite également d'utiliser le Fonction readStringUntil(), pour ne pas temporiser avant l'arrivée de l'entrée.

La question originale n'a pas dit comment les chaînes de longueur variable sont définies, mais je suppose qu'elles sont terminées par un seul caractère de nouvelle ligne - ce qui transforme cela en un problème de lecture de ligne.

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
}

Voici un exemple d'utilisation pour lire les commandes du moniteur série:

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\")");
  }
}
2
répondu Hoylen 2014-04-30 15:06:15
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();
}
2
répondu flamaniac 2014-09-26 10:13:40

Si vous utilisez la méthode concatenate, n'oubliez pas de couper la chaîne si vous travaillez avec la méthode if else.

1
répondu user3528736 2014-04-13 10:38:09

Utilisez l'opérateur string append sur la série.lire(). Cela fonctionne mieux que la chaîne.concat ()

char r;
string mystring = "";

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

Une fois que vous avez terminé d'enregistrer le flux dans une chaîne (mystring, dans ce cas), utilisez les fonctions de sous-chaîne pour extraire ce que vous recherchez.

1
répondu Sarosh 2014-10-07 11:00:02

Le crédit pour cela va au magma. Excellente réponse, mais ici, il utilise des chaînes de style C++ au lieu de chaînes de style c. Certains utilisateurs peuvent trouver cela plus facile.

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");
    }
}
1
répondu j_v_wow_d 2015-01-15 22:53:26

Cela fonctionne toujours pour moi :)

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
    }
  }
}
1
répondu TheJonaMr 2016-10-31 13:35:58

Je pourrais m'en sortir avec ceci:

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

void loop() {
  String message = "";
  while (Serial.available())
    message.concat((char) Serial.read());
  if (message != "")
    Serial.println(message);
}
0
répondu Bengt 2015-10-04 12:23:56

Beaucoup de bonnes réponses, voici mes 2 cents avec des fonctionnalités exactes comme demandé dans la question.

De plus, il devrait être un peu plus facile à lire et à déboguer.

Le Code est testé jusqu'à 128 caractères d'entrée.

Testé sur Arduino UNO r3 (Arduino IDE 1.6.8)

Fonctionnalité:

  • active ou désactive la DEL embarquée Arduino (broche 13) à l'aide de l'entrée de commande série.

Commandes:

  • LED.SUR
  • LED.Hors

Remarque: N'oubliez pas de changer la vitesse de transmission en fonction de la vitesse de votre carte.

// 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());
  } 
}
0
répondu Zunair 2016-08-30 04:40:44