Zuviel Werbung? - > Hier kostenlos beim SPS-Forum registrieren

Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 19

Thema: Bereichslängenfehler bei einem Multiinstanz-FC

  1. #1
    Registriert seit
    05.11.2014
    Beiträge
    13
    Danke
    2
    Erhielt 0 Danke für 0 Beiträge

    Frage


    Zuviel Werbung?
    -> Hier kostenlos registrieren
    Guten Morgen,

    Ich habe hier einen Bereichlängenfehler in einem FC, der im Programm sehr oft aufgerufen wird.
    Es wird eine DB-Adresse berechnet, anhand extern angelegter Daten beim Aufruf.
    Die Adresse ist weit außerhalb des DB-Bereichs, das habe ich schon gesehen, normalerweise ist ein Bereichslängenfehler auch kein Problem für mich.

    Jetzt das große ABER:
    Ich weiß nicht, wie ich nun herausfinden kann, in welchem Aufruf der Fehler passiert.
    Der Baustein wird ca. 500 mal aufgerufen (sehr großes Programm) und nur an ein, zwei stellen tritt der Fehler auf.
    Wie kann ich jetzt herausfinden, in welchem Aufruf das passiert?

    LG
    Sebastian

    PS: Die SPS läuft im Produktivbetrieb, ich kann sie nicht stoppen lassen, indem ich OB121 lösche und dann in die Stacks schaue.
    Zitieren Zitieren Gelöst: Bereichslängenfehler bei einem Multiinstanz-FC  

  2. "Dafür hat siemens z.B. den Simulator erfunden Da kannst du das dann einfach in Stop laufen lassen.

    Aber es gäbe ja noch die Möglichkeit den OB121 den du ja geladen hast auch auszuwerten. Die sind nicht nur dazu da die CPU vorm Stop zu bewahren.

    Code:
    ORGANIZATION_BLOCK "Programming error"
    { S7_Optimized_Access := 'TRUE' }
    VERSION : 0.1
       VAR_TEMP 
          index : Int;
       END_VAR
    
    
    
    
    BEGIN
        FOR #index := 100 TO 1 BY -1 DO
            "FehlerSpeicher".OB121[#index] := "FehlerSpeicher".OB121[#index - 1];
        END_FOR;
        
        "FehlerSpeicher".OB121[0].BlockNr := #BlockNr;
        "FehlerSpeicher".OB121[0].Reaction := #Reaction;
        "FehlerSpeicher".OB121[0].Fault_ID := #Fault_ID;
        "FehlerSpeicher".OB121[0].BlockType := #BlockType;
        "FehlerSpeicher".OB121[0].Area := #Area;
        "FehlerSpeicher".OB121[0].DBNr := #DBNr;
        "FehlerSpeicher".OB121[0].Csg_OBNr := #Csg_OBNr;
        "FehlerSpeicher".OB121[0].Width := #Width;
    END_ORGANIZATION_BLOCK
    Es sollte noch ein anwenderdefinierte Datentyp definiert werden, kann man ebenfalls als Quelle laden:
    Code:
    TYPE "OB121_Struct"
    VERSION : 0.1
       STRUCT
          BlockNr { S7_HMI_Accessible := 'False'; S7_HMI_Visible := 'False'} : UInt;   // Number of causing block
          Reaction { S7_HMI_Accessible := 'False'; S7_HMI_Visible := 'False'} : USInt;   // 0:ignore, 1:substitute, 2:skip
          Fault_ID { S7_HMI_Accessible := 'False'; S7_HMI_Visible := 'False'} : Byte;   // Fault identifier
          BlockType { S7_HMI_Accessible := 'False'; S7_HMI_Visible := 'False'} : USInt;   // 16#01:OB, 16#02:FC, 16#03:FB, 16#04:SFC, 16#05:SFB, 16#06:DB: Type of block causing the error
          Area { S7_HMI_Accessible := 'False'; S7_HMI_Visible := 'False'} : USInt;   // Area where the error occured
          DBNr { S7_HMI_Accessible := 'False'; S7_HMI_Visible := 'False'} : DB_ANY;   // DB number if Area = DB or DI
          Csg_OBNr { S7_HMI_Accessible := 'False'; S7_HMI_Visible := 'False'} : OB_ANY;   // Number of OB causing the error
          Csg_Prio { S7_HMI_Accessible := 'False'; S7_HMI_Visible := 'False'} : USInt;   // Priority of OB causing the error
          Width { S7_HMI_Accessible := 'False'; S7_HMI_Visible := 'False'} : USInt;   // 0:bit, 1:byte, 2:word, 3:dword, 4:lword
       END_STRUCT;
    
    
    END_TYPE
    in einem DB (in meinem Beispiel heisst der "FehlerSpeicher") dadrin ein Array [0..100] of Struct bzw "OB121_Struct" erstellen. Der OB121 sollte also dann nicht unbedingt auf undefinierte Speicherbereiche zugreifen. Also vorher mal testen.

    mfG René

    edit: kleines Beispiel zugefügt
    edit2: weil einige nicht wissen wie das mit Anwenderdefinierten Datentypen funktioniert"


  3. #2
    Registriert seit
    22.11.2006
    Ort
    CH
    Beiträge
    3.618
    Danke
    775
    Erhielt 646 Danke für 492 Beiträge

    Standard

    Dafür hat siemens z.B. den Simulator erfunden Da kannst du das dann einfach in Stop laufen lassen.

    Aber es gäbe ja noch die Möglichkeit den OB121 den du ja geladen hast auch auszuwerten. Die sind nicht nur dazu da die CPU vorm Stop zu bewahren.

    Code:
    ORGANIZATION_BLOCK "Programming error"
    { S7_Optimized_Access := 'TRUE' }
    VERSION : 0.1
       VAR_TEMP 
          index : Int;
       END_VAR
    
    
    
    
    BEGIN
        FOR #index := 100 TO 1 BY -1 DO
            "FehlerSpeicher".OB121[#index] := "FehlerSpeicher".OB121[#index - 1];
        END_FOR;
        
        "FehlerSpeicher".OB121[0].BlockNr := #BlockNr;
        "FehlerSpeicher".OB121[0].Reaction := #Reaction;
        "FehlerSpeicher".OB121[0].Fault_ID := #Fault_ID;
        "FehlerSpeicher".OB121[0].BlockType := #BlockType;
        "FehlerSpeicher".OB121[0].Area := #Area;
        "FehlerSpeicher".OB121[0].DBNr := #DBNr;
        "FehlerSpeicher".OB121[0].Csg_OBNr := #Csg_OBNr;
        "FehlerSpeicher".OB121[0].Width := #Width;
    END_ORGANIZATION_BLOCK
    Es sollte noch ein anwenderdefinierte Datentyp definiert werden, kann man ebenfalls als Quelle laden:
    Code:
    TYPE "OB121_Struct"
    VERSION : 0.1
       STRUCT
          BlockNr { S7_HMI_Accessible := 'False'; S7_HMI_Visible := 'False'} : UInt;   // Number of causing block
          Reaction { S7_HMI_Accessible := 'False'; S7_HMI_Visible := 'False'} : USInt;   // 0:ignore, 1:substitute, 2:skip
          Fault_ID { S7_HMI_Accessible := 'False'; S7_HMI_Visible := 'False'} : Byte;   // Fault identifier
          BlockType { S7_HMI_Accessible := 'False'; S7_HMI_Visible := 'False'} : USInt;   // 16#01:OB, 16#02:FC, 16#03:FB, 16#04:SFC, 16#05:SFB, 16#06:DB: Type of block causing the error
          Area { S7_HMI_Accessible := 'False'; S7_HMI_Visible := 'False'} : USInt;   // Area where the error occured
          DBNr { S7_HMI_Accessible := 'False'; S7_HMI_Visible := 'False'} : DB_ANY;   // DB number if Area = DB or DI
          Csg_OBNr { S7_HMI_Accessible := 'False'; S7_HMI_Visible := 'False'} : OB_ANY;   // Number of OB causing the error
          Csg_Prio { S7_HMI_Accessible := 'False'; S7_HMI_Visible := 'False'} : USInt;   // Priority of OB causing the error
          Width { S7_HMI_Accessible := 'False'; S7_HMI_Visible := 'False'} : USInt;   // 0:bit, 1:byte, 2:word, 3:dword, 4:lword
       END_STRUCT;
    
    
    END_TYPE
    in einem DB (in meinem Beispiel heisst der "FehlerSpeicher") dadrin ein Array [0..100] of Struct bzw "OB121_Struct" erstellen. Der OB121 sollte also dann nicht unbedingt auf undefinierte Speicherbereiche zugreifen. Also vorher mal testen.

    mfG René

    edit: kleines Beispiel zugefügt
    edit2: weil einige nicht wissen wie das mit Anwenderdefinierten Datentypen funktioniert
    Geändert von vollmi (21.04.2016 um 09:39 Uhr)

  4. Folgende 2 Benutzer sagen Danke zu vollmi für den nützlichen Beitrag:

    de vliegende hollander (21.04.2016),Pimp.my.PC (21.04.2016)

  5. #3
    Pimp.my.PC ist offline Neuer Benutzer
    Themenstarter
    Registriert seit
    05.11.2014
    Beiträge
    13
    Danke
    2
    Erhielt 0 Danke für 0 Beiträge

    Standard

    Ja, das is ne gute Idee, danke.
    Ich werds mal probieren.

  6. #4
    Registriert seit
    06.10.2003
    Beiträge
    3.409
    Danke
    449
    Erhielt 504 Danke für 407 Beiträge

    Standard

    Auf die Schnelle grenze ich bei so einem Fehler die Fehlerstelle durch Einfügen von BEA oder durch Auskommentieren von Bausteinaufrufen ein.
    Es gibt viel mehr Leute, die freiwillig aufgeben, als solche, die echt scheitern.
    Henry Ford

  7. #5
    Registriert seit
    22.06.2009
    Ort
    Sassnitz
    Beiträge
    11.177
    Danke
    922
    Erhielt 3.288 Danke für 2.657 Beiträge

    Standard

    Das Auswerten der OB121-Informationen wird bei diesem Fehler vermutlich garnichts bringen.
    Die Info, welche Art Fehler auftrat und auf welche fehlerhafte Adresse zugegriffen werden soll, findet man ja bereits im Diagnosepuffer. (Der Code von vollmi ist im Grunde nichts anderes als ein auf Programmierfehler gefilterter zusätzlicher Diagnosepuffer. Mehr Infos als der CPU-Diagnosepuffer liefert vollmis Puffer nicht.)
    Die Programmadresse wo der Fehler auftrat, wird bei S7-300 nicht mitgeteilt. Und selbst wenn man die Programmstelle wüßte, dann weiß man immer noch nicht, bei welchem Aufruf der Fehler passiert.

    @Pimp.my.PC
    Woher weißt Du, in welchem FC der Zugriffsfehler auftritt?
    Tritt der Fehler in jedem OB1-Zyklus auf oder nur selten/sporadisch?

    500 Aufrufstellen sind schon mal ganz schön viele. Da bräuchte man schon sehr viel Glück und Intuition oder Ausdauer, um den fehlerhaften Aufruf direkt zu finden.

    Bei so vielen potentiellen Fehlerstellen würde ich wahrscheinlich so vorgehen:
    - am Anfang des OB1 eine globale Variable (z.B. Merkerwort MW100) auf 0 schreiben
    - im OB121 das Merkerwort inkrementieren
    - am Ende des OB1 ein "L MW100" einfügen und beobachten --> da sehe ich schon mal, ob und wieviele fehlerhafte Aufrufe es gab
    - beginnend im OB1 ca. in der Mitte des Programms ein "L MW100" einfügen und beobachten --> ist der Wert da noch 0, dann liegt die Fehlerstelle weiter hinten im Programm, ist der Wert <> 0 dann weiter vorn
    - nun in ca. der Mitte des verbleibenden Programmbereichs ein "L MW100" einfügen und beobachten --> und so weiter...

    Auf diese Art sollte nach Einfügen von 10 bis 15 Teststellen der erste fehlerhafte Aufruf zu finden sein. Falls der Fehler nicht in jedem OB1-Zyklus auftritt, dann kann das Testlesen auf ein Umspeichern auf verschiedene MW oder DBW bei <>0 erweitert werden. Dieses Vorgehen kann man in der laufenden Anlage machen.


    Irgendwie ist der Fehler aber auch ein Bug im FC, daß er (unzulässige?) Eingangsparameter (ungeprüft?) verarbeitet und fehlerhafte Zugriffsadressen erzeugt. (oder ist das so ein Baustein zum absolut adressierten 'rumpoken im Datenspeicher, der prinzipiell auf jede denkbare Adresse zugreifen können soll?) Einen Bug könnte man beseitigen und dabei vielleicht eine Fehlerrückgabe programmieren. Zuerstmal prüfen, ob der Fehler vielleicht nur im FC liegt (z.B. falsche Verwendung von TEMP, falsche Verarbeitung von Datentypen, falsche Operationen, falsche Logik) oder ob es wirklich ein fehlerhafter Aufruf ist.

    Harald
    Es ist immer wieder überraschend, wie etwas plötzlich funktioniert, sobald man alles richtig macht.

    FAQ: Linkliste SIMATIC-Kommunikation über Ethernet

  8. #6
    Registriert seit
    22.11.2006
    Ort
    CH
    Beiträge
    3.618
    Danke
    775
    Erhielt 646 Danke für 492 Beiträge

    Standard

    Ich mach dafür einen zusätzlichen speicherplatz in die Struktur.

    zu beginn von OB1 lade ich dann 0
    Code:
    "Auslösestelle" := 0;
    Dann kann man an verschiedenen neuralgischen Punkten die Zuordnungsnummern laden
    z.B. vor dem 1. Aufruf FB11
    Code:
    "Ausloesestelle" := 2020;
    vor dem 2. Aufruf FB11
    Code:
    "Ausloesestelle" := 2021;
    Im OB121 muss dann einfach noch zusätzlich eingefügt werden
    Code:
    "FehlerSpeicher".OB121[0].Ausloesestelle:= "Ausloesestelle";
    Dann hat man zum Fehler auch immer die letzte Ausloesestelle. 0 Wenn die erste Auslösestelle noch nicht erreicht wurde.

    Das kann man übrigens bei kritisch zu parametrierenden Bausteinen, auch fest einplanen. Und an der Schnittstelle eine AufrufID übergeben welche unbedingt auf "Ausloesestelle" kopiert wird (Und zwar vor dem eigentlichen Bausteincode).

    mfG René

  9. #7
    Registriert seit
    22.11.2006
    Ort
    CH
    Beiträge
    3.618
    Danke
    775
    Erhielt 646 Danke für 492 Beiträge

    Standard

    Wenn man jetzt schon den Baustein 500mal aufruft. am Start des Bausteins z.B.
    "Ausloesestelle" := "Ausloesestelle" + 1;
    Einfügen. Dann weiss man zumindest der wievielte Aufruf den Fehler ausgelöst hat.

    mfG René

  10. #8
    Registriert seit
    22.06.2009
    Ort
    Sassnitz
    Beiträge
    11.177
    Danke
    922
    Erhielt 3.288 Danke für 2.657 Beiträge

    Standard

    Ein Übergabeparameter "AufrufID" ist eine gute Variante, nur leider nachträglich nur noch sehr aufwendig einzubauen, weil dadurch alle Aufrufe geändert werden müssen.

    Harald
    Es ist immer wieder überraschend, wie etwas plötzlich funktioniert, sobald man alles richtig macht.

    FAQ: Linkliste SIMATIC-Kommunikation über Ethernet

  11. #9
    Pimp.my.PC ist offline Neuer Benutzer
    Themenstarter
    Registriert seit
    05.11.2014
    Beiträge
    13
    Danke
    2
    Erhielt 0 Danke für 0 Beiträge

    Standard

    Hey,

    Ein Paar Fakten vorab:
    Es ist eine S7-416F
    Das Programm ist nicht von mir, ich betreue lediglich die Anlage.
    Die Anlage läuft und ich kann leider keine einzelnen Aufrufe auskommentieren, oder größere Änderungen vornehmen, da die Produktion gesichert sein muss.

    Es handelt sich hier um einen FC , welcher Daten der zu fördernden Teile auf einen nächsten Förderer (DB) kopiert. Die Förderstrecke ist mehrfach verzweigt und bedient mehrere Anlagen.
    Es ist im Prinzip ne Datenverfolgung. Der FC wird immer von dem jeweiligen Förderer-FC aufgerufen, wenn dieser an den nächsten übergibt.
    Somit ergibt sich kein zyklischer Aufruf.

    @PN/DP: Es ist definitiv ein Bug im FC, da dieser die Eingangsvariable ungeprüft von iQuelle nach iZiel umkopiert. Das weiß ich.
    Aber wenn man ihn überall ordentlich beschreibt, passiert halt nix, deswegen war es nicht notwendig eine Prüfung einzubauen.

    Ich weiß aus dem Diagnosepuffer, welcher FC das is, ich weiß nur nicht, wo er seine falschen Daten herbekommt.

    Ereignis 1 von 120: Ereignis-ID 16# 2523
    Bereichslängenfehler beim Schreiben
    Global -DB , Wortzugriff, Zugriffsadresse: 53536
    FC-Nummer: 800
    Bausteinadresse: 620
    Angeforderter OB: Programmierfehler-OB (OB 121)
    Prioritätsklasse: 1
    interner Fehler, kommendes Ereignis
    08:04:58.651 21.04.2016
    (Kodierung: 16# 2523 0179 8C24 D120 0320 026C)

    Das mit der Aufruf-ID ist auch ne sehr gute Idee, allerdings müsste ich auch dann an jeden aufrufenden Baustein ran, oder an den Baustein selbst.

    LG und danke für die guten Tipps.
    Sebastian

  12. #10
    Registriert seit
    22.11.2006
    Ort
    CH
    Beiträge
    3.618
    Danke
    775
    Erhielt 646 Danke für 492 Beiträge

    Standard


    Zuviel Werbung?
    -> Hier kostenlos registrieren
    du könntest eben im entsprechenden Baustein mal den Code einfügen
    L MW100
    L 1
    +I
    T MW100

    Oder halt entsprechend der Programmiersprache die der Baustein hat.
    zu begin des OB1
    L 0
    T MW100

    Im OB121 muss dann MW100 (oder die entsprechende Variable die du verwendet hast) weggesichert werden.
    Damit hast du dann den n-ten Bausteinaufruf, dieser verursacht den Zugriffsfehler effektiv. Wenn du ihn in die Obengenannte Struktur einpflegst hast du den n-ten Bausteinaufruf zum Fehlereintrag im OB121.

    Es muss also nur der fehlerbehaftete Baustein einmal geladen werden, der DB der als Fehlerspeicher fungiert, plus der geänderte OB121. Achte darauf der OB121 sauber läuft und keine Zugriffsfehler verursacht.
    Schnell im Simulator laden das FIFO und so sauber sind und einen programmfehler verursachen.

    mfG René

Ähnliche Themen

  1. Step 7 Bereichlängenfehler beim schreiben
    Von Enti im Forum Simatic
    Antworten: 5
    Letzter Beitrag: 26.08.2015, 17:18
  2. Antworten: 2
    Letzter Beitrag: 21.05.2014, 13:15
  3. Step 7 Bereichlängenfehler bei Funktionsaufruf
    Von fk- princess im Forum Simatic
    Antworten: 3
    Letzter Beitrag: 31.01.2014, 10:40
  4. Step 7 Bereichlängenfehler beim Lesen
    Von Vokal12 im Forum Simatic
    Antworten: 8
    Letzter Beitrag: 05.11.2013, 10:58
  5. Antworten: 9
    Letzter Beitrag: 16.03.2012, 19:39

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •