2011-04-17 16 views
67

Estoy usando dos Arduinos para enviar cadenas de texto plano entre ellos utilizando newsoftserial y un transceptor RF.¿Quieres convertir serial.read() en una cadena utilizable usando Arduino?

Cada cadena tiene quizás 20-30 caracteres de longitud. ¿Cómo convierto Serial.read() en una cadena para que pueda hacer if x == "testing statements", etc.?

+0

Por favor, compruebe mi respuesta a continuación, es mucho más fácil/simple de lo que la respuesta que eligió –

Respuesta

58

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

si esto no funciona, trate de añadir 'inData.trim'() en caso de que usemos la consola arduino, habrá nueva línea char. Este http://stackoverflow.com/questions/24961402/how-to-compare-string-from-serial-read funciona para mí –

+0

Esto no debería funcionar. La segunda instrucción "si" dentro del ciclo nunca se activará porque ya ha leído los datos seriales de la primera comparación "si". –

105

cadena ilimitado readed

String content = ""; 
    char character; 

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

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

Manera más confiable en un Arduino Leonardo que cualquiera de los otros métodos de lectura. Puede ser un problema en el uso de RAM debido a concat, pero si el boceto puede tomarlo, parece ser la mejor manera de hacerlo. –

+1

+1 - Este es el método más simple. –

+22

Muy útil y simple. Sin embargo, descubrí que tenía que poner una pequeña demora entre la lectura de cada personaje y la serie; de ​​lo contrario, imprimía cada carácter en una línea separada en lugar de concatenar. 'void setup() { Serial.begin (9600); // Inicializar el puerto serie } void loop() { String content = ""; personaje char; while (Serial.available()) { character = Serial.read(); content.concat (personaje); retraso (10); } if (content! = "") { Serial.println (contenido); } } ' –

11

que estaba pidiendo la misma pregunta a mí mismo y después de algunas investigaciones he encontrado algo por el estilo.

Funciona como un encanto para mí. Lo uso para controlar mi Arduino a distancia.

// 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 
     } 
    } 
} 
+1

es mejor que los mejores :-) – Jeevanantham

4

Esto sería manera más fácil:

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

La forma mejor y más intuitivo es usar serialEvent() de devolución de llamada Arduino define junto con el lazo() y configuración().

Hace un tiempo creé una pequeña biblioteca que maneja la recepción de mensajes, pero nunca tuve tiempo para abrirla. Esta biblioteca recibe \ n líneas terminadas que representan un comando y una carga útil arbitraria, separadas por espacios. Puede ajustarlo para usar su propio protocolo fácilmente.

En primer lugar, una biblioteca, 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__ 

Para usarlo, en su proyecto de hacer esto:

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

Para utilizar los comandos recibidos:

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

Puede usar Serial.readString() y Serial.readStringUntil() para analizar las cadenas de Serial en el Arduino.

También puede usar Serial.parseInt() para leer los valores enteros de la serie.

int x; 
String str; 

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

El valor a enviar a través de serie habría my string\n5 y el resultado sería str = "my string" y x = 5

+2

Estaba teniendo fluctuaciones de voltaje extrañas al intentar leer la entrada de serie en un búfer de caracteres manualmente, pero al usar 'Serial.readStringUntil()' solucionó todo para mí, e hizo el código más legible! ¡Gracias! –

+0

He probado y sí, es más fácil. Sin embargo, en comparación con el búfer de caracteres, esta operación requiere significativamente más tiempo y latencia. –

+0

Interesante, ¿puedes compartir más detalles sobre tus hallazgos y la diferencia en el tiempo que estamos hablando aquí? Si tiene números detallados, me encantaría que los compartiera con nosotros. Gracias ! –

2

Si desea leer los mensajes desde el puerto serie y lo que necesita para hacer frente a cada mensaje por separado Sugiero separar los mensajes en partes utilizando un separador de la siguiente manera:

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 esta manera se obtendrá un único mensaje cada vez que se utiliza la función.

1

Si está utilizando el método concatenar, no olvide recortar la cadena si está trabajando con el método if else.

2

Aquí hay una implementación más robusta que maneja condiciones anormales de entrada y carrera.

  • Detecta valores de entrada inusualmente largos y los descarta con seguridad. Por ejemplo, si la fuente tenía un error y una entrada generada sin el terminador esperado; o fue malicioso.
  • Asegura que el valor de la cadena siempre es nulo terminado (incluso cuando el tamaño de la memoria intermedia está completamente lleno).
  • Espera hasta que se capture el valor completo. Por ejemplo, los retrasos en la transmisión pueden hacer que Serial.available() vuelva a cero antes de que el resto del valor termine de llegar.
  • No omite valores cuando varios valores llegan más rápido de lo que pueden procesarse (sujeto a las limitaciones del buffer de entrada en serie).
  • Puede manejar valores que son un prefijo de otro valor (por ejemplo, "abc" y "abcd" pueden leerse).

Utiliza deliberadamente matrices de caracteres en lugar del tipo String, para ser más eficaz y evitar problemas de memoria. También evita usar la función readStringUntil() para no tener que esperar hasta que llegue la entrada.

La pregunta original no decía cómo se definen las cadenas de longitud variable, pero supongo que terminan con un solo carácter de nueva línea, lo que lo convierte en un problema de lectura de línea.

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 
} 

Aquí es un ejemplo de lo que se utiliza para leer comandos desde el monitor serie:

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

Advertencia: A veces su cadena se enviará en dos o más piezas. Coloque un mensaje de "final del mensaje" para verificar que si concatena todos los caracteres del masaje. – flamaniac

1

Usar cadena operador de agregación en el serial.read(). Funciona mejor que string.concat()

char r; 
string mystring = ""; 

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

Después de que haya terminado el ahorro de la corriente en una cadena (mystring, en este caso), las funciones de uso subcadena a extraer lo que busca.

1

El crédito para esto va al magma. Gran respuesta, pero aquí está usando cadenas de estilo C++ en lugar de cadenas de estilo c. Algunos usuarios pueden encontrar eso más fácil.

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

que podía salirse con la suya:

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

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

Muchos grandes respuestas, aquí es mi 2 centavos con funcionalidad exacta como se pide en la pregunta.

Además, debería ser un poco más fácil de leer y depurar.

El código ha sido probado hasta 128 caracteres de entrada.

Probado en Arduino uno r3 (Arduino IDE 1.6.8)

Funcionalidad:

  • Activa Arduino bordo conducido (pin 13) en o fuera mediante la entrada de comando serie.

Comandos:

  • LED.ON
  • LED.OFF

Nota: Recuerde que para cambiar la velocidad de transmisión en base a su velocidad bordo.

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

Esto siempre funciona para mí :)

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