Profibus ausstecken, SPS-Slave-Eingänge gehen alle aus?

Aksels

Level-2
Beiträge
257
Reaktionspunkte
9
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Leute,

ich habe hier ein Projekt angepasst.
Es sind 6 x S7 315 2DP vernetzt über Profibus.
Eine davon ist der Master (klar). Bei den Slaves war jeweils ein Byte als Master Ausgang zu Slave Eingang und umgekehrt projektiert.
Ich sollte nun weitere Daten übertragen und nahm an, ich könnte die üblichen Übertragungsbausteine verwenden. Als ich meine DBs fertig hatte erklärte mir der Siemens Support, das ginge nicht. Ich müsse die Bausteine über dieses Ausgang->Eingang Gedöns übertragen.
Na gut, dann tat ich das eben. Da ich keine Konsistenz der Daten brauche (sind nur Lampen, die geschaltet werden) habe ich die Bits einfach mit einer Schleife auf die Ausgänge ab A20.0 kopiert. Dann auf dem Slave von den Eingängen wieder in den DB.
Klappt auch super.
Aber!
Wenn ich an einer SPS das Profibuskabel abziehe werden alle Eingänge die vom Master kommen auf false gesetzt.
Alle Lampen werden somit dunkel. Ich dachte ich sehe nicht richtig.
Sprich, wenn einer mal aus versehen das Kabel durchschneidet ist das ganze Haus stockduster!
Oder: wenn ich dezentrale Peripherie in einer Industrieanlage benutze und jemand kappt das Kabel fallen sofort alle tonnenschweren Materialien an den Unterdruck oder Magnetkränen herunter. Das gibt's doch gar nicht, oder?
Kann man bei Profibus keine Remanenz bei Ausfall projektieren (habe nichts in den Einstellungen gefunden)?

Ehrlich gesagt bin ich schwer am überlegen, ob ich die Kabel nicht einfach auf den MPI-Anschluss umstecke und meine gewohnten Übertragungsbausteine nehme. Das eine Byte meines Vorgängers krieg ich da auch noch drüber.
Wenn dann die Kommunikation ausfällt, dann bleiben meine Daten in den DBs wenigstens stehen.

MPI müsste doch genauso weit reichen wie Profibus (hat ein Supportmitarbeiter mal gemeint)?
Also wenn ich das Kabel mit Profibus getestet habe, dann funktioniert es mit MPI auch?
 
Das alle Eingänge wegfallen ist aus meiner Sicht korrekt und muss zwingend so funktioneren. In deinem Fall würde ich eine einfache Kommunikationsüberwachung realisieren und die Eingänge nur auf DB kopieren wenn Kommunikation in Ordnung, so bleiben die Eingänge remanent im DB. Dazu würde ich zwingen den Alarm nach aussen führen, denn der Bediener hat unter Umständen keine Kontrolle mehr über seine Anlage, in deinem Fall natürlich nur Beleuchtung.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Im überwiegenden Fall der Fälle ist das verhalten so korrekt und auch absolut so gewünscht.

Für den Rest der Fälle kann man pro Slave die Ansprechüberwachung deaktivieren,
somit behalten sämtliche Ausgänge ihren letzten Wert.

Da du einen Intelligenten Slave hast kannst du im Prinzip aber sowieso programmieren was du lustig bist ...

Mfg
Manuel
 
Daß die Eingänge von DP-I-Slaves bei Ausfall der Verbindung zum DP-Master alle auf 0 gesetzt werden ist so gewollt, weil das normalerweise der "sichere" Zustand ist. Bei Vakuumsaugern und Magnetkränen wird das Abschalten der Haltekraft dadurch verhindert, daß externe Elektrik das SPS-Ausgangssignal invertiert: Ausgang=0 -> Halten Ein / Ausgang=1 -> Halten Aus

