Jap, jetzt läuft der Kasten! Mal sehen was ich jetzt noch tolles an den Bausteinen ändern kann!
Na ja, wenn ich Dein Konstrukt so sehe, wäre ich damit alles Andere als zufrieden, da z.B. immer noch globale Angaben innerhalb des FBs verwendet werden.
Folgende Baustellen gäbe es aus meiner Sicht mindestens, bevor ich mich anderen Bausteinen zugewendet hätte:
Offensichtlich warst Du nicht mal in der Lage, aus einem STRUCT, das 3 BYTES enthält, 3 einzelne BYTES an der Schnittstelle zu machen. Da muss man nur den STRUCT-"Käfig" entfernen und schon kannst Du Deine Stunde, Minute und Sekunde separat übergeben.
Den Zeiger für den Ringspeicher außerhalb des FBs zu speichern (wie Du es jetzt machst) halte ich auch für sinnvoll. Trotzdem sollte auch er nicht global verwendet werden, sondern ebenfalls über die Schnittstelle übergeben werden. In diesem Fall würde man IN_OUT benötigen, da erst der alte Wert gelesen werden soll (IN-Part), dann verändert wird und der neue Wert dann wieder gespeichert werden soll (OUT-Part).
Wenn der Zeiger für den Ringspeicher außerhalb des FBs gespeichert wird, sollte das auch für die aktuelle Ereignisnummer gelten.
Wenn der Ringspeicher mit Nullen resettet wird, würde ich auch noch den Zeiger für den Ringspeicher und die Ereignisnummer resetten.
Durch Ersteres könnte man auch schon nach dem Reset des ersten Datensatzes dort im nächsten Zyklus sofort wieder ein neues Ereignis eintragen, während die nachfolgenden Datensätze weiter genullt werden.
Wie früher schon mal erwähnt, sind die 5ms nicht gerade weit von der Zykluszeit entfernt. Ich würde deshalb einfach jeden Zyklus einen Datensatz resetten. Dadurch könnte man sich den ganzen Timeraufwand sparen.
Ich würde wissen wollen, ob das Resetten noch aktiv ist und einen entsprechenden Ausgang am FB erstellen.
Das doppelte Öffnen des DBs bzw. Sichern des AR1 ist in meinen Augen auch "unschön".
Ich hab' das mal für Dich zur Ansicht umgesetzt (immer noch ungetestet
):
Code:
[FONT=Courier New]FUNCTION_BLOCK "Ereignisspeicher"
TITLE =
AUTHOR : Hucki
VERSION : 0.1
VAR_INPUT
Speichern : BOOL ;
Reset_Start : BOOL ;
Aktuell_Stunden : BYTE ;
Aktuell_Minuten : BYTE ;
Aktuell_Sekunden : BYTE ;
Speicher_DB : BLOCK_DB ;
DS_Anzahl : INT ;
DS_Laenge : INT ;
DS_Offset : INT ;
END_VAR
VAR_OUTPUT
Reset_Aktiv : BOOL ;
END_VAR
VAR_IN_OUT
Zeiger_Ringspeicher : INT ;
Ereigniszaehler : INT ;
END_VAR
VAR
Zeiger_DS_Reset : INT ;
FM_Speichern : BOOL ;
FM_Reset : BOOL ;
END_VAR
VAR_TEMP
Sicherung_AR1 : DWORD ;
END_VAR
BEGIN
NETWORK
TITLE =
UN #Speichern; // Wenn Baustein nichts im DB speichern soll
UN #Reset_Start; // und nicht das Resetten des DBs beginnen soll
UN #Reset_Aktiv; // und auch nicht beim Resetten des DBs ist
BEB ; // dann Baustein gleich beenden, weil er nix zu tun hat
// #### ALLGEMEIN ####################################################################################
// AR1 sichern
TAR1 ; // Adress-Register 1 in Akku1 laden
T #Sicherung_AR1; // und temporär sichern
// Datenbaustein
AUF #Speicher_DB; // Speicher-DB öffnen
//#### DS SPEICHERN ##################################################################################
U #Speichern; // Schließer-Eingang #Speichern
FP #FM_Speichern; // auf positive Flanke (0->1) prüfen
SPBN ResS; // wenn keine Flanke, zum Beginn der RESET-Routine springen
// Ereigniszähler inkrementiern
L #Ereigniszaehler; // Ereigniszähler laden
+ 1; // um 1 erhöhen und
T #Ereigniszaehler; // wieder speichern
// Pointer erstellen
L #Zeiger_Ringspeicher; // Zeiger für Ringspeicher laden
L #DS_Laenge; // Datensatzlänge laden
*I ; // miteinander multiplizieren
L #DS_Offset; // Startadresse des Datenfeldes laden
+I ; // hinzu addieren
SLD 3; // berechneten Wert auf die Byteadresse schieben
LAR1 ; // und ins Adressregister 1 schreiben
// Daten eintragen
L #Ereigniszaehler; // Ereigniszähler laden
T DBW [AR1,P#0.0]; // und im aktuellen Datensatz an WORD 0 sichern
L #Aktuell_Stunden; // Aktuelle Stunde laden
T DBB [AR1,P#4.0]; // und im aktuellen Datensatz an BYTE 4 sichern
L #Aktuell_Minuten; // Aktuelle Minute laden
T DBB [AR1,P#5.0]; // und im aktuellen Datensatz an BYTE 5 sichern
L #Aktuell_Sekunden; // Aktuelle Sekunde laden
T DBB [AR1,P#6.0]; // und im aktuellen Datensatz an BYTE 6 sichern
// Zeiger inkrementieren
L #Zeiger_Ringspeicher; // Zeiger für Ringspeicher laden
+ 1; // um 1 erhöhen
T #Zeiger_Ringspeicher; // und wieder speichern
// Zeiger auf Überlauf prüfen
L #Zeiger_Ringspeicher; // Zeiger für Ringspeicher laden
L #DS_Anzahl; // maximale Anzahl an Datensätzen laden
>I ; // auf Überschreitung prüfen
SPBN ResS; // wenn nicht überschritten, zum Beginn der RESET-Routine springen
L 0; // Wert 0 laden
T #Zeiger_Ringspeicher; // und Zeiger für Ringpuffer auf 0 resetten
//#### DS RESETTEN ###################################################################################
// RESET starten
ResS: U #Reset_Start; // Öffner-Eingang #Reset_Start
FN #FM_Reset; // auf negative Flanke (1->0) prüfen
S #Reset_Aktiv; // und ggf. Reset aktivieren
// RESET aktiviert?
U #Reset_Aktiv; // Reset aktiv?
SPBN Ende; // Nein, dann zum Ende springen
// Bei RESET-Beginn Zeiger_Ringpuffer und Ereigniszähler zurücksetzen
L #Zeiger_DS_Reset; // Reset-Zeiger laden
L 0; // Wert 0 laden
==I ; // auf Gleichheit prüfen
SPBN PoiR; // wenn nicht 0 zum Erstellen des Pointers springen
T #Zeiger_Ringspeicher; // Zeiger für Ringspeicher auf 0 resetten
T #Ereigniszaehler; // Ereigniszähler auf 0 resetten
// Pointer Löschschleife erstellen
PoiR: L #Zeiger_DS_Reset; // Reset-Zeiger laden
L #DS_Laenge; // Datensatzlänge laden
*I ; // miteinander multiplizieren
L #DS_Offset; // Startadresse des Datenfeldes
+I ; // hinzu addieren
SLD 3; // berechneten Wert auf die Byteadresse schieben
LAR1 ; // und ins Adressregister 1 schreiben
// Daten eintragen
L 0; // Wert 0 laden
T DBD [AR1,P#0.0]; // ins (1.) DWORD 0 eintragen
L 0; // Wert 0 laden
T DBD [AR1,P#4.0]; // ins (2.) DWORD 4 eintragen
// Zeiger erhöhen
L #Zeiger_DS_Reset; // Reset-Zeiger laden,
+ 1; // um 1 erhöhen
T #Zeiger_DS_Reset; // und wieder speichern
// Zeiger auf Überlauf prüfen
L #Zeiger_DS_Reset; // Reset-Zeiger laden,
L #DS_Anzahl; // Max. Anzahl an Datensätzen laden
>I ; // auf Überschreitung prüfen
SPBN Ende; // wenn noch nicht überschritten zum Ende springen
R #Reset_Aktiv; // RESET deaktivieren
L 0; // Wert 0 laden
T #Zeiger_DS_Reset; // Reset-Zeiger auf 0 resetten
//#### ALLGEMEIN ####################################################################################
// AR1 wiederherstellen
Ende: L #Sicherung_AR1; // Gesicherten Wert laden
LAR1 ; // und ins Adress-Register 1 zurückschreiben
END_FUNCTION_BLOCK[/FONT]
und der entsprechende Aufruf des FBs:
Und von der Sache her ist das Resetten ja die gleiche Funktion wie das Speichern, nur das halt alles Nullwerte gespeichert werden. Man könnte also theoretisch den FB auch auf die Speicher-Funktion begrenzen (vlt. noch etwas anpassen) und dann für den Reset einen 2. Aufruf des FBs mit anderen Übergabewerten an der Schnittstelle benutzen.