Convert serial.read() into a useable string using Arduino?
我正在使用两个Arduino,使用newsoftserial和RF收发器相互发送纯文本字符串。
每个字符串的长度可能为20-30个字符。 如何将
读取无限字符串
1 2 3 4 5 6 7 8 9 10 11 | String content =""; char character; while(Serial.available()) { character = Serial.read(); content.concat(character); } if (content !="") { Serial.println(content); } |
从带有Seri??al.Read()的帮助中获取字符串:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | 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 "); } if (Comp("m1 off")==0) { Serial.write("Motor 1 -> Offline "); } } |
您可以使用
您也可以使用
1 2 3 4 5 6 7 8 9 10 11 12 | int x; String str; void loop() { if(Serial.available() > 0) { str = Serial.readStringUntil(' '); x = Serial.parseInt(); } } |
通过串行发送的值将是
5
我本人也在问同样的问题,经过一番研究,我发现了类似的问题。
对我来说,它就像是一种魅力。我用它来遥控我的Arduino。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | // 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 == ' ') { Serial.print("Arduino Received:"); Serial.print(inData); // You can put some if and else here to process the message juste like that: if(inData =="+++ "){ // DON'T forget to add" " at the end of the string. Serial.println("OK. Press h for help."); } inData =""; // Clear recieved buffer } } } |
这样会更容易:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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"); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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(); } |
这是处理异常输入和竞争条件的更强大的实现。
- 它检测到异常长的输入值并安全地丢弃它们。例如,如果源有错误并且生成的输入没有预期的终止符;还是恶意的。
- 这样可确保字符串值始终以null终止(即使缓冲区大小已完全填满)。
- 等待直到捕获到完整的值。例如,传输延迟可能导致Serial.available()在其余值完成到达之前返回零。
- 当多个值到达的速度比处理速度快时,不会跳过这些值(受串行输入缓冲区的限制)。
- 可以处理作为其他值前缀的值(例如,可以读入" abc"和" abcd")。
它故意使用字符数组而不是
最初的问题没有说明可变长度字符串是如何定义的,但我假设它们以单个换行符终止-这将使它变成行读取问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | 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 == ' ') { 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 != ' '); 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 } |
这是一个示例,用于从串行监视器读取命令:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 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")"); } } |
如果要从串行端口读取消息,并且需要分别处理每条消息,则建议使用如下分隔符将消息分成多个部分:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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; } |
这样,您每次使用该功能时都会收到一条消息。
最好和最直观的方法是使用Arduino定义的serialEvent()回调以及loop()和setup()。
我不久前建立了一个小库来处理消息接收,但是从来没有时间开放它。
该库接收 n代表命令的终止行和任意有效载荷,以空格分隔。
您可以对其进行调整以轻松使用自己的协议。
首先,一个库SerialReciever.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | #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 == ' ') { 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__ |
要使用它,请在您的项目中执行以下操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #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; } } |
要使用收到的命令:
1 2 3 4 5 6 7 8 9 10 | 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(); } |
值得赞扬的是岩浆。很好的答案,但是这里使用的是c ++样式字符串而不是c样式字符串。一些用户可能会发现这更容易。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | 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 "); } if (Comp("m1 off")) { Serial.write("Motor 1 -> Offline "); } } |
在serial.read()上使用字符串追加运算符。它比string.concat()更好
1 2 3 4 5 6 7 8 | char r; string mystring =""; while(serial.available()) { r = serial.read(); mystring = mystring + r; } |
将流保存为字符串(在本例中为mystring)之后,请使用SubString函数提取要查找的内容。
如果您使用的是串联方法,那么在使用if else方法时不要忘记修剪字符串。
这总是对我有用:)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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 } } } |
许多好答案,这是我的2美分,具有问题中要求的确切功能。
另外,它应该更易于阅读和调试。
代码经过测试,最多可输入128个字符。
在Arduino uno r3(Arduino IDE 1.6.8)上测试
功能:
- 使用串行命令输入打开或关闭Arduino板载LED(引脚13)。
命令:
- 带领
- 灯灭
注意:切记根据板速更改波特率。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | // 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 2 3 4 5 6 7 8 9 10 11 | void setup() { Serial.begin(9600); } void loop() { String message =""; while (Serial.available()) message.concat((char) Serial.read()); if (message !="") Serial.println(message); } |