MODBUS TCP

Z onlinetechnology.cz

Přejít na: navigace, hledání
MODBUS TCP klient je dostupný pro první i druhou produktovou řadu zařízení SDS.

MODBUS TCP je průmyslový standard, který umožňuje přímé čtení a zápis hodnot mezi přístroji, které tento protokol podporují.


Obsah

K čemu je MODBUS TCP dobré

Řada přístrojů a strojů poskytuje své údaje a data prostřednictvím MODBUS TCP. Příkladem mohou být různé PLC, sensory fyzikálních veličin, nebo měniče či systémy solárních elektráren.

Aby šlo pomocí SDS tyto zařízení ovládat a číst z nich údaje, je v SDS k dispozici protokol MODBUS TCP.

Poznámka: SDS umožňuje komunikovat MODBUS protokolem přes RS485 nebo RS232, pokud použijete příslušný program (SDS-C respektive FULL-C).

Obecně, současné používání protokolu MODBUS je založeno na přístupu k "registrům". Každý registr je reprezentován jako jedno 16 bitové číslo (-32768 až +32767), a dále každý registr má svou adresu.

Je na výrobci daného zařízení, jaké údaje v registrech poskytne, kolik jich bude, a na jakých adresách budou jaké registry s jakým významem.

Příklad: chytrý teploměr typ XYZ123, s MODBUS TCP protokolem, poskytuje na čísle registru 30001 hodnotu se změřenou teplotou. Pokud SDS přečte registr číslo 30001 (pomocí MODBUS TCP dotazu), tak mu ten chytrý teploměr vrátí hodnotu tohoto registru, tedy SDS dostane 16bitové číslo, ve kterém bude podle očekávání (tedy dle výrobce teploměru) hodnota změřené teploty.

MODBUS je samozřejmě o něco málo složitější, protože kromě registrů jsou dostupné ještě "cívky" (coils) a "binární vstupy" (discrete inputs). Toto je původně historická záležitost, kdy se přes MODBUS přímo ovládali fyzické prvky (např. ventily), nicméně to zůstalo, a je na každém výrobci daného zařízení, jaký význam (a jesli vůbec) těmto prvkům přiřadí.

Významy si musíte vždy zjistit z dokumentace pro daný výrobek. Příklad takové dokumentace od jednoho z výrobců: https://www.victronenergy.com/live/ccgx:modbustcp_faq


Protokol MODBUS TCP

Postupem času se protokol MODBUS TCP velice rozšířil, a objevili se požadavky na přenos i jiných hodnot, než jen 16bit čísel. Na to se používá trik, kde se čtou registry co jsou adresně hned za sebou, a výsledek se pak spojí dohromady. Tak se dají číst či zapisovat i 32bit čísla, dlouhé řetězce znaků, atd.

SDS dodržuje implementaci dle

Reference [1] je klíčová - odsud si nastudujte, jak se sestavují jednotlivé datové položky.


Implementace v SDS

SDS podporují MODBUS TCP komunikaci za předpokladu, že máte nainstalován aktuální firmware.

MODBUS TCP komunikace se provádí pomocí příslušných SDS-C / FULL-C funkcí.

SDS podporuje následující funkce:

  • CONNECT
  • DISCONNECT
  • ReadCoils (code = 1)
  • ReadDiscreteInputs (code = 2)
  • ReadHoldingRegisters (code = 3)
  • ReadInputRegisters (code = 4)
  • WriteSingleCoil (code = 5)
  • WriteSingleRegister (code = 6)
  • WriteMultipleCoils (code = 15)
  • WriteMultipleRegisters (code = 16)

Všechny další funkce (code) nejsou v tuto chvíli ve firmware SDS implementovány. V budoucnu se to může změnit, ale pro teď jsou k dispozici pouze a jenom ty, které jsou výše vypsány.

Vždy si musíte ověřit, že v SDS máte aktuální FW který MODBUS TCP podporuje. Pro SDS-C si to ověříte přečtením sys[2399].


Implementace v SDS-C a FULL-C

Názvy funkcí a postupy jsou pro oba programovací jazyky shodné.

