Step 7 Baustein von AWL in SCL ändern / Problem mit Schleife

PBO-WE

Level-1
Beiträge
165
Reaktionspunkte
6
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo.

Ich hatte mal einen Baustein zur Störmeldeverarbeitung gebastelt, welchen ich jetzt auch gerne in einer 1200er einsetzen möchte. Zu diesem Zweck habe ich versucht den in SCL zu programmieren. Ich muss dazu sagen, dass ich noch nicht viel Erfahrung in SCL habe.

Leider funktioniert der Baustein nicht so wie er soll, bzw. wie er es in AWL getan hat.
Meldungen im IN_WORD die kommen, sollen den Ausgang auf 1 setzen, wenn das entsprechende Quittierbit gesetzt wurde, soll der Ausgang wieder 0 werden und der Ausgang Quittierung für einen Zyklus 1 sein.

Ich sehe einfach nicht wo der oder die Fehler liegen....

Hier mal die beiden Quellen:
Code:
FUNCTION_BLOCK FB 255
TITLE =Meldebaustein WORD
//Wechselt ein Bit des Melde_WORD auf 1 so wird der Ausgang "Meldung" so lange 1 
//bis die Meldung gegangen und quittiert ist.
AUTHOR : 'T.B.'
VERSION : 0.1

VAR_INPUT
  Quittierung_Extern : BOOL ; 
  Melde_WORD : WORD ; 
END_VAR
VAR_OUTPUT
  Meldung : BOOL ; 
  Quittierung : BOOL ; 
END_VAR
VAR_IN_OUT
  Quittier_WORD : WORD ; 
END_VAR
VAR
  Meldungen : ARRAY  [0 .. 15 ] OF BOOL ; 
  FLM : ARRAY  [0 .. 31 ] OF BOOL ; 
END_VAR
VAR_TEMP
  Meldewort : ARRAY  [0 .. 15 ] OF //Lokal Wort 0
  BOOL ; 
  Quittierwort : ARRAY  [0 .. 15 ] OF //Lokal Wort 2
  BOOL ; 
END_VAR
BEGIN
NETWORK
TITLE =Melde- und Quittierwort in den STAT-Bereich verschieben
//Um mit den einzelnen Bits der Wörter arbeiten zu können müssen die Wörter in 
//den 
//Lokaldatenbereich verschoben werden und als ARRAY abgelegt werden.
      L     #Melde_WORD; 
      T     LW     0; // Meldewort
      L     #Quittier_WORD; 
      T     LW     2; // Quittierwort
NETWORK
TITLE =
      O     #Quittierwort[0]; 
      FP    #FLM[0]; 
      S     #Quittierung; 
.
.  // Hier wird 16 mal das selbe gemacht, daher habe ich es in eine Schleife gepackt und hier entfernt.
.
      O     #Quittierwort[15]; 
      FP    #FLM[15]; 
      S     #Quittierung; 

NETWORK
TITLE =
//////////////////\\\\\\\\\\\\\\\\
      U     #Meldewort[0]; 
      FP    #FLM[16]; 
      S     #Meldungen[0]; 
      R     #Quittierwort[0]; 
      R     #Quittierung; 
      U     #Quittierung_Extern; 
      U     #Meldungen[0]; 
      S     #Quittierwort[0]; 
      U     #Quittierwort[0]; 
      R     #Meldungen[0]; 
//////////////////\\\\\\\\\\\\\\\\
.
.  // Hier wird 16 mal das selbe gemacht, daher habe ich es in eine Schleife gepackt und hier entfernt.
.  
//////////////////\\\\\\\\\\\\\\\\
      U     #Meldewort[15]; 
      FP    #FLM[31]; 
      S     #Meldungen[15]; 
      R     #Quittierwort[15]; 
      R     #Quittierung; 
      U     #Quittierung_Extern; 
      U     #Meldungen[15]; 
      S     #Quittierwort[15]; 
      U     #Quittierwort[15]; 
      R     #Meldungen[15]; 
//////////////////\\\\\\\\\\\\\\\\
      O     #Meldungen[0]; 
      O     #Meldungen[1]; 
      O     #Meldungen[2]; 
      O     #Meldungen[3]; 
      O     #Meldungen[4]; 
      O     #Meldungen[5]; 
      O     #Meldungen[6]; 
      O     #Meldungen[7]; 
      O     #Meldungen[8]; 
      O     #Meldungen[9]; 
      O     #Meldungen[10]; 
      O     #Meldungen[11]; 
      O     #Meldungen[12]; 
      O     #Meldungen[13]; 
      O     #Meldungen[14]; 
      O     #Meldungen[15]; 
      =     #Meldung; 
//////////////////\\\\\\\\\\\\\\\\
      L     LW     2; 
      T     #Quittier_WORD; 

