Kuinka jaan saapuvan merkkijonon?

Lähetän sarjakytkennän kautta luettelon servokohdista arduinolle seuraavassa muodossa

1:90&2:80&3:180 

Mikä jäsennetään muodossa:

servoId : Position & servoId : Position & servoId : Position

Kuinka jaan nämä arvot ja muunnan ne kokonaisluku?

Kommentit

  • minulla on orja (arduino uno) lähettää merkkijono sarjan 30 kautta; 12.4; 1 ja 1 master (esp8266) recive string Haluan isäntälaitteessa olla erillisiä tietoja, kuten 30 12.4 1, ja tallentaa ne mikro-SD-kortille

Vastaa

Päinvastoin muihin vastauksiin, mieluummin pysyisin poissa String -palvelusta seuraavista syistä:

  • dynaaminen muistin käyttö (mikä voi nopeasti johtaa kasan pirstoutuminen ja muistin loppuminen )
  • melko hidas konstruktin vuoksi uction / hävittäminen / määritysoperaattorit

Sulautetussa ympäristössä, kuten Arduino (jopa Megalle, jolla on enemmän SRAM: ia), käytän mieluummin C-vakiotoiminnot :

  • strchr() : etsi merkki C-merkkijonosta (ts char *)
  • strtok() : jakaa C-merkkijono alaryhmiksi erotinmerkin perusteella
  • atoi() : muuntaa C-merkkijonon merkkijono int

Tämä johtaisi seuraavaan koodinäytteeseen:

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

Tässä on etu, että dynaamista muistin allokointia ei tapahdu; Voit jopa julistaa input paikalliseksi muuttujaksi toiminnon sisällä, joka lukee komennot ja suorittaa ne; kun funktio palautetaan, input (pinossa) käyttämä koko palautetaan.

Kommentit

  • Hadn ’ ei ajatellut muistia. tämä on hienoa.
  • Erinomaista. Vastaukseni oli hyvin ” arduino ” perustuva ja käytti tyypillisiä arduino SDK -toimintoja, joihin uusi käyttäjä voisi olla tottuneempi, mutta tämä vastaus on mitä pitäisi tehdä ” tuotanto ” -järjestelmille. Yritä yleensä välttää dynaamista muistin allokointia sulautetuissa järjestelmissä.

Answer

Tätä toimintoa voidaan käyttää erottaa merkkijono paloiksi sen perusteella, mikä erottava merkki on.

String xval = getValue(myString, ":", 0); String yval = getValue(myString, ":", 1); Serial.println("Y:" + yval); Serial.print("X:" + xval); 

Muunna merkkijono int

int xvalue = xvalue.toInt(xval); int yvalue = yvalue.toInt(yval); 

Tämä koodinpalaa vie merkkijonon ja erottaa sen annetun merkin perusteella ja palauttaa erottavan merkin välisen kohteen

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]) : ""; } 

kommentit

  • thats kaunis täydellinen vastaus! kiitos paljon!
  • Sinun pitäisi valita tämä. (Peukkua)
  • tyylikäs! toimii täydellisesti avainarvoparien lähettämiseen

Vastaus

Voit tehdä jotain seuraavista, mutta ota huomioon ottaa huomioon useita asioita:

Jos käytät readStringUntil(), se odottaa, kunnes se vastaanottaa merkin tai aikakatkaisut. Siten nykyisellä merkkijonollasi viimeinen sijainti kestää vähän kauemmin, koska sitä on odotettava. Voit lisätä lopun & tämän aikakatkaisun välttämiseksi. Voit helposti tarkistaa tämän käyttäytymisen monitorissasi, yrittää lähettää merkkijonon ylimääräisen & kanssa tai ilman, ja näet tällaisen aikakatkaisuviiveen.

Teet todella ei tarvitse servohakemistoa, voit vain lähettää merkkijonosi ja saada servoindeksin merkkijonon arvon sijainnin mukaan, esimerkiksi: 90&80&180&. Jos käytät servo-hakemistoa, haluat ehkä tarkistaa sen (muuntaa int -iksi ja sovittaa sitten silmukka-hakemisto i) varmistaaksesi, että viestissäsi ei mennyt pieleen.

Sinun on tarkistettava, että palaava merkkijono osoitteesta readStringUntil ei ole tyhjä. Jos funktion aikakatkaisut, et saanut tarpeeksi tietoa, ja siten kaikki yritykset purkaa int -arvosi tuottavat outoja tuloksia.

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); } } } 