Rozdíl je v indexech:

  • SDS-C má informace a údaje v sys[2399] až sys[2719]
  • FULL-C má informace a údaje dostupné přes get funkci od indexu 12399 až 12719.

Všimněte si, že význam indexů pro SDS-C (2399 až 2719) je 1:1 namapován na FULL-C indexy (12399 až 12719 - tedy FULL-C má pouze aplikováno pevné posunutí o 10000).


Přístup k položkám ve vzdáleném zařízení

SDS umí využít MODBUS TCP pro čtení ze (a zápis do) hodnot "coils", "discrete inputs" a "holding/input registers" ze vzdáleného zařízení.

Je na vás vědět, co přesně chcete číst či zapisovat. SDS je v tomto zcela transparentní.

Každý výrobce si pro své zařízení určil specifické postupy, jak s ním přes MODBUS komunikovat - je na vás si to nastudovat. SDS je dostatečně univerzální aby pokrylo vše co je k realizaci potřeba.


Adresace

MODBUS je univerzální protokol, který přenáší jednu (nebo více hodnot) mezi dvěma body (SDS a vzdálené připojené zařízení).

Aby se dalo přenášet více různých položek, používá se adresace - 1. každé zařízení má svůj identifikátor (UID), a 2. v rámci každého takového zařízení je pak sada položek (coils, inputs, registers). Každá z položek má pak svou unikátní adresu, určenou výrobcem zařízení.

Adresa zařízení, tedy Unit Identifier (UID), určuje výrobce zařízení a od něj ji musíte zjistit (z dokumentace...).

Poznámka: SDS automaticky generuje Transaction Identifier (TID), o to se nemusíte starat. Aktuální použitá hodnota je samozřejmě k dispozici přes sys[]. Hodnotu TID může váš program s výhodou využít pro kontrolu přijatých dat a pro kontrolu potvrzení provedeného zápisu.

MODBUS adresuje všechny prvky (cívky, vstupy, registry) od 1 do MAX. SDS to ve svých funkcích respektuje a používá to stejně. Implementační detail, že v TCP paketu jsou hodnoty adres od nuly, řeší SDS transparetně za vás a nemusíte se tím trápit.


COILS

MODBUS: Ovládání binárních výstupů.

Jedná se o bitové (1 / 0) (zap / vyp) hodnoty, jedna hodnota pro jednu "cívku" (coil). Historicky se skutečně jednalo o ovládání cívek (relé), a od té doby název zůstal.

Jako cívka je typicky bráno nějaké výstupní zařízení (např. relé, stykač, digitální binární výstup, atd.). Samozřejmě mohou existovat i MODBUS zařízení které mají výstupy jen virtuální - ale to vše záleží na tom zařízení, se kterým budete komunikovat, a je na vás vědět co která "cívka" dělá.

Protože se jedná o bitové hodnoty, tak MODBUS vždy slučuje osm hodnot pro osm cívek dohromady do jednoho bajtu (uint8_t).

Pro zápis do coils se používá MODBUS funkce 0x05 nebo 0x0F.

  // --- SDS-C ---
 
  // device uid = 100
  // write: control one COIL (MODBUS function 0x05)
  // selected: coil number 173
  modbus_tcp_writesingle(100, 0x05, 173, 0xFF00);
 
  // and now, you shall wait for a proper WORK RESULT in sys[2405]
  // and process the value correctly (handle any error codes)
 
  // response from server (modbus pdu contents) is put into:
  // sys[2470] = address 
  //  and 
  // sys[2471] = value

POZOR: Funkce 0x05 dle MODBUS akceptuje jen dva možné parametry (0x0000 = vypnout cívku, nebo 0xFF00 = zapnout cívku). Takto je napsána specifikace MODBUS protokolu, a tato záležitost platí jen pro funkci 0x05.

  // --- SDS-C ---
 
  // device uid = 50
  // write: to multiple COILS (MODBUS function 0x0F)
  // start with coil number 20 to coil number 29 (included), e.g. 10 coils
 
  // and for this example, we will send this following sequence:
  // (since we address 10 coils, we need 10 bits; and this fits right into two bytes)
  //
  // Hex:         0xCD                                   0x01
  //              -------------------------------------  ------------------------------------- 
  // Bit on/off:   1    1    0    0    1    1    0    1   0    0    0    0    0    0    0    1    
  // Coil nr.:    27   26   25   24   23   22   21   20   x    x    x    x    x    x   29   28   
 
  // we are writing two data bytes, which represent a number of 0xCD01 
  modbus_tcp_writemultiple(50, 0x0F, 20, 10, 0xCD, 0x01);
 
  // and now, you shall wait for a proper WORK RESULT in sys[2415]
  // and process the value correctly (handle any error codes)
 
  // response from server (modbus pdu contents) is put into:
  // sys[2470] = address 
  //  and 
  // sys[2471] = quantity