END_FUNCTION_BLOCK

Code:
FUNCTION_BLOCK FB256
{ S7_Optimized_Access := 'FALSE' }
TITLE = 'Störmeldungsverarbeitung'
//
// Baustein-Kommentar ...
//
VERSION : '1.0'
AUTHOR  : 'T.B.'
NAME    : 'Fault'
// Bausteinparameter
VAR_INPUT
    // Eingangsparameter
    quittieren : BOOL := 0;
    Meldungen : WORD;
    AT_MeldeArray AT Meldungen : ARRAY[0..15] OF BOOL;
END_VAR
VAR_IN_OUT
    // Durchgangsparameter
    Quittierungen : WORD;
END_VAR
VAR_OUTPUT
    // Ausgangsparameter
    Meldung : BOOL;
    Quittierung : BOOL;
END_VAR
VAR_TEMP
    // temporäre Variablen
    
END_VAR
VAR
    // statische Variablen
    S_Meldungen : ARRAY[0..15] OF BOOL;
//    AT_S_Meldungen AT S_Meldungen : INT;
    FLM : ARRAY[0..31] OF BOOL;
    i : INT := 0;
    j : INT := 0;
    x : INT := 0;
    S_QuittWort : WORD;
    S_QuittArray AT S_QuittWort : ARRAY[0..15] OF BOOL;
    S_Quit_Pulse : ARRAY[0..15] OF BOOL;
    S_Melde_Pulse : ARRAY[0..15] OF BOOL;
END_VAR
S_QuittWort := Quittierungen;
    FOR i := 0 TO 15 DO
        // Flankenauswertung Positiv Quittierbit
        S_Quit_Pulse[i] := S_QuittArray[i] AND NOT FLM[i];
        FLM[i] := S_QuittArray[i];
        // Wenn positive Flanke des Quittierbits
        IF S_Quit_Pulse[i] THEN
            Quittierung := 1; // Setze Ausgang "Quittierung"
        END_IF;
    END_FOR;
    
    FOR j := 0 TO 15 DO
        // Flankenauswertung Positiv Meldebit
        S_Melde_Pulse[j] := AT_MeldeArray[j] AND NOT FLM[j + 16];
        FLM[j + 16] := AT_MeldeArray[j];
        // Wenn positive Flanke dann
        IF S_Melde_Pulse[j] THEN
            S_Meldungen[j] := 1;
            S_QuittArray[j] := 0;
            Quittierung := 0;
        END_IF;
        
        IF quittieren AND AT_MeldeArray[j] THEN
            S_QuittArray[j] := 1;
        END_IF;
        
        IF S_QuittArray[j] THEN
            S_Meldungen[j] := 0;
        END_IF;
    END_FOR;
    
    x := 0;
    FOR i := 0 TO 15 DO
        
        IF S_Meldungen[i] THEN
            x := x + 1;
        END_IF;
    END_FOR;
    
    IF x > 0 THEN
        Meldung := 1;
    ELSE
        Meldung := 0;
    END_IF;
Quittierungen := S_QuittWort;
END_FUNCTION_BLOCK

Gruß
Thomas
 
Was funktioniert denn alles nicht?

Wenn der Ausgang "Quittierung" nur für einen Zyklus auf 1 sein soll, könntest du diesen pauschal am Anfang des Bausteins auf 0 setzen. So wie du es jetzt hast, bleibt er für alle Ewigkeit auf 1 wenn er einmal gesetzt wurde.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hi.

Ich bin gerade etwas verdutzt. Ich habe mir noch mal ein neues Testprojekt angelegt und beide Bausteine dort eingefügt und getestet.
Es scheint, als hätte ich bei meinen vorherigen Tests irgend etwas falsch gemacht.
Der Ausgang "Meldung" war dort dauerhaft gesetzt nachdem einmal eine Meldung gekommen war und konnte nicht quittiert werden.

Danke trotzdem für den Hinweis mit der Quittierung. Das war in dem alten Baustein auch nicht richtig.

Gruß
 
So, Doch noch einen Fehler gefunden.
Man kann Störungen nicht über die Externe Quittierung zurücksetzen wenn die Störung gegangen ist.
 
Zuletzt bearbeitet:
Ich hab jetzt einfach am Anfang wenn quittieren 1 ist alle Quittierbits auf 1 gesetzt, dann geht's.
Hatte auch Probleme mit den Flanken.

Code:
FUNCTION_BLOCK FB256
{ S7_Optimized_Access := 'FALSE' }
TITLE = 'Störmeldungsverarbeitung'
//
// Baustein-Kommentar ...
//
VERSION : '1.0'
AUTHOR  : 'T.B.'
NAME    : 'Fault'
// Bausteinparameter
VAR_INPUT
    // Eingangsparameter
    quittieren : BOOL := 0;
    Meldungen : WORD;
    AT_MeldeArray AT Meldungen : ARRAY[0..15] OF BOOL;
