Multiple instances

Amikor olyan feladatot kell megoldani egy S7 programban, ami ismétlődik, vagyis ugyanazt a feladatot más-más adatokkal kell végrehajtani, célszerű írni egy blokkot, amit megfelelően paraméterezhetünk. Kívülről megadjuk neki a paramétereken keresztül a kiinduló adatokat, a blokk elvégzi a feladatot és az eredményt célszerűen kimenő paraméterekben visszaadja, amit a hívás helyén átveszünk tőle.
Ennek mikéntjére láthatunk példát Az S7 PLC programozása c. írásban.
Ott az is kiderül, hogy ha "nem felejtő" változókra is szükségünk van a blokkon belül, célszerű FC helyett FB blokkot használni, ami a belső változóit egy a blokkhoz hozzárendelt "instance" DB-ben tárolja.
Minden FB híváshoz egy másik DB-t rendelünk hozzá, így ugyanaz a blokk független belső környezetet kap a futása során. Nekünk ezzel nem is kell kívül tovább foglalkozni.

De mi van akkor, ha egy ilyen FB blokkban belül egy másik FB-t (vagy SFB-t) szeretnénk dolgoztatni? Ezekhez is hozzá kell rendelni egy DB-t. Ha ezt abszolút módon megtesszük, akkor azt a blokkot már nem tudjuk több feladatra is felhasználni, mivel a belőle meghívott FB-hez bebetonoztuk egy DB számát, így a másik hívás alkalmából is azt kapja meg, ami komoly bonyodalmakat okoz.

Erre a problémára az ad megoldást, hogy az FB-nk, amiből egy másik FB-t szeretnénk hívni nem kap egy önálló adatblokkot, hanem a hívó DB-jét használhatja. Azt hiszem az a leghatékonyabb, ha ezt egy példán keresztül mutatom be.

Tegyük fel, hogy van egy berendezésünk, ami munkadarabokat munkál meg egyszerre négy állomáson. A négy állomás párhuzamosan, egyszerre dolgozik. Amikor mind a négy elkészült, a munkadarabokat egyel arrább továbbítja. Amelyik az 1-es állomáson volt a 2-esre kerül, amelyik a 2-esen az a 3-asra, stb. A negyedik állomásról kerül le a kész munkadarab.
A gép működésének további részletei nem fontosak a példa szempontjából, nekünk az a feladatunk, hogy mérjük a négy állomás ciklus idejét. Tehát mennyi idő alatt készült el az 1-es, 2-es stb. állomás.
Ezt úgy fogjuk megtenni, hogy írunk egy FB-t az idő mérésére. Azért van szükség FB-re és nem FC-re, mert az FB belső változóinak megtartása itt lényeges a blokk lefutása után is, mivel az idő mérése nem történhet meg a blokk egyszeri lefutása alatt.
A blokk bemenete egy start jel lesz, a blokk azt az időtartamot fogja mérni, amennyi ideig a start jel aktív (TRUE állapotú). Amikor a mérésnek vége lesz, a kimenetén megkapjuk a mért időt.
Kell tehát 4 merker bit, mindegyiuk az egyes állomásokhoz tartozik és TRUE állapotú ameddig az állomás dolgozik. Amikor készen van a művelettel FALSE lesz.
Hogy ne legyen olyan egyszerű és gyakorlatiasabb legyen a példa, az időmérő blokkunk olyan extra funkciót is tartalmaz, hogy 4 mérést tárol, a kimenetén visszaadja az utolsó 4 átlagát a négy közül a legrövidebb és leghosszabb időt is.



Az FB1-ben az időt IEC timerrel fogjuk mérni (SFB 4). Kézenfekvő az IEC timer, mert az időt TIME formátumban méri és nem visszafele, hanem előre számol.
Az FB1 interace részében a következő változók vannak:
Bemeneti vááltozók:
Start: Ez kezdeményezi az időmérést
Akt:: A mérés végén itt adja vissza a mért időt. A következő mérésig az érték megmarad a kimeneten.
Kimeneti változók:
Atlag: Az utolsó 4 mérés időátlagát adja vissza.
Min: Az utolsó 4 mérés közül a legkisebbet adja vissza
Max: Az utolsó 4 mérés közül a legnagyobbat adja vissza
Stat változók:
Timer_I: Ez fogja tartalmazni az IEC timer változóit is ahelyett, hogy külön DB-ben tárolná azokat. Adattípusként az SFB4-et (az IEC timer blokkja) kell megjelölni.
T_RUN:. Az IEC timer ebbe másolja majd bele az időt, miközben az telik. Innen kell majd elmásolnunk a mérés végén.
MT1-MT4. A négy legutolsó mérés idő adatát ezekben tároljuk.
StartNTMP: Egy impulzus változó a start jel megszűnésének érzékeléséhez
TREMP változók:
TMP: A számolgatások részeredményét tároljuk benne.