Funkce 0x0F používá bitové kódování stavů pro jednotlivé cívky. Způsob, jakým se to provádí, viz příklad nahoře, a specifikace [1].

Pro čtení stavu coils se používá MODBUS funkce 0x01.

  // --- SDS-C ---
 
  // device uid = 32
  // read: status of COILS (MODBUS function 0x01)
  // request to read coils number 20 to 24 (included), that is 5 items
  modbus_tcp_read(32, 0x01, 20, 5);
 
  // and now, you shall wait for a proper WORK RESULT in sys[2401]
  // and process the value correctly (handle any error codes)
 
  // actual results are in sys[2470] - do not forget the coding, using single bits, and each such sys value contains just only 8 bits of the answer

Při čtení SDS převezme datové položky 1:1 z MODBUS TCP paketu, tyto položky jsou pak v sys[2470] a dále.


DISCRETE INPUTS

MODBUS: Čtení binárních vstupů.

Stejný postup jako pro COILS, jen s tím nepatrným rozdílem, že se jedná o binární vstupy vzdáleného zařízení (rozdíl z hlediska protokolu není).

Lze tak ze vzdáleného zařízení, přes MODBUS, číst stavy jednotlivých vstupů (stav 1 nebo 0). Každý vstup má svou unikátní adresu, kterou přiděluje výrobce zařízení.

Pro čtení vstupů se používá MODBUS funkce 0x02.

  // --- SDS-C ---
 
  // device uid = 55
  // read: state of DISCRETE INPUTS (MODBUS function 0x02)
  // request to read discrete input values number 197 to 218 (included), that is 22 items
  modbus_tcp_read(55, 0x02, 197, 22);
 
  // and now, you shall wait for a proper WORK RESULT in sys[2402]
  // and process the value correctly (handle any error codes)
 
  // actual results (for this example) are in sys[2470] thru sys[2472] 
  // - do not forget the MODBUS coding: using single bits; Each such sys[] value contains just only 8 bits (exactly as it came in PDU packet)

Výsledky zapsané do sys[2470] (a dále) jsou pro funci 0x02 převzaty přímo z datového paketu (PDU odpověď) ze serveru. Každý tento sys tedy obsahuje vždy 8 bitů, tak jak postupně tyto bajty přišli v paketu ze serveru.


REGISTERS

Jedná se o univerzální položky, o rozměru int16_t, tedy čísla s možnou hodnotou od -32768 až po +32767.

Protože takový rozsah často nestačí, existuje standardní postup jak registry sloučit a dosáhnout tak přenosu větších rozsahů hodnot (typicky 32 bitů) nebo např. delších řetězců (např. nějaký text). Základní pravidlo je že se vždy slučují registry s ihned následujícími adresami (častá chyba je, že se na toto pravidlo zapomene).

Významy jednotlivých položek (registrů) a jejich adresy jsou vždy určen výrobcem zařízení, se kterým bude SDS přes MODBUS komunikovat.

Pro čtení hodnot z registrů se používá MODBUS funkce 0x03 nebo 0x04.

  // --- SDS-C ---
 
  // device uid = 123
  // read: contents of HOLDING REGISTERS (MODBUS function 0x03)
  // request to read holding registers number 108 to 110 (included), that is 3 items
  modbus_tcp_read(123, 0x03, 108, 3)
 
  // and now, you shall wait for a proper WORK RESULT in sys[2403]
  // and process the value correctly (handle any error codes)
 
  // results are (for this example) separatedly stored in sys[2470] thru sys[2472]
  // --- SDS-C ---
 
  // device uid = 21
  // read: contents of INPUT REGISTERS (MODBUS function 0x04)
  // request to read input register number 9, that is 1 item
  modbus_tcp_read(21, 0x04, 9, 1)
 
  // and now, you shall wait for a proper WORK RESULT in sys[2404]
  // and process the value correctly (handle any error codes)
 
  // result is stored in sys[2470] 