Abschalten kann man dieses Verhalten durch Deaktivieren der "Ansprechüberwachung" in HW-Konfig des DP-Slave. Dann bleiben bei Verbindungsausfall alle DP-Eingangswerte auf den zuletzt empfangenen Werten. Das macht aber normalerweise niemand.
Zitat aus der Hilfe in HW-Konfig:
Ansprechüberwachung
Mit der Ansprechüberwachung haben Sie die Möglichkeit, daß der DP-Slave auf einen Fehler vom DP-Master oder auf eine Unterbrechung des Datenverkehrs auf dem Bus reagieren kann.
Wenn der DP-Slave innerhalb der projektierten Ansprechüberwachungszeit nicht angesprochen wird, dann geht der DP-Slave in den sicheren Zustand (alle Ausgänge auf "0" gesetzt oder Ersatzwertausgabe).

Gefahr
Wenn Sie die Ansprechüberwachung ausschalten, dann werden unter Umständen im Fehlerfall die Ausgänge des entsprechenden DP-Slaves auf nicht "0" gesetzt.
Wir empfehlen Ihnen deswegen dringend, die Ansprechüberwachung nur für die Inbetriebnahme auszuschalten.
(bei I-Slaves betrifft dieses Verhalten die DP-Eingänge statt wie hier beschrieben die Ausgänge)

Ist der DP-Slave ein I-Slave (eine CPU), dann ist es einfach, im Programm des Slave für jeden einzelnen Ausgang eine besondere Reaktion auf den DP-Verbindungsausfall zu programmieren. Die Verbindung muß dann natürlich überwacht werden.

In Deinem Fall mit den Lampen könntest Du auch mit der SFC73 "I_PUT" vom Master direkt in DB der Slave-CPUs schreiben und im Slave die DB-Bits den Lampenausgängen zuweisen. Dann bleiben die Lampenausgänge ohne viel Aufwand "remanent".

Harald
 
Schon witzig...

wie man über 10 Umwege doch zum Ziel findet.
Ich hatte ursprünglich DBs im Master und in den Slaves, habe dann festgestellt, daß meine MPI-Übertragungsbausteine für Profibus nicht gehen.
Ich habe den Siemens Support angerufen, der rif dann zurück und meinte einen Baustein zum Übertragen von DBs gibt es bei Profibus nicht. Das einzige was ich machen könnte wäre den Baustein SFC 14 "DPRD_DAT" und SFC 15 zu verwenden. Mit denen kam ich aber irgendwie nicht zurecht.
Da ich die Konsistenz nicht brauche habe ich selber Bausteine geschrieben, die meine DBs in Ausgänge auf dem Master kopiert, diese werden über Profibus auf EIngänge der Slaves gelegt, von wo ich sie dann wieder in DBs auf den Slaves kopiere.

Und jetzt kommt PN/DP daher und sagt man könne ganz einfach mit einem Baustein einen DB auf den Slave kopieren.
Ein herzliches Dankeschön ersteinmal an PN/DP.
Da meine hin und her Kopiererei sehr fehleranfällig ist werde ich das gleich mal versuchen.
Allerdings frage ich mich, was für Leute Siemens beim Support beschäftigt.

Ich glaube in Zukunft frage ich ersteinmal hier nach.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Erste Probleme:

Was ist im Baustein SFC73 "I_PUT" die "IOID" und die "LADDR"?
"LADDR" könnte ich mit vorstellen ist die Profibusadresse ("Logische Adresse der Partnerbaugruppe").
Aber was mache ich mit der "IOID"? Was für eine "Kennung des Adressbereich der Partnerbaugruppe" soll das sein? Muss ich da trotzdem noch einen E/A Bereich im Profibus Slave konfigurieren? Wie groß muss der sein? Welche Adresse gebe ich an, die auf der Master A-Seite oder der Slave E-Seite, oder beide? Ist eine S7-315 DB eine Mischbaugruppe weil man E und A Projektieren kann? Ich liebe Siemens Hilfe! Und das tolle nicht vorhandene Beispielprogramm!

Ich bin drauf und dran die ganzen Stecker auf den MPI-Bus umzustecken und meine Standard-DB-Übertragungsbausteine zu benutzen.
Mein Vorgänger benutzt nur ein einziges Byte bei der Übertragung über Profibus. Die acht Bits bekomme ich auch über MPI drüber.

Was ist den Profibus für ein dummer Bus, das man da nicht einfach einen DB übertragen bekommt *ärger*.
 
