String durchsuchen nach festen Zeichen

mschierer

Level-1
Beiträge
9
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

ich hoffe mir kann jemand helfen!? Ich bin leider nicht sehr Erfahren in der Programmierung.
Ich habe über eine Serielle Schnittstelle eine Waage an meine Wago 750-880 geschlossen, welche dauerhaft das aktuelle Gewicht sendet.
Das Signal kommt bei mir an. Das Problem ist nun, dass wenn der Buffer voll ist und wieder gelöscht wird, fängt die Karte irgendwo im String an zu empfangen. Da ich das nicht richtig erklären kann, habe ich ein Screenshot vom laufenden Programm gemacht.
Ich habe erst versucht nur nach Zahlen in dem String zu suchen oder immer nach der ersten Nummer. Die Position des Gewichts ändert sich jedoch immer.
Wie kann ich einen String nach einer festen Zeichenkette durchsuchen und dann nur die Werte vor dieser Kette lesen?
Ich hoffe ihr könnt mein Problem verstehen!? :confused:
 

Anhänge

  • Screenshot_Eingangswerte.jpg
    Screenshot_Eingangswerte.jpg
    472,3 KB · Aufrufe: 45
  • Screenshot_GlobaleVariable_der_Waage.jpg
    Screenshot_GlobaleVariable_der_Waage.jpg
    439,1 KB · Aufrufe: 32
serielle kommunikation ist ein stream d.h. du brauchst irgendwo eine Länge oder Ende-Kennung in dem Protokoll (oder fixe Größe der Werte) - wie sieht das Protokoll aus?
im Normalfall darfst du den seriellen Puffer nicht löschen, da du sonst nicht mehr sinnvoll den Anfang findest

ansonsten kannst du dich auch mal direkt mit Hercules http://new.hwg.cz/download/sw/version/hercules_3-2-6.exe an die serielle-Schnittstelle hängen und die "unverfälschte" Kommunikation hier Posten
HTErm wäre auch ok http://www.der-hammer.info/terminal/index.htm
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Über Hercules habe ich schon einmal kommuniziert. Das Ergebnis war wie auch über Codesys: XX.XXX_Kg_$R$N. Ich finde den Screenshot gerade aber nicht.
Dabei ist der hintere Teil (_Kg_$R$N) immer gleich. Das ist immer das Ende. Ich weiß aber nicht wie ich das Ende festhalten kann, damit ich den String bestimmen kann.
 
Ich weiß aber nicht wie ich das Ende festhalten kann, damit ich den String bestimmen kann.