Az első networkben a start jel végén (annak lefutó élénél) léptetni kell a 4 belső tároló (MT1-MT4) tartalmát.
Ehhez az MT3-at az MT4-be, az MT2-t az MT3-ba, az MT1-et az MT2-be másoljuk.Végül az IEC timer aktuális tartalmát (ami a számára megadott T_RUN változóban van) átmásoljuk az MT1 tárolóba és a blokkunk Akt kimenetére is.
Fontos, hogy a mért időt az IEC timer hívása előtt kell elvenni tőle, mert amikor észleli a bemenetén megszűnő Start jelet, a kimenetén nullát ad vissza, így tehát a mért idő értéke elveszne.


A következő networkben van az IEC timer hívása.


Látható, hogy nem az SFB4 hívása szerepel itt, hanem a STAT változóként SFB4 típussal létrehozott változónév, a Timer_I!
Ez a kulcsa annak, hogy az FB1-en belül hívott SFB4-hez ne kelljen egy rögzített számú (fix) DB-t hozzárendelni.
Az SFB4 így a saját változóit a mi FB1 blokkunk DB-jében fogja majd tárolni. Biztosítva ezzel azt, hogy amikor a programunkban meghívjuk ezt az FB1-et, akkor az azokból hívott SFB4 blokknak mindnek függetlenül tárolódjanak a változói.
Ha ebben az FB1-ben több IEC timert vagy más FB/SFB blokkokat is használni kellene, akkor azoknak mindnek külön létre kell hozni a saját FB1 STAT változóját! Még akkor is, ha ugyanazt a blokkot hívjuk az FB1-ből. Tehát ha további SFB4 timereket is használnánk, azoknak is külön STAT változó kell, nem adhatjuk meg nekik is a Timer_I-t!

A következő network megkeresi a legnagyobb értéket és a Max kimenetre továbbítja.



Utána megkeresi a legkisebb értéket és a Min kimenetre továbbítja:



Nincs más hátra, mint az átlag kiszámítása és a kimenetre juttatása.


Az utolsó NW biztosítja, hogy az FB1 blokk ENO kimenete mindig TRUE legyen. Így ha több utasítást fűzünk fel egy sorba, mindegyik le fog futni,

A szemfülesebb olvasónak feltűnhetett, hogy nagyvonalúan DI típusú utasításokat használunk TIME típusú változókkal.Ezt két okból tehetjük meg:
Az egyik az, hogy kikapcsoltam a típus ellenőrzést az opciók között:



Ezt a LAD/STL/FBD editor opciói között találjuk, a LAD/FBD fülnél.
Ha ez az opció be van kapcsolva, akkor funkció blokk és létradiagramban nem engedi meg a DI adattípussal dolgozó utasításoknál csak a DI adatot, a TIME-ot nem. Ilyenkor csak STL-ben vagy hosszas típuskonverziókkal tudjuk megoldani.

A másik ok az, hogy a TIME típus lényegében egy duplaszó, ami ezredmásodpercben (ms) tartalmazza az időt,
Ezért tehát problémamentesen számolhatunk vele mind DI adattípus, egészen addig amíg az eredményünk túl nem csordul, vagy negatív nem lesz. Erre bizony oda kell figyelni! A fenti példaprogram nem foglalkozik ezzel a problémával!

Most már csak a 4 állomásról érkező jelzésre van szükség hogy mérhessük a műveleti időket. Legyen az 1-es állomásé az M1.2, a 2-esé az M1.3, a 3-asé az M1.4, a 4-es munkahelyé pedig az M1.5.
Meghívjuk négyszer az FB1-et, mindn hívásnak adva egy külön DB blokkot, mindegyik Start bemenetének átadjuk az iménti merkereket, a kimeneteket pedig DB-ben tároljuk:



Kapcsolódó írások:
Az S7 PLC programozása
Az idő mérése

Felhasznált irodalom:
Siemens AG FAQ: How do you create and update multiple instances?


Szirty