Step 7 S7-400 sfb14/15 put get

vollmi

Level-3
Beiträge
5.425
Reaktionspunkte
1.403
Zuviel Werbung?
-> Hier kostenlos registrieren
Hi zusammen

Ich wollte einen put/get auftrag der bei einer s7 verbindung auf einer 300er einwandfrei läuft auf eine 400er übertragen.
jetzt das problem.

Ich erstelle mir einen anypointer mit dem inhalt
screenshot.33.jpg


Wenn ich den so anhänge
Code:
      CALL  #PUT_1
       REQ   :=
       ID    :=#ID_Red
       DONE  :=
       ERROR :=
       STATUS:=
       ADDR_1:=#zDB_1_Send
       ADDR_2:=
       ADDR_3:=
       ADDR_4:=
       SD_1  :=#zDB_1_Send
       SD_2  :=
       SD_3  :=
       SD_4  :=
Fehler in den Sendebereichszeigern SD_i bezüglich der Datenlänge oder des Datentyps

wenn ich den pointer absolut angebe.
Code:
      CALL  #PUT
       REQ   :=
       ID    :=#ID
       DONE  :=
       ERROR :=
       STATUS:=
       ADDR_1:=P#DB2202.DBX0.0 BYTE 40
       ADDR_2:=
       ADDR_3:=
       ADDR_4:=
       SD_1  :=P#DB2202.DBX0.0 BYTE 40
       SD_2  :=
       SD_3  :=
       SD_4  :=

funktioniert das einwandfrei. Wo liegt denn der Unterschied? Der inhalt ist doch IMHO genau gleich.

mfG René
 
- der ANY #zDB_1_Send ist in TEMP deklariert?
- Du könntest mal den IDB löschen und neu generieren lassen und einspielen
- Du könntest Dir mal bei beiden Versionen den Inhalt von ADDR_1 direkt im IDB anschauen und vergleichen
- Was steht in den anderen nicht belegten ADDR_i und SD_i im IDB? Das erste Byte sollte die Syntax-ID B#16#10 sein, der Rest alles 0
- Geht's, wenn Du dem SFB einen eigenen IDB gibst statt Multiinstanz?
- mal Firmwareversion der CPU checken

PS: Statt DW#16#84000000 würde ich P#DBX0.0 schreiben, doch das hat mit dem Problem nichts zu tun.

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
super. nach komplettem löschen des IDB hatts jetzt funktioniert. Ein Reinit hat es nicht gebracht.

Gibts eigentlich für die 400er auch ein "C_CNTRL" Derivat? Um die Verbindung selbst abzufragen?

mfG René
 
Weiteres Problem. Vermutlich aber nicht 400er spezifisch.

