2011-04-17 534 views
67

我使用兩個Arduinos使用newsoftserial和RF收發器將純文本字符串發送給對方。使用Arduino將serial.read()轉換爲可用字符串?

每個字符串的長度可能是20-30個字符。如何將Serial.read()轉換爲字符串,以便我可以執行if x == "testing statements"等?

+0

請你檢查我的回答如下,它比你選擇 – 2014-02-19 05:27:04

回答

58

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

如果沒有工作,嘗試添加的回答更爲簡單/簡單'inData.trim'()在我們使用arduino控制檯的時候,會有換行符。這個http://stackoverflow.com/questions/24961402/how-to-compare-string-from-serial-read適合我 – 2014-07-25 17:39:31

+0

這不應該工作。循環內的第二個「if」語句永遠不會觸發,因爲您已經從第一個「if」比較中讀取了串行數據。 – 2015-02-03 21:52:33

105

無限串readed

String content = ""; 
    char character; 

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

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

Arduino Leonardo比任何其他閱讀方法更可靠。可能是由於concat引起的內存使用問題,但如果草圖可以接受,它看起來就是這樣做的最佳方式。 – 2012-12-23 15:25:49

+1

+1 - 這是最簡單的方法。 – 2012-12-29 09:38:04

+22

非常有用和簡單。儘管如此,我發現我必須在讀取每個字符的序列之間放置一個小的延遲 - 否則它會將每個字符打印在單獨的行中,而不是拼接在一起。 'void setup(){ Serial.begin(9600); //初始化串口 } void loop() { String content =「」; char character; (Serial.available()){ character = Serial.read(); content.concat(character); 延遲(10); } if(content!=「」)Serial.println(content); } } ' – 2013-03-16 07:56:42

11

我被問同樣的問題我自己和一些研究之後,我發現類似的東西。

它對我來說就像一個魅力。我用它來遠程控制我的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 
     } 
    } 
} 
+1

它比最好的更好:-) – Jeevanantham 2014-05-15 04:59:45

4

這將是比較容易的方式:

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

最好的和最直觀的方法是使用的serialEvent()回調的Arduino與循環()和設置()定義了一起。

我已經建立了一個小型庫,它處理消息接收,但從來沒有時間開放它。 該庫接收\ 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(); 
} 
51

您可以使用Serial.readString()Serial.readStringUntil()從Arduino上的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

+2

當我嘗試手動讀取字符緩衝區中的串行輸入時,出現了奇怪的電壓波動,但是使用'Serial.readStringUntil()'爲我修復了這一切,並將代碼更具可讀性!謝謝! – 2016-01-27 00:31:43

+0

我測試過了,是的它更容易。然而,與字符緩衝區相比,此操作顯然需要更多時間和延遲。 – 2016-10-09 01:03:25

+0

有趣的是,你能分享一些關於你的發現的更多細節,以及我們在這裏討論的時間有多少差異? 如果你有詳細的數字,我會喜歡它,如果你願意與我們分享。謝謝 ! – 2016-10-09 18:30:25

2

如果你想讀從串口的消息,你需要單獨我建議應對每一個消息使用如下分隔符將消息分離成部分:

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

這樣,每次使用該函數時都會得到一條消息。

1

如果你使用連接方法,那麼不要忘記修剪字符串,如果你使用if else方法。

2

這是一個更強大的實現,可處理異常輸入和競態條件。

  • 它可以檢測異常長的輸入值,並安全地丟棄它們。例如,如果源發生錯誤並且生成的輸入沒有預期的終止符;或者是惡意的。
  • 它確保字符串值始終爲空(即使緩衝區大小已完全填滿)。
  • 它一直等到捕獲完整值。例如,傳輸延遲可能導致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\")"); 
    } 
} 
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

警告:有時候您的字符串將會以兩個或更多個部分發送。把一些「消息結束」字符檢查,如果你從按摩連接所有的字符。 – flamaniac 2014-09-26 10:45:53

1

使用串附加上serial.read運算符()。它比string.concat更好()

char r; 
string mystring = ""; 

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

您完成後的字符串保存流(MyString的,在這種情況下),使用字符串函數來提取你在找什麼。

1

對此的信任去了岩漿。很好的答案,但這裏使用的是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"); 
    } 
} 
0

我可以逃脫這樣的:

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

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

很多偉大的答案,這裏是我的2美分,確切的功能的問題提出要求。

加上它應該是更容易閱讀和調試。

代碼最多可測試128個字符的輸入。

測試Arduino uno r3(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()); 
    } 
} 
1

這總是對我的作品:)

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