keine Ahnung was du meinst - steck die empfangenen Happen (die nicht unbedingt ein vollständigen Wert enthalten muessen - wegen seriell) in einen Puffer und durchsuch diesen nach x Vorkommen von \r\n (es könnten ja
schon ein paar Werte vorher gekommen sein - oder ein halber ist jetzt vollständig...

deine Reveices könnten so Ablaufen (abhängig von Geschwindigkeit deiner seriellen Verbindung)

"11.22 Kg \r\n"
--> nach kopie in deinen Puffer steht da jetzt "11.22 Kg \r\n"
--> suchen nach \r\n -> ein Treffer - konvertieren und Treffer aus dem Puffer entfernen
"11.33 Kg"
--> nach kopie in deinen Puffer steht da jetzt "11.33 Kg"
--> suchen nach \r\n -> kein Treffer
" \r\n 22.33"
--> nach kopie in deinen Puffer steht da jetzt "11.33 Kg \r\n22.33"
--> suchen nach \r\n -> ein Treffer - konvertieren und Treffer aus dem Puffer entfernen
" Kg \r\n 44.33 Kg \r\n"
--> nach kopie in deinen Puffer steht da jetzt "22.33 Kg\r\n 44.33 Kg \r\n"
--> suchen nach \r\n ->2 Treffer - konvertieren und Treffer aus dem Puffer entfernen
usw.

und immer daran denke seriell ist kein Bus mit festen Paketgrößen sondern eher wie TCP/IP ist - du bekommst deine Daten in Happen zerlegt die
nicht unbedingt an den logischen Grenzen des Protokolls liegen (also anstatt [11.22 Kg\r\n] auch mal [11][.22 K][g\r\n] daher die Notwendigkeit des häppchenweise Verarbeitens
wird zu oft vergessen (oder ignoriert weils doch richtig aussieht) und dann heulen alle das RS232 soooo schwer ist - fiese ist nur wenn der Anfang der Kommunikation nicht sauber ist - also noch irgendwelche alten Daten reintröpfeln
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
hatte noch ein passendes C-Beispiel - auch seriell mit Trennung nach \r\n als funktionierendes Beispiel
sollte aber nicht schwer sein zu adaptieren

Code:
#include <stdio.h>
#include <string.h>
#include <assert.h>    

//fake daten für den seriellen empfang
const int SERIELL_HAPPEN = 5;
//diese pakete werden nacheinander "empfangen"
char* seriell_happen[SERIELL_HAPPEN]=
{
  "11.22 Kg\r\n",
  "11.33 Kg",
  "\r\n22.33",
  " Kg\r\n44.33 Kg\r\n",
  "55.66 Kg\r\n11.23 Kg\r\n",
};

//buffer fuer die eingangsdaten
const int BUFFER_CAPACITY = 1024;
char buffer[BUFFER_CAPACITY] = {0};
int buffer_size = 0; // wir fangen bei 0 an

int main()
{
  //------------------------------------
  //fake des seriellen empfangs
  for(int t = 0; t < SERIELL_HAPPEN; ++t)
  {
    char* happen_daten = seriell_happen[t];
    int happen_laenge = strlen(happen_daten);

    //-------------------------------------
    //ist der buffer schon zu voll?
    assert(buffer_size+happen_laenge < BUFFER_CAPACITY); //--> fehler

    //seriellen daten an das ende des buffers kopieren
    ::memcpy(buffer+buffer_size, happen_daten, happen_laenge);
    buffer_size = buffer_size + happen_laenge;

    //-------------------------------------
    //dann fertige pakete suchen

    int begin = 0;
    int ende = 0;

    int i = 0;
    while(i < buffer_size-1)
    {
      // stehen wir auf einem abschluss \r\n
      if( buffer[i]=='\r' && buffer[i+1]=='\n' )
      {
        ende = i; // hier faengt das \r\n an

        //ausgabe - hier dann den wert nochmal parsen nach "XX.YYYY Kg"
        for(int c = begin; c < ende; ++c){ printf("%c", buffer[c]); } printf("\n");
        //...[11.22 Kg[\r\n22.33

        begin = i+2; // der naechste start liegt hinter \r\n
      }
      ++i;
    }

    //wert(e) gefunden?
    if( ende != 0 )
    {
      //buffer verkuerzen
      int vorne_abschneiden_laenge = ende + 2; // mit \r\n

      //den verarbeiteten teil mit den daten dahinter ueberschreiben
      int rest_size = buffer_size - vorne_abschneiden_laenge;
      ::memcpy(buffer,buffer+vorne_abschneiden_laenge, rest_size);

      //buffer hinter den kopierten daten "bereinigen" - nicht unbedingt noetig
      ::memset(buffer+rest_size, 0, vorne_abschneiden_laenge);

      buffer_size = rest_size;
    }
    //-------------------------------------
  }
  return 0;
}

liefert dann die Werte

11.22 Kg
11.33 Kg
22.33 Kg
44.33 Kg
55.66 Kg
11.23 Kg
 
Zuletzt bearbeitet:
Ich habe vor kurzem mal eine Grafik gemacht, ist zwar fuer serielle Kommunikation ueber EtherCAT, ich denke jedoch das Prinzip ist sehr aehnlich zu Wago:
Wichtig ist hier wie schon erwaeht, dass du einen 'grossen' Buffer voll mit Bytes (einzelne Zeichen) hast, und daraus deine Werte herausfiltern musst.
SerialCom over EtherCAT.jpg
 
dass du einen 'grossen' Buffer voll mit Bytes

ist ein wenig unklar Formuliert - du hast einen grossen Buffer der ständig mit Empfangshäppchen erweitert wird
und jeweils nach dem Anhängen von vorne nach vollständigen Paketen durchsucht und davon bereinigt wird
man hat also immer 2 Buffer der erste mit dem gerade empfangenden Datenpakte von der Schnittstelle und ein zweiter in
dem man diese Empfangspakete sammelt und die fertigen Pakete verarbeitet - also immer schön, einstellen, schauen, einstellen, schauen, ...
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ok, aber mit dem kleinen Buffer has du eigentlich nichts zu tun. Und ganz genau genommen ist es einen Ringbuffer (der grosse), so dass keine Daten geloescht werden, es wird nur der 'Pointer darauf verschoben'

Den Begriff Buffer habe ich einfach mal vorausgesetzt gehabt...
http://en.wikipedia.org/wiki/Circular_buffer
 
den kleinen Buffer bekommt man vom System - SPS, Windows, whatever... und der ist meistens ein Ringpuffer also selbstüberschreibend wenn man nicht schnell genug ist

den grossen Buffer habe ich in meinem Beispiel als "normalen" (leichter zu implementieren aber mehr copy) Linear-Buffer gemacht weil ich nicht wusste
ob Codesys schon einen Ringbuffer anbietet - in diesem Falle aber für das Problem-Verständnis unrelevant ob Linear oder Circular

Buffer != Circular_Buffer

der Ringpuffer hat auch gefühlt den Nachteil des 0-Durchgangs und Start == Ende könnte Voll oder Leer bedeuten - das war mir dann hier zu viel
noch dazu ist die Kopieraktion bestimmt (in diesem Fall) weniger böse

aber du darfst mich aber gerne Überzeugen :)
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
die paar Folgeposts nach dem C-Code waren nur Implementations-Männer-Detailsgespräche zwischen
gloeru und mir

wie ich so schön schrieb

in diesem Falle aber für das Problem-Verständnis unrelevant ob Linear oder Circular oder whatever

Ist dir ungefähr klar was der C-Code macht - oder was du machen solltest?
 
Ich versuche das jetzt nochmal irgendwie zu lösen.......

du musst es so machen wie hier beschrieben: alles andere ist einfach falsch - die Implementationsdetails können sich unterscheiden aber nicht der Ablauf
und für gebastel ist das ganze dann doch viel zu klein

1. Fragen wenn was unklar und 2. nicht auf eine Copy&Paste Lösung hoffen :)
 