Code:
      L     P##DB_1_Recv
      LAR1  
      L     W [AR1,P#0.0]
      T     #pointing.DB_Nr


      L     #pointing.DB_Nr
      T     #wDummy


      CALL  "TEST_DB"
       DB_NUMBER :=#wDummy
       RET_VAL   :=#RetVAL
       DB_LENGTH :=#wDummy
       WRITE_PROT:=#Write_Prot

Wenn ich diesen Baustein als Multiinstanz zweimal aufrufe. Dann müsste doch im pointer #pointing.DB_Nr den ich im temp deklariert habe den angeschlossenen Any haben? Habe ich was übersehen? denn da steht immer der any vom Baustein der zuvor aufgerufen wird. Mit LAR1 lade ich doch das Adressregister aus dem Akku den ich mit L P##DB_1_Recv schon beschrieben habe. Muss ich trotzdem irgendwo einen Versatz berücksichtigen bei Multiinstanzen?

mfG René
 
Zuletzt bearbeitet:
Um das Laden der Adresse der TEMP-Variable DB_1_Recv in AR1 ganz deutlich sichtbar zu machen, kann man auch gleich in AR1 laden:
Code:
      LAR1  P##DB_1_Recv        //lade Adresse der TEMP-Variable 'DB_1_Recv' in AR1
      L     W [AR1,P#[COLOR="#FF0000"]4[/COLOR].0]       //wenn DB_1_Recv ein ANY ist, dann steht die DB-Nummer im 5. und 6. Byte
      T     #pointing.DB_Nr
Der falsche zusätzliche Offset P#0.0 war nur ein Tippfehler hier im Forum?

Wenn man die Adresse einer TEMP-Variable referenzieren will, dann braucht man keinen Multiinstanz-Versatz. Den braucht man nur, wenn man eine Variable in einer Multiinstanz referenzieren will (IN, OUT, IN_OUT, STAT).

ALLE Variablen in TEMP müssen VOR dem Lesen beschrieben werden - auch ANY! Vorher kann man nicht sagen, daß irgendein bestimmter Wert in der TEMP-Variable drinsteht - eine Vermutung kann zufällig zutreffen, muß aber nicht. Auch der zweite Aufruf eines Bausteins aus der gleichen Aufrufebene kann sich nicht sicher sein, daß in einer TEMP-Variable ein Wert vom ersten Aufruf drinsteht. Ein Baustein weiß halt nicht, was außerhalb des Bausteins passiert ist, weiß nicht ob er direkt zweimal aufgerufen wurde oder ein anderer Baustein dazwischen war, er weiß noch nichtmal, von wem er aufgerufen wurde und in welcher Aufrufebene.

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich kriegs nicht hin.
https://dl.dropboxusercontent.com/u/52388557/SPSFORUM/MasterCom.AWL

Hier mal die quelle des Bausteins. Wohlgemerkt alleine funktioniert er eigentlich. Aber sobald ich den Mutterinstanziere greift er bei beiden auf die Adressen des ersten Aufrufs zu.

Ausserdem habe ich jetzt bei der zweiten slave sps wenn ich die instanz unabhängig mache, das problem dass ich wohl einen db schreiben kann. Aber beim GET bekomme ich ein "Negative Quittung vom Partnergerät. Die Funktion ist nicht ausführbar." keine ahnung wieso dass bei einer tut und bei der anderen nicht.

Ich beschreib doch die temp pointer unbedingt immer am anfang des zyklus in jedem baustein?

mfG René
 
Wenn man die Adresse einer TEMP-Variable referenzieren will, dann braucht man keinen Multiinstanz-Versatz. Den braucht man nur, wenn man eine Variable in einer Multiinstanz referenzieren will (IN, OUT, IN_OUT, STAT).

Hallo René,
ich zitiere hier mal Harald ...
Deine DB's, die du lädtst sind auch IN-Parameter und auf die greifst du mit dem AR1 zu. (Dafür brauchst du also auf alle Fälle das +AR2 für den Pointer)
Weiter habe ich zunächst noch nicht geschaut ...

Gruß
Larry

Code:
LAR1  P##DB_1_Recv; 
[COLOR=#ff0000][B]+AR2[/B][/COLOR]
L     W [AR1,P#0.0];        
T     #pointing.DB_Nr;
 
Zuletzt bearbeitet:
Also soweit läufts jetzt in der Multiinstanz
Allerdings habe ich jetzt noch das Problem dass ich von einigen CPUs abgewiesen werde mit "Negative Quittung vom Partnergerät. Die Funktion ist nicht ausführbar."

Partner sind 315-2pn/dp. Ideen was das sein könnte?

Okay zurück: ich habs glaub ich. Zuviele Bytes vermutlich im recv

mfG René
 
Zuletzt bearbeitet:
Eigentlich nach dem Comm dokument von Siemens müsste man mit den SFB14/15 doch über 400 Byte übertragen können. Ist da bei mir jetzt der Partner der beschränkende Teilnehmer?

Gibts eine bessere Möglichkeit einseitig ne grössere Menge Daten zu übertragen?

mfG René
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo René,
ob dich die Partner-CPU da jetzt einschränkt weiß ich gerade nicht.
Wenn du sehr große Datenmengen übertragen willst dann könntest du so vorgehen, dass du in überschaubaren Datenblöcken arbeitest denen du jeweils ein Kennung mitgibst (als Bestandteil des Datenblocks), die dann die andere Seite in die Lage versetzt, das wieder passend hin-puzzeln zu können.

Gruß
Larry
 
Wieviel ist eine "grössere Menge Daten"?
Kann man denn nicht mit einem PUT/GET-Auftrag 4 Bereiche je >=400 Byte = >=1600 Byte zwischen zwei S7-400 übertragen?
Wieviele Daten übertragen werden können und wovon das abhängig ist, steht im Comm. Kompedium Kapitel 32.2


Du könntest BSEND/BRCV benutzen. Oder eine ISO-on-TCP-Verbindung statt S7-Verbindung. Da kannst Du ..zig KB "riesige" Datenblöcke je Kommunikationsauftrag übertragen.

Warum immer nur die "faulen" einseitigen und beim Server nicht diagnostizierbaren PUT/GET?

Harald
 
Wieviel ist eine "grössere Menge Daten"?
Kann man denn nicht mit einem PUT/GET-Auftrag 4 Bereiche je >=400 Byte = >=1600 Byte zwischen zwei S7-400 übertragen?
Wieviele Daten übertragen werden können und wovon das abhängig ist, steht im Comm. Kompedium Kapitel 32.2

Eben in diesem Kapitel sehe ich eben nix was die Datenmenge einschränken würde. Ich gehe von 417PN intern zu 315PN intern. Und da steht im kapitel 3.2 ja >=160Byte.
Fakt ist aber, sobald die Datenmenge kleiner ist, läuft die Kommunikation.



mfG René

Warum immer nur die "faulen" einseitigen und beim Server nicht diagnostizierbaren PUT/GET?

Eben weil ich faul bin ;) die 300er haben auf ihrer Seite keine Möglichkeit eine Diagnose anzuzeigen. Selbst wenn sie einen Error hätten würde das keiner merken solange die 400er Client nix diagnostiziert.

Aber bleibt mir wohl nur BSEND/BRECV

mfG René
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Schau doch mal in das Handbuch "System- und Standardfunktionen für S7-300/400 Band 2/2" dort im Kapitel 21.1 gibt es ein paar Tabellen zur Nutzdatengröße.
Das Handbuch gibt es hier: http://support.automation.siemens.com/WW/view/de/44240604
Aber ich lese da auch raus, dass du zwischen einer S7-400 und einer S7-300 maximal 160 Byte übertragen kannst udn nur einen der ADDR_i-Parameter verwenden darfst.
 
Mit PUT/GET zwischen S7-400 und S7-300 können nicht höchstens 160 Byte übertragen werden, sondern mindestens
Die exakte Nutzdatengröße findet man in der Hilfe zu den Systemfunktionen "Gemeinsame Parameter der SFBs/FBs und der SFC/FC der S7-Kommunikation".

Wird z.B. von einer S7-400 zu einer S7-300-PN kommuniziert, dann kann ein PUT-Auftrag 212 Bytes senden und ein GET-Auftrag sogar 222 Bytes lesen.

Bei der S7-400 als Client kommt noch hinzu, daß bei Folgeaufrufen der SFB14/SFB15 nicht mehr Nutzdaten übertragen werden können als beim Erstaufruf für die Verbindung angegeben wurden.

Harald
 
Mit dem Kommunikationshandbuch habe ich leider so meine liebe mühe.
Da steht zwar wieviel man mindestens kann. Aber dann dieser nette Nebensatz.
Bei einigen Kommunikationsbausteinen wird angegeben, wie viele Daten mindestens (•x) übertragen werden können.
Wenn diese Mindestanzahl (•x) nicht ausreicht, kann die exakte maximale Anzahl ermittelt werden (Online Hilfe STEP 7).

Denn wer will schon die Mindestmenge wissen? Interessant ist doch nur wieviel kann ich maximal. Und wo man in der Online Hilfe dann diese Info bekommt hab ich auch noch nicht gefunden.

Anyway hab jetzt auf BSEND/RECV geschwenkt bin ich mir gewohnt funktioniert. Muss ja nicht immer was neues anfangen. Hätt halt bei der Kommunikationsmenge gut gepasst wenn man Zentral alles hätte ablegen können ohne bei den Servern noch die Gegenstelle zu parametrieren.

mfG René
 
Zuviel Werbung?
-> Hier kostenlos registrieren
So mit BSEND/BRECV funktionierts jetzt tadellos.

Ich musste ja für die Verbindungsüberwachung in der S7-400 Control (SFC62) statt C_CNTRL nehmen.
Das bringt ein weiteres Problem mit sich. Dafür brauch ich die den InstanzDB eines Kommunikationsbausteins (PUT, BSEND, USEND, BRECV etc)
Nur der InstanzDB ist ja wenn man multiinstanzfähig bleiben will ja immer derselbe. Also brauchts noch den Versatz in dieser Instanz. In SCL hab ich das jetzt so hingekriegt. Und ich denke das war die richtige Wahl da sich SCL um die Adressregister kümmert.

Hier mal die abgespeckte Version meines Bausteins nur zum Senden. Aber halt eben mit Control für die welche es interessiert.
Code:
TYPE "ANY_POINTER"
VERSION : 0.1


    STRUCT
        SyntaxID    : BYTE;
        Bereichstyp   : BYTE;
        Anzahl_Werte  : INT;
        DB_Nr    : INT;
        Startadresse   : DWORD;
    END_STRUCT;
END_TYPE


FUNCTION_BLOCK MasterCom_2


TITLE = 'Kommunikationsbaustein'
// Kommuniziert zu den Slaves
VAR_INPUT
  DB_1_Recv : BLOCK_DB ; 
END_VAR


VAR
  BSEND : "BSEND";   
END_VAR


VAR_TEMP
  zDB_1_Send : ANY ; // Pointer für Sendebaustein
        pDB_1_Send AT zDB_1_Send : ANY_POINTER; 
  zBSENDpointer : ANY ; // Pointer der für Control benötigt wird
        pBSENDpointer AT zBSENDpointer : ANY_POINTER;          
  RetVAL : INT ;         
Control : STRUCT // Structur um Control abzufüllen
      offset : INT;
       error : BOOL;
      status : WORD;
       i_Typ : BYTE;
     i_state : BYTE;
      i_conn : BOOL;
    i_status : WORD;
         END_STRUCT;  
END_VAR


(*Pointer aufbereiten*)
  (*Senden*)
  pDB_1_send.syntaxid         := B#16#10;                                  
  pDB_1_send.Bereichstyp      := 2; // Typ des Bereichs soll Byte sein (INT = 2)
  pDB_1_send.DB_Nr            := WORD_TO_INT(BLOCK_DB_TO_WORD(DB_1_send));  // DB Nummer errechnen
  RetVAL := TEST_DB(DB_NUMBER := BLOCK_DB_TO_WORD(DB_1_send),DB_LENGTH := Anzahl_Werte_SEND ,WRITE_PROT := Write_Prot);
  pDB_1_send.Anzahl_Werte     := WORD_TO_INT(Anzahl_Werte_SEND); // Länge des Pointers weil wir einen BlockDB ohne Länge angeben wollen
  pDB_1_send.Startadresse     := DW#16#84000000;  
  
(*Verbindungsüberwachung*)
zBSENDpointer := BSEND; // um eigenen Instanzdb und versatz von Instanz BSEND rauszufinden.
RetVAL := CONTROL(EN_R :=  TRUE
        ,I_DB := INT_TO_WORD(pBSENDpointer.DB_Nr) // DB Nummer der eigenen Instanz steht durch die Zuweisung oben schon richtig drin.
        ,OFFSET := DWORD_TO_WORD(SHR(in := pBSENDpointer.Startadresse, N:= 3)) // Offset aus Pointer Startadresse filtern.
        ,ERROR := Control.error
        ,STATUS := Control.status
        ,I_TYP :=  Control.i_Typ
        ,I_STATE :=Control.i_state
        ,I_CONN :=  Control.i_conn
        ,I_STATUS := Control.i_status);
END_FUNCTION_BLOCK

mfG René
 
Das Problem ist hier, dass ich zwei Verbindungen zur gleichen SPS über zwei verschiedene Wege projektiere (400H PN/DP) Das heisst ich übertrage ein und denselben DB über zwei Verbindungen. Wenn da drin ein Lifebit mitgeht, dann toggelt der auf beiden Verbindungen. Ich müsste also den empfangenen Datenbereich erstmal zwischenspeichern in einem Lokalen Speicherbereich um zu schauen ob genau nur das Telegramm von Verbindung 1 nicht mehr toggelt. Und dann weiss man immernoch nicht ob die Verbindung fehlt oder die Partnerstation auf Stop ist.

Darum überwache ich die Verbindungen einzeln und die Funktion der Partnerstation getrennt.

mfG René
 
Zurück
Oben