Hogyan bonthatom fel a bejövő karakterláncot?

A soros kapcsolaton keresztüli szervo pozíciók listáját küldöm az arduino-nak a következő formátumban

1:90&2:80&3:180 

Amit a következőként értelmeznének:

servoId : Position & servoId : Position & servoId : Position

Hogyan osztanám fel ezeket az értékeket, és konvertálnám őket egész szám?

Megjegyzések

  • Slave (arduino uno) sztringet küldök a 30-as sorozaton keresztül; 12.4; 1 és 1 master (esp8266) recive string szeretném, ha a masterben külön adatok lennének, például 30 12.4 1, és elmenteném azokat a micro SD kártyára

Válasz

Ezzel ellentétben a többi válaszra inkább a következő okok miatt kerülnék távol a String t:

  • dinamikus memóriahasználat (ami gyorsan vezethet a halom töredezettség és memória kimerültség )
  • meglehetősen lassú a konstrukt miatt uction / destruction / assignment operátorok

Olyan beágyazott környezetben, mint az Arduino (még egy mega esetében is, amelynek több SRAM-ja van), inkább a következőt használom: normál C függvények :

  • strchr() : keressen egy karaktert egy C karakterláncban (pl char *)
  • strtok() : feloszt egy C karakterlánc szubsztrátumokká, elválasztó karakter alapján
  • atoi() : konvertál egy C karakterlánc egy int

Ez a következő kódmintához vezetne:

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

Az előnye, hogy nem történik dinamikus memória-allokáció; akár a input -t is deklarálhatjuk helyi változóként egy függvényen belül, amely elolvassa a parancsokat és végrehajtja őket; amint a függvény visszaadódik, helyreáll a input (a veremben) által elfoglalt méret.

Megjegyzések

  • Hadn ‘ nem gondolt a memória kérdésére. ez nagyszerű.
  • Kiváló. A válaszom nagyon ” arduino ” alapú volt, és tipikus arduino SDK funkciókat használtam, amelyeket egy új felhasználó jobban meg tudott szokni, de ez a válasz mit kell tenni a ” gyártási ” rendszereknél. Általában próbáljon meg elkerülni a beágyazott rendszerek dinamikus memória-allokációját.

Válasz

Ez a funkció használható hogy egy karakterlánc darabokra legyen elválasztva az elválasztó karakter alapján.

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

A karakterlánc konvertálása int

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

Ez a kódrészlet egy karakterláncot vesz fel, és egy adott karakter alapján elválasztja és visszaadja az elválasztó karakter közötti elemet

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

Megjegyzések

  • ez egy gyönyörű tökéletes válasz! nagyon köszönöm!
  • Ezt kell választania. (Remek)
  • elegáns! tökéletesen működik kulcsértékpárok küldéséhez

Válasz

A következőkhöz hasonlót tehet, de kérjük, vegye figyelembe számoljon be több dolgot:

Ha az readStringUntil() t használja, akkor megvárja, amíg megkapja a karaktert vagy az időtúllépést. Így a jelenlegi karakterlánccal az utolsó pozíció egy kicsit tovább fog tartani, mivel várnia kell. Az időkorlát elkerülése érdekében hozzáadhat egy záró & pontot. Könnyedén ellenőrizheti ezt a viselkedést a monitoron, megpróbálhatja elküldeni a karakterláncot az extra & nélkül és anélkül, és ilyen késleltetési időt fog látni.

Valóban nincs szüksége a szervo indexre, egyszerűen elküldheti a pozíciósorozatot, és a szervo indexet megkapja a karakterlánc értékhelyzetével, például: 90&80&180&. Ha a szervo indexet használja, akkor valószínűleg meg akarja ellenőrizni (konvertáljon int fájlra, majd illessze meg az i ciklusindexet), hogy megbizonyosodjon arról, hogy semmi sem romlott az üzenetével.

Ellenőriznie kell, hogy az readStringUntil visszatérő karakterlánca nem üres-e. Ha a funkció időkorlátjai nem kaptak elegendő adatot, így minden kísérlet, amely az int értékek kibontására szolgál, furcsa eredményeket fog eredményezni.

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

