TIA Probleme bei Datenempfang von TRCV

Zuviel Werbung?
-> Hier kostenlos registrieren
In jedem Fall (wie schon von mir geschrieben) hat der eingebaute Timer derzeit keine Auswirkung - also auch keine Änderung ...
Vielleicht überdenkst du dein Konstrukt noch einmal ...
Danke für deinen Hinweis, muss ich nochmals überdenken!

Hab mir mal folgende Logik für das Einlesen überlegt, jedoch sind noch ein paar Fehler drinnen. Wäre super wenn mir jemand weiterhelfen könnte...

Zur Logik: ich möchte Zeichen für Zeichen in einen 2ten Buffer kopieren bis ich das Stringende Zeichen erreiche. Dann werden die Daten ohne die Stringende Zeichen in einen String kopiert.

Code:
//Clear the Buffer
#Data.TempBuffer := #Data.ClearBuffer;

//Detect New Data Received and set Receive Trigger
#NdrPosEdge(CLK := #Internal.TRCV.Ndr,
            Q => #Internal.RcvReq);

#Processing.Ptr := 1;
#Processing.PosOfControlChar := 0;

//Receive Trigger for new data
IF #Internal.RcvReq
THEN
  #Data.RcvLen := #Internal.TRCV.RcvdLen;
  #Processing.Lenght := UDINT_TO_INT(#Data.RcvLen);
 
  FOR #i := 1 TO #Processing.Lenght
  DO
    #Data.TempBuffer[#Processing.Ptr] := #Data.InputBuffer[#i];
    #Processing.Ptr := #Processing.Ptr + 1;
    IF #Data.InputBuffer[#i] = #LineFeed
    THEN
      #Processing.PosOfControlChar := #i;
      #Processing.Cnt1 := #Processing.Ptr - (#Processing.PosOfControlChar - 1);
      #Processing.Cnt2 := INT_TO_UINT(#Processing.Cnt1);
      
      Chars_TO_Strg(Chars := #Data.InputBuffer,
                    pChars := 0,
                    Cnt := #Processing.Cnt2,
                    Strg => #Data."String");
    END_IF;
  END_FOR;
END_IF;
 
Habe das Programm nochmals angepasst: die Variable Ptr = 1 muss natürlich innerhalb der Schleife definiert werden, sonst werden die alten Daten wieder überschrieben.

Habe jetzt wieder das Problem, dass genau das 1te Zeichen fehlt...:). Wie müsste der Code denn dementsprechend angepasst werden?

aktuell: String = 767CE65$R
richtig wäre: String = 7767CE65

1651832454599.png
 
Zuviel Werbung?
-> Hier kostenlos registrieren
die Variable Ptr = 1 muss natürlich innerhalb der Schleife definiert werden, sonst werden die alten Daten wieder überschrieben.
eben weil sie ja im "if" beschrieben wird, werden die ersten Daten überschrieben oder?

Wenn du den Inhalt zweier Telegramme in einen Puffer werfen willst musst du dir merken wo das erste Telegramm aufgehört hat, damit du idealerweise dahinter weitermachen kannst.

Also eigentlich ist das weiterzählen der Variable in der Schleife schon richtig, das rücksetzen auf 1 sollte aber erst passieren wenn du
a) erfolgreich gelesen hast oder
b) du irgendwie die 20 erreicht hast

EDIT:
Ich meine auch, du möchtest eigentlich den Data.TempBuffer und nicht den Data.InputBuffer in einen String wandeln.
 
Zuletzt bearbeitet:
Wenn du den Inhalt zweier Telegramme in einen Puffer werfen willst musst du dir merken wo das erste Telegramm aufgehört hat, damit du idealerweise dahinter weitermachen kannst
so wie ich das verstehe muss ich das in meinem fall nicht machen. Telegramm 1 enthält die Zahl 7, jedoch keine Steuerzeichen!. Nur Telegramm2 mit den restlichen Daten enthält die Steuerzeichen. Deshalb denke ich, dass solange in TempBuffer kopiert werden kann bis das Steuerzeichen erkannt wird
Also eigentlich ist das weiterzählen der Variable in der Schleife schon richtig, das rücksetzen auf 1 sollte aber erst passieren wenn du
a) erfolgreich gelesen hast oder
b) du irgendwie die 20 erreicht hast
du meinst das Rücksetzen von #Processing.Ptr = 0 ? Hmm hast Recht da muas ich nochmals nachbessern.

