Probleme beim Übertragen mit der Funktion Put/Get (SFB14/15 bzw. FB14/15) via SCL

Ultimate_01

Level-1
Beiträge
5
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo liebe Forum-Gemeinde,

bin neu hier und möchte mich erstmal für zahlreiche Infos bedanken.
Leider stehe ich vor einem Problem, bei welchem ich alleine nicht weiter komme Google und Co. auch nichts brachbares finden.

Ich möchte eine Datenkommunikation via Profinet zwischen einer ET200S und einer 315-PN/DP aufbauen.
Es soll von der ET200S ein teil eines Datenbausteins DB300 an die 315 übertragen werden.
Der DB300 ist 12Byte gross. Davon sollen die ersten 8Byte gesendet (put) und die letzen 4 Byte empfangen (get) werden.

Nun habe ich mit der Siemens-"Hilfe" den Anypointer und die Übertragung im SCL zum Laufen bekommen..

ABER....

Hier kommt mein Problem
Ich muss bei der Übertragung immer die ganzen 12Byte übertragen. Sobald ich nur die ersten zwei oder vier Byte übertragen möchte, bringt die Funktion den Status 4 als Fehlermeldung. Und meine Funktion möchte dann wieder neu Senden/bzw. empfangen. Doch mit dem Status 4 kann ich mit der Siemens-"Hilfe" nichts anfangen... :-(

Hier mal meinen prinzipiellen Aufbau des SCL codes:

Teile der Input/Parameter (NICHT Vollständig!!)
VAR_INPUT
I_Int_ADDR_1: ANY; // Interne Adresse des DB´s "Symbolisch"
I_ID: WORD; // ID-Nummer der externen Steuerung
I_DB_Nr: INT; // Nummer des DBs
I_DB_Byte_Adr: INT; // Bereichszeiger auf Bit- und BYTE-Adresse
I_Byte_Count: INT; // Anzahl der Byte
END_VAR

VAR
Get_Data: "GET"; //"FB_Get"; // Struktur von FB14 "Get" in Instanz DB (GET=SFB 14 FB_Get=FB14)
Put_Data: "PUT"; //"FB_Put"; // Struktur von FB15 "Put" in Instanz DB (PUT=SFB 15 FB_Put=FB15)

Get_Impuls: BOOL; // Startimpuls DB empfangen
Put_Impuls: BOOL; // Startimpuls DB senden
END_VAR

VAR_TEMP
Buffer: "UDT_ANY_Pointer"; // Zwischenspeicher für Pointer
Temp_Any_Pointer AT Buffer: ANY; // Any-Pointer
END_VAR




//Teile des SCL Codes
//======================================
// Any Pointer deklarieren
//======================================
Buffer.Syntax_ID := b#16#10; //Pufferlänge
Buffer.DataTyp := b#16#02; //Code für Datentyp BYTE
Buffer.Count := INT_TO_WORD(AnzahlBytes); //Anzahl der Nutzdaten-Byte
Buffer.DB_Number := INT_TO_WORD(300); //Nummer des Ziel-DBs für die Nutzdaten
Buffer.Byte_Pointer := dw#16#84000000; //Pointer auf Globaldaten DBX0.0

//Byte-Adresse in Pointer laden
//Buffer.Byte_Pointer:= Buffer.Byte_Pointer OR (SHL(in:=WORD_TO_DWORD(INT_TO_WORD(StartByte)),N:=3));;

Schritt := Schritt;
//======================================
// Function"Get": DB receive
//======================================
Get_Data(REQ := Get_Impuls // DB empfangen
,ID := I_ID // ID-Nummer der externen Steuerung
,ADDR_1 := Temp_Any_Pointer //Temp_Any_Pointer // Externe Adresse des DB´s
,RD_1 := I_Int_ADDR_1); // Interne Adresse des DB´s

//======================================
// Function "Put": DB send
//======================================
Put_Data(REQ := Put_Impuls // DB senden
,ID := I_ID // ID-Nummer der externen Steuerung
,ADDR_1 := Temp_Any_Pointer // Externe Adresse des DB´s
,SD_1 := I_Int_ADDR_1); // Interne Adresse des DB´s


Habe is mit den SFC und den FC aus der Siemens Bibliotek versucht. Beides läuft nur wenn ich immer den ganzen DB übertrage. Ich möchte aber nur einen Teil senden und einen anderen Teil empfangen..

Mache ich was falsch, oder wo könnte der Fehler sein?

Besten dank schonmal..

Grüsse
 
Du holst die Daten und sendest die selben Daten zurück.
Wie machst du das, wenn du unterschiedliche Bereiche senden/empfangen willst?
Dann mußt du Put und Get auch mit unterschiedlichen Adressen versorgen.

Also von dir aus 8 Byte per Put an die entfernte SPS, Byte 0-7 und 4 Byte per Get holen, Byte 8-11.
Demnach müssen deine je 2 Any für Put und Get jeweils unterschiedlich sein. Dann sollte das auch gehen.
Die Größe von Temp_Any_Pointer und I_Int_ADDR_1 muß jeweils gleich groß sein, also bei Put 8 Byte Länge, bei Get 4 Byte Länge.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Die Datenbereiche der eigenen CPU (was senden + wohin empfangen) willst Du per ANY-Parameter an Deinen Baustein übergeben, die Adressen der remote Partner-CPU (wohin senden + woher empfangen) willst Du aus Einzelangaben zusammenstellen.

Damit Du unterschiedlich große Bereiche senden und empfangen kannst, brauchst Du 2 In-Parameter für die eigenen Datenbereiche: I_Int_Send_Buf, I_Int_Recv_Buf
Damit Du mit unterschiedlichen Bereichen für Schreiben/Lesen in der remote CPU arbeiten kannst, brauchst Du getrennte In-Parameter für die Schreib/Lese-Adressen: I_Rem_DB, I_Rem_Put_Adr, I_Rem_Get_Adr

Code:
VAR_INPUT
  I_Rem_ID: WORD;       // Verbindungs-ID zur remote CPU
  I_Rem_DB : INT;       // Nummer des DB für Put und Get in der remote CPU
  I_Rem_Put_Adr : INT;  // Ziel-Anfangsadresse für Put in dem remote DB
  I_Rem_Get_Adr : INT;  // Quell-Anfangsadresse für Get in dem remote DB
  I_Int_Send_Buf : ANY; // Bereich der eigenen CPU: was gesendet werden soll
  I_Int_Recv_Buf : ANY; // Bereich der eigenen CPU: wohin empfangen werden soll
END_VAR

Daten in eine remote CPU schreiben mit dem SFB/FB 15 "PUT" schrieb:
Sie müssen darauf achten, daß die über die Parameter ADDR_i und SD_i definierten Bereiche in der Anzahl, in der Länge und im Datentyp zueinander passen.
Daten aus einer remoten CPU lesen mit dem SFB/FB 14 "GET" schrieb:
Sie müssen darauf achten, daß die über die Parameter ADDR_i und RD_i definierten Bereiche in der Anzahl, in der Länge und im Datentyp zueinander passen.
Die Längenangaben der Bereiche in der eigenen CPU und der remote CPU müssen jeweils GLEICH GROSS sein:
PUT: Der Zielbereich in der remote CPU muß so groß sein wie die Anzahl der von der eigenen CPU zu sendender Byte.
GET: Der Empfangspuffer in der eigenen CPU muß so groß sein wie die Anzahl der von der remote CPU zu lesender Byte.
Also am besten die Längenangaben aus den ANY der eigenen CPU entnehmen und in die ANY der remote CPU eintragen.
Code:
//======================================
// GET: Daten aus remote CPU lesen
//======================================
Temp_Any_Pointer := I_Int_Recv_Buf;  //Syntax-ID, Datentyp und Länge vom eigenen Bereich übernehmen
Buffer.DB_Number := INT_TO_WORD(I_Rem_DB);
Buffer.Byte_Pointer:= DW#16#84000000 OR SHL(IN:=INT_TO_DWORD(I_Rem_Get_Adr),N:=3);

Get_Data(REQ := Get_Impuls           // Daten aus remote CPU lesen
         ,ID := I_Rem_ID             // Verbindungs-ID zur remote CPU
         ,ADDR_1 := Temp_Any_Pointer // Bereich in der remote CPU
         ,RD_1 := I_Int_Recv_Buf     // Empfangspuffer
         );

//======================================
// PUT: Daten in remote CPU schreiben
//======================================
Temp_Any_Pointer := I_Int_Send_Buf;  //Syntax-ID, Datentyp und Länge vom eigenen Bereich übernehmen
Buffer.DB_Number := INT_TO_WORD(I_Rem_DB);
Buffer.Byte_Pointer:= DW#16#84000000 OR SHL(IN:=INT_TO_DWORD(I_Rem_Put_Adr),N:=3);

Put_Data(REQ := Put_Impuls           // Daten in remote CPU schreiben
         ,ID := I_Rem_ID             // Verbindungs-ID zur remote CPU
         ,ADDR_1 := Temp_Any_Pointer // Bereich in der remote CPU
         ,SD_1 := I_Int_Send_Buf     // Sendedaten
         );

S7-300 CPU haben keine SFC14/SFC15. Es sind die FB14 "GET" und FB15 "PUT" zu verwenden.

Harald
 
Guten morgen zusammen,
danke für eure Hilfe. Ich habe wohl im Eifer des Gefechts den falschen Quellcode kopiert.
Hier mal den richtigen bei welchem die beiden Any-Pointer unterschiedlich sind. Den erzeugten DB habe ich "vorerst" direkt als Baustein in die andere CPU rüber kopiert, so dass diese zu 100% identisch sind. Dies läuft ja auch, bis ich halt die Anzahl der zu übertragenden Byte änder...

//======================================
//Daten senden (PUT)
//======================================
//----------------------------
// Any Pointer deklarieren
//----------------------------
Buffer_Put.Syntax_ID := b#16#10; //Pufferlänge
Buffer_Put.DataTyp := 2; //Code für Datentyp BYTE
Buffer_Put.Count := INT_TO_WORD(I_Byte_Count_Put); //Anzahl der Nutzdaten-Byte
Buffer_Put.DB_Number := INT_TO_WORD(I_DB_Nr_Put); //Nummer des Ziel-DBs für die Nutzdaten
Buffer_Put.Byte_Pointer := dw#16#84000000; //Pointer auf Globaldaten DBX0.0

//Byte-Adresse in Pointer laden
Buffer_Put.Byte_Pointer:= Buffer_Put.Byte_Pointer OR (SHL(in:=WORD_TO_DWORD(INT_TO_WORD(I_DB_Byte_Adr_Put)),N:=3));

//----------------------------
// Function "Put": DB send
//----------------------------
Put_Data(REQ := Put_Impuls // DB senden
,ID := I_ID // ID-Nummer der externen Steuerung
,ADDR_1 := Temp_Any_Pointer_Put // Externe Adresse des DB´s
,SD_1 := I_Int_ADDR_1_Put); // Interne Adresse des DB´s


//======================================
//Daten empfangen (GET)
//======================================
//----------------------------
// Any Pointer deklarieren
//----------------------------
Buffer_Get.Syntax_ID := b#16#10; //Pufferlänge
Buffer_Get.DataTyp := 2; //Code für Datentyp BYTE
Buffer_Get.Count := INT_TO_WORD(I_Byte_Count_Get); //Anzahl der Nutzdaten-Byte
Buffer_Get.DB_Number := INT_TO_WORD(I_DB_Nr_Get); //Nummer des Ziel-DBs für die Nutzdaten
Buffer_Get.Byte_Pointer := dw#16#84000000; //Pointer auf Globaldaten DBX0.0

//Byte-Adresse in Pointer laden
Buffer_Get.Byte_Pointer:= Buffer_Get.Byte_Pointer OR (SHL(in:=WORD_TO_DWORD(INT_TO_WORD(I_DB_Byte_Adr_Get)),N:=3));

//----------------------------
// Function"Get": DB receive
//----------------------------
Get_Data(REQ := Get_Impuls // DB empfangen
,ID := I_ID // ID-Nummer der externen Steuerung
,ADDR_1 := Temp_Any_Pointer_Get // Externe Adresse des DB´s
,RD_1 := I_Int_ADDR_1_Get); // Interne Adresse des DB´s



Leider verstehe ich nicht ganz was du damit meinst:
Die Längenangaben der Bereiche in der eigenen CPU und der remote CPU müssen jeweils GLEICH GROSS sein:
PUT: Der Zielbereich in der remote CPU muß so groß sein wie die Anzahl der von der eigenen CPU zu sendender Byte.
GET: Der Empfangspuffer in der eigenen CPU muß so groß sein wie die Anzahl der von der remote CPU zu lesender Byte.
Also am besten die Längenangaben aus den ANY der eigenen CPU entnehmen und in die ANY der remote CPU eintragen.

Die DB´s sind ja zu 100% identisch. Oder muss der Empfangsbereich sowie der Sendebereich jeweils gleich gross sein?

Besten Dank schon einmal!!

Liebe Grüsse
 
Hallo zusammen,
habe nun meinen Fehler gefunden..

Ich habe im FB als Eingangsvariable den internen DB symbolisch zugewiesen. Dabei macht der SCL-Compiler aus dem Symbolischen Namen nur einen Pointer ohne Längenangabe.
Somit ist klar warum es nur Funktioniert hat, wenn ich als Eingangsparameter den gesamten DB angegeben habe..

Trotzdem danke nochmals für eure Tipps und hilfen
;)
Grüsse Manuel
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen,
habe nun meinen Fehler gefunden..

