Step 7 SCL - Auswertung von Daten eines aufgerufenen FC's

MW

Level-1
Beiträge
1.186
Reaktionspunkte
272
Zuviel Werbung?
-> Hier kostenlos registrieren
Jetzt habe ich auch mal wieder ein kleines Problem mit einem für mich(kein SCL-Freak) unerklärlichen Verhalten beim Aufruf des FC50 (AG_LRECV).

Ich rufe in einem FC den FC50 auf und will dort immer nur ein Byte aus dem Empfangspuffer des CP's lesen und in anschliesssend in einen String einfügen.

Code:
VAR_INPUT
 ID : INT;      //Verbindungs-ID
 LADDR : WORD;  // Log. Adresse des CP 
END_VAR

VAR_IN_OUT
 NEW_DAT : BOOL ;       // alte Nachricht löschen    
 PUFFER : STRING[11] ;  // Zwischenspeicher der Nachricht
 REC_LEN : INT ;        // Länge der Empfangenen Nachricht
END_VAR

VAR_TEMP
[COLOR=#ff0000]tmp_byte[/COLOR]: BYTE;    
tmp_ndr: BOOL;
tmp_error: BOOL;
tmp_status: WORD;
tmp_len: INT;
tmp_str : STRING[11];  
END_VAR    


BEGIN
// Temp Initialisieren
[COLOR=#ff0000]tmp_byte[/COLOR]:= 63;
tmp_ndr := FALSE;
tmp_error := FALSE;
tmp_status := W#16#0;
tmp_len := 0;
tmp_str := PUFFER;

IF NEW_DAT  THEN    // Alte Daten löschen wenn neues Telegramm erwartet wird
    NEW_DAT := FALSE;
    tmp_str := '';
    REC_LEN := 0;
END_IF;

// Daten empfangen
AG_LRECV (ID:= ID,
          LADDR:= LADDR,
          RECV:= [COLOR=#ff0000]tmp_byte[/COLOR],
          NDR:= tmp_ndr,
          ERROR:= tmp_error,
          STATUS:= tmp_status,
          LEN:= tmp_len);

// Empfangenes Zeichen in String einfügen
IF tmp_ndr AND (REC_LEN < 11) THEN
    tmp_str := CONCAT (IN1:= tmp_str,                                
                       IN2:= BYTE_TO_CHAR([COLOR=#ff0000]tmp_byte[/COLOR])); 
    REC_LEN := REC_LEN + 1;                   
END_IF;

// String sichern
PUFFER:= tmp_str;

Jetzt zum Problem:
Die gewünschten Daten(7Bytes) werden vom CP empfangen und der AG_LRECV liest sie auch aus, sichtbar wird dies am hochzählen des "REC_LEN".
Im "PUFFER" kommen dabei nur 7 Fragezeichen(CHAR-Wert = 63) an, also der Wert mit dem "tmp_byte" initialisiert wurde, das wirklich empfangene Zeichen, das nach dem Aufruf des AG_LRECV in "tmp_byte" stehen müsste, wird einfach ignoriert.

Jetzt habe ich mir das mal in AWL angesehen, da kommt auszugsweise folgendes raus:
Code:
 L     #ID
      T     LW    20
      L     #LADDR
      T     LW    22
      L     DW#16#10020001
      T     LD    24
      L     W#16#0
      T     LW    28
      L     DW#16#87000000      [COLOR=#ff0000]// 87 = Vorgänger Lokaldaten - Adresse 0[/COLOR]
      T     LD    30
      UC    "AG_LRECV"
            P#L 20.0
            P#L 22.0
            P#L 24.0
            P#L 1.0
            P#L 1.1
            P#L 2.0
            P#L 4.0
      L     #tmp_byte
      UD    DW#16#FF
      L     W#16#100
      T     LW    20
      TAK   
      SLW   8
      L     LD    20
      UD    DW#16#FF0000FF
      OD    DW#16#10000
      OD    
      T     LD    20                 [COLOR=#ff0000]// Das müsste jetzt das empfangene Byte sein - landet in den aktuellen Lokaldaten Adresse 20[/COLOR]
      L     W#16#0
      T     LW    24
      L     DW#16#87000030
      T     LD    26
      L     W#16#0
      T     LW    30
      L     DW#16#870000A0 [COLOR=#ff0000]// 87 = Vorgänger Lokaldaten - Adresse 20[/COLOR]
      T     LD    32
      L     W#16#0
      T     LW    36
      L     DW#16#87000030
      T     LD    38
      UC    "CONCAT"
            P#L 24.0
            P#L 30.0
            P#L 36.0

Wieso arbeitet der SCL-Compiler beim Aufruf des CONCAT da mit den Vorgängerlokaldaten, wenn doch das konvertierte empfangene Byte in den aktuellen Lokaldaten abgelegt wurde?

Da ich mir das jetzt nicht erklären konnte, habe ich das "tmp_byte" aus dem oberen Beispiel mal in den INOUT Bereich verschoben, das Initialisieren mit der Zahl 63 weggelassen und die Variable "tmp_byte" von aussen mit einem Byte aus dem STAT-Bereich des aufrufenden FB's belegt. Jetzt landet im "Puffer" immer der Wert den die STAT-Variable "tmp_byte" besitzt, also auch nur Mist.

Wenn ich jetzt allerdings an diese INOUT-Variable ein Byte im Merkerbereich eingebe, funktioniert die ganze Sache auf einmal.

Ich könnte das ganz ja so lassen, sieht aber doof aus ich will jetzt auch wissen woran das liegt bzw. wie ich den Baustein ändern muss damit es auch mit der temp-Variable funktioniert.
 
Zuletzt bearbeitet:
Hallo MW,

ich habe nun gerade kein Step7 zur Hand und kann es deshalb nicht genau gegenchecken - aber :
erwartet der AG_LRecV am Eingang RecV nicht einen ANY-Pointer, der auf einen Speicherbereich (also z.B. ein Array of Byte) zeigt in dem seine Daten abgelegt werden sollen ?
Vielleicht erzeugst du dir mal dieses Array_of_Byte in ausreichender Größe und läßt da die Daten reinschreiben. Wenn dich dann nur der Inhalt des Byte 7 interessiert so kannst du ja dann auch nur auf den Index zugreifen.
Zum Debuggen von so etwas ist es m.E. auch immer ganz hilfreich, einen Empfangspuffer zunächst in einen statischen Bereich zu legen damit man sehen (und kontrollieren) kann, was ankommt.

Gruß
Larry
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Also die Bausteindokumentation des AG_LRECV sagt:
Der für die Datenübernahme angegebene Datenbereich kann ein PA-Bereich, ein Merkerbereich oder ein Datenbausteinbereich sein.
Es steht aber dort nichts von Lokaldaten. Allerdings hätte ich in dem Fall eine Fehlermeldung der Funktion erwartet, denn unter den Fehlercodes gibt es zumindest die Fehlermeldung des ungültigen Speicherbereichs. Evtl. mal die Bausteinversion prüfen, ob es da eine aktuellere gibt?
 
Ich würde mich Larry anschließen.
Hatte gerade bei einer 1500-er ein ähnlich gelagertes Problem.
Kannst du denn sicherstellen, dass immer nur eine Byte geschickt wird? Wenn der Empfangs-Bereich nicht paßt, wird nichts reingeschrieben, das hatte ich auch gerade, mit einem String (was man nicht machen sollte, wenn man nicht sicherstellen kann, dass auch ein "echter" S7-String vom Sender geschickt wird!) als Empfänger für Recv. Nur wenn dort in den ersten beiden Byte eine Ziffer stand (das ist ja Länge und Max.Länge des Strings), kam der String in RECV an. Waren dort irgendwelche anderen "ungültigen" Zeichen angekommen ($ z.B.), dann sah man die empfangen Zeichen an der Recive-Funktion , aber sie waren nicht im angelegten statischen String. (Fehlermeldung --> Nope, keine).
Lösung: "Array of Char", das war ja dann immer gültig und anschließend Wandlung in einen String.
Ähnliches würde ich mal mit deiner Funktion ebenfalls versuchen.
 
Zuletzt bearbeitet:
Danke für eure Tipps.

Der Grund warum ich immernur ein Byte aus dem Puffer des CP's lesen will, ist das ich derzeit ein Telegramm mit einer Länge von 7 Byte erwarte, die Gegenstelle kann mir aber später auch Telegramme mit anderer Länge über diese Verbindung(reines TCP) schicken. Deshalb will ich mit dem AG_LRECV jeden Zyklus nur ein Byte aus dem Puffer lesen und in einen String einfügen, wenn ich da eine feste Empfangslänge von mehr als einem Byte eintragen würde, könnte es bei der TCP-Verbindung zu Datenversatz kommen, falls zwischendurch mal ein Telegramm mit unerwarter Länge kommen würde.
In dem so empfangenen String sind auch Zeichen enthalten die ich nicht brauche (Nachrichtanfangs-, Nachrichtend-kennung usw.), aber ich kann ja den zusammengesetzten String einfach nach meinem erwarteten Code durchsuchen und wenn der gefunden wurde, gebe ich das als Meldung an den aufrufenden Baustein zurück.

@Larry: deine Vermutung ist korrekt, der AG_LRECV erwartet einen Any am Eingang.
In dem Any könnte man ja auch auf die aktuellen Lokaldaten verweisen wenn man es "zu Fuß" programmieren würde, aber der SCL-Compiler macht das aus einem mir bisher unerklärlichen Grund nicht und baut da die Vorgängerlokaldaten ein.

Der Hinweis von Thomas ist auch nicht schlecht, daran hatte ich jetzt garnicht gedacht, dass der FC eventuell garkeinen Verweis auf die Lokaldaten in dem Any zulässt. Aber wie du schon geschrieben hast, hätte ich da auch mal eine Fehlermeldung erwartet. Aber nö, er setzt das "NDR" Bit und meine Variable "REC_LEN" zählt dadurch schön bis 7 hoch, signalisiert mir so das die 7 Bytes empfangen wurden und das alles in Ordnung ist. Die 7 Bytes werden also gelesen, landen nur nicht da wo ich sie haben will.

Da ich das ganze bisher in einen FC geschrieben habe, kann ich die Empfangsdaten leider nicht in den Statischen Bereich legen, im Grunde interessiert mich das einzelne Byte ja auch nicht, da ich es ja sowieso in einen CHAR konvertiere und in einen String einfüge wo ich es dann beobachten kann.
Ich hatte ich es ja auch schon probiert dieses Empfangsbyte über die INOUT Schnittstelle an den FC zu übergeben und dann in den statischen Bereich des aufrufenden FB's zu speichern, wie im ersten Post erwähnt leider ohne Erfolg. Interessanterweise ging es aber wenn ich an dieses INOUT ein Merkerbyte von aussen übergab.

Im schlimmsten Fall belasse ich es bei der Verwendung dieses Merkerbytes, aber dank eurer Vorschläge/Hinweise kann ich morgen noch etwas weiter testen, vorrausgesetzt ich finde dafür Zeit. :rolleyes:
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich vermute ebenfalls, daß der AG_LRECV nicht mit RECV-Puffer in TEMP klarkommt. Der ANY-Pointer auf tmp_byte wird vom Compiler jedenfalls korrekt als "P#V0.0 BYTE 1" erstellt.
(1) Wenn Du sowieso nur 1 Byte empfangen willst, dann versuche mal den FC6 AG_RECV (Familie: CP_400) anstatt FC60 AG_LRECV. Vielleicht geht es mit dem.

Das mit den "Vorgänger Lokaldaten" ist schon richtig so, wie man auch beim funktionierenden CONCAT-Aufruf sehen kann. Für den aufgerufenen FC liegen die übergebenen Variablen in den Vorgänger-Lokaldaten.

(2) Alternativ zum Merkerbyte sollte auch ein Byte aus einem DB/IDB funktionieren, allerdings müsste das DB/STAT-Byte als ANY an den FC übergeben werden, im FC auf eine TEMP-ANY-Variable umkopiert werden und diese Kopie an den AG_RECV übergeben werden - weil ein DB-Aktualparameter vom aufrufenden Baustein als Pointer auf eine TEMP-Kopie an den FC übergeben wird, wodurch ein Vorgänger-Vorgänger-Lokaldaten-Konflikt entsteht. Vielleicht löst der SCL-Compiler den Konflikt durch Umkopieren auf lokalen TEMP - das führt dann aber zur selben Situation wie die Übergabe des tmp_byte an AG_RECV. Dies würde das Scheitern der Übergabe des STAT-Bytes erklären.

Harald
 
Zurück
Oben