Pro zápis hodnot do jednoho nebo více registrů se používá MODBUS funkce 0x06 nebo 0x10.

  // --- SDS-C ---
 
  // device uid = 99
  // write: to a single REGISTER (MODBUS function 0x06)
  // write value +12345 to register number 2
  modbus_tcp_writesingle(99, 0x06, 2, 12345);
 
  // and now, you shall wait for a proper WORK RESULT in sys[2406]
  // and process the value correctly (handle any error codes)
 
  // response from server (modbus pdu contents) is put into:
  // sys[2470] = address 
  //  and 
  // sys[2471] = value
  // --- SDS-C ---
 
  // deviceuid = 36
  // write: to multiple REGISTERs (MODBUS function 0x10)
  // write to registers number 2 and 3, that is 2 items
  // to register number 2, write value 0x000A
  // to register number 3, write value 0x0102
  modbus_tcp_writemultiple(36, 0x10, 2, 2, 0x000A, 0x0102);
 
  // and now, you shall wait for a proper WORK RESULT in sys[2416]
  // and process the value correctly (handle any error codes)
 
  // response from server (modbus pdu contents) is put into:
  // sys[2470] = address 
  //  and 
  // sys[2471] = quantity


MODBUS TCP umožnuje zápis až 250 registrů v rámci funkčního příkazu 0x10, ale SDS-C má interní omezení na celkový možný počet parametrů při volání SDS-C funkce, pozor na to. (Toto omezení neplatí pro příjem, SDS umí příjmout všech až 250 údajů a vložit je do patřičných sys[], tedy není zde limit).


MODBUS funkce 0x16 a 0x17 a 0x18 nejsou v současné době v SDS implementovány.


Kontrola přijatých dat

Pokud odešlete dotaz do připojeného zařízení, musí váš program počkat na odpověď, a správně ošetřit eventuální chybu (když vyprší čekací doba, nebo když server odpoví špatné nebo ohlásí chybu). To vše se dozvíte skrze čtení specifického sys[], viz příklady k jednotlivým funkcím.

Dále je potřeba zkontrolovat, že odpověď skutečně přišla od toho zařízení, od kterého měla (kontrola UID) a že data jsou ze správné adresy ! To je vždy nezbytné.

SDS interně, při přijmu datových paketů ze serveru, tyto kontroly provádí (PID, UID, TID) a pokud ve stanoveném čase od zaslání požadavku nepřijde správná a odpovídající odpověď ze serveru, je patřičná funkce uzavřena s chybovým kódem -6.

Poznámka: jednotlivé stavy zpracování jednotlivých MODBUS funkcí jsou uloženy každý v jiném sys - pozor na to !


Logická a Fyzická adresa

MODBUS TCP přenáší adresy které začínají seznam od nuly (0). Nicméně fyzicky v zařízení se typicky adresuje od jedničky (1), např. cívka 1, vstup 1 atd. - Potom je mapování jasné, logická adresa 0 je fyzická adresa 1 a tak dále.

Dejte si na to pozor - pokud vám to nebude fungovat jak chcete, často je chyba právě zde, v pomíchání typů adres !

SDS ve všech funkcích a sys[] položkách pro MODBUS TCP, pracuje s adresací začínající od jedničky (1), a interně se stará o převod na adresaci uvnitř protokolu.


Způsob kódování dat - SDS-C

Pro COILs a DISCRETE INPUTs jsou data jednobitová, a vždy předávána po osmi (v rámci jednoho bajtu).

Musíte se důsledně seznámit se způsobem jakým jsou jednotlivé bity využívány.