Ich habe im FB als Eingangsvariable den internen DB symbolisch zugewiesen. Dabei macht der SCL-Compiler aus dem Symbolischen Namen nur einen Pointer ohne Längenangabe.
Somit ist klar warum es nur Funktioniert hat, wenn ich als Eingangsparameter den gesamten DB angegeben habe..

Trotzdem danke nochmals für eure Tipps und hilfen
;)
Grüsse Manuel

Kannst du bitte noch einmal genau erläutern, was da falsch war? Ich kann deiner Erklärung überhaupt nicht folgen, welche Variable meinst du?
 
Hallo Ralle,

Ich versuche es mal... :-D

Also ich hatte die ganze Kommunikation in einem FB untergebracht. Per Inputvariable konnte man den Internen DB für die Put/Get Funktion Symbolisch anlegen. Für den Ziel DB auf der Fremdsteuerung musste man nur noch die DB-Nummer, die Byte-Anzahl und die ID angeben. (Symbolischer DB-Name wurde mit dem Datentyp ANY eingelesen)
Der SCL-Compiler hat aus dem Symbolisch angelegten internen DB einen Pointer gemacht, jedoch ohne eine Anzahl an Byte.
Somit war an den Eingängen des PUT/Get Bausteins ADDR_1= ein Pointer mit Bytelänge und am Eingang SD_1 ein Pointer ohne Bytelänge. Was dann dazu führte, dass es beim übertragen des kompletten DBs funktionierte und sobald der Pointer am SD_1 eine andere Bytelänge als der gesamte DB hatte eben nicht...

Nun habe ich für jeden Eingang der Put/Get-Funktion einen eigenen Pointer zusammengebaut. Ich kann nun in meinem Funktionsbaustein, welcher die gesamte Kommunikation inkl. Überwachung und Auswertung übernimmt, folgende Parameter einstellen.

-> ID der Partnersteuerung

Parameter für das Senden
-> Intere DB-Nr
-> Internes Startbyte
-> Externe DB-Nr
-> Externes Startbyte
-> Bytelänge

Und das gleiche dann wieder, um Daten zu Empfangen

Liebe Grüsse
 
Jetzt verstehe ich, du hattest also rein den DB symbolisch an den Input geschrieben und nicht eine Struct aus diesem DB (was sich da gut anbietet) oder eben auch nur den Any pur (absolut adressiert).
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Ralle,


Jetzt verstehe ich, du hattest also rein den DB symbolisch an den Input geschrieben und nicht eine Struct aus diesem DB (was sich da gut anbietet) oder eben auch nur den Any pur (absolut adressiert).

Genau!
Hatte es nur symbolisch angehängt. Somit hat der Compiler aus dem symbolischen Namen nur eine absolute Adressierung gemacht ohne einen Pointer mit Byte Anzahl.

Grüsse
 
Zurück
Oben