A könyv fő nyelve — szintaxis, vezérlési szerkezetek, és az a néhány dolog, amit PLC-ben másképp kell csinálni, mint egy számítógépen.
- 12.1 A szintaxis alapjai
- 12.2 Operátorok és kiértékelési sorrend
- 12.3 Elágazás:
IF - 12.4 Elágazás:
CASE - 12.5 Ciklusok — és miért veszélyesek PLC-ben
- 12.6 Funkcióblokk hívása ST-ben
- 12.7 Kidolgozott mintafeladat
- 12.8 Olvasható kód
- 12.9 Tipikus kezdő hibák
- Összefoglalás
- Gyakorlatok
- Ellenőrző kérdések
- Tudáspróba
- A fejezet forrásai
Az eddigi fejezetekben már láttál ST-kódot: időzítőket hívtunk, számlálókat léptettünk. Most következik a nyelv rendszeres bemutatása.
Az ST (Structured Text, strukturált szöveg) a könyv fő nyelve. Három okból:
- A legkifejezőbb. Amit létradiagramban tíz hálózat, azt ST-ben gyakran öt sor.
- A hatályos szabványban is központi. Az IEC 61131-3 negyedik kiadásának nyelvcsomagjában ez az egyetlen szöveges nyelv (6. fejezet).
- Átvihető tudás. Aki ismer bármilyen modern programozási nyelvet, itt otthon érzi magát — és fordítva: aki ST-t tanul, könnyebben lép tovább.
12.1 A szintaxis alapjai
Az ST utasításokból áll, és minden utasítást pontosvessző zár le.
iDarab := 0;
bMotor := TRUE;
rNyomas := rNyersertek * 0.01;Az értékadás jele :=, nem =. Az = az összehasonlítás operátora:
iA := 5; (* értékadás: iA legyen 5 *) bEgyenlo := (iA = 5); (* összehasonlítás: igaz-e, hogy iA értéke 5 *)
Ha véletlenül = helyett :=-t írsz egy feltételbe (vagy fordítva), a fordító általában
hibát jelez — de nem mindig. Érdemes tudatosan figyelni rá: kettőspont-egyenlő = adok
értéket, egyenlő = kérdezek.
Megjegyzések kétféleképpen írhatók:
(* Ez egy megjegyzés, akár
több soron át is. *)
// Ez egy soros megjegyzés a sor végéig.Az ST szabadon tördelhető: a sortörések és a behúzások nem befolyásolják a működést, csak az olvashatóságot. Ezt használd ki (12.8).
12.2 Operátorok és kiértékelési sorrend
Ha egy kifejezésben több operátor van, a kötési erősség dönti el, melyik hajtódik végre előbb.
A sorrend, a legerősebbtől a leggyengébbig:1 2
| Erősség | Művelet | Jel |
|---|---|---|
| legerősebb | zárójel | ( ) |
| ↓ | függvényhívás | Nev(paraméterek) |
| ↓ | hatványozás | EXPT |
| ↓ | előjel, tagadás | -, NOT |
| ↓ | szorzás, osztás, maradék | *, /, MOD |
| ↓ | összeadás, kivonás | +, - |
| ↓ | összehasonlítás | <, >, <=, >= |
| ↓ | egyenlő, nem egyenlő | =, <> |
| ↓ | logikai ÉS | AND |
| ↓ | logikai KIZÁRÓ VAGY | XOR |
| leggyengébb | logikai VAGY | OR |
És a szabály azonos erősség esetére:2
„Ha egy kifejezésben több operátor van, a magasabb precedenciájú operátorok értékelődnek ki előbb. Ha két operátornak azonos a precedenciája, a bal oldali értékelődik ki előbb.”
Ez fontos, és sokan pont fordítva gondolják. Ez a kifejezés:
bRiaszt := rNyomas > 8.0 AND bUzem;így értékelődik ki: (rNyomas > 8.0) AND bUzem — mert az összehasonlítás erősebben köt,
mint az AND. Ez itt véletlenül jó, de ne bízd a szerencsére.
Gyakorlati szabály: összetett logikai feltételben mindig tegyél zárójelet. Nem a fordítónak írsz, hanem annak, aki fél év múlva olvassa.
A MOD az osztási maradékot adja. Két helyen nagyon hasznos:
- ciklikus számlálás:
iAllas := (iAllas + 1) MOD 8;— a számláló 0…7 között forog körbe; - oszthatóság vizsgálata:
IF (iDarab MOD 10) = 0 THEN— minden tizedik darabnál.
12.3 Elágazás: IF
Az IF szerkezet alakja:
IF rHomerseklet < 0.0 THEN iAllapot := 1; ELSIF rHomerseklet = 0.0 THEN iAllapot := 2; ELSE iAllapot := 3; END_IF
Amit érdemes megjegyezni:
- az
ELSIFegy szó (nemELSE IF), és tetszőleges számú lehet belőle; - az
ELSElegfeljebb egy, és a végén áll; - a szerkezetet
END_IFzárja; - az ágak fentről lefelé értékelődnek ki, és az első igaz ág fut le — a többi már nem.
Ez a kód sosem jut el a második ágig:
IF rNyomas > 5.0 THEN iSzint := 1; ELSIF rNyomas > 8.0 THEN iSzint := 2; (* SOHA nem fut le *) END_IF
Ha a nyomás 9 bar, az első feltétel is igaz, tehát az fut le. A tartományos vizsgálatoknál mindig a legszűkebb feltételt tedd előre — vagy adj meg alsó és felső határt is.
12.4 Elágazás: CASE
Ha ugyanannak az egész változónak sok értékét vizsgálod, a CASE olvashatóbb.
IF-lánc különböző feltételeket vizsgál sorban; a CASE egyetlen egész érték szerint ágazik el.A gyártói dokumentáció szerinti alak:3
CASE iAllapot OF 1, 5: bLampa := TRUE; 10..20: bLampa := TRUE; ELSE bLampa := NOT bLampa; END_CASE
Amit a forrás kimond:3
- a feltétel egész típusú változó;
- több címke vesszővel sorolható fel (
1, 5); - tartomány két ponttal írható (
10..20); - az
ELSEág „opcionális, legfeljebb egyszer” fordulhat elő, és „alapértelmezett ugrási célpont, amelyre akkor ugrik, ha egyik korábbi címke sem egyezik a feltétellel”.
A 23. és a 26. fejezetben állapotgépeket fogsz írni. Azoknak ez a szerkezete:
CASE iLepes OF 0: (* alaphelyzet *) IF bIndit THEN iLepes := 10; END_IF 10: (* adagolás *) bAdagolo := TRUE; IF bTele THEN iLepes := 20; END_IF 20: (* ürítés *) bAdagolo := FALSE; bUrito := TRUE; IF bUres THEN iLepes := 0; END_IF END_CASE
Figyeld meg a tízesével növekvő lépésszámokat: így később be lehet szúrni közéjük egy új állapotot anélkül, hogy mindent át kellene számozni.
12.5 Ciklusok — és miért veszélyesek PLC-ben
Az ST-ben három ciklusfajta van.
FOR, a WHILE és a REPEAT ciklus, valamint az EXIT és a CONTINUE utasítás.FOR — ismert számú ismétlés
FOR i := 1 TO 100 BY 2 DO IF arrErtek[i] = 70 THEN j := i; EXIT; END_IF END_FOR;
A BY megadja a lépésközt (elhagyható, ekkor 1). Ez a legbiztonságosabb ciklusfajta, mert
a ciklusszám előre látszik.
WHILE — elöltesztelő
WHILE j <= 100 AND arrErtek[j] <> 70 DO j := j + 2; END_WHILE;
A feltételt a rendszer a ciklus elején vizsgálja: ha eleve hamis, a ciklus egyszer sem fut le.
REPEAT — hátultesztelő
REPEAT j := j + 2; UNTIL j = 101 OR arrErtek[j] = 70 END_REPEAT;
Itt a vizsgálat a végén történik, tehát a ciklus legalább egyszer lefut.
EXIT és CONTINUE
EXIT— kilép a ciklusból, és a ciklus utáni utasításon folytatja.CONTINUE— „aFOR,WHILEvagyREPEATcikluson belül használatos, hogy a ciklus következő végrehajtásának elejére ugorjon”.5
A gyártó saját példája jól mutatja, mire jó a CONTINUE:5
FOR Counter := 1 TO 5 BY 1 DO INT1 := INT1 / 2; IF INT1 = 0 THEN CONTINUE; (* to avoid a division by zero *) END_IF Var1 := Var1 / INT1; (* executed, if INT1 is not 0 *) END_FOR; Erg := Var1;
A veszély
A gyártói súgó szó szerint figyelmeztet a WHILE-nál:4
„Ha a logikai kifejezés soha nem veszi fel a
FALSEértéket, akkor az utasítások végtelenül ismétlődnek, aminek következtében futásidejű hiba keletkezik.”
És hozzáteszi: „Programozással kell gondoskodnod arról, hogy ne keletkezzenek végtelen ciklusok.”
De a veszély ennél tágabb, és a PLC sajátossága.
Gondold végig a 2. fejezet ciklusmodelljét: bemenetek beolvasása → program futása → kimenetek kiírása. Ha a programodban egy ciklus sokáig fut, akkor:
- a kimenetek addig nem frissülnek — a berendezés „nem reagál”;
- a ciklusidő megnő, ami elrontja az időzítéseket;
- ha a ciklusidő átlépi a (Time × Sensitivity) határt, a watchdog kiold, és a task kivétellel megáll (8. fejezet).
Egy asztali programban természetes, hogy megvárjuk, amíg valami befejeződik. PLC-ben ez tilos. Ha várni kell, azt a ciklusok között kell megtenni — állapotgéppel vagy időzítővel.
Rossz (PLC-ben):
WHILE NOT bKesz DO ; (* várunk, hogy megérkezzen a jel *) END_WHILE;
Ez soha nem fog kilépni, mert amíg a ciklus fut, a bemenetek nem frissülnek — a bKesz
értéke nem tud megváltozni. Ez a klasszikus PLC-s önbecsapás.
Jó (PLC-ben):
CASE iLepes OF 10: (* a következő cikluson újra megnézzük *) IF bKesz THEN iLepes := 20; END_IF 20: (* mehet tovább *) END_CASE
Mire használd mégis a ciklust? Tömbökön való végigmenéshez, ha a tömb mérete kicsi és ismert: 8 csatorna ellenőrzése, 16 riasztásbit összegzése, 100 elemű átlagolás. Ezek véges, rövid ciklusok — nem várakozás.
12.6 Funkcióblokk hívása ST-ben
A 10. fejezetből tudod: a funkcióblokkot példányon keresztül hívjuk. ST-ben ez így néz ki:
VAR tonKesleltet : TON; ctuDarab : CTU; END_VAR tonKesleltet(IN := bIndit, PT := T#5S); bKesz := tonKesleltet.Q; ctuDarab(CU := bEl, RESET := bTorol, PV := 100); bTele := ctuDarab.Q;
A minta három részből áll:
- példány deklarálása a
VARblokkban; - hívás a bemeneti paraméterekkel;
- kimenet olvasása pontozott jelöléssel (
példány.kimenet).
A hívás és a kimenetolvasás külön sorban is történhet, és sokszor így olvashatóbb — de figyelj a sorrendre: a kimenetet a hívás után olvasd, különben az előző ciklus értékét kapod.
A kimenet a híváson belül is átvehető a => jellel:
tonKesleltet(IN := bIndit, PT := T#5S, Q => bKesz);
Ez ugyanaz, mint a fenti két sor. Melyiket használd? Amelyik az adott helyen olvashatóbb — de egy projekten belül maradj következetes.
12.7 Kidolgozott mintafeladat
Feladat. Egy szállítószalag indítógombra indul, leállítógombra megáll. A szalagon áthaladó darabokat egy érzékelő számolja. Ha a darabszám eléri az 500-at, a szalag megáll, és jelzőlámpa gyullad ki. A lámpát és a számlálót nyugtázó gombbal lehet törölni. A szalag csak akkor indulhat, ha nincs vészjelzés.
PROGRAM PLC_PRG VAR (* bemenetek *) bIndit : BOOL; bLeallit : BOOL; bErzekelo : BOOL; bNyugtaz : BOOL; bVesz : BOOL; (* kimenetek *) bSzalag : BOOL; bLampa : BOOL; (* belső *) rtErzekelo : R_TRIG; rsSzalag : RS; ctuDarab : CTU; END_VAR (* 1. Darabszámlálás – csak a felfutó élre *) rtErzekelo(CLK := bErzekelo); ctuDarab(CU := rtErzekelo.Q, RESET := bNyugtaz, PV := 500); (* 2. A szalag indítás–leállítás logikája, reset-dominánsan *) rsSzalag( SET := bIndit, RESET1 := bLeallit OR bVesz OR ctuDarab.Q ); bSzalag := rsSzalag.Q1; (* 3. Jelzőlámpa a teljesítésről *) bLampa := ctuDarab.Q;
Nézzük végig, mi miért így van:
| Rész | Miért? |
|---|---|
R_TRIG az érzékelőn |
a darab több cikluson át takarja az érzékelőt — élfigyelés nélkül sokat számolna (18. fejezet) |
RS (reset-domináns) |
ha egyszerre van indítás és leállítás vagy vészjel, a szalag ne induljon (18. és 24. fejezet) |
a RESET1 három jelet fog össze |
leállítógomb, vészjelzés és a teljesített darabszám — bármelyik megállítja |
PV := 500 |
a beállított érték a hívásban is megadható |
| a nyugtázás a számlálót törli | és mivel a lámpa a ctuDarab.Q-ra épül, a lámpa is elalszik |
A bVesz itt jelzés, amit a PLC kap. A tényleges vészleállítást a 24. fejezet szerint
hardveres biztonsági relé végzi, a vezérlőtől függetlenül. A programban lévő vészág csak
azt biztosítja, hogy a vezérlés is tudjon róla.
12.8 Olvasható kód
Egy PLC-program élettartama 10–20 év. Nagy eséllyel nem te fogod javítani.
Elnevezés. Használj beszélő neveket, és jelöld a típust előtaggal — ez nem szabvány, hanem elterjedt szokás, de nagyon segít:
| Előtag | Típus | Példa |
|---|---|---|
b |
BOOL |
bSzalagFut |
i, di |
INT, DINT |
iDarab, diOsszes |
r |
REAL |
rNyomas |
s |
STRING |
sReceptNev |
t |
TIME |
tKesleltetes |
Tagolás. Csoportosítsd a kódot, és tedd ki, mi micsoda:
(* ---------- 1. Jelek előkészítése ---------- *) (* ---------- 2. Vezérlési logika ---------- *) (* ---------- 3. Kimenetek kiadása ---------- *)
Megjegyzés. Ne azt írd le, mit csinál a kód — az látszik. Azt írd le, miért:
(* rossz *) iDarab := iDarab + 1; (* megnöveljük a darabszámot *) (* jó *) iDarab := iDarab + 1; (* a vevő minden 500. darab után kér mintavételt *)
Konstansok. Varázsszám helyett nevesített konstans (10. fejezet):
VAR CONSTANT MAX_DARAB : INT := 500; END_VAR
12.9 Tipikus kezdő hibák
| Hiba | Következmény | Megoldás |
|---|---|---|
= és := felcserélése |
fordítási hiba vagy rossz logika | tudatos figyelem |
| Élfigyelés elhagyása | többszörös számlálás, ismételt indítás | R_TRIG / F_TRIG (18. fejezet) |
| Egy funkcióblokk-példány két helyen | mindkét működés elromlik | annyi példány, ahány működés (10. fejezet) |
Várakozó WHILE ciklus |
végtelen ciklus, watchdog-kioldás | állapotgép vagy időzítő |
| Ugyanaz a kimenet több helyen írva | az utolsó írás nyer, a többi hatástalan | egy kimenetet egy helyen írj |
| Zárójel nélküli összetett feltétel | nehezen olvasható, néha rossz logika | zárójelezés |
REAL használata egész értékekhez |
kerekítési hiba (4. fejezet) | egész típus |
| Nem inicializált változó | kiszámíthatatlan induló viselkedés | kezdőérték a deklarációban |
Ez a kód nem azt csinálja, amit elsőre gondolnál:
IF bFeltetel1 THEN bMotor := TRUE; END_IF IF bFeltetel2 THEN bMotor := FALSE; END_IF
Ha mindkét feltétel igaz, a motor nem indul el — mert a második írás felülírja az elsőt. A ciklikus végrehajtás miatt mindig az utolsó értékadás jut ki a kimenetre.
Szabály: egy kimenetnek egy helye legyen a programban, ahol az értéke eldől.
Összefoglalás
- Az ST utasításokból áll, minden utasítást pontosvessző zár. Az értékadás
:=, az összehasonlítás=. - Az operátorok kötési erőssége a zárójeltől az
OR-ig csökken; azonos erősségnél balról jobbra történik a kiértékelés. Összetett feltételt zárójelezz. - Az
IF … ELSIF … ELSE … END_IFágai fentről lefelé értékelődnek ki, és az első igaz ág fut le. - A
CASEegy egész változó értéke szerint ágazik el; a címkék vesszővel sorolhatók, tartomány..-tal írható, és van opcionálisELSEág. - Három ciklus van:
FOR(ismert számú),WHILE(elöltesztelő),REPEAT(hátultesztelő). AzEXITkilép, aCONTINUEa következő menetre ugrik. - PLC-ben nem várakozunk ciklussal. A hosszú ciklus megnöveli a ciklusidőt, és watchdog-kioldáshoz vezet. Várakozáshoz állapotgép vagy időzítő kell.
- A funkcióblokkot példányon keresztül hívjuk; a kimenet a
példány.kimenetalakkal vagy a híváson belül=>jellel olvasható. - Az olvasható kód nem stílusgyakorlat: 10–20 évig kell működnie, és nem te fogod javítani.
- Egy kimenetnek egy helye legyen, ahol az értéke eldől.
Gyakorlatok
Írd le, milyen sorrendben értékelődnek ki a következő kifejezések, és mi az eredményük, ha
iA := 4, iB := 10, bC := TRUE:
a) iA + iB * 2
b) (iA + iB) * 2
c) iA > 3 AND iB < 5 OR bC
d) iB MOD iA
e) NOT bC AND iA = 4
Utána írd be őket a CODESYS-be, futtasd szimulációban, és hasonlítsd össze az eredményt a saját számításoddal. Ahol eltérés van, keresd meg, melyik operátor kötési erősségét mérted fel rosszul.
Az alábbi kód a nyomás alapján akar három szintet megkülönböztetni, de hibás:
IF rNyomas > 2.0 THEN iSzint := 1; ELSIF rNyomas > 5.0 THEN iSzint := 2; ELSIF rNyomas > 8.0 THEN iSzint := 3; END_IF
Írd le, mi történik rNyomas = 9.0 esetén. Javítsd ki kétféleképpen: (a) a sorrend
megfordításával, (b) alsó és felső határ megadásával. Melyik a jobb, és miért?
Írd át a 12.2. gyakorlat javított kódját CASE szerkezetre. Figyelj arra, hogy a CASE
feltétele egész típusú — tehát előbb valamilyen egész értékké kell alakítanod a nyomást
(például REAL_TO_INT(rNyomas)). Fogalmazd meg, milyen pontosságot veszítesz ezzel, és mikor
elfogadható ez.
Írj egy FOR ciklust, amely egy 1000 elemű tömböt tölt fel értékekkel minden PLC-ciklusban.
Nézd meg a task-monitorozóban, mennyivel nőtt a ciklusidő. Növeld 10 000-re, majd 100 000-re,
és jegyezd fel az értékeket. Mikor lép közbe a watchdog? Mit állítottál be Time és
Sensitivity értéknek?
Egészítsd ki a 12.7. alfejezet programját: (a) a szalag csak akkor indulhasson, ha egy
biztonsági ajtó zárva van; (b) minden 100. darabnál villanjon fel egy másik lámpa fél
másodpercre (TP időzítő, 17. fejezet); (c) a darabszám élje túl az újraindítást
(10. fejezet). Írd le a kódot, és jelöld meg, melyik fejezetből melyik elemet használtad.
Ellenőrző kérdések
- Mi a különbség a
:=és az=jel között? - Kétféle megjegyzésforma van az ST-ben — melyek ezek?
- Sorold fel az operátorok kötési erősségét a legerősebbtől a leggyengébbig!
- Mi történik azonos erősségű operátoroknál?
- Mire való a
MODoperátor? Mondj két gyakorlati példát! - Hány
ELSIFés hányELSEág lehet egyIFszerkezetben? - Miért nem fut le soha a
rNyomas > 8.0ág, ha előtterNyomas > 5.0áll? - Milyen típusú lehet a
CASEfeltétele? Hogyan írsz benne értéklistát és tartományt? - Mi a különbség a
WHILEés aREPEATközött? - Mit csinál az
EXIT, és mit aCONTINUE? - Miért nem szabad
WHILEciklussal várni egy bemeneti jelre? - Mi történik, ha egy ciklus túl sokáig fut?
- Hogyan hívsz funkcióblokkot ST-ben, és hogyan olvasod a kimenetét?
- Miért hibás ugyanazt a kimenetet két helyen írni?
Tudáspróba
Válaszd ki az egyetlen helyes választ!
1. Az értékadás jele ST-ben:
a) :=
b) =
c) ==
d) =>
2. Melyik operátor köt a legerősebben?
a) AND
b) zárójel
c) *
d) +
3. A logikai OR operátor:
a) a legerősebben köt;
b) ugyanolyan erősen köt, mint az AND;
c) a leggyengébben köt;
d) erősebben köt, mint az összehasonlítás.
4. Az IF szerkezetben:
a) tetszőleges számú ELSE ág lehet;
b) az ELSIF két külön szó;
c) minden igaz ág lefut;
d) az első igaz feltételű ág fut le.
5. A CASE feltétele:
a) egész típusú;
b) BOOL típusú;
c) REAL típusú;
d) STRING típusú.
6. A CASE szerkezetben a 10..20 jelentése:
a) 10 és 20 értékek;
b) a 10-től 20-ig terjedő tartomány;
c) 10 vagy 20;
d) érvénytelen szintaxis.
7. Melyik ciklus fut le biztosan legalább egyszer?
a) FOR
b) WHILE
c) REPEAT
d) mindegyik
8. A CONTINUE utasítás:
a) kilép a ciklusból;
b) megszakítja a programot;
c) újraindítja a taskot;
d) a ciklus következő végrehajtásának elejére ugrik.
9. Ha egy WHILE ciklus feltétele soha nem lesz hamis:
a) végtelen ismétlés és futásidejű hiba keletkezik;
b) a fordító hibát jelez;
c) a ciklus automatikusan kilép 1000 menet után;
d) a task prioritása csökken.
10. Ha ugyanazt a BOOL kimenetet két helyen írod egy cikluson belül:
a) a két érték logikai VAGY kapcsolatba kerül;
b) az utolsó értékadás érvényesül;
c) az első értékadás érvényesül;
d) fordítási hiba keletkezik.
A megoldókulcs a B függelékben található.
A fejezet forrásai
-
Structured Text (ST) – operátorok kötési erőssége és utasítástáblázat. Beckhoff Information System. (2026-07-31) ↩
-
Expression (IEC 61131-3) – A Computation to Return a Value. Fernhill Software. (2026-07-31) Az operátor-precedencia független megerősítése. ↩↩
-
CODESYS Online Help: ST Instruction: CASE (V3.5.22.0). CODESYS GmbH. (2026-07-31) ↩↩
-
CODESYS Online Help: ST Instruction: WHILE (V3.5.22.0). CODESYS GmbH. (2026-07-31) ↩
-
CODESYS Online Help: EXST Instruction: CONTINUE (V3.5.22.0). CODESYS GmbH. (2026-07-31) ↩↩