SDS přebírá jednotlivé přijaté bajty ze MODBUS TCP zprávy a tyto jsou pak k dispozici v sys[2470] a dále (jeden bajt = jeden sys). Vždy jeden celý bajt na jeden sys[]. Je pak už na SDS-C programu si tyto bajty rozpadnout na bity a vědět, ke které adrese cívky či vstupu, daný bit patří.

Znovu je potřeba zopakovat, v případě COILs nebo DISCRETE INPUTs, se do sys[2470] až sys[2719] ukládají jen jednotlivé bajty. Každý sys tedy obsahuje jen osm platných bitů (tedy decimální hodnotu 0 až 255).


Pro REGISTERs jsou data vždy kódována jako int16_t, tedy 16bitů (dva bajty).

V tomto případě jsou hodnoty z MODBUS TCP zprávy uloženy opět postupně za sebou do jednotlivých sys. Zde sys[2470] obsahuje číselnou hodnotu pro první příchozí registr ve zprávě, sys[2471] pro druhý atd.

Skutečná logická adresa registru, jehož hodnota je v sys[2470], je k dispozici v sys[2469] (a další registry pak mají postupně o 1 rostoucí adresu). Pozor uvedená adresa je logická dle MODBUS (tzn. logické adresy začínají od nuly, fyzické adresy ale od 1).


Způsob kódování dat - FULL-C

Bude doplněno. Prakticky shodné, jen na jiných indexech.


Jak vyvíjet a testovat

Simulátor SDSC.exe

V okně "NETWORK" otevřete kartu "MODBUS TCP".

Zde lze simulovat chyby (neprovedené připojení) a tak odzkoušet robustnost svého SDS-C programu.

Dále jsou zde tři seznamy - COILS, DISCRETE INPUTS a REGISTERS. Do každého můžete přidávat nové řádky, nebo řádky odstranit.

Všechny seznamy pracují na stejném principu: první sloupec je UID (0..max), druhý sloupec je fyzická ADRESA (1..max) a třetí sloupec je hodnota (1 nebo 0, respektive -32768 až +32767).

Simulátor umí správně zpracovat zápis 0xFF00 pro zapnutí COIL pro MODBUS funkci 0x05 (do seznamu zapíše 1 jako "zapnuto").

Simulátor spuštěný na počítači

SDS lze přes Ethernet připojit k počítači, kde se spustí simulátor MODBUS TCP serveru. Z hlediska SDS není rozdíl, je-li SDS připojeno přes MODBUS TCP k nějakému zařízení či k počítači se simulátorem.

http://easymodbustcp.net/modbus-server-simulator

Připojení ke skutečnému MODBUS TCP zařízení

Toto je cílový stav. Máte-li správně napsaný program, musí komunikace fungovat. Pokud ne, zkontrolujte důsledně obsahy jednotlivých sys[] před a po volání jednotlivých funkcí.

Na SDS lze vždy sledovat stav MODBUS TCP klienta prostřednictvím informační webové stránky 192.168.1.250/cgi_mbtc (je nutné být přihlášený).


Vzorový program

Připojení ke vzdálenému zařízení, které je TCP SERVER, se provede na začátku programu. Pokud dojde ke ztrátě připojení, je potřeba se připojit znovu (musíte si to hlídat).

 // GENERIC START
 
 // network communication shall be started only after the SDS is connected to network (ethernet is up)
 echo('waiting for network availability');
 
waiting_ethernet:
 if (sys[24] == 0) goto waiting_ethernet;
 if (sys[27] == 0) goto waiting_ethernet;
 
 // OK, now we have an ethernet connection up and running
 
 
 // EXAMPLE START
 echo('modbus client example start');
 
 //                 ip   ip   ip   ip   port  reserved
 modbus_tcp_connect(192, 168,   1,  20,  502, 0);
 
 // waiting for the TCP connection
waiting_mtcp_connect:
 
 // error... ?
 if (sys[2400] < 0) goto error;
 
 // done yet ?
 if (sys[2400] != 2) goto waiting_mtcp_connect;
 
 // TCP connection is open and OK
 
 // now we can talk via MODBUS TCP
 echo('modbus client connected');
 
 // ...
 
 
 // example:
 
 // let us write to UID=99 register=2 value=12345 , using MODBUS function 0x06 (write to single register)
 modbus_tcp_writesingle(99, 0x06, 2, 12345);
 
 // now we will use a simple waiting procedure for the server response
