TIA Fehler-Array auswerten / Neuen Fehler erkennen

fabey

Level-2
Beiträge
114
Reaktionspunkte
7
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen,

aufbauend auf diesem Thema: Es gibt ein Bool-Array, jedes Bit steht für eine Fehlermeldungen und es gibt einen Sammelfehler.

Folgende Frage: Wenn ich jetzt nicht nur einen Sammelfehler generieren möchte, sondern auch detektieren möchte, ob ein neuer Fehler hinzugekommen ist. Damit könnte man z.B. eine Hupe für einige Sekunden einschalten immer wenn ein neuer Fehler (zu eventuell bereits bestehenden Fehlern) hinzukommt? Wie mache das am besten?

Vielen Dank
 
In der LGF gäbe es den FB LGF_CountRisInDWord.
Dieser zählt dir die positiven Flanken der einzelnen Bits in einem DWord.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
neuer Fehler hinzugekommen = jetzt ist ein Fehler, der vorher noch nicht da war = Standardproblem Flankenerkennung
das ganze gleich Wordweise: neustoerung := (Meldeword_1 AND NOT Meldeword_1_vorher) OR (Meldeword_2 AND NOT Meldeword_2_vorher) OR ...

Forumssuche: Neustörung

Harald
 
Vielen Dank @R4m80 das ist ein guter Hinweis.

Die LGF (für alle die es nicht kennen poste ich noch den Link) hatte ich tatsächlich auch mal verwendet um zwei Arrays zu vergleichen mit dem Baustein LGF_CompareVariant. Das ist ja auch eine Möglichkeit, wenn man ein zweites gleich großes Array mit allen Elementen auf FALSE anlegt, um zu sich einen Sammelfehler zu bilden.

Danke @PN/DP wenn man das Wort zur Suche verwendet findet man ja wirklich viele Ergebnisse! Damit muss ich mal prüfen was für mich die beste Lösung des Problemens ist.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Nein.
Weggefallene Fehler sind jetzt nicht mehr da, waren aber vorher da und werden so erkannt:
weggefallen := (NOT Meldeword_1 AND Meldeword_1_vorher) OR (NOT Meldeword_2 AND Meldeword_2_vorher) OR ...

PS: Am besten mal die Logiktabellen aufschreiben:
Code:
vorher 1100
jetzt  0101
-----------
Neu    0001   = jetzt und nicht vorher  =  jetzt = 1 und vorher = 0
Weg    1000   = nicht jetzt und vorher  =  jetzt = 0 und vorher = 1

Harald
 
Zuletzt bearbeitet:
Hallo fabey,
Hallo Zusammen,
ich nutzte folgenden Baustein. Dieser kopiert mir die Störmeldungen auch passen für WinCCflex um, so das "Meld 123" auch im HMI "Meld 123" ist.
Zudem gibt er ein Sammelbit, das eine Meldung vorhanden und ob eine neue Meldung hinzu gekommen ist aus. Vielleicht passt ja was bzw kannst Du davon nutzen.

Aufruf:
CALL "fcAllg_ChangeStoerBits"
ia_Quellzeiger :=P#DB18.DBX0.0 WORD 32
idi_ZielOffset :=DINT#64
idi_AltwertOffset :=DINT#192
ib_ResetImp :="xVImpStörReset"
iT_Nr_Reset :="tSE ResetHMI"
iob_Hupe :="m SStörHupe"
iob_SStoer :="m SStörmeldung"
iob_Hilfsbit1 :="m HM21.4"
iob_Hilfsbit2 :="m HM21.5"

"DB18":
Stoerung Array[1..512] of Bool 0.0 Quellbereich für KopierFC (für die Störmeldungen) Adresse 0 !nicht ändern !!
Stoer_SPSQuitt Array[0..63] of Word 64.0 Zielbereich für KopierFC / Quelle für Visualisierung (für die Störmeldungen)
AltwertStoerung Array[0..31] of Word 192.0 dient zum Vergleich ob eine neue Störung hinzugekommen ist



der Baustein..