Oder: wenn ich dezentrale Peripherie in einer Industrieanlage benutze und jemand kappt das Kabel fallen sofort alle tonnenschweren Materialien an den Unterdruck oder Magnetkränen herunter.

Also wenn da deine einzige Sicherheit das nichts runterfällt die Funktionierende Kommunikation ist, will Ich nicht drunter stehen!
 
Ich mach....

... in diesem Projekt doch nur Licht. Photonen die herunterfallen tun nicht so arg weh.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Was ist im Baustein SFC73 "I_PUT" die "IOID" und die "LADDR"?
Bei IOID ist fast immer B#16#54 einzutragen, bei LADDR wird die in HW-Konfig vergebene Diagnoseadresse des Partners angegeben. Siehe Step7-Hilfe zu SFC72/SFC73.

* Wie können Sie von einem DP-Master mit SFC72 "I_GET" und SFC73 "I_PUT" über PROFIBUS DP auf eine andere CPU zugreifen, die als Slave am PROFIBUS DP betrieben wird?

* Beispiel, wenn beide Stationen im selben Step7-Projekt sind

* Beispiel, wenn beide Stationen in verschiedenen Step7-Projekten sind ...
... dann muß die zur Partner-CPU exakt passende GSD-Datei installiert sein (sonst geht die BF-LED nicht aus **):
* PROFIBUS GSD-Dateien : SIMATIC
Nach der Installation der GSD-Datei sind die im Hardware-Katalog hier zu finden:
PROFIBUS-DP > Weitere Feldgeräte > SPS > SIMATIC

* Beispiel Applikation: Client/-Server Kommunikation zu (I)-Slaves über S7-Basiskommunikation (I_PUT/ I_GET)

**
Wird nicht die richtige GSD-Datei benutzt, dann leuchtet die Profibus-BF-LED rot,
weil der DP-Master die zyklische DP-Kommunikation mit dem Slave nicht aufnimmt.
(weil der reale DP-Slave eine andere Profibus-Ident-Nummer hat als in der GSD-Datei angegeben,
Diagnose: "Profibus-Slave ist nicht vorhanden")
Die Kommunikation per I_PUT/I_GET läuft aber, weil sie den Partner nicht als DP-Slave sondern als "andere Station" über die Profibus-Adresse anspricht.

Harald
 
Was ist den Profibus für ein dummer Bus, das man da nicht einfach einen DB übertragen bekommt *ärger*.
Bekommt man doch, wenn man weiß wie. ;)

Das "kleine" Problem ist nur, daß bei den S7-300-CPU bei der S7-Basiskommunikation über Profibus nur Master Client sein können und nur Slaves Server sein können.
CPU-CPU Kommunikation mit SIMATIC Controllern (Kompendium)
Deshalb muß die Partner-CPU DP-Slave der Client-CPU sein, wofür mindestens 1 Byte E/A-Daten zu projektieren ist. Dieses Byte muß keine Informationen enthalten, es muß nicht im Programm gelesen/geschrieben werden, die zyklische Master-Slave-DP-Kommunikation muß noch nicht einmal aufgebaut sein (z.B. wegen falscher GSD-Datei).

I_PUT/I_GET sind eigentlich für den azyklischen Datenaustausch gedacht, man kann aber auch seine gesamte zyklische Kommunikation mit I_PUT/I_GET abwickeln. Ist wegen dem Protokoll-Overhead allerdings langsamer als DP-Kommunikation. Bei 1,5MBit/s zwischen zwei 315-2DP dauert ein kompletter Schreib/Lesezyklus von jeweils 50 Byte ca. 50..60ms.
Bei I_PUT/I_GET kann die Partner-CPU nicht beeinflussen, auf welche Adressen die Client-CPU zugreift, dafür muß sie aber auch keine Kommunikationsbausteine aufrufen.

Ich benutze die Kommunikation per I_PUT/I_GET gerne zum Datenaustausch mit SPS anderer Lieferanten, weil man da sehr leicht die Konfiguration ändern/erweitern kann, ohne eine neue HW-Konfig in die CPU laden zu müssen.
Bei Verbindungsausfall entstehen keine Peripheriezugriffsfehler, wenn man das/die E/A-Byte nicht nutzt.
Wenn die Partner-CPU eine CPU mit integrierter DP-Schnittstelle ist, und die Partner-CPU wird gegen eine neuere CPU ausgetauscht, dann muß die DP-Konfiguration des Masters (zunächst) nicht angepasst werden, I_PUT/I_GET funktionieren weiterhin, nur die DP-Master-Slave-Kommunikation wird nicht mehr aufgebaut und die BF-LED leuchtet. I_PUT/I_GET kann notfalls auch noch nachträglich eingerichtet werden, ohne in der Partner-CPU am Programm was ändern zu müssen.

Weil man den Partner als DP-Slave anbinden muß, hat man automatisch die Diagnosepuffer-Einträge und OB8x-Aufrufe bei Änderung des Verbindungsstatus zur Verfügung. I_PUT/I_GET funktionieren auch dann, wenn der Partner in STOP ist. Die Verbindung sollte durch Übertragen eines Lifebits überwacht werden, das reicht völlig aus.

Hier mal ein Beispiel aus einem meiner Projekte
Master DB166.DBB0..DBB49 <--- I_GET <--- Partner DB182.DBB0..DBB49
Master DB167.DBB0..DBB49 ---> I_PUT ---> Partner DB181.DBB0..DBB49
Code:
FUNCTION_BLOCK FB 1
TITLE =Profibus-Communication CC28-CS110 CoolingSystem
//DP-Master/Slave-Communication via I_PUT/I_GET
AUTHOR : PN_DP
VERSION : 0.1

VAR
  REQ_get : BOOL ;
  REQ_put : BOOL ;
  BUSY_get : BOOL ;
  BUSY_put : BOOL ;
  STAT_spare_04 : BOOL ;
  STAT_spare_05 : BOOL ;
  STAT_spare_06 : BOOL ;
  STAT_spare_07 : BOOL ;
  STAT_spare_B1 : BYTE ;
  RET_VAL_get : INT ;
  RET_VAL_put : INT ;
  ComTime_Counter : INT ;
  ComTime_Last : INT ;
END_VAR
VAR_TEMP
  LADDR_CS110 : WORD ;         //Logical Address of the DP slave station
END_VAR
BEGIN
NETWORK
TITLE =Assign Slave-Diagnostic-Address to logical Partner-Address
//The Logical Address of the DP slave station is the Diagnostic Address
//(see HW Config DP-Slave 10).
      L     2042 ;             //Diagnostic Address DP-Slave 10 Cooling System
      T     #LADDR_CS110 ;     //Logical Address of the DP slave station