EDIT:
Ich meine auch, du möchtest eigentlich den Data.TempBuffer und nicht den Data.InputBuffer in einen String wandeln.
stimmt hab ich vergessen. muss der Temp Buffer sein.
 
Deshalb denke ich, dass solange in TempBuffer kopiert werden kann bis das Steuerzeichen erkannt wird
ja aber du erwartest doch den String 7767CE65, sprich die Zahl "7" aus dem ersten Telegramm muss an den String vom 2. Telegramm "767CE65" + Steuerzeichen gehangen werden.

Dein Programm wie es hier steht kopiert doch erst das erste Telegramm mit "7" an die erste Stelle von deinem TempBuffer, bevor du genau die Stelle + die Folgenden mit dem zweiten Telegramm überschreibst.

das Stichwort hier ist wohl "solange", heißt vor "Übertragung Fertig" oder "Array Grenze erreicht" darfst du deinen Pointer nicht rücksetzen um den Puffer nicht zu überschreiben.

Vielleicht hab ichs aber auch ganz falsch verstanden
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Die beiden Telegramme kommen ja wahrscheinlich nicht direkt hintereinander. (Aus Sicht der SPS)
Die SPS sieht 2 Telegramme, jeweils mit NDR unnd LEN und Daten.
Beim Antriggern des Empfangs löscht du einmalig den Buffer und setzt den Pointer für die Stelle auf 1.
Dann wartest du auf das 1. NDR. Wenn das kommt kopierst du die Daten mit LEN ab Pointer in den ZwischenBuffer. Den Pointer setzt du auf die Stelle, wohin die nächsten Daten geschieben werden müssen. Außerdem prüfst du, ob schon Endezeichen da sind. Wenn ja, ist das in diesem Fall eigentlich ein Fehler, da du beim ersten NDR schon die Endekennung hast. Ich würde das verwerfen und einen Fehler ausgeben.
Beim 2.NDR kopierst du wieder LEN Daten ab ,dem nun auf das leere Zeichen dach dem ersten Empfang stehenden, Pointer in den Zwischenbuffer.
Nun prüfst du wieder auf Endekennung, wenn ja, dann den Zwischenbuffer in deinen String umkopieren, Zwischenbuffer löschen, Pointer auf 1, fertig. Wenn keine Endekennung, dann würde ich das verwerfen und eine Fehlermeldung ausgeben, denn auch dann paßt ja etwas nicht.

FÜr die SPS sieht das ganze so aus, als ob sie einfach 2 Datenpaktet bekommt und zwar auf jeden Fall nicht innerhalb eines SPS-Zyklus. Also mußt du dir immer "merken", in welchem Teil der Auswertung du gerade bist. Das macht im Prinzip gerade der Pointer und die Endekennung, aber du könntest auch noch zur Kontrolle eine Variable auf 1 und 2 hochzählen.

Online siehst du wahrscheinlich immer nur den 2. Teil, das geht so schnell, dass du das nicht sehen kannst. Tracen wäre noch eine Möglichkeit, also NDR, LEN und die Empfangsdaten mal ein einem Trace mitschneiden.
 
Ich habe mal einen kleinen FB geschrieben, den du hinter den TRCV hängen kannst, und der die einzeln empfangenen Daten vom TRCV zusammensetzt und bei Erkennung eines $R$L an "Strg" ausgibt.
Wenn es bei dir vorkommt, dass auch mal mehrere Kennungen in einem Rutsch vom TRCV empfangen werden, und du alle mitbekommen möchtest, dann solltest du dir an entsprechender Stelle einen Fifo programmieren. In der jetzigen Version wird an "Strg" nur der letzte Wert ausgegeben.

Eigentlich wollte ich mir das mit Adhoc bei meiner 1200er auch mal selber ansehen, aber meine Test-CPU ist so alt, da funktioniert das entgegen der Dokumentation nicht. Aber ich gehe mal davon aus, dass bei dir NDR vom TRCV auch nur einen Zyklus lang ansteht.
Code:
FUNCTION_BLOCK "TCPproto"