Megjegyzések

  • Ez nagyon jó megoldásnak tűnik, köszönöm. A példa tökéletesen tisztázza
  • Mi lenne, ha lenne meghatározatlan számú szervo bemenet? példámban 3 volt. De mi lenne, ha néha több vagy kevesebb lenne. Tudna ajánlani egy ilyen forgatókönyv kezelésére
  • Biztos: Két lehetőség van. 1 .Először küldje el a szervók számát: 3: val1 & val2 & val3 &, olvassa el ilyen számot a hurok megkezdése előtt. 2. Használjon másik terminátort annak jelzésére, hogy nincs több szervója, hurok, amíg meg nem találja: val1 & val2 & val3 & # például.
  • Örülök, hogy ez a megoldás segített neked, @ValrikRobot. Kérem, erősítsd meg a választ, ha hasznos volt?
  • vagy te csak eltávolíthatja a for-t, és így a kód csak akkor működik, amikor parancsot küld.

Válasz

Használhatja a Stream.readStringUntil(terminator) elemeket, amelyek minden részhez más-más terminátort adnak át.

Minden résznél akkor hívja a következőt: String.toInt

Válasz

A legegyszerűbb megoldás a sscanf () használata.

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

Ez a következő kimenetet adja:

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

Egészségére!

Hozzászólások

  • A serial.read () esetén nem működik … bármely i Dea miért? A következő hibát kapom: invalid conversion from 'int' to 'char*' [-fpermissive]

Válasz

Lásd a példát: 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; } 

Válasz

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

Válasz

jfpoilpret nagyszerű választ adott az Arduino soros parancsának elemzéséhez. Az Attiny85-nek azonban nincs kétirányú sorozata – a SoftwareSerialt kell használni. Így hordozza ugyanazt a kódot az 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, "&"); } } }  

Attiny85 sémák a pin-számokhoz ide írja be a kép leírását

A vázlat a következőkbe áll:

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. 

Tehát bőven van hely és memória a kód többi részéhez

Megjegyzések

  • Hogyan lehet egy ATtiny85 sorozatról olvasni, nem ‘ nem igazán része a kérdésnek.
  • Sajnálom eltér a kérdéstől, de az Attiny számára elérhető közösség és erőforrások sokkal kisebbek, mint az Arduino esetében. Az olyan emberek, mint én, akik válaszokat keresnek, Arduino kulcsszót használnak, és néha nagyon trükkös helyzetekbe kerülnek, amikor Arduino kódot helyeznek el Az Attiny nem mindig triviális: az eredeti kódot konvertálni kellett az Attiny-ra, tesztelni kellett, és úgy döntött, hogy sha újra
  • Ez a webhely Q & A formátumú. A válaszoknak válaszolniuk kell a kérdésre. A tiéd csak hozzáad valamit, ami ‘ nincs kapcsolatban vele.

Válasz

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 } 

Válasz

Itt van Arduino metódus egy karakterlánc felosztásához válaszként a “Hogyan lehet szétválasztani egy karakterláncot az alfejezetben?” kérdésre válaszolva a jelen kérdés másolata.

A megoldás célja a GPS sorozatának elemzése. SD-kártya fájlba bejelentkezett pozíciók. Ahelyett, hogy egy karakterláncot kapna az Serial címről, a karakterláncot fájlból olvassa be.

A függvény StringSplit() elemzés a karakterlánc sLine = "1.12345,4.56789,hello" – 3 karakterlánc sParams[0]="1.12345", sParams[1]="4.56789" & sParams[2]="hello".

  1. String sInput: az elemzendő bemeneti sorok,
  2. char cDelim: a paraméterek közötti elválasztó karakter,
  3. String sParams[]: a paraméterek kimeneti tömbje,
  4. int iMaxParams: a paraméterek maximális száma,
  5. Output int: az elemzett szám paraméterek,

A függvény a String::indexOf() és a String::substring() alapú:

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

És a használata nagyon egyszerű:

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

válasz

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

Válasz

Ez nem válasz a kérdésedre, de hasznos lehet valakinek. Ha a karakterláncnak van egy meghatározott előtagja, akkor egyszerűen használhatja a startsWith és a substring parancsokat. Pl.

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

Ezután küldje el height 10, hogy mi fogja kivonni a 10 .

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük