Come si divide una stringa in entrata?

Sto inviando una lista di posizioni del servo attraverso la connessione seriale all'arduino nel seguente formato

1:90&2:80&3:180

Che verrebbe analizzato come:

servoId : Posizione & servoId : Posizione & servoId : Posizione.

Come potrei dividere questi valori e convertirli in un intero?

Soluzione

Contrariamente ad altre risposte, preferisco stare lontano da String per i seguenti motivi:

  • uso dinamico della memoria (che può portare rapidamente alla frammentazione dell'heap e esaurimento della memoria)
  • abbastanza lento a causa degli operatori di costruzione/distruzione/assegnazione

In un ambiente embedded come Arduino (anche per un Mega che ha più SRAM), preferirei usare funzioni C standard:

  • strchr(): cerca un carattere in una stringa C (cioè char *)
  • strtok(): divide una stringa C in sottostringhe, basandosi su un carattere separatore
  • atoi(): converte una stringa C in un `int

Questo porterebbe al seguente esempio di codice:

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

Il vantaggio qui è che non ha luogo alcuna allocazione dinamica di memoria; si può anche dichiarare input come variabile locale all'interno di una funzione che leggerebbe i comandi e li eseguirebbe; una volta che la funzione viene restituita si recupera la dimensione occupata da input (nello stack).

Commentari (2)

Potreste fare qualcosa come la seguente, ma tenete conto di diverse cose:

Se usate readStringUntil(), aspetterà finché non riceve il carattere o va in timeout. Quindi, con la tua stringa attuale, l'ultima posizione durerà un po' di più, dato che deve aspettare. Puoi aggiungere un trailing & per evitare questo timeout. Puoi facilmente controllare questo comportamento nel tuo monitor, prova a inviare la stringa con e senza l'extra & e vedrai questo ritardo di timeout.

In realtà non hai bisogno dell'indice del servo, puoi semplicemente inviare la tua stringa di posizioni, e ottenere l'indice del servo dalla posizione del valore nella stringa, qualcosa come: 90&80&180&. Se usi l'indice del servo, forse vuoi controllarlo (convertire in int, e poi abbinare l'indice i del loop) per assicurarti che nulla sia andato storto con il tuo messaggio.

Devi controllare che la stringa di ritorno da readStringUntil``` non sia vuota. Se la funzione va in timeout, non hai ricevuto abbastanza dati, e quindi ogni tentativo di estrarre i tuoi valoriint``` produrrà strani risultati.


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

void loop() {
    for(int i=1; i
Commentari (5)

Potete usare Stream.readStringUntil(terminator) passando un terminatore diverso per ogni parte.

Su ogni parte si chiama poi String.toInt

Commentari (0)