Bagaimana cara membagi masuk string?

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?

Mengomentari pertanyaan (1)
Larutan

Sebaliknya untuk jawaban yang lain, saya'd agak menjauh dari String untuk alasan berikut:

  • dinamis penggunaan memori (yang dapat dengan cepat menyebabkan tumpukan fragmentasi dan memori kelelahan)
  • cukup lambat karena konstruksi/kehancuran/assignment operator

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.

Komentar (2)

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 
Komentar (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
Komentar (5)

Anda dapat menggunakan Streaming.readStringUntil(terminator) melewati berbagai terminator untuk masing-masing bagian.

Pada setiap bagian anda kemudian memanggil String.toInt

Komentar (0)

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!

Komentar (1)

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; iindex) {
            //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;
}
Komentar (0)

String getValue(String data, char separator, int index)
{
    int maxIndex = data.length() - 1;
    int j = 0;
    String chunkVal = "";

    for (int i = 0; i 
Komentar (0)

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 

// 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, "&");
    }
  }
}

Attiny85 skema nomor pin

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

Komentar (3)
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
}
Komentar (0)
void setup() {
Serial.begin(9600);
char str[] ="1:90&2:80";
char * pch;
pch = strtok(str,"&");
printf ("%s\n",pch);

pch = strtok(NULL,"&"); //pch=next value
printf ("%s\n",pch);
}
void loop(){}
Komentar (0)

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.

Komentar (0)

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".

  1. String sInput: jalur input untuk diurai,
  2. char cDelim: karakter delimiter antara parameter,
  3. String sParams[]: array output parameter,
  4. int iMaxParams: jumlah maksimum dari parameter,
  5. Output 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
Komentar (0)