NETWORK
TITLE =Get Data from CS110 Cooling System
//We use Get + Put in maximum speed, this is the only productive Communication
//(the CPU can also read 1 PEB via cyclic DP-Read, but without information from slave)
      UN    #BUSY_get ;        //Get-job not in work
      UN    #BUSY_put ;        //Put-job not in work
      =     #REQ_get ;         //start Get-job

      CALL "I_GET" (                             //Call SFC72
           REQ      := #REQ_get,                 //True -> start get-job
           CONT     := TRUE,                     //Connection remains existing 
           IOID     := B#16#54,                  //Identifier of the partner address
           LADDR    := #LADDR_CS110,             //Logical address of the partner 
           VAR_ADDR := P#DB182.DBX 0.0 BYTE 50,  //Source in partner
           RET_VAL  := #RET_VAL_get,             //Error code (return value)
           BUSY     := #BUSY_get,                //High, if a job is in work
           RD       := P#DB166.DBX 0.0 BYTE 50); //Destination here 

NETWORK
TITLE =Put Data into CS110 Cooling System

      UN    #BUSY_get ;        //Get-job not in work
      UN    #BUSY_put ;        //Put-job not in work
      =     #REQ_put ;         //start Put-job

      CALL "I_PUT" (                             //Call SFC73
           REQ      := #REQ_put,                 //True -> start put-job
           CONT     := TRUE,                     //Connection remains existing
           IOID     := B#16#54,                  //Identifier of the partner address
           LADDR    := #LADDR_CS110,             //Logical address of the partner 
           VAR_ADDR := P#DB181.DBX 0.0 BYTE 50,  //Destination in partner
           SD       := P#DB167.DBX 0.0 BYTE 50,  //Source here
           RET_VAL  := #RET_VAL_put,             //Error code (return value)
           BUSY     := #BUSY_put);               //High, if a job is in work

NETWORK
TITLE =Info: Calculate time duration of 1 communication cycle

      L     #ComTime_Counter ;

      U     #REQ_get ;
      SPBN  CNT ;
      T     #ComTime_Last ;
      L     0 ;
      T     #ComTime_Counter ;

CNT:  L     "OB1_PREV_CYCLE" ; //MW8: Copy of #OB1_PREV_CYCLE
      +I    ;
      T     #ComTime_Counter ;

//watch ComTime_Last (ms)
      L     #ComTime_Last ;

END_FUNCTION_BLOCK

Harald
 
Perfekt.

Hallo Leute.

Vielen Dank für die Hilfe.
Ich habe die ganze Eingangs-Ausgangs Krücke entfernt und mit den Übertagungsbausteinen gearbeitet. Klappt super. Musste nur wegen der geringen max Übertragungslänge die Bausteine stückchenweise übertragen.
Das Problem mit dem Abstecken ist damit auch nicht mehr existent. Wobei ich dafür schon die Lösung mit dem Überwachungsbaustein von Siemens gestestet habe (Cruise Missile für nen Spatz).

Gruß,
Aksels


Code:
FUNCTION FC_Put_Data : void
// Bausteinparameter
VAR_INPUT
    // Eingangsparameter
    i_Reset : bool;
END_VAR

VAR_IN_OUT
    // Durchgangsparameter
END_VAR

VAR_OUTPUT
    // Ausgangsparameter
END_VAR

VAR_TEMP
    // temporäre Variablen
    t_ret:INT;
    Quelle : ANY;
    QuellPointer AT Quelle : STRUCT
        SyntaxID : BYTE;
        Datentyp : BYTE;
        Laenge : INT;
        db_Nummer : INT; 
        BytePointer : DWORD;
            END_STRUCT; 
    Ziel : ANY;
    ZielPointer AT Ziel : STRUCT
        SyntaxID : BYTE;
        Datentyp : BYTE;
        Laenge : INT;
        db_Nummer : INT; 
        BytePointer : DWORD;
    END_STRUCT; 
    a: DINT;
    b: DINT;
    LADDR_CS110 : WORD ;
END_VAR

    IF i_Reset THEN
        db120.Start :=0;
    END_IF;
    
    QuellPointer.BytePointer := dw#16#84000000 OR SHL ( IN:= DINT_TO_DWORD(db120.DB_Uebertragung[db120.DatensatzNr].Quelle_Start),N:=3); // 84h für DB
    ZielPointer.BytePointer := dw#16#84000000 OR SHL ( IN:= DINT_TO_DWORD(db120.DB_Uebertragung[db120.DatensatzNr].Ziel_Start),N:=3);
    QuellPointer.SyntaxID := b#16#10;
    QuellPointer.Datentyp := b#16#4; //Datentyp WORD
    QuellPointer.db_nummer := db120.DB_Uebertragung[db120.DatensatzNr].Quelle_Baustein; //zum Bleistift DB100
    ZielPointer.SyntaxID := b#16#10;
    ZielPointer.Datentyp := b#16#4; //Datentyp WORD
    ZielPointer.db_nummer := db120.DB_Uebertragung[db120.DatensatzNr].Ziel_Baustein; //zum Bleistift DB100
    QuellPointer.Laenge := db120.DB_Uebertragung[db120.DatensatzNr].Daten_Laenge;
    ZielPointer.Laenge := db120.DB_Uebertragung[db120.DatensatzNr].Daten_Laenge;
    LADDR_CS110:= db120.DB_Uebertragung[db120.DatensatzNr].LADDR;
    IF db120.DB_Uebertragung[db120.DatensatzNr].Send THEN
   
        db120.DB_Uebertragung[db120.DatensatzNr].Status_Alt:=db120.DB_Uebertragung[db120.DatensatzNr].Status; 
        db120.DB_Uebertragung[db120.DatensatzNr].Status:=I_PUT(REQ := db120.Start // IN: BOOL
        ,CONT := false // IN: BOOL
        ,IOID := B#16#54 // IN: BYTE
        ,LADDR := LADDR_CS110 // IN: WORD
        ,VAR_ADDR := Ziel // IN: ANY
        ,SD := Quelle // IN: ANY
        ,BUSY := db120.Busy // OUT: BOOL
        ); // INT
    ELSE
        
        db120.DB_Uebertragung[db120.DatensatzNr].Status_Alt := db120.DB_Uebertragung[db120.DatensatzNr].Status;
        db120.DB_Uebertragung[db120.DatensatzNr].Status := I_GET(REQ := db120.Start // IN: BOOL
              ,CONT := false // IN: BOOL
              ,IOID := B#16#54 // IN: BYTE
              ,LADDR := LADDR_CS110 // IN: WORD
              ,VAR_ADDR := Quelle // IN: ANY
              ,BUSY := db120.Busy // OUT: BOOL
              ,RD := Ziel // OUT: ANY
              ); // INT
         
    END_IF;
    IF db120.Busy THEN
        IF db120.Busy_old THEN
            ;
        ELSE
            db120.Busy_old:=true;
        END_IF;
                
    ELSE
        IF db120.Busy_old THEN
            //Fallende Flanke
            db120.Start:=false;
            db120.Busy_old:=false;

        ELSE
            db120.DatensatzNr := db120.DatensatzNr + 1;
            IF db120.DatensatzNr > db120.Ausf_bis_DSNr THEN
                db120.DatensatzNr:=0;
            END_IF;
            
            db120.Start:=true;
        END_IF;

        
    END_IF;
    

END_FUNCTION
Hier der dazugehörige DB:

Code:
TYPE "UDT_SendRec"
VERSION : 0.1


  STRUCT     
   Send : BOOL ;    //Senden oder empfangen
   Quelle_Baustein : INT ;    
   Quelle_Start : INT ;    
   Ziel_Baustein : INT ;    
   Ziel_Start : INT ;    
   Daten_Laenge : INT ;    
   LADDR : WORD ;    
   Status : INT ;    
   Status_Alt : INT ;    
  END_STRUCT ;    
END_TYPE

DATA_BLOCK DB 120
TITLE =
VERSION : 0.1


  STRUCT     
   Start : BOOL ;    
   Busy : BOOL ;    
   Busy_Old : BOOL ;    
   DatensatzNr : INT ;    
   Ausf_bis_DSNr : INT ;    
   DB_Uebertragung : ARRAY  [0 .. 1 ] OF "UDT_SendRec";    
  END_STRUCT ;    
BEGIN
   Start := FALSE; 
   Busy := FALSE; 
   Busy_Old := FALSE; 
   DatensatzNr := 0; 
   Ausf_bis_DSNr := 1; 
   DB_Uebertragung[0].Send := TRUE; 
   DB_Uebertragung[0].Quelle_Baustein := 101; 
   DB_Uebertragung[0].Quelle_Start := 0; 
   DB_Uebertragung[0].Ziel_Baustein := 101; 
   DB_Uebertragung[0].Ziel_Start := 0; 
   DB_Uebertragung[0].Daten_Laenge := 24; 
   DB_Uebertragung[0].LADDR := W#16#7FE; 
   DB_Uebertragung[0].Status := 0; 
   DB_Uebertragung[0].Status_Alt := 0; 
   DB_Uebertragung[1].Send := TRUE; 
   DB_Uebertragung[1].Quelle_Baustein := 101; 
   DB_Uebertragung[1].Quelle_Start := 24; 
   DB_Uebertragung[1].Ziel_Baustein := 101; 
   DB_Uebertragung[1].Ziel_Start := 24; 
   DB_Uebertragung[1].Daten_Laenge := 24; 
   DB_Uebertragung[1].LADDR := W#16#7FE; 
   DB_Uebertragung[1].Status := 0; 
   DB_Uebertragung[1].Status_Alt := 0; 
END_DATA_BLOCK
 
Zurück
Oben