Kaip padalyti įeinančią eilutę?

Servo pozicijų sąrašą siunčiu per nuosekliąją jungtį į "arduino" tokiu formatu

1:90&2:80&3:180

Kuris būtų analizuojamas kaip:

servoId : Position & servoId : Position & servoId : Position

Kaip galėčiau suskaidyti šias vertes ir paversti jas sveikuoju skaičiumi?

Sprendimas

Skirtingai nei kiti atsakymai, aš verčiau laikyčiausi atokiau nuo String dėl šių priežasčių:

  • dinamiškas atminties naudojimas (dėl to gali greitai atsirasti aplinkos fragmentacija ir atminties išsekimas)
  • didelį lėtumą dėl konstravimo, naikinimo ir priskyrimo operatorių

Įterptinėje aplinkoje, pavyzdžiui, "Arduino" (net ir "Mega", turinčioje daugiau SRAM), verčiau naudoti standartines C funkcijas:

  • strchr(): simbolio paieška C eilutėje (t. y. char *)
  • strtok(): suskaido C eilutę į pojuostes pagal skiriamąjį simbolį
  • atoi(): konvertuoja C eilutę į int

Tai leistų sukurti tokį kodo pavyzdį:

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

Privalumas yra tas, kad nereikia atlikti jokio dinaminio atminties paskirstymo; galite netgi deklaruoti input kaip vietinį kintamąjį funkcijos, kuri skaitytų komandas ir jas vykdytų, viduje; kai funkcija grįžta, atstatomas input užimtas dydis (steke).

Komentarai (2)

Galėtumėte daryti panašiai, tačiau atsižvelkite į keletą dalykų:

Jei naudosite readStringUntil()`````, ji lauks, kol gaus simbolį arba pasibaigs laikas. Taigi su jūsų dabartine eilute paskutinė pozicija truks šiek tiek ilgiau, nes ji turi laukti. Kad išvengtumėte šio laiko limito, galite pridėti galinį simbolį ```&```. Šią elgseną galite lengvai patikrinti monitoriuje, pabandykite išsiųsti eilutę su papildoma ```& ir be jos, ir pamatysite tokį timeout uždelsimą.

Iš tikrųjų jums nereikia servopavarų indekso, galite tiesiog nusiųsti pozicijų eilutę ir gauti servopavarų indeksą pagal reikšmės poziciją eilutėje, pvz: 90&80&180&. Jei naudojate servo indeksą, galbūt norėsite jį patikrinti (konvertuoti į ````int````` ir tada suderinti su ciklo indeksu i), kad įsitikintumėte, jog jūsų pranešime neatsitiko nieko blogo.

Turite patikrinti, ar grįžtanti eilutė iš readStringUntil nėra tuščia. Jei funkcija užtruko, vadinasi, negavote pakankamai duomenų, todėl bet koks bandymas išgauti ```int```` reikšmes duos keistų rezultatų.


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

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

Galite naudoti Stream.readStringUntil(terminator), kiekvienai daliai nurodydami skirtingą terminatorių.

Tada kiekvienai daliai iškvieskite String.toInt.

Komentarai (0)