FUNCTION "fcAllg_ChangeStoerBits" : Void
{ S7_Optimized_Access := 'FALSE' }
VERSION : 0.2
//6.12.2011 erweitert kontrolle auf gegangene Störung...
//
//Beispiel wie ein DB aussehen sollte
//
//Stoerung Array [1..512] of bool [32 WORD]
//Stoer_SPS_Quitt Array[0..63] [64 WORD] (Ziel und Quittiebereich fürs HMI)
//AltwertStoerung Array[0..31] [32 WORD] (zur Erkennung auf neue Störungen)
//
//Aufruf
// CALL "fc ChangeStoerBits"
// ia_Quellzeiger :=P#DB18.DBX 0.0 WORD 32 //Stoerung Array [1..512]
// idi_ZielOffset :=L#64 //Stoer_SPS_Quitt Array[0..63]
// idi_AltwertOffset:=L#192 //AltwertStoerung Array[0..31]
// ib_Reset :=M1000.0
// iT_Nr_Reset :=T10
// iob_Hupe :=M1000.1
// iob_SStoer :=M1000.2
// iob_Hilfsbit :=M1000.3
//
VAR_INPUT
ia_Quellzeiger : Any; // P#DBxx.DBXy.y WORD 16
idi_ZielOffset : DInt; // der auf den Quellzeiger hinzuaddiert wird
idi_AltwertOffset : DInt; // der auf den Quellzeiger hinzuaddiert wird
ib_ResetImp : Bool;
iT_Nr_Reset : Timer;
END_VAR

VAR_IN_OUT
iob_Hupe : Bool;
iob_SStoer : Bool;
iob_Hilfsbit1 : Bool;
iob_Hilfsbit2 : Bool;
END_VAR

VAR_TEMP
tby_datentyp : Byte;
tw_wdh : Word;
tw_db_no : Word;
tdw_zeiger : DWord;
ti_SchleifenIindex : Int;
tdw_ZielZeiger : DWord;
tdw_OffsetQuittbereich : DWord;
tdw_StartZeiger : DWord;
END_VAR


BEGIN
NETWORK
TITLE =
// CALL "000fc ChangeStoerBits"
// ia_Quellezeiger:="000db_KopplungVisu".Stoerungen.Gruppe100
// ip_Offset :=P#100.0
//
// Quellzeiger zerlegen

