FUNCTION_BLOCK "Ringpuffer" TITLE =Ringpuffer (FIFO) mit 32-bit breiten Elementen VERSION : 0.1 VAR_INPUT eingabe : BOOL ; ausgabe : BOOL ; eingabe_wert : DWORD ; reset : BOOL ; END_VAR VAR_OUTPUT ausgabe_wert : DWORD ; ueberlauf : BOOL ; unterlauf : BOOL ; fuellstand : INT ; END_VAR VAR fm_eingabe : BOOL ; fm_ausgabe : BOOL ; anzahl_belegt : INT ; ptr_eingabe : DWORD ; ptr_ausgabe : DWORD ; elemente : ARRAY [0 .. 31 ] OF DWORD ; END_VAR VAR_TEMP max_anzahl_elemente : INT ; zaehler : INT ; END_VAR BEGIN NETWORK TITLE =Konstanten definieren L 32; // Groesse des "elemente" Arrays T #max_anzahl_elemente; NETWORK TITLE =Ringpuffer entladen U #ausgabe; // "ausgabe" positive Flanke? FP #fm_ausgabe; SPBN end1; // Nein? Dann Ende. L #anzahl_belegt; L 0; ==D ; // anzahl_belegt == 0? SPBN nunt; // ... dann kein Unterlauf SET ; = #unterlauf; // ... sonst Unterlauf anzeigen L 0; T #ausgabe_wert; SPA end1; // Und Ende. nunt: L P##elemente; L #ptr_ausgabe; +D ; // AR1 = element_0 + ptr_ausgabe LAR1 ; // AR1 zeigt auf das erste belegte Element L D [AR1,P#0.0]; T #ausgabe_wert; // ausgabe_wert = erstes belegtes Element L 0; // Element nullen. (Nicht unbedingt noetig) T D [AR1,P#0.0]; L #anzahl_belegt; L 1; -D ; // anzahl_belegt -= 1 T #anzahl_belegt; L #ptr_ausgabe; L P#4.0; +D ; // ptr_ausgabe += 4 T #ptr_ausgabe; L #max_anzahl_elemente; L P#4.0; *D ; // akku = Pointer auf Ringende L #ptr_ausgabe; >D ; // ptr_ausgabe < Ringende SPB end0; // ... dann Ende L P#0.0; // ... sonst ptr_ausgabe = P#0.0 T #ptr_ausgabe; end0: CLR ; = #ueberlauf; // Fehleranzeigen zuruecksetzen = #unterlauf; end1: NOP 0; NETWORK TITLE =Ringpuffer beladen U #eingabe; // "eingabe" positive Flanke? FP #fm_eingabe; SPBN end3; // Nein? Dann Ende. L #anzahl_belegt; L #max_anzahl_elemente; D ; // ptr_eingabe < Ringende SPB end2; // ... dann Ende L P#0.0; // ... sonst ptr_eingabe = P#0.0 T #ptr_eingabe; end2: CLR ; = #ueberlauf; // Fehleranzeigen zuruecksetzen = #unterlauf; end3: NOP 0; NETWORK TITLE =Reset-Signal verarbeiten U #reset; SPBN nrst; // Statische Variablen und Ausgaenge nullen L 0; T #ausgabe_wert; T #fuellstand; T #anzahl_belegt; T #ptr_eingabe; T #ptr_ausgabe; CLR ; = #ueberlauf; = #unterlauf; // Alle Elemente nullen. // Dies ist nicht unbedingt notwendig, aber zur Fehlersuche sinnvoll. L #max_anzahl_elemente; next: T #zaehler; L 1; -D ; L P#4.0; *D ; L P##elemente; +D ; LAR1 ; L 0; T D [AR1,P#0.0]; L #zaehler; LOOP next; nrst: NOP 0; NETWORK TITLE =Fuellstand ausgeben L #anzahl_belegt; T #fuellstand; END_FUNCTION_BLOCK DATA_BLOCK "DB_Ringpuffer" "Ringpuffer" BEGIN END_DATA_BLOCK ORGANIZATION_BLOCK OB 1 VAR_TEMP OB1_EV_CLASS : BYTE; // Bits 0-3 = 1 (Coming event), Bits 4-7 = 1 (Event class 1) OB1_SCAN_1 : BYTE; // 1 (Cold restart scan 1 of OB 1), 3 (Scan 2-n of OB 1) OB1_PRIORITY : BYTE; // Priority of OB execution OB1_OB_NUMBR : BYTE; // 1 (Organization block 1, OB 1) OB1_RESERVED_1 : BYTE; OB1_RESERVED_2 : BYTE; OB1_PREV_CYCLE : INT; // Cycle time of previous OB 1 scan (milliseconds) OB1_MIN_CYCLE : INT; // Minimum cycle time of OB 1 (milliseconds) OB1_MAX_CYCLE : INT; // Maximum cycle time of OB 1 (milliseconds) OB1_DATE_TIME : DATE_AND_TIME; // Date and time OB 1 started END_VAR BEGIN U "clock_100ms" = E 0.0 U "clock_200ms" = E 0.1 L L#31337 T ED 2 U A 0.0 = E 0.2 CALL "Ringpuffer", "DB_Ringpuffer" ( eingabe := E 0.0, ausgabe := E 0.1, eingabe_wert := ED 2, reset := E 0.2, ausgabe_wert := AD 2, ueberlauf := A 0.0, unterlauf := A 0.1, fuellstand := AW 6, ) L ED 2 L AD 2 L AW 6 END_ORGANIZATION_BLOCK