Danke für eure Hilfe!
Ich habe es geschafft! Ich habe es jetzt mit Bausteinen von OSCAT geregelt. Aber ihr habt mir den richtigen Denkanstoß gegeben.

Lösung.jpg
 
Zuviel Werbung?
-> Hier kostenlos registrieren
und wie sieht jetzt die Verarbeitung deiner seriellen Daten aus - dein Screenshot zeigt ja nur das parsen eines Wertes welchen wir hier GAR NICHT angesprochen haben

sammelst du jetzt deine Happen in einem Hilfspuffer und zerlegst den dann nach Vorkommen von \r\n - alles andere wäre einfach falsch und funktioniert nur wegen Glück - oder erleuchte mich
 
Oh, dann habe ich mich falsch ausgedrückt! Die Verarbeitung der seriellen Daten hatte ich schon fertig. Nur die Daten, die aus dem Puffer gegeben wurden stimmten nicht! Aber mit euren Denkanstößen hat dann auch mal der "Programmierdepp" (ich) das ganze verstanden!Serielle Verarbeitung.jpg
Ich durchsuche jetzt den String in dem Puffer nach der Position von 'Kg $R$N' ziehe dann von der aktuellen Position die Anzahl der Zeichen vom Gewicht vor 'Kg $R$N' ab. Dann lasse ich mir den String nur von dieser neuen Position ausgeben und begrenze ihn noch von links, damit ich nur den reinen Wert habe.
 
du Spassvogel!

das hättest du auch am Anfang sagen können - das macht alle 8!! Danke völlig sinnfrei - bedanke dich nicht für Sachen deren Sinn du in dem Kontext nicht verstehst
sonst denke andere wie ich das du Folgst und es bei deinem Problem hilft - besonders weil du ja schon eine Ringpuffer für deine Kommunikations nutzt...
war es so schwer zu erkennen das wir beide nur von der Kommunikation geredet habe - ich bin verwirrt

und aus welchen Post von uns hast du denn den Denkanstoss für die Oscat-Lösung bekommen???

Fürs nächste mal: Reduzier deine Frage aufs wesentliche, also nix mit seriell blabla - du hattest ein Problem mit dem parsen eines Strings mehr nicht - hätte vieles vereinfacht
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

ich hoffe mir kann jemand helfen!? Ich bin leider nicht sehr Erfahren in der Programmierung.
Ich habe über eine Serielle Schnittstelle eine Waage an meine Wago 750-880 geschlossen, welche dauerhaft das aktuelle Gewicht sendet.
Das Signal kommt bei mir an. Das Problem ist nun, dass wenn der Buffer voll ist und wieder gelöscht wird, fängt die Karte irgendwo im String an zu empfangen. Da ich das nicht richtig erklären kann, habe ich ein Screenshot vom laufenden Programm gemacht.
Ich habe erst versucht nur nach Zahlen in dem String zu suchen oder immer nach der ersten Nummer. Die Position des Gewichts ändert sich jedoch immer.
Wie kann ich einen String nach einer festen Zeichenkette durchsuchen und dann nur die Werte vor dieser Kette lesen?
Ich hoffe ihr könnt mein Problem verstehen!? :confused:

Hallo :), ich habe ein ähnliches Problem bei mir, es geht auch um Auslesen einer Serielle Schnittstelle. Mein Problem ist: Es wird eine Längemessung durchgeführt und angefordert, da ich sehr unerfahren bin in der Programmierung finde ich keine Lösung, wie ich mein Ergebnis, der auch durch den Baustein: SERIAL_INTERFACE realisiert wird, richtig auslesen kann. Ich verwende dafür Baugruppe -652 und WAGO 750-830
Die Messwerte werden immer in der selbe Reihenfolge Empfangen und der Protokoll sieht so aus:
Unbenannt2.JPGUnbenannt3.JPG

Meine Gedanke ist, die Werte die ich brauche befinden sich ab dem 6byte also "Length", ich weiss es aber nicht wie ich die Stelle richtig abfragen kann ...

Kann mir bitte jemand helfen
 
Wenn du ein String empfängst, dann nutze die Funktion MID() um Strings zu zerstückeln.
Wenn die Daten als Array (Datenblock) empfangen werden, kannst du direkt darauf zugreifen (DATA[6] usw), musst diese aber typecasten. Die einzelnen Bytes musst du zusammenführen. Je nachdem wie der Master die Daten formatiert hat.
 
Ring_Buffer erlaubt mir die Abfrage ReceiveBuffer[6] nicht, anscheind ist das kein Array, da die Fehlermeldung heißt, das es kein gültiger Aufruf für Ring_Buffer ist
1.JPG
Das Programm sieht bei mir wie in diesem Forum auch aus
MID() Baustein habe ich noch nie benutzt, werde ich gleich mal schauen wie der funktioniert ...
 
Zurück
Oben