kommentit

  • Tämä tuntuu erittäin hyvältä ratkaisulta kiitos. Esimerkki selvittää sen täydellisesti
  • Entä jos meillä olisi määrittelemätön määrä servotuloja? esimerkissäni oli 3. Mutta entä jos joskus sitä olisi enemmän tai vähemmän. Voitteko tarjota ehdotuksia tällaisen skenaarion käsittelemiseksi
  • Toki: On olemassa kaksi mahdollisuutta. 1 .Lähetä ensin servojen määrä: 3: val1 & val2 & val3 &, lue tällainen numero ennen silmukan aloittamista. 2. Käytä toista terminaalia ilmaisemaan, että sinulla ei ole enää servoja, silmukka, kunnes löydät sen: val1 & val2 & val3 & # esimerkiksi.
  • Onneksi tämä ratkaisu auttoi sinua, @ValrikRobot, voisitko vahvistaa vastauksen, jos se oli hyödyllinen?
  • vai sinä voi vain poistaa haun for, joten koodi toimii vain, kun lähetät komennon.

Vastaa

Voit käyttää Stream.readStringUntil(terminator) välittämällä jokaiselle osalle eri pääte.

Kummassakin osassa soitat sitten String.toInt

vastaus

Yksinkertaisin ratkaisu on käyttää 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); 

Tämä antaa seuraavan tuloksen:

n=6 id1=1, pos1=90 id2=2, pos2=80 id3=3, pos3=180 

Kippis!

Kommentit

  • Se ei toimi sarjassa.read () … mikä tahansa i dea miksi? Saan seuraavan virheen: invalid conversion from 'int' to 'char*' [-fpermissive]

Vastaa

Katso esimerkki osoitteesta: 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; } 

vastaus

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; } } } 

vastaus

jfpoilpret tarjosi loistavan vastauksen sarjakomennon jäsentämiseen Arduinossa. Attiny85: llä ei kuitenkaan ole kaksisuuntaista sarjaa – on käytettävä SoftwareSerialia. Näin siirrät saman koodin Attiny85: lle

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

Attiny85-kaaviot pin-numeroille kirjoita kuvan kuvaus tähän

Luonnos kääntyy:

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. 

Joten muulle koodille on tarpeeksi tilaa ja muistia

Kommentit

  • Kuinka lukea sarjasta ATtiny85: ssä, ei ’ ole oikeastaan osa kysymystä.
  • Anteeksi eroaa kysymyksestä, mutta Attinylle käytettävissä oleva yhteisö ja resurssit ovat paljon pienempiä kuin Arduinolle. Minun kaltaiset vastauksia etsivät ihmiset käyttävät Arduino -avainsanaa ja joutuvat joskus hyvin hankaliin tilanteisiin Arduino-koodia käytettäessä Attiny ei ole aina triviaali: Piti muuntaa alkuperäinen koodi toimimaan Attiny: n kanssa, testasi sen toimivan ja päätti sha uudelleen se
  • Tämä sivusto on muodossa Q & A. Vastausten tulisi vastata kysymykseen. Sinun vain lisää jotain, joka ’ ei liity siihen.

Vastaa

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 } 

Vastaa

Tässä on Arduino -menetelmä merkkijonon jakamiseksi vastauksena kysymykseen ”Kuinka jako merkkijono alalomakkeessa?” kaksoiskappale tästä kysymyksestä.

Ratkaisun tarkoituksena on jäsentää sarja GPS SD-kortin -tiedostoon kirjautuneet sijainnit. Merkkijono vastaanotetaan Serial -kohdan sijaan, mutta merkkijono luetaan tiedostosta.

Funktio on StringSplit() jäsennetty a Merkkijono sLine = "1.12345,4.56789,hello" – 3 merkkijonoa sParams[0]="1.12345", sParams[1]="4.56789" & sParams[2]="hello".

  1. String sInput: jäsennettävät syöttörivit,
  2. char cDelim: parametrien välinen erotinmerkki,
  3. String sParams[]: lähtöryhmä parametreja,
  4. int iMaxParams: parametrien enimmäismäärä,
  5. lähtö int: jäsennetty määrä parametrit,

Toiminto perustuu String::indexOf() ja 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); } 

Ja käyttö on todella yksinkertaista:

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(""); } 

Vastaa

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(){} 

Vastaa

Se ei ole vastaus kysymykseesi, mutta se voi olla hyödyllinen jollekulle. Jos merkkijonolla on tietty etuliite, voit käyttää yksinkertaisesti startsWith ja substring. Esim.

void loop () if(Serial.available()){ command = Serial.readStringUntil("\n"); Serial.println("Received command: " + command); if(command.startsWith("height")) { Serial.println(command.substring(7)); } } } 

Ja lähetä sitten height 10 mikä purkaa 10 .

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *