Cykly jsou přesně ten důvod, proč použít jazyk ST. Použití jednoduchého cyklu si ukážeme na výpočtu průměrné hodnoty za posledních 15 minut. Jde o průběžný nevážený průměr.
Proměnná MINUTY je typu Analogový posuvný registr (B110_SHIFT_REGISTER), deklarací na řádku 6 se vlastně vkládá a pojmenovává funkční blok tohoto typu. Pokud nastane celá minuta, tedy ukazatel vteřin SINT1 = 0, náběžná hrana proměnné SHIFTNOW posune hodnoty v posuvném registru o jednu dál a na vstup IN vloží aktuální hodnotu výkonu. V posuvném registru jsou tedy vzorky hodnot po minutách za posledních (alespoň) 15 minut (posuvný registr má 24 pozic, ale budeme potřebovat jen prvních 15). V cyklu FOR…END_FOR (viz řádky 20 až 22) se posledních 15 hodnot sečte a v následujícím řádku se vydělením spočítá průměr.
WHILE J<10 DO
J:=J+2;
END_WHILE;
REPEAT
J:=J+2;
UNTIL J>10;
Liší se zejména tím, že u REPEAT se podmínka vyhodnocuje až na konci, tedy cyklus proběhne alespoň jednou. Podmínka by měla být napsána „bezpečně“, aby se nemohlo stát, že bude přeskočena a cyklus se bude opakovat do nekonečna.
Stupňové spínání se záskokem a rotací
Pro řízení skupiny agregátů, jako je kaskáda kotlů, sada tepelných čerpadel, nebo jen vícestupňový el. ohřev, se hodí blok se střídáním výstupů pro pravidelnější opotřebení a záskokem v případě, že jsou některé z agregátů nefunkční. V příkladu níže je upravený text standardního bloku T14. Vidíme v něm i práci s poli, ačkoli pole nejsou deklarována klasicky
test : ARRAY [0..15] OF BOOL;
TYPE
MultiIoBool : ARRAY[0..15] OF BOOL;
END_TYPE
FUNCTION_BLOCK t14_light
VAR
BxPrev : BOOL;
BxfPrev : BOOL;
i, j : INT;
Set : INT;
InOKRot, OutDerot : Lib.Core.V1_0.MultiIoBool := [16(false)];
END_VAR
VAR_INPUT
Bx : BOOL := FALSE;
Bxf : BOOL := FALSE;
// seznam agregátů schopných funkce (odvozeno např. z alarmových bloků)
InOK : Lib.Core.V1_0.MultiIoBool := [true, 15(false)];
NumOfActive, NumOfOutputs : INT := 1;
// NumOfActive: kolik výstupů má být aktivních (např. požadavek z PI regulátoru)
// NumOfOutputs: celkový instalovaný počet agregátů (konstanta)
END_VAR
VAR_OUTPUT
Out : Lib.Core.V1_0.MultiIoBool;
END_VAR
VAR RETAIN
Shift : INT; // O kolik jsou výstupy rotovány kvůli střídání
END_VAR
METHOD IncrementShift
Shift := Shift + 1;
IF Shift > NumOfOutputs - 1 THEN
Shift := 0;
END_IF;
END_METHOD
IF NOT BxPrev AND Bx THEN //detekce náběžné hrany pro rotaci
IncrementShift();
END_IF;
IF BxfPrev AND NOT Bxf THEN
IncrementShift();
END_IF;
FOR i := 1 TO 16 DO // vynulování výstupního pole
Out[i] := False;
END_FOR;
// derotace seznamu připravených vstupů o Shift, takže výstupy mohou být aktivovány počínaje 1
FOR j := 1 TO NumOfOutputs DO
IF (j - Shift < 1) THEN
InOKRot[(j - Shift + NumOfOutputs)] := InOK[j]
ELSE
InOKRot[(j - Shift)] := InOK[j]
END_IF;
END_FOR;
// vynulování výstupního pole a dalších pomocných proměnných
FOR i := 1 TO 16 DO
OutDerot[i] := False;
END_FOR;
Set := 0;
i := 0;
// nastavení počtu aktivních výstupů při přeskočení nefunkčních - díky derotaci začínáme od 1
WHILE NOT (Set >= NumOfActive OR i > NumOfOutputs) DO
IF InOKRot[i] THEN
OutDerot[i] := True;
Set := Set + 1;
END_IF;
i := i + 1;
END_WHILE;
// Rotace výstupů zpět k fyzicky správnému pořadí
FOR j := 1 TO NumOfOutputs DO
IF (j - Shift < 1) THEN
Out[j] := OutDerot[(j - Shift + NumOfOutputs)]
ELSE
Out[j] := OutDerot[(j - Shift)]
END_IF;
END_FOR;
BxPrev := Bx; // pro detekci náběžné či sestupné hrany pro Shift
BxfPrev := Bxf;
END_FUNCTION_BLOCK
Proměnná ActiveOutputs obsahuje požadavek na počet aktivních výstupů. Celkový počet agregátů je konstantou a proto není tento vstup vyveden. Pomocný blok Bool_to_MultiIoBool převádí příslušný počet proměnných typu bool (zde 8) na pole binárních proměnných, což je datový typ, který je využit ve standardním bloku T14, viz deklarace
InOKRot, OutDerot : Lib.Core.V1_0.MultiIoBool := [16(false)];
FUNCTION_BLOCK Bool_to_MultiIoBool
VAR
i: int;
END_VAR
VAR_INPUT
in1, in2, in3, in4, in5, in6, in7, in8: bool; // může být i více
END_VAR
VAR_OUTPUT
out : Lib.Core.V1_0.MultiIoBool;
END_VAR
out[1] := in1;
out[2] := in2;
out[3] := in3;
out[4] := in4;
out[5] := in5;
out[6] := in6;
out[7] := in7;
out[8] := in8; // atd.
END_FUNCTION_BLOCK
Určitě by šlo se v bloku t14_light obejít i bez pole a deklarovat vstupy „natvrdo“, ale stejně bychom je museli uvnitř vložit do nějakého pole kvůli rotačním operacím a cyklům. Navíc datový typ MultiIoBool umožňuje v bloku použít dynamické výstupy:
a tím snadno modifikovat počet viditelných výstupů bloku v grafice FUPLA.
test : ARRAY [0..15] OF BOOL := [16(false)];
znamená, že všech 16 pozic pole má výchozí hodnotu False. Výchozí hodnoty lze zapsat buď každou zvlášť, nebo více najednou. Oba způsoby lze kombinovat:
test : ARRAY [0..15] OF BOOL := [true, 15(false)];
nastaví první pozici na True a ostatních 15 na False.