Adatcsere S7 PLC-k között MPI buszon keresztül (1. rész)


A Siemens S7 (300/400) PLC-k fejlett kommunikációs képességekkel rendelkeznek. Mindegyik rendelkezik beépített MPI csatlakozóval (MultiPort Interface) ami RS485 alapú. Más CPU típusokon van beépített Profibus illesztő is, vagy azzal egy bővítő segítségével utólag bővíthető. Az MPI porton keresztül programozhatjuk, diagnosztizálhatjuk, különféle megjelenítő eszközöket (OP, PC) kapcsolhatunk rá.
Ahogy a nevéből is kiderül, az MPI portra több eszközt is ráköthetünk, maximum 32-t. Összeköthetjük pl. egy automatizálási rendszer PLC vezérlőit egymással. Egy ilyen kapcsolat több előnnyel is jár:
Ez a cikk a PLC-k közötti MPI buszos adatcserével foglalkozik, a több lehetséges módszer közül bemutat egyet.

Az MPI busz
Az MPI tehát (mellesleg a Profibusz is) RS485 alapú hardverre épül. Egy csavart érpáron továbbítja az adatokat.
Az MPI és a profibusz kábelezésekor figyelembe kell venni néhány alapszabályt. A busz sorban, eszközről eszközre fut (sín topológia). Minden eszköznem van egy címe, ami azonosítja. Egy buszon természetesen nem lehet két azonos című eszköz. MPI esetén a címtartomány 0-31, az alapértelmezett adatsebesség pedig 187.5 kbps.
A buszt le kell zárni mindkét végén, vagyis az első és az utolsó eszköznél. A Siemens speciális csatlakozói tartalmaznak lezárást, amit egy kapcsolóval lehet aktiválni:


Ha a csatlakozó lezárását bekapcsoljuk (On) a kapcsoló egyúttal leválasztja a továbbmenő kábelt is.
A buszhoz árnyékolt csavart érpárt használnak. A csavart érpár jelentősen növeli a zavarvédettséget.



Ugyanez a speciális csatlakozó teszi lehetővé, hogy egy bekötött MPI portra utólag kívülről rácsatlakozzunk (pl. egy számítógéppel):
A 187.5 kbit-es sebesség 1000m-es kábelhosszt enged meg leágazás nélkül. Ennél nagyobb távolsághoz aktív elemet kell használni (pl. RS485 repeater).

                           

PLC-PLC kommunikáció

Egy közös MPI buszra felfűzött S7 PLC-k egymás között is tudnak adatot cserélni. Erre többféle módot is találhatunk gyári programblokkok formájában.
Az alábbi blokkok foglalkoznak adatcserével:

SFB8/FB8  USEND
SFB9/FB9 URCV
SFB12/FB12  BSEND
SFB13/FB13 BRCV
SFB14/FB14  GET
SFB15/FB15  PUT
SFC 65 X_SEND
SFC 66 X_RCV
SFC 68 X_PUT
SFC 67 X_GET

SFC 65 (X_SEND),  SFC 66 (X_RCV)
A példában az SFC 65 (X_SEND) blokkot és párját az SFC 66 (X_RCV) funkcióblokkokat használjuk.
Az X_SEND és X_RCV a hw konfigurációban nem szereplő külső kommunikációs partnerrel történő MPI kommunikációra használható. Ezzel lehetővé válik, hogy nem egy Step7 projectben szereplő rendszerek között valósítsunk meg adatcserét ("idegen" S7 PLC-vel).
Természetesen a hardver konfigban szereplő másik S7-el való kommunikációra is alkalmas.

Adatküldés

Az SFC 65 (X_SEND)
Sending Data to a Communication Partner outside the Local S7 Station with SFC 65 "X_SEND"



