hu:arduino:modbus

Differences

This shows you the differences between two versions of the page.

hu:arduino:modbus [2022/04/21 15:02] ()
 1:  1:
 +====== Arduino - Modbus TCP/RTU ======
 +===== Modbus kommunikáció =====
 +A Modbus protokoll kialakulása szorosan összefonódott az első PLC születésével. Az első PLC, a "Modicon 084" 1969-ben kezdte meg első ciklusait, és rá egy évre, létrehozták a Modbus-t. Nyilván azóta jelentős változásokon esett át a protokoll, de napjainkig megmaradt egy **De-facto-standard**-nak, azaz, igen széles körben alkalmazott kommunikációs rendszernek.
  
 +A Modbus két hordozóközegen bukkan fel a leggyakrabban, az RS485-ön (RTU) és az etherneten (TCP). A Modbus magasabb szintű műveletei mindkét esetben megegyeznek, azaz lehet vegyes hálózatokat képezni a protokollal, ahol az átvitel RTU-bval és TCP-vel is megvalósul.
 +
 +{{ wiki:comm:modbus1.png |Modbus communication}}
 +
 +A Modbus egy monomaster hálózatot vagy pont-pont kapcsolatot feltételez. Mindkét esetben egy master és legalább egy slave szükséges a kommunikációhoz. A Modbus RTU csak egy master egység jelenlétét teszi lehetővé.
 +
 +===== Modbus master / slave =====
 +Fontos megjegyezni, hogy sok más kommunikációs technológiával szemben az adatokat a slave egységek tárolják (jellemzően regiszteres formában) és a master jogosult ezeket az adattartalmakat lekérdezni. Más közelítésben azt mondhatjuk, hogy **a Modbus esetén a slave a szerver**. Az Arduino-k ebben a hálózatban mint slave, mint master szerepet is betölthetnek:
 +
 +{{ :hu:arduino:modbus_master_slave.png |Modbus master / slave}}
 +
 +===== Multimaster =====
 +A Modbus hálózaton egyszerre több master is jelen lehet (multimaster), de ez esetben ún. multimaster-gateway-t kell beiktatnunk a kummunikációs hálózatba, és a masterek csak Modbus TCP-re lehetnek felfűzve:
 +
 +{{ :hu:arduino:modbus_multimaster.png |Modbus Multimaster}} 
 +
 + A TCP esetén az RTU-t telepítették a TCP-re, így az ethernetes hálózatok összes előnyét sikerült beágyazni a Modbusba. Mivel az etherneten az állomások címe nagyságrendekkel magasabb, mint az RTU/ASCII-nél, így ennek a korlátját a Modbus-ban definiált 1 bájtos címe jelenti (itt is marad az 1..247 korlát).
 +
 +===== Modbus funkciókódok =====
 +^Function Code^Register Type|
 +|1|Read Coil|
 +|2|Read Discrete Input|
 +|3|Read Holding Registers|
 +|4|Read Input Registers|
 +|5|Write Single Coil|
 +|6|Write Single Holding Register|
 +|15|Write Multiple Coils|
 +|16|Write Multiple Holding Registers|
 +
 +====== Modbus RTU ======
 +Az RS-485 technikai jellemzői:
 +^ ^RS-485|
 +^Működési mód|[[hu:comm:start#szinkron|szinkron átvitel]]|
 +^Meghajtók és vevők\\ száma egy vonalon|32 állomás szegmensenként|
 +^Adatátvitel módja|[[hu:comm:start#half_duplex|félduplex]] / [[hu:comm:start#duplex|duplex]]|
 +^Adatátvitel|[[hu:comm:start#multipoint|multipoint]]|
 +^Max. kábelhosszúság|1200 m|
 +^Max. adatátvitel\\ 12 m\\ 1200 m|\\ 35 Mbps\\ 100 kbps|
 +^Max. jelváltozási\\ sebesség (slew rate)|n.a.|
 +^Vevő bemeneti\\ ellenállás|≧ 12 kΩ|
 +^Meghajtó terhelés-\\ impedancia|54 Ω|
 +^Vevő "holtsáv"|±200 mV|
 +^Vevő feszültségszint|--7..12 V|
 +^Meghajtó kimenő\\ feszültség max.|--7..12 V|
 +^Meghajtó kimenő\\ feszültség min. (terheléssel)|±1.5 V|
 +^Meghajtó kimeneti\\ rövidzárási áram limit|150 mA tól Test felé\\ 250 mA Vcc felé|
 +^Vevő hiszterézis|50 mV|
 +
 +Az RS-485 egy szimmetrikus átviteli mód. Az EIA-485 megnevezés azonos az RS-485 standarddal. A 32 egység / szegmens elvi határon belül az adó és vevő egységek száma szabadon variálható (multipoint).
 +
 +A maximum 32 egység / szegmens határ az előre definiált meghajtó terhelés (Unit Load [**UL**]) mellett érvényes, ami az RS-485 esetében 12 kΩ. Az egységek száma emelhető, ha a meghajtó terhelés csökken. Jellemzően ezt - az UL-t - a negyedére (48 kΩ) vagy nyolcadára (96 kΩ) szokás csökkenteni, így az állomások száma rendre 128-ra, vagy 256-ra emelhető. Hálózati erősítővel (repeaterrel) az állomások száma szintén emelhető.
 +
 +Az RS-485 120 Ω vonalimpedanciát tételez fel a vezetéktől. A szegmens két végét 680 Ω-os 120W-os (10%, 1/2 watt) véglezárókkal szükséges zárni.
 +
 +=== RTU/ASCII ===
 +A slave-ek száma nem haladhatja meg a 246-ot, címzésük az 1..247-es tartományban történhet. A gyakorlat szerint egy szegmensben 32 állomás lehet, és csak repeater-ekkel bővíthető a hálózat. A 0. címmel broadcast üzeneteket lehet küldeni, amennyiben ez a művelet logikai szinten nincs korlátozva. A master jellemzően az 1. címet szokta megkapni, Modbus RRU egy hálózat-szegmensben csak egy master-t enged meg.
 +
 +=== RS-485 jelráta ===
 +Az RS-485-nek nincs definiálva maximális hossz, de jellemzően a jeleket 1200 méter távolságig tudja továbbítani, és kb. 50 méterig lehet biztosítani a 10 Mbps átvitelt. Az átviteli ráta / távolság hányadosa jelentősen függ az alkalmazott vezeték minőségétől és a vonali erősítők (repeaterek) számától.
 +
 +{{wiki:comm:rs_signal_rate.png?562x383|RS-232, RS-422, RS-485 compare signal rates }} \\
 +
 +=== RS-485 jelszintek ===
 +{{wiki:comm:rs485_jelszint.png?346x327|RS-485 signal levels}} \\
 +
 +A meghajtó kimenő feszültsége +12V..-7V tartományban kell, hogy maradjon. A +0.2V..-0.2V a holtsáv. A +0.2V..+6V tartomány a vevő oldalon a logikai "0" értéknek felel meg, a -0.2V..-6V tartomány pedig a logikai "1"-nek.
 +
 +=== RS-485 half duplex kapcsolás ===
 +{{wiki:comm:rs485hd.png?442x328|RS-485 half duplex plate}} \\
 +
 +=== RS-485 full duplex kapcsolás ===
 +{{wiki:comm:rs485fd.png?442x328|RS-485 full duplex plate}} \\
 +
 +=== RS-485 / Modbus RTU kapcsolás ===
 +A Modbus RTU-hoz jellemzően a félduplex vezetékezést szokás használni, így három vezetéket tartalmaz az átvitel D+, D- és GND.
 +A vezetékek feszültségszintjeit ellenállásokkal szokás stabilizálni (a puulup, pulldown esetén a lenti ellenállás a minimális érték, ez akár pár kΩ is lehet):
 +
 +{{:hu:arduino:modbus_pull_down.png|RS-485 / Modbus RTU kapcsolás}}
 +
 +{{ :hu:arduino:arduino_modbus_panel.png?150|MAX485 modul}}
 +
 +=== Arduino Modbus RTU könyvtárak ===
 +
 +Modbus RTU slave: https://www.arduino.cc/reference/en/libraries/modbusrtu_slave/ \\
 +Modbus RTU slave RS-485: https://www.arduino.cc/reference/en/libraries/modbusrtu_slave_rs485/ \\
 +Modbus RTU master: https://www.arduino.cc/reference/en/libraries/modbusmaster/ \\
 +Modbus RTU ESP8266: https://www.arduino.cc/reference/en/libraries/modbus-esp8266/ \\
 +ModbusConfig ESP8266/ESP32/Arduino: https://www.arduino.cc/reference/en/libraries/modbusconfig/ \\
 +
 +===== MAX485 modul =====
 +A MAX 485 modul egy egyszerű csatlakozási lehetőséget kínál az Arduino oldalról a Modbus RTU hálózathoz. A modul viszonylag egyszerűen csatolható az Arduinokhoz:
 +
 +{{:hu:arduino:example-rs485-mqtt.png?400|MAX485 modul}}
 +
 +== Vezetékezés ==
 +{{:hu:comm:c25b.png?400|MAX485 modul}}
 +
 +|Pin|Leírás|
 +|Vcc|5V DC|
 +|A|A+ Modbus|
 +|B|B- Modbus|
 +|GND|GND|
 +|RO|receiver output (Rx)|
 +|RE|Receiver enable|
 +|DE|driver enable|
 +|DI|driver input (Tx)|
 +
 +
 +
 +
 +{{ :hu:comm:rs485_shield_1.png?200|RS-485 shield}}
 +===== RS-485 shield =====
 +Az RS485-Shield kibővítheti az Arduinót egy RS-485 interfésszel.
 +Az Arduinók többsége csak egy UART soros porttal van ellátva, ennek a funkcióit bővíti ki (cseréli le) ez a shield RS485-re.
 +
 +A bővítmény az Arduino D0-D7 közötti portjait tudja az RS-485-re "átirányítani", így mér az Arduino Mega boardon is csak a normál Serial portot tudja felhasználni. Ez azért probléma, mert az Arduinókra a program letöltésére is a soros, normál "serial" kerül felhasználásra. A shield esetén a megoldás erre a problémára, hogy a program letöltése idejére mindkét jumpert el kell távolítani a címkijelölő portról. Kényelmetlen, de ez van. A jumpereket egyébként a serial-hoz kell igazítani, azaz a D0 az RX, a D1 a TX.
 +
 +**A modbus shield részei:**
 +
 +{{:hu:comm:rs485_shield_2.png|RS-485 shield részei}}
 +
 +  * 1: címkijelölő port, a serialhoz D0 az RX, a D1 a TX
 +  * 2: kommunikációs jellemző, érdemes TX_CTRL-en hagyni
 +  * 3: a kommunikáció jelzése: ha felváltva néha felvillan, nyertünk
 +  * 4: a Modbus csatlakozók, elég csak egyet bekötni
 +  * 5: tápfeszültség kiválasztása, Uno esetén pl. 5V
 +
 +A board mind Modbus Slave mind Master funkcióval is felruházható. Ebben az esetben javaslom ezeknek a libeknek az alkalmazását:
 +
 +  * ArduinoRS485.h : https://www.arduino.cc/en/Reference/ArduinoRS485
 +  * ArduinoModbus.h : https://www.arduino.cc/en/ArduinoModbus/ArduinoModbus
 +
 +==== Modbus slave példaprogram ====
 +  * a D8 portra kötöttem egy LEDet a 2.regiszter állapotjelzésére (ha nem nulla, világít a LED)
 +  * a D4 portra egy DS18B20 hőmérséklet szenzor onewire kommunikációval, ennek eredménye az első regiszterben található.
 +
 + 
 +<code c>
 +/*
 + OB121 Modbus slave example, 2021. Vamos Sandor
 + 
 +reg 0: life register
 +reg 1: temperature (*100)
 +reg 2: led on/off
 +reg 3: copy to reg 4
 +reg 4: copy from reg 3
 +*/
 +#include <OneWire.h>
 +#include <DallasTemperature.h>
 +#include <ArduinoRS485.h> // ArduinoModbus depends on the ArduinoRS485 library
 +#include <ArduinoModbus.h>
 +
 +// Data wire is plugged into port 4
 +#define ONE_WIRE_BUS 4
 +
 +// Setup a oneWire instance to communicate with any OneWire devices 
 +OneWire oneWire(ONE_WIRE_BUS);
 +
 +// Pass our oneWire reference to Dallas Temperature.
 +DallasTemperature sensors(&oneWire);
 +
 +uint8_t sensor1[8] = { 0x28, 0x20, 0x54, 0x29, 0x05, 0x00, 0x00, 0xF4  }; //copied from the address scanner
 +
 +float tempSensor1;
 +uint16_t reg0, reg1, reg2, reg3, reg4;
 +bool ledsta;
 +const int ledPin = LED_BUILTIN;
 +
 +void setup() {
 +  sensors.begin(); 
 +  Serial.begin(9600);
 +
 +  // start the Modbus RTU server, with (slave) id 1
 +  if (!ModbusRTUServer.begin(1, 9600)) {
 +    while (1);
 +  }
 +
 +  // configure the LED
 +  pinMode(8, OUTPUT);
 +  digitalWrite(8, LOW);
 +
 +  // configure Holding Registers from address 0x00
 +  ModbusRTUServer.configureHoldingRegisters(0x00, 20);
 +}
 +
 +void loop() {
 +  sensors.requestTemperatures();
 +  tempSensor1 = sensors.getTempC(sensor1); // Gets the values of the temperature
 +  
 +  // poll for Modbus RTU requests
 +  ModbusRTUServer.poll();
 +
 +  reg1 = (word)(tempSensor1*100); 
 +  reg0++;
 +   
 +  ModbusRTUServer.holdingRegisterWrite(0, reg0);
 +  ModbusRTUServer.holdingRegisterWrite(1, reg1);
 +  reg2 = ModbusRTUServer.holdingRegisterRead(2);
 +  reg3 = ModbusRTUServer.holdingRegisterRead(3);
 +  ModbusRTUServer.holdingRegisterWrite(4, reg3);
 +  // read the current value of the coil
 +  //int coilValue = ModbusRTUServer.coilRead(0x00);
 +  
 +  if (reg2 == 0) {
 +    
 +    digitalWrite(8, LOW);
 +  } else {
 +    
 +    digitalWrite(8, HIGH);
 +  }
 +}
 +</code>
 +
 +
 + 
  • hu/arduino/modbus.txt
  • 2022/04/21 15:02
  • ()