Alle Lektionen anzeigen
Teil 1
Grundlagen
Teil 2
Modbus RTU
- Lektion 5RS485 erklärt: A, B, Common und Terminierung20 Min.
- Lektion 6Baudrate und Parität: warum 8E1 Standard ist16 Min.
- Lektion 7Das Modbus RTU Frame Byte für Byte, plus CRC18 Min.
- Lektion 8Mehrere Modbus Geräte an einem RS485-Bus16 Min.
- Lektion 9Ihr erstes Modbus Gerät mit mbpoll auslesen22 Min.
- Lektion 10Modbus RTU Fehlersuche: vom Symptom zur Ursache20 Min.
Teil 3
Modbus TCP
Teil 4
Fortgeschritten
- Lektion 16Sicher auf ein Modbus Gerät schreiben18 Min.
- Lektion 17Word Order und Float: gleiche Bytes, anderer Wert22 Min.
- Lektion 18Poll-Intervall und Buslast selbst berechnen18 Min.
- Lektion 19Modbus Sicherheit: das Protokoll hilft nicht16 Min.
- Lektion 20Modbus integrieren: SPS, Home Assistant, Cloud20 Min.
- Lektion 21Modbus Inbetriebnahme: Checkliste und Spickzettel18 Min.
Modbus Adressierung: von 40001 zur Adresse
Modbus Adressierung erklärt an einem echten Frame. Sie rechnen 40001 in die Adresse auf der Leitung um und erkennen den klassischen Off-by-one-Fehler.
Was diese Lektion behandelt
- Die vier Datenblöcke und die zugehörigen Funktionscodes
- Von 40108 im Datenblatt zur Adresse 107 auf der Leitung
- Was Ihr Werkzeug mit Address meint, und der Test, der das klärt
Vorher lesen: Modbus lernen: warum das Protokoll bleibt
Die Modbus Adressierung ist der Grund, warum ein Gerät im Display sauber 230,0 V anzeigt und Ihre Software an derselben Stelle eine 0 oder einen völlig anderen Wert bekommt. Zwischen der Nummer im Datenblatt und der Adresse im Frame liegen zwei Rechenschritte, und wer sie überspringt, liest ohne jede Fehlermeldung das Nachbarregister. Nach dieser Lektion rechnen Sie jede Datenblattnummer in die Adresse auf der Leitung um, dezimal und in hex, und Sie belegen das Ergebnis mit einem Test, der eine halbe Minute dauert.
Warum Ihr Zähler 2300 zeigt und Ihre Software 0
Weil das Datenblatt und Ihr Client zwei verschiedene Zählweisen benutzen. Ein typischer Fall aus der Gebäudeautomation: ein Energiezähler hängt am RS485-Strang, das Datenblatt listet "40001 Spannung L1", und Ihr Werkzeug fragt nach einer Adresse. Sie tragen 40001 ein.
Ein Werkzeug, das ab 1 zählt, schickt daraufhin die Startadresse 40000, also 0x9C40, auf die Leitung. Auf den meisten Servern existiert diese Adresse nicht, dann kommt Exception 02 zurück. Auf einem Gerät mit sehr vielen Registern bekommen Sie einen Wert, der plausibel aussieht, und das ist der schlimmere Fall: es fällt monatelang niemandem auf. Was in einer Registertabelle sonst noch steht, zeigt die Erklärung der Modbus-Register in der Wissensdatenbank.
Die vier Datenblöcke im Überblick
Modbus kennt genau vier Datenblöcke, und jedes Register gehört zu genau einem davon. Zwei Blöcke sind 1 Bit breit, zwei sind 16 Bit breit, und je einer der beiden Sorten ist beschreibbar.
Pro Block erlaubt das Protokoll bis zu 65536 Elemente. Wichtig ist die Einschränkung, die die Spezifikation selbst macht: die vier Blöcke müssen keine vier getrennten Speicherbereiche sein. Ein Hersteller darf sie überlagern, und die Spezifikation nennt das ausdrücklich üblich. Deshalb liefert Holding-Register 40001 bei der einen Marke denselben Wert wie Input-Register 30001 und bei der anderen nicht.
Drei Zählweisen, die verwechselt werden
Vier Spalten für dasselbe Register, darin steckt der ganze Konflikt. Nehmen wir das Holding-Register mit der Datenmodellnummer 108:
| Zählweise | Schreibweise | Herkunft |
|---|---|---|
| Klassisch, 5-stellig | 40108 | Modicon-Konvention, nicht Teil der Norm |
| Klassisch, 6-stellig | 400108 | Industriekonvention, ebenfalls keine Norm |
| Datenmodell, 1-basiert | 108 | Modbus-Spezifikation, Abschnitt 4.4 |
| PDU-Adresse, 0-basiert | 107, hex 0x006B | genau so geht es über die Leitung |
Die Schreibweise 40001 kommt in der aktuellen Spezifikation nirgends vor. Sie ist ein Erbe der Modicon-Dokumentation. Wer behauptet, die Norm schreibe 40001 vor, irrt sich.
Die Umrechnung in drei Regeln
Zuerst ein vollständiges Beispiel. Ihr Datenblatt sagt "40108, Wirkleistung gesamt", und Sie wollen dieses Register plus die beiden folgenden lesen. Der Client sendet diese PDU:
| Byte | Wert | Feld |
|---|---|---|
| 1 | 03 | Funktionscode FC03, Holding-Register lesen |
| 2 bis 3 | 00 6B | Startadresse 107, PDU-Adresse, 0-basiert |
| 4 bis 5 | 00 03 | Anzahl der Register: 3 |
Der Server antwortet mit derselben PDU-Struktur:
| Byte | Wert | Feld |
|---|---|---|
| 1 | 03 | Funktionscode, gespiegelt |
| 2 | 06 | Byte Count: 6 Datenbytes |
| 3 bis 4 | 02 2B | Wert von 40108: 555 |
| 5 bis 6 | 00 00 | Wert von 40109: 0 |
| 7 bis 8 | 00 64 | Wert von 40110: 100 |
Erst jetzt die Regel, in drei Sätzen. Erstens: die PDU-Adresse ist die Datenmodellnummer minus 1. Zweitens: die PDU-Adresse ist die klassische Nummer minus die Blockziffer minus 1, aus 40108 wird also 108 und daraus 107. Drittens: die Blockziffer steht nicht in der Nachricht, welcher Block gemeint ist, folgt aus dem Funktionscode.
Blockziffer abziehen, danach noch einmal 1 abziehen.
Ein zweites Beispiel, das sich an genau einem Punkt unterscheidet. Das Datenblatt sagt "30009", also ein Input-Register. Gerechnet wird identisch: die Blockziffer 3 fällt weg, es bleibt 9, minus 1 ergibt PDU-Adresse 8, hex 0x0008. Nur der Funktionscode wechselt, denn Input-Register liest man mit FC04. Die Anfrage lautet 04 00 08 00 01, die Antwort 04 02 00 0A, also der Wert 10.
Dieselbe Adresse, vier Bedeutungen
Weil im Frame kein Platz für den Block ist. Die Nachricht trägt eine Adresse von 0 bis 65535 und einen Funktionscode, mehr nicht. Vier Anfragen mit derselben Startadresse 0x0000 treffen deshalb vier verschiedene Dinge:
| Funktionscode | Block | Im Datenblatt |
|---|---|---|
| FC01 | Coils | 00001 |
| FC02 | Discrete Inputs | 10001 |
| FC03 | Holding-Register | 40001 |
| FC04 | Input-Register | 30001 |
Die alte Modicon-Dokumentation formuliert es so: der Funktionscode legt die Operation auf einem Holding-Register bereits fest, deshalb ist die Angabe 4XXXX implizit. Welcher Funktionscode welchen Block anspricht, steht in der Referenz der Modbus-Funktionscodes. Was passiert, wenn Sie den falschen nehmen, sehen Sie in der Lektion zu Funktionscodes und Exception-Codes.
Was Ihr Werkzeug mit "Address" meint
Fragen Sie das Werkzeug, nicht Ihr Gedächtnis. Die drei Clients, die Ihnen am häufigsten begegnen, verhalten sich so:
| Werkzeug | Feld | Zählweise |
|---|---|---|
| mbpoll | -r | ab 1, mit dem Schalter -0 ab 0 |
| pymodbus | address | ab 0, also die PDU-Adresse |
| Home Assistant | address | ab 0, also die PDU-Adresse |
Bei den Herstellern ist es genauso gemischt. Fronius schreibt ausdrücklich in die Anleitung, dass Register bei 1 beginnen und man für Register 40001 die Adresse 40000 (0x9C40) verwenden muss. Daikin schreibt knapp "Register Base 0". SolarEdge druckt konsequent zwei Spalten nebeneinander, base 0 und base 1. Bei einem Datenblatt, das die Zählweise verschweigt, messen Sie statt zu raten. Wie das Feld in einer fertigen Konfiguration aussieht, zeigt die Anleitung zur Home-Assistant-Modbus-Einbindung.
Manche Clients nehmen Ihnen die Frage ab. Der Register Explorer in ModbusCloud Diagnostics zeigt die Protokolladresse und die Datenmodell-Adresse desselben Registers nebeneinander, sodass Sie sehen, welche der beiden Sie eintragen. Das Werkzeug ist kostenlos und läuft offline; mbpoll bleibt der Weg, der auf jedem System funktioniert.
Der Test, der Zweifel beendet
Lesen Sie dasselbe Register zweimal und vergleichen Sie. Einmal mit der Zählweise ab 1 auf Nummer 1, einmal mit der Zählweise ab 0 auf Adresse 0. Kommt beide Male derselbe Wert, stimmt Ihr Bild vom Werkzeug. Lesen Sie danach mit der Zählweise ab 0 die Adresse 1, dann bekommen Sie das Nachbarregister und haben den Off-by-one bewusst erzeugt, statt monatelang mit ihm zu leben.
Registertyp
Notation Ihres Datenblatts
- Klassisch, 5-stellig
- 40001
- Klassisch, 6-stellig
- 400001
- 1-basiert
- 1
- 0-basiert, dezimal
- 0
- 0-basiert, hex
- 0x0000
- Funktionscode lesen
- 03
- Funktionscode schreiben
- 06, 16
Was Sie pro Werkzeug eintragen
| Werkzeug | Eingabe |
|---|---|
| mbpoll | -t 4 -r 1-0 -t 4 -r 0 |
| QModMaster | Start Address: 0Base Addr 1: 1 |
| Modbus Poll | Address: 0PLC Base 1: 40001 |
| pymodbus | read_holding_registers(0, count=1) |
| Home Assistant | address: 0input_type: holding |
Werkzeuge unterscheiden sich in ihrer Standardnotation. mbpoll zählt ab 1, pymodbus ab 0.
Liegen Sie genau 1 daneben, lesen Sie das Nachbarregister. Das liefert einen plausiblen Wert und keine Fehlermeldung.
Häufige Fehler
40001 wörtlich eintragen. Ein Werkzeug, das ab 1 zählt, schickt dann die Startadresse 40000 (0x9C40) auf die Leitung, ein Werkzeug, das ab 0 zählt, wie Home Assistant oder pymodbus, sogar 40001 (0x9C41). Die meisten Server antworten mit Exception 02, manche mit einem plausiblen Wert aus einem ganz anderen Bereich. Richtig ist die Datenmodellnummer 1 und damit PDU-Adresse 0.
Nur die Startadresse kontrollieren. Exception 02 bewertet Startadresse plus Anzahl. Auf einem Server mit 100 Registern, PDU-Adressen 0 bis 99, liefert eine Anfrage nach 4 Registern ab Adresse 96 sauber ein Ergebnis, eine Anfrage nach 5 Registern ab Adresse 96 dagegen nicht. Zählen Sie beim Blocklesen immer bis zum letzten Register mit.
Die Blockziffer als Teil der Adresse lesen. Die 4 in 40108 geht nie mit auf die Leitung, sie sagt Ihnen nur, welchen Funktionscode Sie wählen müssen. Wer sie mitschickt, landet um Zehntausende daneben und wundert sich über Exception 02.
Praxisübung
Ziel: Sie führen dieselbe Lesung zweimal aus und sehen, dass das Ergebnis identisch ist. Das ist der Beweis statt der Behauptung. mbpoll ist frei nutzbar, auch gewerblich. Adapter anschließen und mbpoll einrichten steht ausführlich in der Lektion über das erste Gerät; ohne Hardware fahren Sie dieselbe Übung auf dem Server aus der Lektion über den Simulator.
mbpoll -m rtu -a 1 -b 9600 -P none -t 4 -r 1 -c 2 -1 /dev/ttyUSB0
mbpoll -m rtu -a 1 -b 9600 -P none -t 4 -r 0 -c 2 -0 -1 /dev/ttyUSB0
mbpoll -m rtu -a 1 -b 9600 -P none -t 4 -r 1 -c 2 -0 -1 /dev/ttyUSB0
- 1
Erste Lesung, Zählweise ab 1
Der erste Befehl liest zwei Register ab Nummer 1. Unter Windows heißt der Port
COM3, unter macOS/dev/cu.usbserial-XXXXXXXX. Notieren Sie beide Werte. - 2
Zweite Lesung, Zählweise ab 0
Der zweite Befehl setzt
-0und liest ab PDU-Adresse 0. Notieren Sie die beiden Werte wieder. - 3
Vergleichen
Die beiden Ausgaben müssen gleich sein, denn
-r 1ohne-0und-r 0mit-0zeigen auf dasselbe Register. - 4
Den Fehler absichtlich erzeugen
Der dritte Befehl kombiniert
-r 1mit-0. Jetzt lesen Sie ein Register weiter. Genau dieser Griff passiert in der Praxis unbemerkt. - 5
Gegen das Datenblatt halten
Schlagen Sie nach, was laut Datenblatt auf 40001 stehen soll, und kontrollieren Sie, ob Schritt 1 diesen Wert liefert.
Ohne Hardware. Starten Sie den Simulator von pymodbus, der Modbus TCP auf Port 5020 anbietet, und wiederholen Sie dieselbe Vergleichsreihe gegen 127.0.0.1 statt gegen die serielle Schnittstelle. pymodbus ist ebenfalls frei nutzbar, auch gewerblich.
pymodbus.simulator --modbus_server server --modbus_device device
mbpoll -m tcp -p 5020 -a 1 -t 4 -r 1 -c 2 -1 127.0.0.1
mbpoll -m tcp -p 5020 -a 1 -t 4 -r 0 -c 2 -0 -1 127.0.0.1
mbpoll -m tcp -p 5020 -a 1 -t 4 -r 1 -c 2 -0 -1 127.0.0.1
Erwartetes Ergebnis: zwei gleiche Ausgaben, eine dritte, die um ein Register verrutscht ist, und die Gewissheit, dass Ihr Werkzeug nichts falsch macht.
Zusammenfassung
- Die PDU-Adresse ist die Datenmodellnummer minus 1, bei einer klassischen Nummer ziehen Sie zuerst die Blockziffer ab: aus 40108 wird PDU-Adresse 107, hex
0x006B. - Modbus kennt vier Datenblöcke mit je bis zu 65536 Elementen, und ein Hersteller darf sie überlagern.
- Die Blockziffer aus 40001 oder 30001 geht nie mit auf die Leitung, den Block bestimmt allein der Funktionscode.
- mbpoll zählt ohne
-0ab 1, pymodbus und Home Assistant zählen ab 0. - Zwei Lesungen desselben Registers in beiden Zählweisen kosten eine halbe Minute und schließen den Off-by-one dauerhaft aus.
Überprüfen Sie sich selbst
Vier Fragen zu dieser Lektion. Zu jeder Antwort gibt es eine Erläuterung.
Frage 1 von 4
Selbst sehen, wie es funktioniert?
Das ModbusCloud Gateway liest die Geräte aus diesem Kurs aus, ohne dass Sie ein einziges Register programmieren.