Paraméterek:
REQ Küldés kérése. Logikai 1 hatására az SFC65 megpróbálja elküldeni az adatokat
CONT Folyamatos kapcsolat (continue).
Ha a CONT=0, akkor küldés végén bontja a kapcsolatot a kommunikációs partnerrel, újabb adatküldéskor a kapcsolatot újra felveszi minden alkalommal. Ha egy hívással akarunk felváltva különböző című S7 CPU-nak adatokat küldeni, akkor ezt a módszert használjuk.
Ha CONT=1, akkor a kapcsolatot fenntartja a küldés után is. Ha ciklikusan akarunk adatot küldeni ugyanannak az MPI buszos S7-nek, akkor használjuk ezt a módot, mert így gyakrabban tudunk adatot küldeni, mint ha minden küldés után újra és újra felépítené a majd lebontaná a kapcsolatot (a kapcsolat felépítése és bontása időt vesz igénybe).
DEST_ID A címzett (cél) azonosítója (Destination identifier), vagyis az MPI címe. A paraméter WORD típusú, ne feledjük, hogy ezért a címet hexadecimális alakban kell megadni. Pl. ha a 17-es MPI címet kell megadni, akkor ide 11-et, pontosabban W#16#11-et kell írni! (mivel 17 decimális = 11 hexa). Ide tehát azt a címet kell beírni, ami a buszon lévő másik eszköz hardver konfigban beállított MPI címe:
REQ_ID    Kérés azonosítója. Egy tetszőleges azonosítót kell megadnunk a blokk hívásakor egy DWORD típusú paraméterben.
Ezt az azonosító számot a kommunikációs partner PLC-ben futtatott X_RCV blokk (ami ennek a blokknak az adatküldését fogadja) visszaadja.
Szükségessége akkor lesz nyilvánvaló, amikor párhuzamosan futtatunk egyszerre több különböző adatot küldő X_SEND és X_RCV kérést. A vevő oldalon ebből a REQ_ID-ből fogjuk tudni, hogy a vett adatcsomagot melyik küldő adta fel és hogy az adatcsomag milyen adatokat tartalmaz. Más szóval a REQ_ID-ből tudjuk meg, hogy a csomagot melyik X_SEND hívás adta fel. Ebből következik, hogy ha a buszon lévő több PLC-ben, vagy egy PLC programban többször is használjuk az X_SEND hívást, akkor mindegyiknek más-más REQ_ID-t kell megadnunk.
SD A küldendő adatra mutató paraméter. Egy ANY típusú paraméter, ami a küldendő adatokat tartalmazó memóriaterületre mutat
RET_VAL Visszatérési érték. Az SFC hívás ebben a kimenő paraméterben adja vissza az adatküldéssel kapcsolatos állapot információt és hibakódot.
BUSY Logikai kimenő érték. Állapota 1, amikor az adatküldés folyamatban van (foglaltság jelzés)

A küldés menete a következő:
"Összehordjuk" a küldendő adatokat egy összefüggő memória területre. Ez lehet local (L), kimenet (Q), bemenet (I), merker (M) vagy DB (D) memóriaterület.
Az SD-ben megadjuk az erre a területre mutató ANY típusú paramétert. Pl. ha az M10.0-M11.7 tartományban lévő 16 merker bitet akarjuk elküldeni, akkor SD-ben ezt kell megadnunk: P#M10.0 BYTE 2
Beállítjuk a CONT paramétert, majd bekapcsoljuk a REQ-t, ha a BUSY nem 1 állapotú és figyeljük a RET_VAL értékét. A RET_VAL értéke a hívás után nulla lesz, ha az adatot sikerült elküldeni és azt a címzett fogadta. Ha bármilyen probléma merül fel (a címzett nem tudta fogadni az adatot, vagy egyéb hiba lépett fel) akkor a RET_VAL egy hibakódot tartalmaz, ami a problémára utal.
A hibakódokról a Step7 helpben vagy az "S7-300/400 System and Standard Functions" című PDF doksiban tájékozódhatunk az "Error Information of the Communication SFCs for Non-Configured S7 Connections" című résznél..
Fontosabb RET_VAL értékek:
Ha a REQ bemenet inaktív és az adatküldő blokknak nincs dolga, akkor a 7000h kódot adja. Ha a REQ bemenetet olyankor aktiváljuk, amikor az előző adatküldés még nem fejeződött be, akkor a 7002h kódot adja vissza, amikor pedig a kérést indítjuk, azaz a REQ-t bekapcsoljuk, akkor 7001h-t kapunk.

