A Modbus az egyik legrégebbi és legelterjedtebb ipari kommunikációs protokoll — egyszerű, és a specifikációja bárki számára ingyenesen elérhető, ezért sokféle ipari eszköz támogatja valamilyen formában. Ebben a fejezetben megérted, hogyan épül fel egy Modbus-üzenet, mi a különbség a három fő változata (RTU, ASCII, TCP) között, és hogyan gondolkodik a Modbus az eszközök adatairól.
4.1 A Modbus rendszer felépítése, rétegei
Alkalmazási rétegbeli (az OSI-modell 7., alkalmazási rétegén futó), kliens/szerver (korábbi elnevezéssel: master/slave) elven működő kommunikációs protokoll, amelyet a Modbus Organization (nyílt, gyártói konzorcium) gondoz. FONTOS: a specifikációt nem szabványügyi testület, hanem a Modbus Organization teszi közzé, nyilvánosan és ingyenesen elérhető formában. A protokollhoz IEC-szabványsorozatokban is kapcsolódik profil (IEC 61158 Type 15, IEC 61784 CPF 15), a gyakorlatban azonban a Modbus Organization specifikációja a hivatkozott dokumentum.
A Modbus különlegessége, hogy önmagában NEM ír elő fizikai réteget — rá lehet építeni soros vonalra (RS-232 vagy RS-485, lásd 1.4.) éppúgy, mint Ethernet (TCP/IP) hálózatra. Ez a rugalmasság az egyik oka annak, hogy ilyen elterjedt lett.
A Modbus-hálózaton egy eszköz (a kliens, korábbi elnevezéssel „master”) kezdeményezi a kommunikációt egy kéréssel; a megcélzott eszköz (a szerver, korábbi elnevezéssel „slave”) válaszol rá. A szerver soha nem kezdeményez önmagától kommunikációt.
A Modbusnak három fő változata van, amelyeket a következő alfejezetekben részletesen is megismersz:
- Modbus RTU: soros vonalon, bináris kódolással.
- Modbus ASCII: soros vonalon, olvasható karakteres kódolással.
- Modbus TCP: Ethernet (TCP/IP) hálózaton.
Mivel a Modbus maga csak a legfelső réteget adja, a gyakorlatban mindig egy „rétegkötegben” találkozol vele. A két tipikus köteg:
| Réteg | Soros vonali Modbus | Modbus TCP |
|---|---|---|
| Alkalmazási (7.) | Modbus (funkciókódok, adatmodell) | Modbus (funkciókódok, adatmodell) |
| Közbenső rétegek | soros vonali keretezés (RTU vagy ASCII) | TCP/IP |
| Fizikai (1.) | RS-232 vagy RS-485 (lásd 1.4.) | Ethernet |
Bármelyik köteget nézed, a legfelső sor változatlan: ugyanazok a funkciókódok, ugyanaz a négy adattáblázat. Ezért tud egy meglévő Modbusos alkalmazás szinte változtatás nélkül átköltözni soros vonalról Ethernetre — csak a keretezés cserélődik alatta.
4.2 Telegramok csoportosítása, felépítése; adat- és címzési modell
Adatmodell
A Modbus négy alapvető adattáblázat-típust különböztet meg — ezt a négyet minden Modbus-eszköznek ismernie kell:
Egybites, ÍRHATÓ ÉS OLVASHATÓ adat — például egy relé ki/be állapota.
Egybites, CSAK OLVASHATÓ adat — például egy kapcsoló pillanatnyi állapota.
16 bites, CSAK OLVASHATÓ adat — például egy mért érték (hőmérséklet, nyomás).
16 bites, ÍRHATÓ ÉS OLVASHATÓ adat — például egy beállítási paraméter (pl. egy kívánt érték, setpoint).
Sok gyártói dokumentációban találkozol olyan, „5 jegyű” jelöléssel, mint a „40001” vagy a „10001” — ez egy ELTERJEDT, de NEM HIVATALOS konvenció, amit maga a Modbus-specifikáció nem ír elő. Ebben a jelölésben az első számjegy azt mutatja, MELYIK adattáblázatról van szó: a coilok számozása 0-val (00001-től), a diszkrét bemeneteké 1-gyel (10001-től), a holding regisztereké 4-gyel (40001-től) kezdődik. Vagyis a „10001” NEM coilt, hanem DISZKRÉT BEMENETET jelöl — ez gyakori tévesztés, és éppen ellentétes következtetésre visz (csak olvasható bemenet helyett írható kimenetet feltételezel). Az input regisztereknek is saját tartományuk van; a konkrét számozást mindig az eszköz dokumentációjából vedd.
A protokoll saját, belső adatcseréjében ezzel szemben egyszerű, 0–65535 közötti számcímek szerepelnek. A gyártói dokumentációkban ELŐFORDULHATNAK ELTÉRÉSEK abban is, hogyan számozzák a címeket (0-alapú vagy 1-alapú számozás) — mindig ellenőrizd a konkrét eszköz saját dokumentációját!
Function Code (funkciókód)
Minden Modbus-üzenet tartalmaz egy funkciókódot, amely megmondja, MILYEN műveletet kér a kliens — például „olvass ki N darab holding registert” vagy „írj be egy értéket egy coilba”. A funkciókód teszi lehetővé, hogy ugyanaz az alap üzenetformátum sokféle műveletet le tudjon írni.
Telegramok csoportosítása
A Modbus-telegramokat (üzeneteket) három szempont szerint érdemes csoportosítani. Ha ezt a hármat külön tudod választani, bármilyen Modbus-forgalomban eligazodsz.
1. Irány szerint: kérés és válasz. Minden váltás egy KÉRÉSSEL indul, amit a kliens küld, és egy VÁLASSZAL zárul, amit a megcélzott szerver küld vissza. Szerver soha nem szólal meg magától, és két kérés sem „keresztezi” egymást ugyanazon a soros vonalon.
2. A funkciókód szerint. A specifikáció a funkciókódokat kategóriákba sorolja. A gyakorlatban egy funkciókód lényegében három kérdésre válaszol:
- MELYIK adattáblázatot érinti (coil, diszkrét bemenet, input regiszter, holding regiszter);
- OLVAS vagy ÍR;
- EGY elemre vagy TÖBB, egymást követő elemre vonatkozik.
Ebből következik, hogy melyik adattáblázathoz milyen művelet létezik egyáltalán:
| Adattáblázat | Méret | Lehetséges művelet |
|---|---|---|
| Coils | 1 bit | olvasás és írás |
| Discrete Inputs | 1 bit | csak olvasás |
| Input Registers | 16 bit | csak olvasás |
| Holding Registers | 16 bit | olvasás és írás |
Diszkrét bemenetre vagy input regiszterre tehát hiába keresel „írás” funkciókódot: a protokoll szintjén sem létezik, mert ezek az adatok az eszköz szempontjából bemenetek. A fejezet kidolgozott példájában szereplő 03-as funkciókód a „Read Holding Registers” („olvass ki N darab holding registert”) műveletet jelenti.
3. A keretezés szerint. Ugyanaz a kérés más-más keretbe csomagolva megy a vezetéken attól függően, hogy RTU-ról, ASCII-ról vagy TCP-ről van szó — erről szól a 4.3. alfejezet.
Ha a szerver a kérést nem tudja teljesíteni (például nem létező címet kérdezel le, vagy nem támogatja az adott funkciókódot), akkor nem hallgat el: hibajelzéssel, úgynevezett kivételválasszal (exception response) felel. Ez is válasz-telegram, csak a tartalma nem adat, hanem hibajelzés. A hibajelzés konkrét kódjainak jelentését mindig az eszköz dokumentációjában, illetve a Modbus-specifikációban keresd — eszközönként eltérhet, melyik hibaokot melyik helyzetben adja vissza.
Nézz meg egy Modbus-kompatibilis eszköz (pl. frekvenciaváltó, PLC) regisztertérkép- dokumentációját. Azonosíts legalább egy-egy példát mind a négy adattáblázat-típusra (coil, discrete input, input register, holding register), és indokold meg, miért éppen abba a kategóriába tartozik az adott adat (írható-e, és hány bites).
Kidolgozott példa: egy Modbus RTU telegram byte-szintű felépítése
Egy Modbus RTU keret négy részből áll, mindig ebben a sorrendben:
eszközcím – funkciókód – adatmező – CRC
Az első két rész egy-egy bájt, a CRC kettő; az adatmező hossza a funkciókódtól és a művelettől függ. Nézzük meg konkrétan, hogyan néz ki ez egy valódi üzeneten. Tegyük fel, hogy a 17-es eszközcímű berendezéstől 3 darab holding regisztert szeretnénk kiolvasni, a 40108-as címtől kezdve (tehát 40108, 40109, 40110).
A hagyományos, „5 jegyű” regisztercímzés (lásd fent) NEM egyezik meg a ténylegesen a
telegramban elküldött címmel — minden adattáblázatnak megvan a saját „eltolása”: a
holding regiszterek esetén ez 40001. A ténylegesen elküldött cím tehát:
40108 - 40001 = 107, ami hexadecimálisan 0x006B.
A KÉRÉS (kliens → szerver) bájtjai:
| Bájt(ok) | Érték (hex) | Jelentés |
|---|---|---|
| 1 | 11 |
Eszközcím (a szerver címe; a régi dokumentációkban SlaveID) — 17 decimálisan = 0x11 |
| 1 | 03 |
Funkciókód — „Read Holding Registers” |
| 2 | 006B |
Az első regiszter címe (107 = 40108-40001) |
| 2 | 0003 |
Az olvasandó regiszterek száma (3 darab) |
| 2 | 7687 |
CRC-ellenőrzőösszeg (alacsony bájt elöl) |
A VÁLASZ (szerver → kliens) bájtjai:
| Bájt(ok) | Érték (hex) | Jelentés |
|---|---|---|
| 1 | 11 |
Eszközcím (visszaigazolásként) |
| 1 | 03 |
Funkciókód (visszaigazolásként) |
| 1 | 06 |
A következő adatbájtok száma (3 regiszter × 2 bájt = 6) |
| 2 | AE41 |
1. regiszter értéke (44 609 decimálisan, előjel nélküli 16 bites értékként értelmezve) |
| 2 | 5652 |
2. regiszter értéke |
| 2 | 4340 |
3. regiszter értéke |
| 2 | 49AD |
CRC-ellenőrzőösszeg (alacsony bájt elöl) |
A cím- és darabszám-mezőket a Modbus RTU MAGAS bájttal elöl küldi (a 107-es cím a
vezetéken 00 6B), a keret végén álló CRC-t viszont ALACSONY bájttal elöl. Ezért látod a
táblázatban 76 87 alakban azt az értéket, amit egy CRC-számoló 0x8776-ként ad vissza (a
válasznál ugyanígy: 49 AD a kiszámolt 0xAD49-ből). Ha valaha nem egyezik a kézzel
újraszámolt CRC-d a forgalomban látottal, először a bájtsorrendet nézd meg — a hibák
többsége itt van, nem a számításban.
A AE41 (hex) bitminta önmagában csak egy 16 bites számot jelent — hogy ez egy
előjel nélküli egész szám (44 609), egy előjeles egész szám (−20 927), vagy akár egy
2 karakteres szöveg-darabka, azt KIZÁRÓLAG az adott regiszterhez tartozó, a gyártói
dokumentációban rögzített ADATTÍPUS dönti el. A Modbus protokoll maga nem „tudja”,
milyen típusú adatot szállít — csak nyers bájtokat továbbít.
4.3 Modbus ASCII, RTU és TCP telegramformátumok
A Modbus mindhárom változata UGYANAZT az adatmodellt és funkciókód-rendszert használja — csak abban különböznek, HOGYAN keretezik és viszik át fizikailag az üzenetet.
Soros vonalon (RS-232 vagy RS-485) futó változat, amely a bájtokat BINÁRIS (nem olvasható) formában küldi. Hibaellenőrzésre CRC (Cyclic Redundancy Check)-et használ. Kompakt: ugyanazt a tartalmat kevesebb bájton viszi át, mint az ASCII változat.
Szintén soros vonalon fut, de minden bájtot KÉT OLVASHATÓ ASCII-karakterként (hexadecimális számjegyenként) kódol — emiatt kétszer annyi karaktert igényel, mint az RTU, cserébe a forgalom emberi szemmel (pl. egy egyszerű terminálprogrammal) is nyomon követhető. Hibaellenőrzésre LRC (Longitudinal Redundancy Check)-et használ. A keret egy kettősponttal („:”) kezdődik, és kocsivissza + sorvég (CR/LF) karakterekkel zárul.
Ethernet (TCP/IP) hálózaton futó változat. Mivel az Ethernet és a TCP/IP protokoll már önmagában is biztosít hibaellenőrzést, a Modbus TCP-nél NINCS szükség külön CRC-re vagy LRC-re. Helyette a küldő egy MBAP (Modbus Application Protocol) fejlécet told az üzenet elé, amely tartalmazza a tranzakcióazonosítót, a protokollazonosítót, a hosszmezőt és az egységazonosítót (unit identifier — ez azonosítja, melyik konkrét eszközt célozza az üzenet, ha egy átjárón/gateway-en keresztül több soros eszköz is elérhető TCP-n).
Összefoglaló táblázat:
| Jellemző | RTU | ASCII | TCP |
|---|---|---|---|
| Átviteli közeg | soros (RS-232/RS-485) | soros (RS-232/RS-485) | Ethernet (TCP/IP) |
| Kódolás | bináris | olvasható ASCII (hex) | bináris |
| Hibaellenőrzés | CRC | LRC | nincs szükség rá (Ethernet/TCP biztosítja) |
| Jellemző előny | kompakt, gyors | emberi szemmel követhető | hálózati infrastruktúrán fut |
Az eredeti Modbus (RTU, ASCII) a soros vonalak korszakában született, amikor a legtöbb ipari eszköz RS-232/RS-485 porttal rendelkezett. Ahogy az ipari hálózatok egyre inkább Ethernet-alapúak lettek, a Modbus TCP tette lehetővé, hogy a jól bevált Modbus-logikát (adatmodell, funkciókódok) modern hálózaton is használni lehessen, anélkül, hogy az alkalmazási szintű programozást újra kellene írni.
Kidolgozott példa: ugyanaz a kérés Modbus ASCII keretben
A legtanulságosabb, ha a 4.2. alfejezet kidolgozott RTU-kérését — 17-es eszközcím, 03-as
funkciókód, 0x006B cím, 3 regiszter — átírjuk ASCII keretbe. A tartalom SZÓ SZERINT
ugyanaz, csak a leírás módja más: az RTU egy bájtként küldi a 0x11 értéket, az ASCII
viszont a „11” karakterpárt, vagyis KÉT olvasható karaktert.
Az RTU-kérés hat tartalmi bájtja:
11 03 00 6B 00 03
Ugyanez ASCII-ban, karakterről karakterre:
: 1 1 0 3 0 0 6 B 0 0 0 3 L L CR LF
Az ASCII keret mezői:
| Mező | Hossz (karakter) | Tartalom a példában |
|---|---|---|
| Kezdőjel | 1 | : (kettőspont) |
| Eszközcím | 2 | 11 |
| Funkciókód | 2 | 03 |
| Adatmező | az adatbájtok számának kétszerese | 006B0003 (4 bájt → 8 karakter) |
| LRC | 2 | a keret tartalmából számolt ellenőrző érték |
| Zárójel | 2 | CR + LF (kocsivissza + sorvég) |
Számoljunk: az RTU-kérés a vezetéken 8 bájt (6 tartalmi bájt + 2 bájt CRC). Ugyanez ASCII-ban 1 + 2 + 2 + 8 + 2 + 2 = 17 karakter. Több mint kétszeres forgalom ugyanazért az információért — cserébe a keret egy egyszerű terminálprogramban is olvasható.
A keret belsejében kizárólag hexadecimális számjegyek (0–9, A–F) állnak, így a kezdő kettőspont a kereten belül nem fordulhat elő — a keret eleje tehát összetéveszthetetlen, a vége pedig a CR/LF. Ezért tudod egy egyszerű soros terminálon szinte „soronként” olvasni a forgalmat, ami hibakeresésnél komoly előny.
A fenti keretben az LRC helyén szándékosan L L áll: az LRC (és az RTU CRC) számítási
algoritmusa túlmutat a fejezet anyagán. Amit tudnod kell: minden ASCII-keret végén, közvetlenül
a CR/LF előtt két hexadecimális karakter áll, ez az ellenőrző érték; a vevő újraszámolja, és
eltérés esetén eldobja a keretet. A konkrét számítási eljárást a Modbus soros vonali
implementációs útmutatója írja le.
Kidolgozott példa: ugyanaz a kérés Modbus TCP-n
Vegyük megint ugyanazt a kérést. TCP-n az üzenet MAGJA — a funkciókód és az adatmező — BÁJTRA UGYANAZ marad:
03 00 6B 00 03
Ami eltűnik: a soros vonali eszközcím és a CRC. Ami megjelenik helyettük: az MBAP-fejléc.
| Sorrend | Mező | Szerepe |
|---|---|---|
| 1. | Tranzakcióazonosító (MBAP) | a kérés és a hozzá tartozó válasz összepárosítása |
| 2. | Protokollazonosító (MBAP) | azt jelöli, hogy Modbus-üzenetről van szó |
| 3. | Hosszmező (MBAP) | az utána következő rész hossza |
| 4. | Egységazonosító (MBAP) | melyik eszközt célozzuk egy átjárón (gateway) túl |
| 5. | Funkciókód | 03 — az üzenet magja |
| 6. | Adatmező | 006B0003 — az üzenet magja |
| — | CRC / LRC | NINCS: a hibaellenőrzést az Ethernet és a TCP/IP adja |
Ez a táblázat a fejléc mezőit a nevük szerinti szerepükben mutatja be; a mezők pontos bájthosszát és kitöltési szabályait a Modbus TCP/IP implementációs útmutatója rögzíti.
Ha a három keretet egymás mellé teszed, látod a Modbus egész logikáját: a „mit kérek” rész (funkciókód + cím + darabszám) mindhárom változatban azonos, és csak a köré épülő boríték cserélődik — RTU-nál eszközcím és CRC, ASCII-nál kettőspont, karakterpárok, LRC és CR/LF, TCP-nél MBAP-fejléc, ellenőrzőösszeg nélkül. Ezért tud egy Modbus RTU/TCP átjáró (gateway) gyakorlatilag „átcsomagolni” üzeneteket a két világ között.
4.4 Gyakorlat: rendszerkiépítés, konfigurálás, forgalomtesztelés, hibaelhárítás
- Építs ki egy Modbus RTU kapcsolatot legalább egy kliens (pl. PC-s szoftver vagy PLC) és egy szerver (pl. szimulátor vagy valódi eszköz) között.
- Konfiguráld be mindkét oldalon ugyanazt az átviteli sebességet és a szerver címét.
- Olvass ki legalább egy holding registert és egy input registert, majd írj be egy értéket egy coilba.
- Rögzítsd egy kérés és a hozzá tartozó válasz bájtjait, és azonosítsd bennük a keret négy részét (eszközcím, funkciókód, adatmező, CRC) a 4.2. alfejezet kidolgozott példája alapján.
- Ha van rá lehetőséged, ismételd meg a forgalmat Modbus TCP-n keresztül is, és hasonlítsd össze a két forgalom „láthatóságát” (pl. egy hálózati elemzővel).
- Idézz elő szándékosan egy hibát (pl. rossz szerver-cím, rossz sebesség, vagy egy nem létező regisztercím lekérdezése), figyeld meg, mit kapsz vissza: elmarad a válasz, vagy kivételválasz érkezik? Ezután javítsd ki a hibát.
Összefoglalás
- A Modbus egy nyílt, kliens/szerver elvű, alkalmazási rétegbeli protokoll, amelyet a Modbus Organization gondoz; a specifikációja nyilvánosan, ingyenesen elérhető.
- Négy alapvető adattáblázat-típusa van: coils (írható-olvasható 1 bit), discrete inputs (csak olvasható 1 bit), input registers (csak olvasható 16 bit), holding registers (írható-olvasható 16 bit).
- A „40001”-féle, „5 jegyű” címjelölés elterjedt, de NEM hivatalos része a protokollnak: benne a 0-val kezdődő tartomány a coiloké, az 1-gyel kezdődő a diszkrét bemeneteké, a 4-gyel kezdődő a holding regisztereké. A protokoll maga 0–65535 közötti számcímeket használ.
- A funkciókód mondja meg, milyen műveletet kér egy Modbus-üzenet: melyik adattáblázatot érinti, olvas vagy ír, és hány elemre vonatkozik.
- Minden váltás kérés (kliens → szerver) és válasz (szerver → kliens) párból áll; ha a szerver nem tudja teljesíteni a kérést, kivételválasszal felel.
- Az RTU keret négy része: eszközcím, funkciókód, adatmező, CRC — a CRC-t alacsony bájttal elöl küldi, a többi mezőt magas bájttal elöl.
- Három fő változata van: RTU (soros, bináris, CRC), ASCII (soros, olvasható, bájtonként két hexadecimális karakter, „:” kezdet, LRC, CR/LF zárás) és TCP (Ethernet, MBAP-fejléc, nincs külön hibaellenőrzés). Az üzenet magja (funkciókód + adat) mindháromban azonos.
Ellenőrző kérdések
- Mit jelent a kliens/szerver (master/slave) elv a Modbusnál?
- Sorold fel a négy Modbus adattáblázat-típust, és mondd meg mindegyikről, hány bites és írható-e.
- Miért nem hivatalos része a protokollnak a „40001”-féle címjelölés, és miért fontos ezt tudni?
- Mire való a funkciókód egy Modbus-üzenetben, és melyik három kérdésre ad választ?
- Mi a fő különbség a Modbus RTU és a Modbus ASCII kerete között kódolás és kerethossz szempontjából?
- Miért nincs szükség CRC-re vagy LRC-re a Modbus TCP-nél?
- Mit tartalmaz az MBAP fejléc, és mire való benne az egységazonosító (unit identifier)?
- Miért terjedt el három különböző fizikai megvalósítása is ugyanannak a protokollnak?
Tudáspróba
1. Melyik Modbus adattáblázat-típus 16 bites és csak olvasható? a) Input Registers b) Holding Registers c) Coils d) Discrete Inputs
2. Melyik hibaellenőrzési módszert használja a Modbus RTU? a) LRC b) CRC c) Paritásbit d) Nincs hibaellenőrzés
3. Egy gyártói adatlap „10005”-ös címet ad meg egy kapcsoló állapotához. Milyen adattáblázat-típusra következtetsz ebből a „5 jegyű” jelölésből, írható-e ez az adat, és miért kell óvatosnak lenned ezzel a jelöléssel?
4. Igaz vagy hamis: a Modbus TCP-nél a küldő maga számol CRC-t az üzenethez, mert az Ethernet nem elég megbízható.
5. Egy Modbus RTU kérés hat tartalmi bájtból (eszközcím, funkciókód, adatmező) és a CRC-ből áll. Hány karakter hosszú ugyanez a kérés Modbus ASCII keretben? Írd le a számítást mezőnként.
6. Melyik mezőre van szükség a Modbus TCP-nél ahhoz, hogy egy átjárón (gateway-en) keresztül elérhető, több soros eszköz közül beazonosítható legyen a célzott eszköz?
7. Egy szerver eszköz spontán módon, kérés nélkül küld egy adatot a hálózatra. Összhangban van-e ez a Modbus kliens/szerver elvével? Indokold meg.
8. Ki gondozza a Modbus specifikációját, és milyen gyakorlati következménye van annak, hogy nyilvánosan, ingyenesen elérhető, a tanulás és a forráskeresés szempontjából?