L P##ia_Quellzeiger;
LAR1;
L B[ AR1, P#1.0];
T #tby_datentyp;// word
L W[ AR1, P#2.0];
T #tw_wdh;
L W[ AR1, P#4.0];
T #tw_db_no;
L D[ AR1, P#6.0];
T #tdw_zeiger;

// Zurücksetzen
U #ib_ResetImp;
R #iob_Hupe;
R #iob_SStoer;

// Datenbaustein öffnen
AUF DB[ #tw_db_no];


// Offset für Zielzeiger HMI-Quittierbereich
L #tw_wdh;
L 2;
*D;
T #tdw_OffsetQuittbereich;
NETWORK
TITLE = Meldungen am Display quittieren


U #ib_ResetImp;
S #iob_Hilfsbit1;
S #iob_Hilfsbit2;

UN #ib_ResetImp;
U #iob_Hilfsbit1;
L S5T#1S;
SE #iT_Nr_Reset;
U #iT_Nr_Reset;
R #iob_Hilfsbit1;

U #ib_ResetImp;
SPBN w003;

// #### Zeiger zusammen setzen #################

L #tdw_zeiger;
L #tdw_OffsetQuittbereich;
SLD 3;// Pointer bilden
+D;
L #idi_ZielOffset;
SLD 3;
+D;
T #tdw_ZielZeiger;


// #### SCHLEIFE ###############################
L #tw_wdh;
s003: T #ti_SchleifenIindex;

// #### Meldungen Quittierbit setzen ###########
L 16#FFFF;
T DBW[ #tdw_ZielZeiger];

// Zeiger um ein Word erhöhen
L #tdw_ZielZeiger;
L P#2.0;
+D;
T #tdw_ZielZeiger;

L #ti_SchleifenIindex;
LOOP s003;

// #### ENDE SCHLEIFE ##########################

w003: NOP 0;

UN #iob_Hilfsbit1;
U #iob_Hilfsbit2;
SPBN w004;

// #### Zeiger zusammen setzen #################
L #tdw_zeiger;
L #tdw_OffsetQuittbereich;
SLD 3;// Pointer bilden
+D;
L #idi_ZielOffset;
SLD 3;
+D;
T #tdw_ZielZeiger;


// #### SCHLEIFE ##############################
L #tw_wdh;
s004: T #ti_SchleifenIindex;

// #### Quittierbit zurück nehmen #############
L 16#0000;
T DBW[ #tdw_ZielZeiger];

// Zeiger um ein Word erhöhen
L #tdw_ZielZeiger;
L P#2.0;
+D;
T #tdw_ZielZeiger;


L #ti_SchleifenIindex;
LOOP s004;

// #### ENDE SCHLEIFE #########################
U #iob_Hilfsbit2;
R #iob_Hilfsbit2;
w004: NOP 0;

NETWORK
TITLE = Bytes drehen und kopieren, Störung vorhanden?
//SPS -> HMI
//Byte n+0 -> Byte n+1
//Byte n+1 -> Byte n+0
////####################################################################
//// Zeiger zusammensetzen
//// für den HMI-Bereichzeige
//
// L #tdw_zeiger
// LAR1
//
// L #idi_ZielOffset
// SLD 3
// L #tdw_zeiger
// +D
// T #tdw_ZielZeiger
// LAR2
//
//// #### SCHLEIFE zum kopieren / auswerten ####
//
// L #tw_wdh
//s001: T #ti_SchleifenIindex
//
//
//// Kopieren und Bytes im Word tauschen
// L DBW [AR1,P#0.0] // Quellword laden
// TAW // bytes im worden tauschen
// T DBW [AR2,P#0.0] // ins HMI-Zielword ablegen
// L 0
// ==I
// SPB w001 // Sprung wenn keine Störung vorhanden
//
//// wenn ja dann Störmelder setzen
// SET
// S #iob_SStoer
//w001: NOP 0
//
// +AR1 P#2.0
// +AR2 P#2.0
//
// L #ti_SchleifenIindex
// LOOP s001
//// #### ENDE SCHLEIFE ########################
//
//####################################################################
// Zeiger zusammensetzen
// für den HMI-Bereichzeige

L #tdw_zeiger;
T #tdw_StartZeiger;

L #idi_ZielOffset;
SLD 3;
L #tdw_zeiger;
+D;
T #tdw_ZielZeiger;

// #### SCHLEIFE zum kopieren / auswerten ####

L #tw_wdh;
s001: T #ti_SchleifenIindex;


// Kopieren und Bytes im Word tauschen
L DBW[ #tdw_StartZeiger];// Quellword laden
TAW;// bytes im worden tauschen
T DBW[ #tdw_ZielZeiger];// ins HMI-Zielword ablegen
L 0;
==I;
SPB w001;// Sprung wenn keine Störung vorhanden

// wenn ja dann Störmelder setzen
SET;
S #iob_SStoer;
w001: NOP 0;


L #tdw_StartZeiger;
L P#2.0;
+D;
T #tdw_StartZeiger;


L #tdw_ZielZeiger;
L P#2.0;
+D;
T #tdw_ZielZeiger;


L #ti_SchleifenIindex;
LOOP s001;
// #### ENDE SCHLEIFE ########################


NETWORK
TITLE = Vergleich auf Altwert -> neu Störung vorhanden?
//6.12.2011 erweitert kontrolle auf gegangene Störung...
//
//#####################################################################
// Auf neue Meldungen vergleichen
// Zeiger zusammensetzen
// für den Altwert zum vergleichen

L #tdw_zeiger;
T #tdw_StartZeiger;

L #idi_AltwertOffset;
SLD 3;
L #tdw_zeiger;
+D;
T #tdw_ZielZeiger;


// #### SCHLEIFE zum kopieren / auswerten ####
L #tw_wdh;
s002: T #ti_SchleifenIindex;

// Auf Neue Störung Checken
L DBW[ #tdw_ZielZeiger];// Altwert laden
L DBW[ #tdw_StartZeiger];// Aktualwert laden
XOW;// Exklusiv-Oder
L DBW[ #tdw_StartZeiger];// mit Aktualwert vergleichen
UW;
L 0;
==I;
SPB w002;// Sprung wenn kein Unterschied

// wenn ja dann Hupe setzen
SET;
S #iob_Hupe;
w002: NOP 0;

//#################################################
//### 6.12.2011 ## auf gegangen kontrollieren #####

// Auf gegangen kontollieren
L DBW[ #tdw_ZielZeiger];// Altwert laden
L DBW[ #tdw_StartZeiger];// Aktualwert laden
XOW;// Exklusiv-Oder
L DBW[ #tdw_ZielZeiger];// mit Altwert vergleichen
UW;
L 0;
==I;
SPB w012;// Sprung wenn kein Unterschied

// wenn ja dann LM resetten wird ja wieder bei der nächsten Abfrage gesetzt,
// falls noch eine Störung vorhanden ist
UN #iob_Hupe;
R #iob_SStoer;
w012: NOP 0;
//### 6.12.2011 ## ENDE ###########################
//#################################################


// #### Altwert sichern #######################

L DBW[ #tdw_StartZeiger];// Aktualwert laden
T DBW[ #tdw_ZielZeiger];// und als Altwert sichern


L #tdw_StartZeiger;
L P#2.0;
+D;
T #tdw_StartZeiger;


L #tdw_ZielZeiger;
L P#2.0;
+D;
T #tdw_ZielZeiger;


L #ti_SchleifenIindex;
LOOP s002;

// #### ENDE SCHLEIFE #########################


END_FUNCTION
 
Zuviel Werbung?
-> Hier kostenlos registrieren
ich hab dafür bereits eine komplett fertige Funktion, die bereits vielfach im Einsatz ist!
Ist in SCL für S7Classic. Müsste so aber auch auf TIA laufen!


Das Bild zeigt die Verschaltung des Bausteinaufrufs
 

Anhänge

  • FB1014_Aufruf.jpg
    FB1014_Aufruf.jpg
    128,3 KB · Aufrufe: 37
Danke für die die beiden Antworten.
Mit AWL / Step7 Classic Bausteinen konnte ich jetzt unmittelbar (ohne größeres Bearbeiten) nichts anfangen, aber es war trotzdem lehrreich zu sehen. Schön, dass du @Maagic7 deine Bausteine auf Github veröffentlichst!

Wenn jemand mal Lust hat über meine Lösung zu schauen die ich wahrscheinlich so verwenden werde, der "Ausdruck" ist im Anhang als PDF. Bei meinen Testens war die Lösung ziemlich effizient. Gerne Anmerkungen posten!
 

Anhänge

Wenn du damit deine Lösung gefunden hast, ist doch alles super.

Ich verstehe nur nicht ganz, wieso ein Array of Bool in ein Array of Byte gewandelt wird, wenn dann doch wieder mit Bits gearbeitet wird.
Ausserdem interessant, wie oft doch eine "While"-Schleife verwendet wird.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Wenn jemand mal Lust hat über meine Lösung zu schauen die ich wahrscheinlich so verwenden werde, der "Ausdruck" ist im Anhang als PDF. Bei meinen Testens war die Lösung ziemlich effizient. Gerne Anmerkungen posten!

  • Netzwerk 2 wird nie einen Fehler melden. Dazu müsste das Programm #tempNumBytes überhaupt erstmal etwas zuweisen, bevor es einen zu großen Wert anmeckert.
    PS EDIT: Wieso wird in Deinem Programmausdruck Netzwerk 2 VOR dem Netzwerk 1 gedruckt?? Macht TIA das wirklich so, oder ist das von Dir manipuliert?
  • 0008 IF NOT (#tempCurCyclByte = 0) THEN
    kann man auch ohne Hirnknoten so schreiben:
    IF #tempCurCyclByte <> 0 THEN
  • Code:
    0013 FOR #j := #FIRST_BIT TO #LAST_BIT DO
    0014     IF (#tempCurCyclByte.%X0 AND NOT #tempPrevCyclByte.%X0) THEN
    0015         // Rising edge detected
    0016         #newBitIsTrue := TRUE;
    0017     END_IF;
    0018
    0019     // Shift one bit right for continuous slice access
    0020     #tempCurCyclByte := SHR(IN := #tempCurCyclByte, N := 1);
    0021     #tempPrevCyclByte := SHR(IN := #tempPrevCyclByte, N := 1);
    0022 END_FOR;
    Das ganze "Geschleife" kann man komplett ersetzen durch:
    Code:
    IF (#tempCurCyclByte AND NOT #tempPrevCyclByte) <> 0 THEN
        #newBitIsTrue := TRUE; // Rising edge detected
    END_IF;
  • Code:
    0003 WHILE #i <= #tempNumBytes DO
    ...
    0025
    0026     // Save compare array from current cycle for next cycle
    0027     #prevCyclArray[#i] := #curCyclArray[#i];
    0028
    0029     // Counter++
    0030     #i := #i + 1;
    0031 END_WHILE;
    Die WHILE-Schleife kann man besser als FOR-Schleife, wo #i am Anfang garantiert und deutlich sichtbar initialisiert wird. Und das Array am Ende am Stück kopieren ist auch viel effizienter:
    Code:
    0003 FOR #i := 0 TO #tempNumBytes DO
    ...
    0025 END_FOR;
    0026
    0027 // Save compare array from current cycle for next cycle
    0028 #prevCyclArray := #curCyclArray;
    0029
    0030
    0031
  • Netzwerk 4 die umständliche Konstruktion mit dem TON kann (und wird) dazu führen, daß neu kommende Bits nicht signalisiert werden, wenn da gerade der TON vom vorherigen #newBitIsTrue abläuft.
    Besser: einfach ein TOF verwenden, und das TOF-Triggerbit nur 1 Zyklus lang machen. Das benötigt allerdings noch eine Hilfsvariable, weil #newBitIsTrue ein Output ist.
    Baustein-Outputs mehrmals etwas zuweisen und Baustein-Outputs wieder zurücklesen ist ein sehr unschöner und fehleranfälliger Stil. Wird das nicht eigentlich auch von TIA angemeckert?

Harald
 
Zuletzt bearbeitet:
Vielen Dank lieber Harald / @PN/DP für deine lange Analyse, freut mich sehr dass du dir die Zeit genommen hast und ich etwas lernen kann!

Wieso wird in Deinem Programmausdruck Netzwerk 2 VOR dem Netzwerk 1 gedruckt?? Macht TIA das wirklich so, oder ist das von Dir manipuliert?
Ja hat TIA so gemacht, bin über Druckvorschau gegangen und da ist sowieso nur die Option "Kompakt" brauchbar, da sonst jedes Array-Element einzeln aufgelistet wird und der Ausdruck dann unendlich lang ist. Aber in jeder Version war Netzwerk 2 vor Netzwerk 1.

kann man auch ohne Hirnknoten so schreiben
Da hast du absolut Recht! Bei Not muss man immer doppelt denken!

Das ganze "Geschleife" kann man komplett ersetzen durch
Wow viel einfacher und ich wusste nicht das man Bytes logisch verknüpfen kann.

besser als FOR-Schleife
Ja ist übersichtlicher, hatte das erst wegen eines anderen Lösungsweg als while gemacht.

Besser: einfach ein TOF verwenden
Ja ist besser! Habe eine Tempvariable verwendet um den TOF anzutriggern.

Baustein-Outputs mehrmals etwas zuweisen und Baustein-Outputs wieder zurücklesen ist ein sehr unschöner und fehleranfälliger Stil.
Bei größeren Bausteinen ist es sicher unschön. Fehleranfällig ist richtig. Habe es bei geändert, dass die Outputs nur 1x an einer Stelle gesetzt werden und ansonsten mit Temp Variablen.

==> Habe den überarbeiteten Baustein angehängt sowohl als Ausdruck (jetzt hat TIA die Netzwerke in der richtigen Reihenfolge angeordnet!), als auch als "Externe Quelle". Habe alles nochmal rein in SCL geschrieben, um den Baustein als Quelle exportieren zu können, falls ihn jemand verwenden möchte der das hier liest.

Anmerkung: Vielleicht könnte man noch die beiden Temp-Variablen (#tempCurCyclByte und #tempPrevCyclByte) in der Schleife einsparen. Die waren vorher nur notwendig wegen dem SHR.

Code:
FOR #i := 0 TO #tempNumBytes DO
    // Check if any bit of byte is true
    IF #curCyclArray[#i] <> 0 THEN
        // Any bit is true
        #tempAnyBitTrue := TRUE;
        
        // Check for rising edge with array of previous cycle
        IF (#curCyclArray[#i] AND NOT #prevCyclArray[#i]) <> 0 THEN
            // Rising edge detected
            #tempNewBitTrue := TRUE;
        END_IF;
    END_IF;
END_FOR;
 

Anhänge

Zuletzt bearbeitet:
Zurück
Oben