Rendkívül fontos tudni, hogy a kommunikáció aszinkron módon zajlik le.
Ez azt jelenti, hogy az X_SEND meghívásakor a progaram nem áll le az adat elküldésének idejére, hanem tovább fut. Küldés közben az SFC 65-öt újra és újra meghívjuk, eközben annak BUSY és RET_VAL állapotjelzései alapján tudjuk meg, hogy az adat el lett-e küldve és hogy a címzett megkapta-e az adatot. Ilyenkor a RET_VAL 0.
Ha olyan adatokat küldünk át, amelyek megérkezéséről az adó oldalon a programnak tudnia kell (pl. jelzést adni ha a küldés sikertelen) akkor a RET_VAL értékét figyelni kell.
A legegyszerűbb, ha egy időtaggal figyeljük a RET_VAL 0 értékét. Ha egy ideig az nem lesz 0, akkor bekapcsolunk egy jelző bitet:



(A RET_VAL az MW2-ben van)
Az M1.1 1 állapotba kerül, ha a fenti SFC 65 adatküldése sikertelen volt folyamatosan 3 másodpercen keresztül. A T1 türelmi időt úgy kell meghatározni, hogy az adatküldések gyakoriságánál hosszabb legyen.

Adatfogadás
Az SFC 65 (X_SEND) rendszerfunkcióval küldött adatokat a címzett PLC-ben az SFC 66 (X_RCV) rendszerhívással lehet fogadni.
Receiving Data from a Communication Partner outside the Local S7 Station with SFC 66 "X_RCV"



Parméterek
EN_DT Az adat olvasás engedélyezése (Enable Data Transfer). Boolean típusú paraméter, amely 1 állapotával lehet elindítani az adat kiolvasását.
RET_VAL Visszatérési érték. Ebben az Integer típusú paraméterben adja vissza az X_RCV blokk a vétel sikerességével kapcsolatos hibakódot.
REQ_ID Itt kapjuk vissza az adó oldalon az X_SEND hívás REQ_ID-jénél megadott azonosító számot. A programunkban ennek segítségével tudjuk azonosítani, hogy ki és milyen adatot küldött.
NDA Boolean kimenő paraméter, amely 1 állapotú lesz, amikor adat érkezik (New Data Arrived)
RD ANY típusú paraméter, amivel közöljük, hogy a vett adatokat hova tegye.

Az adatfogadás menete a következő:
Kitöltjük a megfelelő paramétereket. Az RD-nél nem a közvetlenül a célterületet adjuk meg, mert az adat érkezésekor még nem biztos hogy azokat az adatokat olvastuk be, amelyik ennek az SFC 66-nak szól. Létrehozunk tehát a vett adatok számára előkészített, az adatok számával megegyező méretű puffert és annak a mutatóját adjuk meg az RD paraméterben.
Meghívjuk az SFC 66-ot. Megvizsgáljuk az NDA állapotát. Ha az logikai 1, akkor adat érkezett.
Ekkor kiolvassuk a REQ_ID-t és egy feltétel vizsgálatnak vetjük alá, hogy kiderüljön milyen adat jött. Az RD által megadott adatterületről a vett adatokat kimásoljuk a megfelelő helyre.

Az MPI buszról az adatokat az S7 operációs rendszere egy átmeneti tárolóba olvassa be (queue). Az SFC 66 ebből a tárolóból veszi elő az érkezett adatokat.
Amikor a blokk hívásakor az EN_DT 0 állapotú és nem érkezik adat (a queue üres), akkor a blokk 7000h RET_VAL értéket ad vissza. Ha EN_DT=0 állapotú és meghívjuk a blokkot amikor adat érkezett, akkor az NDA kimenet jelzi az adat érkezését (1 állapotú lesz), a RET_VAL az érkezett adat hosszát (byte-ban), a REQ_ID pedig az azonosítóját tartalmazza, de az adatokat nem olvassa ki. Az csak akkor történik meg, amikor az EN_DT-t aktiváljuk.
Amikor EN_DT=1, és adat érkezett, akkor a RET_VAL tartalmazza a vett adatblokk hosszát byte-ban, és az SFC 66 az queue-ban lévő legrégebbi adatokat az RD-ben megadott helyre másolja. Ha a híváskor hiba lép fel, akkor a RET_VAL a hiba kódját tartalmazza (7000h-nál nagyobb érték).


Példa:
A vett adatokat az SFC 66 a DB1 adatblokk első 2 byte-jára másolja, a REQ-ID-t pedig a DB1 DBD2-es duplaszavába.





Példaprogram

