Saya mengirimkan daftar servo posisi melalui koneksi serial ke arduino dalam format berikut
1:90&2:80&3:180
Yang akan diuraikan sebagai:
servoId : Posisi & servoId : Posisi & servoId : Posisi
Bagaimana saya akan membagi nilai-nilai ini, dan mengkonversi mereka ke integer?
Sebaliknya untuk jawaban yang lain, saya'd agak menjauh dari String
untuk alasan berikut:
Dalam tertanam lingkungan seperti Arduino (bahkan untuk Mega yang memiliki lebih SRAM), I'd suka menggunakan fungsi-fungsi standar C:
strchr()
: mencari karakter dalam string C (yaitu char *
)strtok()
: membagi C string menjadi substring, berdasarkan karakter pemisah atoi()
: mengkonversi string C untuk sebuah int
Itu akan mengarah pada contoh kode berikut:
// Calculate based on max input size expected for one command
#define INPUT_SIZE 30
...
// Get next command from Serial (add 1 for final 0)
char input[INPUT_SIZE + 1];
byte size = Serial.readBytes(input, INPUT_SIZE);
// Add the final 0 to end the C string
input[size] = 0;
// Read each command pair
char* command = strtok(input, "&");
while (command != 0)
{
// Split the command in two values
char* separator = strchr(command, ':');
if (separator != 0)
{
// Actually split the string in 2: replace ':' with 0
*separator = 0;
int servoId = atoi(command);
++separator;
int position = atoi(separator);
// Do something with servoId and position
}
// Find the next command in input string
command = strtok(0, "&");
}
Keuntungan di sini adalah bahwa tidak ada alokasi memori dinamis berlangsung; anda bahkan dapat menyatakan input
sebagai variabel lokal dalam fungsi yang akan membaca perintah dan mengeksekusi mereka; setelah fungsi ini mengembalikan ukuran ditempati oleh input
(dalam stack) pulih.
Fungsi ini dapat digunakan untuk memisahkan string menjadi potongan-potongan yang didasarkan pada apa yang memisahkan karakter.
String xval = getValue(myString, ':', 0);
String yval = getValue(myString, ':', 1);
Serial.println("Y:" + yval);
Serial.print("X:" + xval);
Mengkonversi String ke int
int xvalue = stringToNumber(xval);
int yvalue = stringToNumber(yval);
Ini Potongan code yang mengambil string dan memisahkannya berdasarkan karakter tertentu dan kembali Item antara memisahkan karakter
String getValue(String data, char separator, int index)
{
int found = 0;
int strIndex[] = { 0, -1 };
int maxIndex = data.length() - 1;
for (int i = 0; i <= maxIndex && found <= index; i++) {
if (data.charAt(i) == separator || i == maxIndex) {
found++;
strIndex[0] = strIndex[1] + 1;
strIndex[1] = (i == maxIndex) ? i+1 : i;
}
}
return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
}
Anda bisa melakukan sesuatu seperti berikut, tetapi perlu mempertimbangkan beberapa hal:
Jika anda menggunakan readStringUntil()
, itu akan menunggu sampai menerima karakter atau timeout. Dengan demikian, dengan anda saat ini string, posisi terakhir akan berlangsung sedikit lebih lama, karena harus menunggu. Anda dapat menambahkan akhiran &
untuk menghindari hal ini timout. Anda dapat dengan mudah memeriksa perilaku ini di monitor anda, cobalah untuk mengirim string dengan dan tanpa tambahan &
dan anda akan melihat seperti penundaan waktu habis.
Anda sebenarnya tidak perlu servo indeks, anda hanya dapat mengirim string dari posisi, dan mendapatkan servo indeks dengan nilai posisi pada string, seperti: 90&80&180&
. Jika anda menggunakan servo indeks, mungkin anda ingin check it (mengkonversi ke int
, dan kemudian mencocokkan lingkaran indeks i) untuk memastikan bahwa tidak ada yang salah dengan pesan anda.
Anda harus memeriksa bahwa mengembalikan string readStringUntil
tidak kosong. Jika fungsi timeout, anda didn't menerima data yang cukup, dan dengan demikian setiap upaya untuk mengekstrak int
nilai-nilai akan menghasilkan hasil yang aneh.
void setup() {
Serial.begin(9600);
}
void loop() {
for(int i=1; i<=3; i++) {
String servo = Serial.readStringUntil(':');
if(servo != ""){
//here you could check the servo number
String pos = Serial.readStringUntil('&');
int int_pos=pos.toInt();
Serial.println("Pos");
Serial.println(int_pos);
}
}
}
Anda dapat menggunakan Streaming.readStringUntil(terminator)
melewati berbagai terminator untuk masing-masing bagian.
Pada setiap bagian anda kemudian memanggil String.toInt
Solusi yang paling sederhana adalah dengan menggunakan sscanf().
int id1, id2, id3;
int pos1, pos2, pos3;
char* buf = "1:90&2:80&3:180";
int n = sscanf(buf, "%d:%d&%d:%d&%d:%d", &id1, &pos1, &id2, &pos2, &id3, &pos3);
Serial.print(F("n="));
Serial.println(n);
Serial.print(F("id1="));
Serial.print(id1);
Serial.print(F(", pos1="));
Serial.println(pos1);
Serial.print(F("id2="));
Serial.print(id2);
Serial.print(F(", pos2="));
Serial.println(pos2);
Serial.print(F("id3="));
Serial.print(id3);
Serial.print(F(", pos3="));
Serial.println(pos3);
Ini memberikan output sebagai berikut:
n=6
id1=1, pos1=90
id2=2, pos2=80
id3=3, pos3=180
Cheers!
Lihat contoh di: https://github.com/BenTommyE/Arduino_getStringPartByNr
// splitting a string and return the part nr index split by separator
String getStringPartByNr(String data, char separator, int index) {
int stringData = 0; //variable to count data part nr
String dataPart = ""; //variable to hole the return text
for(int i = 0; i<data.length()-1; i++) { //Walk through the text one letter at a time
if(data[i]==separator) {
//Count the number of times separator character appears in the text
stringData++;
} else if(stringData==index) {
//get the text when separator is the rignt one
dataPart.concat(data[i]);
} else if(stringData>index) {
//return text and stop if the next separator appears - to save CPU-time
return dataPart;
break;
}
}
//return text if this is the last part
return dataPart;
}
String getValue(String data, char separator, int index)
{
int maxIndex = data.length() - 1;
int j = 0;
String chunkVal = "";
for (int i = 0; i <= maxIndex && j <= index; i++)
{
chunkVal.concat(data[i]);
if (data[i] == separator)
{
j++;
if (j > index)
{
chunkVal.trim();
return chunkVal;
}
chunkVal = "";
}
else if ((i == maxIndex) && (j < index)) {
chunkVal = "";
return chunkVal;
}
}
}
jfpoilpret disediakan besar jawaban untuk parsing perintah serial pada Arduino. Namun Attiny85 doesn't memiliki dua arah serial - SoftwareSerial untuk digunakan. Ini adalah bagaimana anda port kode yang sama untuk Attiny85
#include <SoftwareSerial.h>
// Calculate based on max input size expected for one command
#define INPUT_SIZE 30
// Initialize SoftwareSerial
SoftwareSerial mySerial(3, 4); // RX=PB3, TX=PB4
// Parameter for receiving Serial command (add 1 for final 0)
char input[INPUT_SIZE + 1];
void setup() {
mySerial.begin(9600);
}
void loop() {
// We need this counter to simulate Serial.readBytes which SoftwareSerial lacks
int key = 0;
// Start receiving command from Serial
while (mySerial.available()) {
delay(3); // Delay to allow buffer to fill, code gets unstable on Attiny85 without this for some reason
// Don't read more characters than defined
if (key < INPUT_SIZE && mySerial.available()) {
input[key] = mySerial.read();
key += 1;
}
}
if (key > 0) {
// Add the final 0 to end the C string
input[key] = 0;
// Read each command pair
char* command = strtok(input, "&");
while (command != 0)
{
// Split the command in two values
char* separator = strchr(command, ':');
if (separator != 0)
{
// Actually split the string in 2: replace ':' with 0
*separator = 0;
int servoId = atoi(command);
++separator;
int position = atoi(separator);
}
// Find the next command in input string
command = strtok(0, "&");
}
}
}
Sketsa mengkompilasi menjadi:
Sketch uses 2244 bytes (27%) of program storage space. Maximum is 8192 bytes.
Global variables use 161 bytes (31%) of dynamic memory, leaving 351 bytes for local variables. Maximum is 512 bytes.
Jadi ada banyak ruang dan memori untuk sisa dari kode
char str[] = "1:90&2:80&3:180"; // test sample serial input from servo
int servoId;
int position;
char* p = str;
while (sscanf(p, "%d:%d", &servoId, &position) == 2)
{
// process servoId, position here
//
while (*p && *p++ != '&'); // to next id/pos pair
}
It's tidak menjawab pertanyaan anda, tapi mungkin bisa berguna bagi seseorang. Jika anda string memiliki awalan tertentu, maka anda dapat menggunakan hanya startsWith
dan substring
. E. g.
void loop ()
if(Serial.available()){
command = Serial.readStringUntil('\n');
Serial.println("Received command: " + command);
if(command.startsWith("height")) {
Serial.println(command.substring(7));
}
}
}
Dan kemudian mengirim ketinggian 10
apa yang akan mengekstrak 10
.
Berikut ini adalah Arduino metode untuk membagi String sebagai jawaban untuk pertanyaan "Bagaimana untuk membagi string di substring?" dinyatakan sebagai duplikat dari pertanyaan ini.
Tujuan dari solusi untuk mengurai serangkaian GPS posisi login ke SD file. Alih-alih memiliki String yang diterima dari Berantai
, String yang dibaca dari file.
Fungsi adalah StringSplit()
mengurai String sLine = "1.12345,4.56789,hello"
3 String sParams[0]="1.12345"
, sParams[1]="4.56789"
& sParams[2]="hello"
.
String sInput
: jalur input untuk diurai,char cDelim
: karakter delimiter antara parameter,String sParams[]
: array output parameter,int iMaxParams
: jumlah maksimum dari parameter,int
: jumlah parsing parameter,Fungsi ini didasarkan pada String::indexOf()
dan String::substring()
:
int StringSplit(String sInput, char cDelim, String sParams[], int iMaxParams)
{
int iParamCount = 0;
int iPosDelim, iPosStart = 0;
do {
// Searching the delimiter using indexOf()
iPosDelim = sInput.indexOf(cDelim,iPosStart);
if (iPosDelim > (iPosStart+1)) {
// Adding a new parameter using substring()
sParams[iParamCount] = sInput.substring(iPosStart,iPosDelim-1);
iParamCount++;
// Checking the number of parameters
if (iParamCount >= iMaxParams) {
return (iParamCount);
}
iPosStart = iPosDelim + 1;
}
} while (iPosDelim >= 0);
if (iParamCount < iMaxParams) {
// Adding the last parameter as the end of the line
sParams[iParamCount] = sInput.substring(iPosStart);
iParamCount++;
}
return (iParamCount);
}
Dan penggunaan sangat sederhana:
String sParams[3];
int iCount, i;
String sLine;
// reading the line from file
sLine = readLine();
// parse only if exists
if (sLine.length() > 0) {
// parse the line
iCount = StringSplit(sLine,',',sParams,3);
// print the extracted paramters
for(i=0;i<iCount;i++) {
Serial.print(sParams[i]);
}
Serial.println("");
}