In dieser Lektion

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.

BlockGrößeZugriffFunktionscodesCoils0xxxx1 Bitlesen und schreiben01 / 05, 15Discrete Inputs1xxxx1 Bitnur lesen02Input-Register3xxxx16 Bitnur lesen04Holding-Register4xxxx16 Bitlesen und schreiben03 / 06, 16
Vier Blöcke, zwei Größen, zwei Zugriffsrechte. Der Funktionscode entscheidet, welchen Block Sie treffen.

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ählweiseSchreibweiseHerkunft
Klassisch, 5-stellig40108Modicon-Konvention, nicht Teil der Norm
Klassisch, 6-stellig400108Industriekonvention, ebenfalls keine Norm
Datenmodell, 1-basiert108Modbus-Spezifikation, Abschnitt 4.4
PDU-Adresse, 0-basiert107, hex 0x006Bgenau 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:

ByteWertFeld
103Funktionscode FC03, Holding-Register lesen
2 bis 300 6BStartadresse 107, PDU-Adresse, 0-basiert
4 bis 500 03Anzahl der Register: 3

Der Server antwortet mit derselben PDU-Struktur:

ByteWertFeld
103Funktionscode, gespiegelt
206Byte Count: 6 Datenbytes
3 bis 402 2BWert von 40108: 555
5 bis 600 00Wert von 40109: 0
7 bis 800 64Wert 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.

40001Datenblatt, klassische Notation0x0000Adresse auf der Leitung (PDU)400010x0000400020x0001400030x0002401000x0063499990x270E401080x006B

Blockziffer abziehen, danach noch einmal 1 abziehen.

40001 geht als 0x0000 über die Leitung, 40108 als 0x006B. Immer eins weniger.

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:

FunktionscodeBlockIm Datenblatt
FC01Coils00001
FC02Discrete Inputs10001
FC03Holding-Register40001
FC04Input-Register30001

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:

WerkzeugFeldZählweise
mbpoll-rab 1, mit dem Schalter -0 ab 0
pymodbusaddressab 0, also die PDU-Adresse
Home Assistantaddressab 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

WerkzeugEingabe
mbpoll-t 4 -r 1-0 -t 4 -r 0
QModMasterStart Address: 0Base Addr 1: 1
Modbus PollAddress: 0PLC Base 1: 40001
pymodbusread_holding_registers(0, count=1)
Home Assistantaddress: 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.

Tippen Sie die Adresse aus Ihrem Datenblatt ab und lesen Sie ab, was Sie in Ihrem Werkzeug eintragen.

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. 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. 2

    Zweite Lesung, Zählweise ab 0

    Der zweite Befehl setzt -0 und liest ab PDU-Adresse 0. Notieren Sie die beiden Werte wieder.

  3. 3

    Vergleichen

    Die beiden Ausgaben müssen gleich sein, denn -r 1 ohne -0 und -r 0 mit -0 zeigen auf dasselbe Register.

  4. 4

    Den Fehler absichtlich erzeugen

    Der dritte Befehl kombiniert -r 1 mit -0. Jetzt lesen Sie ein Register weiter. Genau dieser Griff passiert in der Praxis unbemerkt.

  5. 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 -0 ab 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
Ihr Datenblatt sagt: 40108, Wirkleistung gesamt. Welche Startadresse steht im Frame?
Ein Werkzeug sendet FC03 mit Startadresse 0x0000. Ein zweites Werkzeug sendet am selben Server FC04 mit Startadresse 0x0000. Was gilt?
Sie lesen einen Energiezähler mit Home Assistant aus. Das Datenblatt sagt, die Netzspannung steht auf 40001. Sie tragen address: 40001 ein, der Sensor bleibt leer. Was ist der erste Eingriff?
Warum kann dieselbe PDU-Adresse 0x0000 vier verschiedene Dinge bedeuten?

Kommen Sie bei einem Projekt nicht weiter?

Beschreiben Sie, was Sie sehen und wo es hakt. Wir schauen es uns an und sagen Ihnen, was wir tun würden.

Weiterlesen in der Wissensdatenbank