Példaprogram az SFC65 SFC 66 felhasználásával az adatcserére.
A példában a küldő PLC 2 különböző adatcsomagot küldözget eltérő gyakorisággal, de ciklikusan a címzettnek, ami a kapott adatokat azonosítja és a megfelelő adatterületre másolja.



A 5-ös MPI című CPU két másodpercenként elküldi az 4-es MPI című CPU-nak a DB1 első 8 byte-ját (4 integer változót) 1-es azonosítóval.

A DB1 felépítése:


Továbbá az MB10-es merker byte-ot (M10.0-M10.7) egy tized másodpercenként szintén elküldi 4-es MPI című CPU-nak, 2-es azonosítóval.
Az adó és a vevő CPU-ban egyaránt két-két időtag figyeli az adatforgalmat.
Ha az adatküldés vagy fogadás sikertelen, akkor letelik az adathoz hozzárendelt türelmi idő és kikapcsol az időtag. Az időtagot "érintkezője" jelzi ha az adatküldés és fogadás leállt, ezt a programban felhasználhatjuk az ilyenkor szükséges lépések megtételéhez.

Feltétel, hogy a küldő PLC HW config-jában a clock memory MB255-re legyen állítva. Erre azért van szükség, mert a példaprogram a rendszer által ebben a clock memory byte-ban megvalósított négyszög impulzusokat használja fel a küldés ütemezésére.
Az OB1 tartalma mindkét PLC-n azonos:
      CLR   
      =     M      0.0
      CALL  FC     3
Az M0.0 egy olyan merker, ami mindig ki van kapcsolva. Akkor használható, amikor pl. egy blokk paraméterének konstans 1 vagy 0 állapotot akarunk megadni.

A példaprogramot mindkét PLC-ben az FC3 tartalmazza.

Az adatküldő CPU programja

Az FC3 blokkban használt lokális változók:




Ez a két network egy jelzést valósít meg, ami a DB1 adatküldést kezdeményezi, kezeli a küldés végének jelzését, és az elküldött adat megérkezésének jelzését, valamint a türelmi idő kezelését.
Az M2.0 RS tárolót bekapcsolja a 2 másodperces folyamatos impulzus sorozat felfutó éle. (A DB1 2 másodpercenként kerül átküldésre), ami majd az adatküldést kezdeményezi.
Az #RW1 lokális változóban a DB1-et küldő X_SEND funkció blokk RET_VAL visszatérési értéke található (lásd alább). Az #RW1 tartalma tehát 0 lesz, amikor a blokknak sikerül elküldeni a DB1-et és az a vevőhöz meg is érkezett. Az M2.2 tehát minden alkalommal, amikor a küldött adatot a vevő veszi, egy ciklus ideig 1-be billen, ami törli az adat kérését kezdeményező M2.0 merkert.
Közben ugyanez az impulzus mindig újraindítja T1  kikapcsolásra késleltető timert, ami 6 másodper elteltével kikapcsol, ha ennyi ideig nem sikerül elküldeni az adatot.
A ciklikus adatküldés gyakoriságának háromszorosa a türelmi idő. Ha az adatküldés zavartalan, akkor két másodpercenként a timer újraindul az impulzusok miatt, így az nem tud letelni.



Az SFC65 (X_SEND) hívása
Ismét megjegyzem, hogy a kommunikáció aszinkron módon történik. Ezért az SFC65-öt minden PLC ciklusban meg kell hívni, hogy tenni tudja a dolgát.
A REQ bemenettel kell vezérelnünk, vagyis azt 1 állapotúra állítani, ha adatot akarunk küldeni. De figyelembe kell venni, hogy amíg az adatküldés zajlik, ne küldjünk újabb adatot. Erre szolgál az M1.2, és az M1.4 merker bit a REQ sorában. Ez a két merker a két SFC65 "BUSY" foglaltságot jelző kimenetének másolata. (lásd a program végén).
Persze megtehetnénk azt is, hogy a REQ bemenetet fixen 1-re állítjuk, és akkor az X_SEND olyan sebességgel küldeni, ahogy csak a "csövön kifér". De ha több különböző adatot is akarunk küldeni külön X_SEND hívással (akár másik CPU-nak) akkor ez a teljes sebességű küldés teljesen lefoglalja a PLC-nk kommunikációs részét. A másik hívás leggyakrabban a "nem érek rá" jelzéssel fogja visszautasítani az adatküldési próbálkozásainkat. Persze néha sikerülni fog neki a küldés, de nem lehet előre megmondani milyen gyakorisággal.
Érdemes tehát a küldést ütemezni. Csak akkor küldjünk adatot, ha az tényleg szükséges.
Ebben a példában az adatküldés ciklikus, de természetesen lehet esemény bekövetkezéséhez is kötni az adatküldés kezdeményezését. Ilyenkor azonban másképpen fest az adat megérkezésének a visszaigazolása.