VERSION : 0.1
   VAR_INPUT
      TRCV_NDR : Bool;   // New data received
      TRCV_RCVD_LEN : UInt;   // Length of received data
      TRCV_DATA : Array[0..25] of Char;   // Received data
      RESET  : Bool;   // Rücksetzen der internen Speicherung
   END_VAR

   VAR_OUTPUT
      NDR : Bool;   // New data received
      ERROR : Bool;   // Es ist ein Fehler aufgetreten
      Strg  : String;   // Ergebnis String
   END_VAR

   VAR
      sBuf : Array[0..#BUF_MAX] of Char;   // Buffer
      sBuf_pos : Int;   // Buffer Länge / Index der Schreibposition
   END_VAR

   VAR_TEMP
      i : Int;
      j : Int;
      start : Int;
   END_VAR

   VAR CONSTANT
      BUF_MAX : Int := 49;
   END_VAR


BEGIN
    IF #RESET THEN
        #sBuf_pos := 0;
        #Strg := '';
    END_IF;
  
    #NDR := false;
    #ERROR := false;
    IF #TRCV_NDR THEN
        // Neue Daten an Buffer anhängen
        FOR #i := 0 TO UINT_TO_INT(#TRCV_RCVD_LEN) - 1 DO
            #sBuf[#sBuf_pos] := #TRCV_DATA[#i];
            #sBuf_pos += 1;
            IF #sBuf_pos > #BUF_MAX THEN // Buffer voll -> Fehler
                #ERROR := true;
                EXIT;
            END_IF;
        END_FOR;
      
        IF NOT #ERROR THEN
            // Nach $R$L suchen
            #start := 0;
            #i := 0;
            WHILE #i < #sBuf_pos - 1 DO
                IF #sBuf[#i] = '$R' AND #sBuf[#i + 1] = '$L' THEN
                    // Zeichen in String konvertieren ohne $R$L
                    Strg := '';
                    Chars_TO_Strg(Chars := #sBuf,
                                  pChars := #start,
                                  Cnt := INT_TO_UINT(#i - #start),
                                  Strg => #Strg);
                    // -> hier bei Bedarf Strg auf einen Fifo schieben
                  
                    // Startposition setzen für nächsten String, falls noch einer vorhanden sein sollte.
                    #start := #i + 2;
                    // $L überspringen
                    #i += 1;
                    #NDR := true;
                END_IF;
                #i += 1;
            END_WHILE;
          
            // Wenn Endekennung gefunden, dann Buffer an Null-Position neu ausrichten
            IF #start > 0 THEN
                IF #start < #sBuf_pos THEN
                    #j := 0;
                    FOR #i := #start TO #sBuf_pos DO
                        #sBuf[#j] := #sBuf[#i];
                        #j := #j + 1;
                    END_FOR;
                    // Neue Länge (Endposition) setzen
                    #sBuf_pos := #j - 1;
                ELSE
                    // Wenn keine Kennung gefunden, dann direkt auf Anfang
                    #sBuf_pos := 0;
                END_IF;
            END_IF;
        END_IF;
    END_IF;
  
    // Bei Fehler zurücksetzen
    IF #ERROR THEN
        #sBuf_pos := 0;
        #Strg := '';
    END_IF;
  
END_FUNCTION_BLOCK
 
Zuletzt bearbeitet:
Vielen Dank nochmals an alle für eure Lösungsansätze, nun funktioniert mein Programm so wie es sollte!!!

Ich habe mal einen kleinen FB geschrieben, den du hinter den TRCV hängen kannst, und der die einzeln empfangenen Daten vom TRCV zusammensetzt und bei Erkennung eines $R$L an "Strg" ausgibt.
Wenn es bei dir vorkommt, dass auch mal mehrere Kennungen in einem Rutsch vom TRCV empfangen werden, und du alle mitbekommen möchtest, dann solltest du dir an entsprechender Stelle einen Fifo programmieren. In der jetzigen Version wird an "Strg" nur der letzte Wert ausgegeben.
Hallo Thomas, habe dein Programm vorhin getestet und es funktioniert einwandfrei. 👌Ich weiß garnicht wie ich dir danken soll, für deinen geschriebenen FB!!(y). Jetzt ist mir auch die umgesetzte Logik klar!
 
Zurück
Oben