Modbus TCP
Modbus-Register und Spulen über TCP/IP, mit typisierter Adressierung, Steuerung der Byte-Reihenfolge und einem begrenzten Suchlauf im Netz.
Der Treiber Modbus TCP liest und schreibt Modbus-Register und Spulen über TCP/IP: Steuerungen, Zähler, Gateways und jeden Server, der Modbus/TCP spricht. Die Adressierung ist vollständig typisiert: Sie wählen eine Registerklasse und eine ab 0 gezählte Registernummer, und die Anwendung setzt die Anfrage auf dem Bus zusammen; es gibt keine Freitextadresse, bei der man sich vertun kann.
Gerät
| Feld | Bedeutung | Standard |
|---|---|---|
| Hostadresse | DNS-Name, IPv4- oder IPv6-Adresse des Modbus-Servers oder Gateways. | leer: Das Gerät wird erst verbunden, wenn einer eingetragen ist |
| Port | TCP-Port, 1 bis 65535. Ein leeres Feld zeigt 502 grau, und das Gerät wird über diesen Port angewählt; ein mit 0 gespeichertes Gerät liest sich genauso. | 502 |
| Unit-ID | Die Modbus-Kennung der Einheit (Slave), die jede Anfrage trägt, und die ein Gateway verwendet, um an das Gerät dahinter weiterzuleiten. 0 bis 255. | 1 |
| Rahmenformat | Wie jede Anfrage über die Verbindung geht: MBAP, der Modbus TCP-Header vor jeder Anfrage, oder RTU, der RTU-Rahmen mit seiner CRC, unverändert gesendet, für einen Seriell-Ethernet-Umsetzer im transparenten Modus (siehe RTU über TCP). Host, Port, Unit-ID und Tags sind in beiden Fällen dieselben. | MBAP |
| Mindestabstand zwischen Transaktionen (ms) | Taktung zur Verträglichkeit: die kürzeste Ruhe nach einer abgeschlossenen Transaktion, bevor die nächste beginnt, 0 bis 1000. Null fügt keine künstliche Verzögerung hinzu. | 0 |
| Abfrageintervall (ms) | Standardtakt des zyklischen Lesens für Tags, die ihn nicht selbst festlegen. | 1000 |
Der Basis-URI in der Kopfzeile des Bereichs ist modbus+tcp://host:port/unitID, dazu
?minimumTransactionIntervalMs=n, wenn das Intervall gesetzt ist.
Geräte, die sich Host und Port teilen, teilen sich auch ein Tor für Transaktionen: Anfragen an denselben Endpunkt überlappen sich nie, und das größte eingestellte minimale Transaktionsintervall unter den aktivierten Geräten an diesem Endpunkt taktet sie alle. Der Bereich sagt es, wenn ein anderes Gerät das wirksame Intervall über das hier eingestellte hebt. Das Intervall regelt nur den Verkehr, den diese Anwendung aussendet: Es ist eine Hilfe für einen langsamen Server oder ein langsames Gateway, keine Reparatur für Fehler im Netz.
Das Verbinden wartet höchstens 5 Sekunden; auf eine Antwort wird höchstens 10 Sekunden gewartet; auf Protokollebene wird nichts wiederholt. Die Wiederholschleife im Hintergrund besitzt das erneute Verbinden, ein Gerät, das aus ist, kostet also nichts außer einem Messwert schlechter Qualität.
RTU über TCP
Ein Seriell-Ethernet-Umsetzer im transparenten Modus spricht selbst kein Modbus TCP: Was an seinem Socket ankommt, geht unverändert auf seinen seriellen Bus, und was der Bus antwortet, kommt zurück. Ein Gerät dahinter ist ein Modbus TCP-Gerät mit Rahmenformat auf RTU: Die Station sendet den RTU-Rahmen (Unit-ID, Anfrage und CRC) ohne MBAP-Header und glaubt einer Antwort nur, wenn ihre CRC stimmt. Der Basis-URI trägt dann framing=rtu in seiner Abfrage, zum Beispiel modbus+tcp://192.168.0.20:502/1?framing=rtu; ein Gerät auf MBAP behält die Adresse, die es immer hatte. Alles andere auf dieser Seite gilt unverändert: die Registerklassen, die Funktionscodes, die Schreibwarteschlange, die Zeitlimits und der Mindestabstand.
- Die Unit-ID ist die Adresse des Geräts auf dem seriellen Bus hinter dem Umsetzer, 1 bis 247.
- Die Geräte hinter einem Umsetzer teilen sich seinen Host und Port und damit seine Transaktionssperre: eine Anfrage nach der anderen, mehr trägt ein serieller Bus ohnehin nicht. Braucht der Umsetzer eine Pause zwischen den Rahmen, erhöhen Sie den Mindestabstand zwischen Transaktionen (ms).
- Die seriellen Einstellungen des Umsetzers selbst (Baudrate, Format) werden am Umsetzer eingestellt; die Station sieht sie nie.
- Ein RTU-Rahmen trägt keine Transaktionsnummer, deshalb verwirft die Station vor jeder Anfrage alles, was der Umsetzer bereits gesendet hat: Eine Antwort, die nach dem Zeitlimit ihrer Anfrage eintrifft, wird nie für die Antwort der nächsten gehalten.
Adressierung der Tags
| Feld | Bedeutung | Standard |
|---|---|---|
| Registerklasse | Welche Modbus-Größe das Tag adressiert: Spule (0xxxx), Diskreter Eingang (1xxxx), Eingangsregister (3xxxx) oder Holding-Register (4xxxx). Jede trägt die erste Ziffer, die die Adresse im Handbuch für sie hat, ein Handbuch, das nur 30001 druckt, meint also die Eingangsregister. | Aus Typ und Zugriff abgeleitet: Tags vom Typ Boolean bekommen einen diskreten Eingang (nur lesen) oder eine Spule (schreibbar); jeder andere Typ bekommt ein Eingangsregister (nur lesen) oder ein Holding-Register (schreibbar). |
| Registernummer (ab 0) | Die rohe Adresse des Protokolls. Das ist die ab 0 gezählte Adresse auf dem Bus, nicht die Schreibweise des Handbuchs: Das Holding-Register 40001 ist die Registernummer 0. 30001 hier einzutippen wählt die Klasse nicht, denn manche Geräte haben wirklich Register über 30000: Die Klasse wird oben gewählt. Das Register reist als 16-Bit-Zahl über den Bus, das Feld nimmt also 0 bis 65535 an und lehnt dort, wo es eingetippt wird, alles Breitere ab. | 0 |
| Anzahl (Register, leer = automatisch) | Wie viele 16-Bit-Register der Wert belegt. Das Feld wird nur bei Tags vom Typ String gezeichnet: Jeder andere Typ hat eine feste Breite, es gibt also nichts zu übersteuern. | Nach Typ: Boolean, Int16 und UInt16 1, Int32 und Float 2, String 4 |
| Höchstwertiges Byte zuerst (MSB first, Big-Endian) | Welches Byte jedes 16-Bit-Registers zuerst über den Bus geht; die Wörter in Klammern sind die, die Handbücher dafür drucken. Bei numerischen Tags und bei einem Tag vom Typ Boolean in einem Holding- oder Eingangsregister; ein Boolean in einer Spule oder einem diskreten Eingang ist ein einzelnes Bit ohne Byte zum Ordnen, dort wird das Feld also nicht gezeichnet. | ein (was die Modbus-Spezifikation verlangt) |
| Höchstwertiges Wort zuerst (High-Word zuerst) | Welches Register eines Werts aus zwei Registern die obere Hälfte trägt. Nur bei Tags vom Typ Int32 und Float: Ein Wert aus einem einzigen Register (Boolean, Int16, UInt16) hat kein zweites Register, dort wird das Feld also nicht gezeichnet. Unter den beiden Feldern nennt Byte-Reihenfolge des Werts die Anordnung, die sie ergeben, in den Buchstaben eines Handbuchs (Byte- und Wortreihenfolge). | ein |
Die Karte Quelle endet mit Adresse im Handbuch, wo das Tag in der Schreibweise steht, die das Handbuch des Geräts druckt: die erste Ziffer der Klasse, dann das ab 1 gezählte Register. Eingangsregister 0 liest sich 30001, ein Float in Holding-Register 100 liest sich 40101 bis 40102, und ein Register über 9998 bekommt sechs Stellen (Holding-Register 9999 liest sich 410000), der Bereich lässt sich also Zeile für Zeile mit dem Handbuch vergleichen.
Werttypen und Anzahlen
Sechs Werttypen werden angeboten, und die Breite jedes einzelnen auf dem Protokoll ist fest:
| Datentyp | Register | Form auf dem Bus |
|---|---|---|
| Boolean | 1 | Auf einer Registerklasse: Jedes Register ungleich null liest wahr, und ein Schreibvorgang sendet 1 oder 0. Auf Coil/DiscreteInput: das Bit selbst. |
| Int16 | 1 | Vorzeichenbehaftete 16-Bit-Ganzzahl in einem einzigen Register, -32768 bis 32767. |
| UInt16 | 1 | Vorzeichenlose 16-Bit-Ganzzahl in einem einzigen Register, 0 bis 65535. Dasselbe Register liest sich als UInt16 als 65535 und als Int16 als -1: Das Vorzeichen kommt vom gewählten Datentyp, nicht vom Register. |
| Int32 | 2 | Vorzeichenbehaftete 32-Bit-Ganzzahl über ein Registerpaar. |
| Float | 2 | IEEE 754 mit einfacher Genauigkeit über ein Registerpaar. |
| String | 1 oder mehr (Standard 4) | UTF-8-Bytes, zwei je Register gepackt. Ein Lesevorgang endet am ersten NUL-Byte; ein Schreibvorgang muss in die erklärte Anzahl passen (2 Bytes je Register) und wird mit Nullen aufgefüllt. |
Ein Tag vom Typ String wird in der Reihenfolge gelesen und geschrieben, in der das Gerät die Bytes hält, und ein Schreibvorgang sendet immer UTF-8. Bytes, die kein gültiges UTF-8 sind, und so sieht ein Bereich aus, den das Gerät nie beschrieben hat, oder Text in einer anderen Kodierung, werden als Unicode-Ersatzzeichen gelesen, statt fehlzuschlagen: Das Tag zeigt sichtbar etwas Falsches, und jedes andere Tag an diesem Gerät liest weiter.
Anzahl (Register, leer = automatisch) wird nur bei Tags vom Typ String gefragt. Die Breiten von Boolean, Int16, UInt16, Int32 und Float sind fest, das Feld wird an diesen Punkten also nicht gezeichnet, weder im Bereich des Tags noch in der Tabelle der Tags; die Übersteuerung gibt es, um Tags vom Typ String zu bemessen.
Byte- und Wortreihenfolge
Das Feld zur Byte-Reihenfolge wird bei numerischen Tags und bei einem Boolean in einem Register gezeichnet, das zur Wort-Reihenfolge nur bei denen aus zwei Registern (Int32, Float). Sie sind zwei
unabhängige Fragen: welches Byte innerhalb eines Registers führt und welches Register über
ein Paar hinweg führt. Modbus legt für Text keines von beiden fest, ein Tag vom Typ String
bekommt sie deshalb nicht angeboten: Seine Bytes reisen in der Reihenfolge, in der das
Gerät sie hält. Für den Wert 0x01020304, mit A als höchstwertigem Byte, ergeben sich
vier Anordnungen:
| Höchstwertiges Byte zuerst | Höchstwertiges Wort zuerst | Bytes auf dem Bus |
|---|---|---|
| ein | ein | AB CD (der Standard der Spezifikation) |
| ein | aus | CD AB (der klassische Wort-Tausch) |
| aus | ein | BA DC |
| aus | aus | DC BA |
Lesen und Schreiben wenden dieselben zwei Antworten in derselben Reihenfolge an, ein Schreibvorgang legt also genau die Bytes ab, die ein Lesevorgang zurückgebracht hätte. Byte-Reihenfolge des Werts unter den Feldern sagt die Anordnung in einem Wort (ABCD, CDAB, BADC oder DCBA), so wie ein Handbuch sie nennt.
Ein Wert vom Typ Int16 oder UInt16 ist ein einziges Register, deshalb gilt für ihn nur die
Byte-Reihenfolge: Für 0x1234 gehen mit dem höchstwertigen Byte zuerst 12 34 über den
Bus, mit ausgeschaltetem Feld 34 12. Es gibt kein zweites Register einzuordnen, deshalb wird das Feld zur Wort-Reihenfolge für
ihn nicht gezeichnet.
Funktionscodes
| Registerklasse | Lesen | Schreiben |
|---|---|---|
| Holding-Register (4xxxx) | 3 (Read Holding Registers) | 6 (einzelnes Register) oder 16 (mehrere Register) |
| Eingangsregister (3xxxx) | 4 (Read Input Registers) | nur lesen; ein Schreibvorgang wird abgelehnt |
| Spule (0xxxx) | 1 (Read Coils) | 5 (Force Single Coil, eine einzelne Spule) |
| Diskreter Eingang (1xxxx) | 2 (Read Discrete Inputs) | nur lesen; ein Schreibvorgang wird abgelehnt |
Ein Schreibvorgang gilt erst dann als erfolgreich, wenn die Antwort des Servers auf Protokollebene die Annahme bestätigt; erst dann rückt auch der zwischengespeicherte Wert nach.
Gerätesuche
Der Suchlauf ist ausdrücklich und begrenzt: Die Anwendung leitet Ihr lokales Teilnetz nie ab und fährt es nie von sich aus ab. Das Formular für den Umfang nimmt an:
| Feld | Bedeutung | Standard |
|---|---|---|
| IPv4-Host oder CIDR | Eine Adresse (192.168.1.10) oder ein Teilnetz nicht breiter als /24 (192.168.1.0/24). Netz- und Broadcast-Adressen werden übersprungen. |
erforderlich |
| Port | Der Port, der abgetastet wird. | 502 |
| Unit-IDs | Werte, durch Komma getrennte Listen oder aufsteigende Bereiche: 1, 1,5,9, 1, 3, 8-16 (0 bis 255). |
1 |
| Rahmenformat | Der Rahmen, in dem jede Abtastung gesendet wird. Ein Umsetzer im transparenten Modus antwortet nur auf RTU-Rahmen, suchen Sie ihn also mit RTU. | MBAP |
| Mindestabstand zwischen Transaktionen (ms) | Taktung zwischen abgeschlossenen Abtastungen auf demselben Host, 0 bis 1000. | 0 |
Die Gerätesuche sendet jede Abtastung im gewählten Rahmenformat. Bei RTU ist jede Abtastung der bloße RTU-Rahmen, und eine Antwort zählt nur, wenn ihre Unit-ID passt und ihre CRC stimmt; so werden die Einheiten hinter einem Umsetzer im transparenten Modus gefunden wie alle anderen. Eine gefundene Einheit behält das Rahmenformat der Suche, wenn sie hinzugefügt wird.
Ein einzelner Suchlauf darf höchstens 256 Abtastungen senden (Hosts × Unit-IDs); ein größerer Plan wird abgelehnt, bevor ein Socket geöffnet wird. Die einzige gesendete Anfrage ist Read Basic Device Identification (Funktion 43/14): Die Gerätesuche liest nie Register und rät nie eine Registerbelegung. Eine vollständig gültige Modbus-Ausnahme als Antwort beweist, dass eine Einheit da ist, ohne ihre Identität zu behaupten; Erreichbarkeit über TCP, Zeitüberschreitungen und fehlerhafte Rahmen tun das nicht. Bis zu vier Hosts werden nebeneinander abgetastet, innerhalb eines Hosts nacheinander, mit 750 ms Zeitlimit für Verbinden und Abtasten.
Die Ergebnisse tragen den vollständigen Endpunkt und einen vorgeschlagenen Namen aus Hersteller und Produktcode, wenn das Gerät sie meldet. Kandidaten haben null Tags: Register werden nach Hinzufügen eingerichtet. Eine bereits konfigurierte Einheit wird als solche gekennzeichnet und bietet Öffnen an, statt ein Duplikat anzulegen.
Grenzen, die man kennen sollte
- Andere Ganzzahlbreiten (SByte, Byte, UInt32, Int64, UInt64) und Double werden nicht angeboten: Der Codec auf dem Bus überträgt genau die sechs Typen oben verlustfrei hin und zurück.
- Je Endpunkt ist immer nur eine Anfrage unterwegs; viele Geräte hinter einem Gateway teilen sich diese Reihung von Haus aus.
- Schreibvorgänge adressieren jeweils eine Spule oder eine Folge von Registern; ein Schreibvorgang über mehrere Spulen gibt es nicht.