wait_for_answer_06:
 if (sys[2406] < 0) goto error; 
 if (sys[2406] == 256) goto wait_for_answer_06;
 
 // modbus reply handling
 if (sys[2406] == 0) { echo('MODBUS function 0x06 done OK'); } else { echo('MODBUS reported error ',sys[2406]); };
 
 // 0x06 done.
 
 
 // ... (SDS will keep the connection open as long as required, using TCP KEEPALIVE mechanism)
 
 
 // ... etc.
 
 //
finish:
 
 //
 echo('disconnecting');
 
 // once fully done, we shall close the TCP connection
 modbus_tcp_disconnect();
 
 // and wait until we are properly disconnected
wait_for_mbtc_disconnect:
 if (sys[2400] == 4) goto wait_for_mbtc_disconnect
 
 // EXAMPLE IS DONE
 
 // do not continue to the error handler...
 return;
 
 // error handling - a very simple example
error:
 echo('MODBUS CLIENT error: sys2400 = ',sys[2400]);


Všimněte si způsobu zjisťování chyb. Podle odpovědi v patřičném sys[] se vás program musí vždy správně zařídit.

Zejména je potřeba umět správně obsloužit chybovou hodnotu -3. Ta se objeví v případě, že máte nesprávně zapsán svůj program, a tedy voláte modbus funkce dříve než je to povoleno (tedy voláte další funkci dříve, než byla dokončena ta předchozí).

Pro chybu -6 je potřeba obvykle informovat obsluhu, nebo přijmou jiná opatření. Chyba -6 znamená, že server neodpověděl na zaslaný příkaz ve stanoveném čase (je prakticky odvozen od hodnoty keepalive).

Chyby -4 a -5 jsou opět čistě chybami programátor - opravte si svůj program. Voláte funkci s nesprávnymi parametry (mimo povolený rozsah) nebo s nesprávným počtem parametrů.


Udržování trvale otevřeného spojení na server

MODBUS TCP protokol nemá specifický mechanismus jak udržet spojení stále otevřené. Proto musí SDS provádět TCP Keep Alive postup aby spojení bylo udrženo. v opačném případě, pokud by byla na straně SDS delší nečinnost tzn. neprováděl-li by SDS-C program komunikaci na server po delší dobu, tak by server SDS od sebe odpojil.

SDS se tedy umí připojit k MODBUS serveru a toto připojení udržovat teoreticky po nekonečnou dobu stále aktivní, takže SDS-C program může pak kdykoliv přímo posílat MODBUS příkazy.

Vždy je ale doporučeno zkontrolovat obsah sys[2400] před zadáním každého MODBUS příkazu, je-li skutečně ještě to připojení aktivní.

TCP Keep Alive je prováděno dle RFC1122 sekce 4.2.3 (specificky: KeepAlive ACK bez přidaného garbage byte). Odpovídá to tedy průmyslovému standardu. Pokud váš MODBUS Server toto nezvládá, tak zvažte jeho výměnu za takový, který splňuje průmyslové standardy (a odpovídá RFC) - nebude-li to možné, řešení pak je snadné - v rámci vašeho SDS-C programu, pro každý modbus příkaz se znovu připojit a hned odpojit (takto se TCP Keep Alive nemá šanci uplatnit, ale za cenu mnohem složitějšího programu a eventuálně pomalejší komunikace).

Informace:

API timeout je 90 sekund.

Pokud do uvedeného timeoutu od zavolání kterékoliv MODBUS funkce nedojde k jejímu dokončení (tzn. nepřijde odpověď ze serveru), dojde k vyhlášení chyby -6, a je pak na vás jak se zařídíte.

Informace:

TCP Keep Alive je 10 minut.

Současný firmware v SDS má nastaveno TCP KeepAlive pro MODBUS TCP spojení na uvedenou pevnou dobu. Počítadlo se pro každou platnou komunikaci se serverem nuluje. TCP Keep Alive je tedy odeslán jen v případě, že po uvedenou dobu nebyl na socketu jakýkoliv datový provoz.

Osobní nástroje
Translate