Ich habe endlich mal den Baustein getestet und noch so einige Fehler gefunden und verschiedene Sachen geändert.
Für die gesuchte Funktion ist eigentlich nur der untere Teil wichtig.(Ab // Durchsuche DB Bits nach "TRUE" und.....)
Die Anzeigezeit könnte man ja dann sogar rausnehmen und den Ausgang in einen FIFO schieben.
Gute Nacht
Code:
FUNCTION_BLOCK FB100
//***********************************************************************************************************************************
//Der Baustein setzt oder rücksetzt ein Bit in einem DB mit 1024 boolschen Variablen. Die Anwahl des Bits erfolgt über eine Int-Zahl
//am Eingang :"Sperr_Nr". Die Nummerierung und Adressierung sind gleich mit den Störmeldungen im WinCC flexible. Über "Set" wird das
//gewählte Bit gesetzt und über "Reset" wieder zurückgesetzt. "Reset_All" setzt alle Bits im DB auf Signal "0".
//Am Ausgang "Anz_Sperr_Nr" werden nacheinander alle auf "TRUE" gesetzten Bits für mindestens 2sek angezeigt.
//***********************************************************************************************************************************
AUTHOR : 'T.H.'
NAME : 'Sperren'
VERSION : '1.0'
//vom 17.11.2012
//Vereinbarungsteil (Deklaration):
//--------------------------------
//Eingangsvariablen
VAR_INPUT
Sperr_DB : BLOCK_DB ;
Sperr_Nr : INT := 0 ;
Set : BOOL := False ;
Reset : BOOL := False ;
Reset_All : BOOL := False ;
Takt_10Hz : BOOL := False ;
END_VAR
//---------------------------------
//Ausgangsvariablen
VAR_OUTPUT
Anz_Sperr_Nr : INT := 0 ;
END_VAR
//---------------------------------
//Durchgangsvariablen
VAR_IN_OUT
END_VAR
//---------------------------------
//Statische Variablen:
VAR
Loeschindex : INT := 0 ;
HM : ARRAY [0..7] OF BOOL ; // Noch nicht eingesetzte Hilfsmerker: 4; 5; 6; 7;
Word_Index : INT := 0 ;
Bit_Index : INT := 0 ;
Anz_Stop : BOOL:= FALSE ; // Sperrt den Wechsel der Anzeige für die min Anzeigedauer (2sek)
Min_Anzeigezeit : INT := 0 ;
END_VAR
//---------------------------------
//Temporäre Variablen:
VAR_TEMP
Wordnummer : INT ;
Wordadresse : INT ;
Bitnummer : INT ;
Bit_Maske : WORD ;
END_VAR
//----------------------------------
//Sprungmarken:
LABEL
No_Choose ;
No_Anz ;
END_LABEL
//Anweisungsteil (Programm):
//***********************************************************************************************************************************
BEGIN
// Setze / Rücksetze Sperre
//---------------------------
IF Sperr_Nr <= 0 OR Sperr_Nr > 1024 THEN // Freigabe
GOTO No_Choose ;
ELSIF Sperr_Nr > 0 THEN // Berechnung Wordadresse
Wordadresse := ((Sperr_nr-1)/16)*2 ;
Bitnummer := (Sperr_Nr-1)-(Wordnummer*16) ; // Berechnung Bitnummer
END_IF ;
IF Set = TRUE AND HM[0] = FALSE THEN // Erzeuge Setzimpuls
HM[0] := TRUE ;
Bit_Maske := 2#0000_0000_0000_0001 ; // Setze Alle Bits auf "False" nur Bit 0 auf "TRUE"
Bit_Maske := ROL(IN:= Bit_Maske, N:=Bitnummer) ; // Rotiere "TRUE" auf richtige Position
Sperr_DB.DW[Wordadresse] := Bit_Maske OR Sperr_DB.DW[Wordadresse]; // Schreibe Ergebnis in Datenbaustein ohne andere Bits zu verändern
ELSIF Set = FALSE AND HM[0] = TRUE THEN
HM[0] := FALSE ; // Hilfsmerker Flanke zurücksetzen
END_IF ;
// Rücksetzen Bit
IF Reset = TRUE AND HM[1] = FALSE THEN // Erzeuge Rücksetzimpuls
HM[0] := TRUE ;
Bit_Maske := 2#1111_1111_1111_1110 ; // Setze alle Bits auf "TRUE" nur Bit 0 auf "False"
Bit_Maske := ROL(IN:= Bit_Maske, N:=Bitnummer) ; // Rotiere "FALSE" auf richtige Position
Sperr_DB.DW[Wordadresse] := Bit_Maske AND Sperr_DB.DW[Wordadresse] ; // Schreibe Ergebnis in Datenbaustein ohne die anderen Bits zu beeinflussen
ELSIF Reset = FALSE AND HM[1] THEN
HM[1] := FALSE ; // Hilfsmerker Flanke zurücksetzen
END_IF ;
No_Choose:
// Alles zurücksetzen
//---------------------
IF Reset_All = TRUE AND HM[2] = FALSE THEN // Impuls setzen für Reset All
HM[2] := TRUE ;
Loeschindex := 0 ; // Setze Löschindex einmalig auf 0
REPEAT
Sperr_DB.DW[Loeschindex] := 0 ; // Schreibe 0 in Datenwort
Loeschindex := Loeschindex +2 ; // Index erhöhen für nächstes Datenwort
UNTIL Loeschindex = 128 // Bis Endadresse erreicht ist
END_REPEAT ;
ELSIF Reset_All = FALSE THEN // Rücksetze Hilfsmerker
HM[2] := FALSE ;
END_IF ;
// Durchsuche DB Bits nach "TRUE" und Ausgabe der Sperrnummern im 2Sek Takt
//--------------------------------------------------------------------------
IF Word_index = 126 AND Bit_index > 15 AND Anz_Stop = TRUE THEN // Word_index und Bit_index auf max und Mindestanzeigedauer ist noch nicht abgelaufen
GOTO No_Anz ; // Überspringe Suchfunktion
END_IF ;
// Bit_Index über Ende? Wenn ja Setze Bit_index auf "0" und erhöhe Word_index um "2"
//-----------------------------------------------------------------------------------------------
IF Bit_index > 15 THEN // Hat der Bit_index max überschritten
Bit_index := 0 ; // setze Bit_index auf 0
Word_index:= Word_index+2 ; // erhöhe Word_index um 2( Wortadressierung nur über gerade Bytenummern)
END_IF ;
// Word_Index auf Ende? Wenn ja setze Index auf Anfang
//--------------------------------------------------------------------
IF Word_index >= 128 THEN // Hat der Word_index max überschritten
Word_index := 0 ; // Setze Word_index auf 0
Anz_Sperr_Nr := 0 ; // Lösche Anzeige
END_IF ;
// Durchsuche Sperrword Bitweise auf "TRUE" und berechne und übergebe Sperrnummer an Anzeige
//--------------------------------------------------------------------------------------------------------
Bit_Maske := 2#0000_0000_0000_0001 ; // In Bitmaske das erste Bit auf "1" setzen
Bit_Maske := ROL(IN:=Bit_Maske, N:=Bit_index) ; // Die "1" auf den richtigen Platz rotieren
IF (Sperr_DB.DW[Word_index] AND Bit_Maske) = 0 THEN // Falls der Bitvergleich "0" ist
Bit_index := Bit_index+1 ; // erhöhe den Bit_index für die nächste Bitüberprüfung
GOTO No_Anz ; // Überspringe Ausgabe auf Anzeige
ELSIF (Sperr_DB.DW[Word_index] AND Bit_Maske) <> 0 AND Anz_Stop = FALSE THEN // Bitvergleich auf nicht Signal "0"
Anz_Sperr_Nr := ((Word_index/2)*16)+(Bit_index+1) ; // Wenn Bitvergleich "1" berechne Sperrnummer und sende zur Anzeige
Anz_Stop := TRUE ; // Sperre die Anzeige einer weiteren Sperrnummer bis die min. Anzeigezeit die Freigabe erteilt
Bit_index := Bit_index+1 ; // Erhöhe den Bit_index für die nächte Bitüberprüfung
END_IF ;
No_Anz:
// Minimale Anzeigezeit (2Sekunden)
//------------------------------------
IF Anz_Stop = TRUE AND Takt_10Hz = TRUE AND HM[3] = FALSE THEN // Erzeuge Zähltakt
HM[3] := TRUE ;
Min_Anzeigezeit := Min_Anzeigezeit+1 ; // Zähle Zeitspeicher hoch
ELSIF Takt_10Hz = FALSE THEN
HM[3] := FALSE ; // Rücksetze Hilfsmerker
END_IF ;
IF Min_Anzeigezeit = 20 THEN // Abfrage ob 2 sek erreicht
Anz_Stop := FALSE ; // Wenn ja rücksetze Anzeigen Stop
Min_Anzeigezeit := 0 ; // und rücksetze Zeitspeicher
END_IF ;
//Programmende