A küldő program következő 3 network-je az MB10 merker byte küldését végzi ugyanazzal a szisztémával, de a küldés gyakorisága itt 100ms, a türelmi idő pedig 300ms.




A következő két network a két adatküldő X_SEND blokk foglaltságát jelző állapotbitjeit másolja másik merker bitekbe.


Erre azért van szükség, hogy amikor az X_SEND meghívásra kerül, akkor abban a PLC ciklusban, amikor a BUSY kimenete 1 állapotúra vált, ne tudjon hatással lenni a REQ bemenetének sorában szereplő foglaltság jelzésre, csak a következő PLC ciklusban.

Az adatokat fogadó CPU programja

Az adatokat egyetlen X_RCV hívással olvassuk be egy átmeneti tárolóba, ami a DB2 adatblokkban kapott helyet.
Azért használunk átmeneti tárolót, mert csak az adat beolvasása után derül ki, hogy melyik azonosítóval küldött adat érkezett meg. Vagyis a DB1 8 byte jött, vagy az MB10 egy byte-ja.
A dolog máshogy is megoldható, mert az X_RCV hívása az adat kiolvasása nélkül is képes közölni a REQ_ID kimenetén keresztül a vételi queue-ban lévő adat hovatartozását, az azonban valamelyest növeli az SFC hívás feltételeinek a bonyolultságát. Igaz így meg külön írni kell egy szeparátor rutint, ami az átmeneti pufferből az adatot a rendeltetési helyére másolja :)
Az olvasási puffer szerkezete az alábbi:

DB2


Az FC3 lokális változói:




Az adat fogadását intéző X_RCV hívás.
Az EN_DT bemenet, ami az adat olvasását engedélyezi, folyamatosan 1 állapotban van, így az olvasás állandóan zajlik. A blokk az #NDA lokális változóba másolja az adat érkezését jelző kimenetének az állapotát, a #REQ_ID-be a vett adatot azonosító számot és #RV-be a visszatérési kódot.
Ezeket a következő network használja fel, ami STL-ben íródott:



A fenti kód megvizsgálja, hogy jött-e adat.
Ha nem akkor nem hajtódik végre, tovább lép. Ha jött, akkor megnézi, hogy 1-es (DB1 jött) vagy 2-es (MB10 jött) azonosítóval jött-e adat. Ha 1-es az azonosító, akkor bekapcsolja M1.0-át, ami DB1 érkezését jelzi, majd átmásol 8 integert a DB2 átmeneti pufferből a DB1-be.
Ha az azonosító 2, akkor a puffer első byte-ját belerakja MB10-be, mert MB10 érkezett.



A fenti két network figyeli az adatok érkezésének gyakoriságát T1 és T2 időtag segítségével.
Ha DB1 érkezik, akkor M1.0 impulzust ad, ami újraindítja T1 időtagot, így az bekapcsolva marad.
Ha MB10 érkezik, akkor M1.1 impulzust ad, ami újraindítja T2 időtagot, így az szintén bekapcsolva marad.
Ha az adatok folyamatosan érkeznek, akkor mindkét időtag be van kapcsolva. Ha bármilyen okból valamelyik adat többször kimarad, akkor a hozzá tartozó időtag letelik, és kikapcsol.

Egy-egy VAT táblával egyszerűen ellenőrizhető az adatátvitel.
Az egyikben az adó CPU DB1-ét és MB10-ét a másikban a vevőjét jelenítjük meg:



Mindkettőt monitorba tesszük, ami már csak azért is lehetséges, mivel a két PLC amúgy is egy MPI buszon van.
A küldő CPU DB word-jeibe és MB10 byte-jába értékeket irkálunk és figyeljük megjelenik-e a vevő CPU VAT táblájában. Ha minden sikerült, akkor igen :)

Az írás második része itt olvasható



Szirty