FUNCTION_BLOCK FB211 // FB_FIFO
// Beschreibung: FB_FIFO
// In diesem Baustein wurde ein FIFO Puffer (Ring-Puffer) realisiert.
// Es gibt zwei Zeiger einen Schreiben Zeiger und einen Lesen Zeiger. In den Puffer werden über diese Zeiger die Daten geschrieben und gelesen.
// Der Puffer kann bei Bedarf neu initialisiert (gelöscht) werden. Mit dem Fuellen Eingang kann der Puffer zum testen mit vorbelegten
// Standardwerten gefüllt werden.
// Schreiben hat in der Regel Vorrang vorm Lesen, das heißt steht z.B Schreiben und Lesen im gleichen Zyklus an, wird zuerst geschrieben und
// anschließend gelesen. Ist der Puffer jetzt allerdings voll, würde es durch diese Vorgehensweise ja zu einem Überlauf kommen, daher wird in diesem Fall
// zuerst gelesen und anschließend geschrieben.
// Ansonsten hat Init Vorrang vor Schreiben und Lesen. Das heißt steht Schreiben oder Lesen und eine Initialisierung im selben Zyklus an, dann wird
// der Auftrag fürs Schreiben bzw. Lesen verworfen.
// Füllen hat wiederum Vorrang vorm Initialisieren, steht hier beides in einem Zyklus an wird der Puffer initialisiert und anschließend gefüllt.
// Ersteller: Didaddy
// Erstelldatum: 21.01.2010
// Änderungen:
AUTHOR: Didaddy;
Version: '1.0';
VAR_INPUT
nIn :INT:= 0; // Der Wert der in den Puffer geschrieben werden soll
bSchreiben :BOOL:= FALSE; // Wert in Puffer schreiben (Bei Dauersignal wird der Auftrag nur einmalig ausgeführt (pos.Fl))
bLesen :BOOL:= FALSE; // Wert aus Puffer lesen (Bei Dauersignal wird der Auftrag nur einmalig ausgeführt (pos.Fl))
bInit :BOOL:= FALSE; // Puffer neu Initialisieren
bFuellen :BOOL:= FALSE; // Puffer mit Standardwerten füllen
END_VAR
VAR_OUTPUT
nOut :INT:= 0; // Der Wert der aus dem Puffer ausgelesen werden soll
nZS :INT:= 1; // Zeiger Schreiben
nZL :INT:= 1; // Zeiger Lesen
nAnzVorhDaten :INT:= 0; // Anzahl der vorhandenen Daten im Puffer
bUeberlauf :BOOL:= 0; // Der älteste Daten Eintrag wurde durch einen neuen überschrieben
END_VAR
CONST
PG := 9; // Puffergrenze
END_CONST
VAR
bSchreibenAlt :BOOL:= FALSE;
bLesenAlt :BOOL:= FALSE;
bInPufferSchreiben:BOOL:= FALSE;
bAusPufferLesen :BOOL:= FALSE;
bPufferInit :BOOL:= FALSE;
bPufferFuellen :BOOL:= FALSE;
nI :INT:= 0;
bVorrangLesen :BOOL:= FALSE; // Das Lesen aus dem Puffer hat Vorrang
anPuffer :ARRAY[1..PG] OF INT:= [PG(0)];
END_VAR
LABEL
Schreiben, Lesen;
END_LABEL
(******************** Kommandos entgegennehmen **********************)
// Kommando in Puffer schreiben
IF bSchreiben AND NOT bSchreibenAlt THEN
bInPufferSchreiben:= TRUE;
END_IF;
bSchreibenAlt:= bSchreiben;
// Kommando aus Puffer Lesen
IF bLesen AND NOT bLesenAlt THEN
bAusPufferLesen:= TRUE;
END_IF;
bLesenAlt:= bLesen;
// Kommando Puffer Initialisieren
IF bInit THEN
bInPufferSchreiben:= FALSE; // Gleichzeitig in Puffer schreiben wird ignoriert
bAusPufferLesen:= FALSE; // Gleichzeitig aus Puffer lesen wird ignoriert
bPufferInit:= TRUE;
END_IF;
// Kommando Puffer fuellen
IF bFuellen THEN
bInPufferSchreiben:= FALSE; // Gleichzeitig in Puffer schreiben wird ignoriert
bAusPufferLesen:= FALSE; // Gleichzeitig aus Puffer lesen wird ignoriert
bPufferFuellen:= TRUE;
END_IF;
(********** Puffer Initialisieren/Füllen, Überlauf checken **********)
// Puffer Initialisieren
IF bPufferInit THEN
FOR nI := 1 TO PG BY 1 DO
anPuffer[nI]:= 0;
END_FOR;
nAnzVorhDaten:= 0;
nZS:= 1;
nZL:= 1;
bUeberlauf:= FALSE;
bPufferInit:= FALSE;
END_IF;
// Puffer füllen
IF bPufferFuellen THEN
FOR nI := 1 TO PG BY 1 DO
anPuffer[nI]:= nI;
END_FOR;
nAnzVorhDaten:= PG;
nZS:= 1;
nZL:= 1;
bUeberlauf:= FALSE;
bPufferFuellen:= FALSE;
END_IF;
// Schreiben Zeiger hat Ringgrenze erreicht
IF nZS > PG THEN
nZS:= 1;
END_IF;
// Lesen Zeiger hat Ringgrenze erreicht
IF nZL > PG THEN
nZL := 1;
END_IF;
// Anzahl vorhandene Daten eingrenzen
IF nAnzVorhDaten > PG THEN
nAnzVorhDaten:= PG;
ELSIF nAnzVorhDaten < 0 THEN
nAnzVorhDaten:= 0;
END_IF;
// Erkennung ob der Puffer voll ist und Lesen und Schreiben gleichzeitig ansteht
IF nAnzVorhDaten = PG AND bInPufferSchreiben AND bAusPufferLesen THEN
GOTO Lesen;
bVorrangLesen:= TRUE; // dann muss erst gelesen und anschließend geschrieben werden (wegen unnötigem Überlauf)
ELSE
bVorrangLesen:= FALSE;
END_IF;
(********************* In den Puffer schreiben **********************)
Schreiben:
// Wert in Puffer schreiben
IF bInPufferSchreiben THEN
// Überlauf checken
IF nAnzVorhDaten = PG THEN
bUeberlauf:= TRUE; // Überlauf wird lediglich signalisiert, neue Daten werden natürlich trozdem eingetragen
nZL:= nZL + 1; // Der Lesen Zeiger wird auf den nächsten gültigen Eintrag gesetzt
ELSE
bUeberlauf:= FALSE;
END_IF;
anPuffer[nZS]:= nIn;
nZS:= nZS + 1;
// Nur erhöhen wenn die Puffergrenze noch nicht erreicht ist (mehr passt ja nicht rein)
IF nAnzVorhDaten < PG THEN
nAnzVorhDaten:= nAnzVorhDaten + 1;
END_IF;
bInPufferSchreiben:= FALSE;
END_IF;
// Wenn Lesen Vorrang hatte dann wurde dies ja bereits erledigt
IF bVorrangLesen THEN
RETURN; // also Ende hier
END_IF;
(*********************** Aus dem Puffer lesen ***********************)
Lesen:
// Nur wenn Daten vorhanden sind, können Werte ausgelesen werden
IF nAnzVorhDaten > 0 AND bAusPufferLesen THEN
bUeberlauf:= FALSE; // Sobald Daten wieder ausgelesen werden, bügeln wir das Überlaufbit wieder nieder
nOut:= anPuffer[nZL];
anPuffer[nZL]:= 0; // Nachdem wir den Puffer ausgelesen haben, schreiben wir ne 0 rein
nZL:= nZL + 1;
nAnzVorhDaten:= nAnzVorhDaten - 1;
bAusPufferLesen:= FALSE;
ELSIF nAnzVorhDaten = 0 AND bAusPufferLesen THEN // Sind keine Daten vorhanden
// nichts machen
bAusPufferLesen:= FALSE;
END_IF;
// Wenn Lesen Vorrang hatte
IF bVorrangLesen THEN
GOTO Schreiben; // dann muß ja noch geschrieben werden
END_IF;
END_FUNCTION_BLOCK