END_VAR
VAR_IN_OUT
    // Durchgangsparameter
    Quittierungen : WORD;
END_VAR
VAR_OUTPUT
    // Ausgangsparameter
    Meldung : BOOL;
    Quittierung : BOOL;
END_VAR
VAR_TEMP
    // temporäre Variablen
    
END_VAR
VAR
    // statische Variablen
    S_Meldungen : ARRAY[0..15] OF BOOL;
//    AT_S_Meldungen AT S_Meldungen : INT;
    FLM : ARRAY[0..31] OF BOOL;
    i : INT := 0;
    j : INT := 0;
    x : INT := 0;
    S_QuittWort : WORD;
    S_QuittArray AT S_QuittWort : ARRAY[0..15] OF BOOL;
    S_Quit_Pulse : ARRAY[0..15] OF BOOL;
    S_Melde_Pulse : ARRAY[0..15] OF BOOL;
END_VAR
S_QuittWort := Quittierungen;

        
        IF quittieren THEN
            FOR i := 0 TO 15 DO
                 S_QuittArray[i] := 1;
            END_FOR;
        END_IF;

    FOR i := 0 TO 15 DO
        // Flankenauswertung Positiv Quittierbit
        S_Quit_Pulse[i] := S_QuittArray[i] AND NOT FLM[i];
        FLM[i] := S_QuittArray[i];
        // Wenn positive Flanke des Quittierbits
        IF S_Quit_Pulse[i] THEN
            Quittierung := 1; // Setze Ausgang "Quittierung"
        END_IF;
    END_FOR;
    
    FOR j := 0 TO 15 DO
        // Flankenauswertung Positiv Meldebit
        S_Melde_Pulse[j] := AT_MeldeArray[j] AND NOT FLM[j + 16];
        FLM[j + 16] := AT_MeldeArray[j];
        // Wenn positive Flanke dann
        IF S_Melde_Pulse[j] THEN
            S_Meldungen[j] := 1;
            S_QuittArray[j] := 0;
            Quittierung := 0;
        END_IF;
        
        IF S_QuittArray[j] THEN
            S_Meldungen[j] := 0;
        END_IF;
    END_FOR;
    
    x := 0;
    FOR i := 0 TO 15 DO
        
        IF S_Meldungen[i] THEN
            x := x + 1;
        END_IF;
    END_FOR;
    
    IF x > 0 THEN
        Meldung := 1;
    ELSE
        Meldung := 0;
    END_IF;
Quittierungen := S_QuittWort;
END_FUNCTION_BLOCK
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Für meinen Geschmack ist das alles unnötig kompliziert.
Wenn die Meldungen schon als Variable vom Typ WORD vorliegen, würde ich das auch mit Wortverknüpfung erledigen (AND, XOR, usw.). Das wird nicht nur übersichtlicher, sondern auch schneller. Und da der At-Zugriff wegfällt, kannst du auch die "optimierte" Bausteinoption setzen.
 
etwas Kritik

Wieviele Jahrzehnte schleppt Ihr schon diesen umständlichen und nicht ganz sauberen Baustein mit Euren Projekten mit? ;)
Die Konvertierung zu SCL könntest Du zum Anlaß nehmen, mal über die Funktion des Bausteins nachzudenken und den Code komplett neu und effizient zu formulieren. Dann könnte der Baustein sogar mit "optimiertem Zugriff" funktionieren. :cool:

Statt Deine WORDs in Bits zu zerpflücken und umständlich in zwei Schleifen für 16 Bits das selbe zu machen, könntest Du auch alle 16 Bits auf einmal als WORD verarbeiten. Auch das Zählen der Bits in einer dritten Schleife könnte man auf den simplen Vergleich eines WORD auf <> 0 reduzieren.

Und statt "IF x > 0 THEN Meldung := 1; ELSE Meldung := 0; END_IF;" kann man einfacher schreiben "Meldung := x > 0 ;"

Harald
 
Danke für die Anregungen... :)

Ich würde mich im Vergleich zu den Meisten hier nur als Hobby-Programmierer bezeichnen.
Ich habe zwar schon ein paar Jahre SPS Erfahrung, aber das Problem ist, dass ich der Einzige bin, und somit keinen Erfahrungsaustausch unter Kollegen möglich war.
Auch Internetzugriff habe ich in der Firma erst seit zwei Wochen.... Traurig, aber wahr.

Ich werde mir das mit den Wort-Verknüpfungen mal ansehen. Danke.

Gruß
 
Zurück
Oben