Modbus-Kommunikation in CODESYS

Bei den meisten Automatisierungsanlagen steht man über kurz oder lang vor der Aufgabe eine Feldbusanbindung zu realisieren. Unter anderem kann das notwendig sein, wenn externe Sensoren benötigt werden, oder diverse I/O-Module integriert werden sollen. Außerdem kann über ein Feldbussystem der Datenaustausch zwischen verschiedenen Steuerungsgeräten erfolgen. Dieser Artikel beschreibt die einzelnen Schritte zur Realisierung einer Modbus-Kommunikation zwischen zwei CODESYS Steuerungen (Win Control V3 und Raspberry Pi).

Modbus-Protokoll

Die Modus-Kommunikation basiert auf der Master/Slave-Architektur und gilt in der Industrie als De-facto-Standard. Deshalb unterstützen, so ziemlich die meisten Geräte, Modbus. Falls Ihr euch bzgl. eurer CODESYS SPS unsicher seid, könnt Ihr dies im CODESYS Device Directory nachprüfen. Mehr dazu findet Ihr in einem meiner früheren Beiträge: Wie finde ich die passende SPS?

Jedes Gerät im Netzwerk, kann zugleich die Funktionalität eines Masters oder Slaves übernehmen. Dadurch könnt Ihr die Struktur eures Feldbussystems beliebig flexibel gestalten. Die Geräte können somit je nach Aufgabe eine andere Rolle erfüllen.

Erhält ein Slave eine Anfrage (Request) des Masters, beantwortet er diese mit einem Response, welche die angefragten Daten überträgt. Sofern es zu einem Übertragungsfehler kommt, werden Informationen über die Fehlerursache, anstelle der angefragt Daten übertragen. Je nach Betriebsart können dann die Daten vom Anwender im Netzwerk gelesen werden.

Es wird zwischen den folgenden Betriebsarten/Funktionen unterschieden:

  • RTU: Serielle Übertragung der Daten in binärer Form
  • ASCII: Serielle Übertragung der Daten im ASCII Format und dadurch direkt lesbar
  • TCP: Übertragung der Daten mittels TCP/IP auf Port 502

In diesem Blog Beitrag werde ich nur die Betriebsart über TCP verwenden.

Speicherbereich

Die Modbus-Geräte speichern die Daten innerhalb vier verschiedener Tabellen. Hier gibt es zwei Datenmodelle. Zum einen könnt Ihr für jeden Objekttyp einen eigenen Adressbereich definieren. Anderseits ist es gängige Praxis, die vier Tabellen zu überlagern und damit ein Speicherbereich zu erhalten. Hier erfolgt dann ein überlappender Zugriff.

Eine Hilfreiche Beschreibung kann in der Modbus Spezifikation (Kapitel 4.3) nachgelesen werden.

Objekttyp Zugriff Größe
Einzelner Ein-/Ausgang „Coil“ Read/Write 1-bit
Einzelner Eingang „Discrete Input“ Read 1-bit
Eingänge „Input Register“ Read 16-bits
Ein-/Ausgänge „Holding Register“ Read/Write 16-bits

Funktionscode

Der Master führt einen Request an einem Slave durch ⇒ Der Header beinhaltet den sogenannten Funktionscode. Dadurch weiß der Slave in welcher Tabelle er die Daten abrufen soll. Ebenfalls regelt der Funktionscode klar, ob ein Schreib- oder Lesezugriff erfolgt. Genauso wird durch den Funktionscode die Anzahl der bearbeiteten Feldelemente (Dateigröße) bestimmt.

Funktionscode Zugriff Speicherbereich
01 (01 hex) Read Einzelner Ausgang „Coil“
05 (05 hex) Write single Einzelner Ausgang „Coil“
15 (0F hex) Write multiple Einzelner Ausgang „Coil“
02 (02 hex) Read single Einzelner Eingang „Discrete Input“
04 (04 hex) Read multiple Eingänge „Input Register“
06 (06 hex) Write single Ein-/Ausgänge „Holding Register“
03 (03 hex) Read multiple Ein-/Ausgänge „Holding Register“
16 (10 hex) Write multiple Ein-/Ausgänge „Holding Register“

In der oberen Tabelle seht ihr die unterschiedlichen Funktionscodes und deren Zugriffsparameter. Außerdem ist in der ersten Spalte der Funktionscode zusätzlich als Hexadezimalwert abgebildet. Das hilft euch, wenn Ihr z.B. mit Wireshark den Netzwerkverkehr bei Modbus TCP mitschneidet. Denn der Funktionscode gibt dann direkt Aufschluss darüber, wie Ihr die übertragenen Daten interpretieren könnt.

ACHTUNG: Byte-Reihenfolge (Byte Order) ist von den Geräteherstellern unterschiedlich implementiert. Achtet darauf, dass die Reihenfolge bei Master und Slave gleich ist.

Voraussetzungen & Vorbereitung für die Modbus-Kommunikation

Um eine Modus-Kommunikation zu betreiben sind nur ein paar grundlegende Konfigurationen erforderlich. Ansonsten sind, außer der physikalischen Vernetzung, für unseren Aufbau keine weiteren Maßnahmen notwendig.

Beide Teilnehmen müssen lediglich im gleichen IP-Adressbereich sein.

Ich werde, für mein Beispiel, jeweils ein CODESYS Projekt für jeden Teilnehmer anlegen. Der Master wird mit einem Raspberry Pi realisiert, und den Slave werde ich mit meiner Win Control V3 SPS simulieren.

Modbus-Master (Quelle: https://store.codesys.com/)
Modbus-Slave (Quelle: https://store.codesys.com/)

Modbus Master-Konfiguration (Raspberry Pi)

Für die Konfiguration des Masters müssen wir zunächst dem CODESYS Device ein „Ethernet Knoten“ im Gerätebaum einfügen ⇒ Device (rechtsklick) ⇒ Gerät anhängen…

Gerätebaum - Gerät anhägen
Gerätebaum – Gerät anhägen

Ethernet Adapter ⇒ Ethernet ⇒ Gerät anhängen

Gerät anhängen - Ethernet Knoten
Gerät anhängen – Ethernet Knoten

Anschließend hängt Ihr nun den Modbus TCP Master an das zuvor eingefügten Ethernet Element. Im Gerätebaum ⇒ Ethernet (rechtsklick) ⇒ Gerät anhängen… ⇒ Modbus TCP Master

Modbus TCP Master anhängen
Modbus TCP Master anhängen

Tipp: Die Geräte können bei geöffnetem Editor „Gerät anhängen“ durch Doppelklick an das aktuell ausgewählte Element angefügt werden.

Der Modbus TCP Master ist nun unterhalb des Ethernet-Knotens im Gerätebaum verfügbar. Zunächst müssten wir aber das Ethernet parametrieren. Dazu öffnen wir (per Doppelklick auf Ethernet) den Konfigurator und klicken auf den Button (…) hinter Netzwerkschnittstelle.

Raspberry Pi Netzwerkschnittstelle festlegen
Raspberry Pi Netzwerkschnittstelle festlegen

In dem nachfolgenden Dialog wählt Ihr nun „eth0“ (wie hier bei meinem Raspberry Pi) oder einen anderen passenden Adapter eurer Steuerung.

Netzwerk-Adapter (eth0)
Netzwerk-Adapter (eth0)

ACHTUNG: Um die Netzwerkschnittstelle parametrieren zu können müsst Ihr mit dem Gerät verbunden sein.

Allgemeine Parameter

Ebenso ist beim Modbus TCP Master eine Einstellung erforderlich. Hierzu ebenfalls den Geräteeditor öffnen und im Reiter „Allgemein“ die Option für Auto-reconnect aktivieren.

Modbus Master - Parameter
Modbus Master – Parameter

Jetzt haben wir alle Einstellungen für den Master fertiggestellt, und müssen nun noch den Slave mit dem Master verknüpfen. In CODESYS müsst Ihr hierzu einfach im Geräteeditor den Slave als Knotenelement unter den Master hängen. Im Gerätebaum ⇒ Modbus_TCP_Master (rechtsklick) ⇒ Gerät anhängen… ⇒ Modbus TCP Slave

Modbus Slave zu Master Knoten hinzufügen
Modbus Slave zu Master Knoten hinzufügen

Jetzt haben wir ein Slave Element in unserem Gerätebaum. Dieses hat jedoch noch nichts mit unserem reellen Slave auf meine zweiten Steuerung zu tun. Hierzu müssen wir im Editor für den Slave die IP-Adresse des Slaves (hier in diesem Fall die IP Adresse meines PCs mit der Win Control V3) angeben. Prüft in diesem Fall auch ob Ihr bei beiden Geräten den Port gleich ausgewählt habt (hier Standard 502).

Modbus Slave - Zielsystem IP Adresse
Modbus Slave – Zielsystem IP Adresse

Der Reiter „Allgemein” hat die folgenden Einstellungen für Modbus TCP:

  • Slave IP-Adresse – die IP-Adresse des Slaves
  • Response Timeout – das Zeitintervall, in dem der Master die Antwort vom Slave-Gerät abwartet. Das hier angegebene Timeout überschreibt die allgemeine Einstellung „Response Timeout“ des zugehörigen Masters.
  • Port – Port-Nummer des Slaves (Standard 502)

Tipp: Solltet Ihr häufig Probleme mit Verbindungsabbrüchen haben, empfehle ich euch die „Response Timeout“ auf 2000ms zu erhöhen.

Funktionscodes

Als nächstes müssen wir noch die Funktionscodes angeben um Daten zu übertragen. Dazu können wir im Reiter „Modbus Slave-Kanal“ die Kanäle hinzufügen. Wie oben in der Tabelle erwähnt gibt es mehrere Möglichkeiten. Ich nutze nun für das Beispiel den Funktionscode 23 (Read/Write Multiple Registers) um gleichzeitig Werte zu lesen und zu schreiben. Die Daten länge habe ich exemplarisch mit 4 Byte (2 WORD) angegeben. Hier müsst ihr natürlich entsprechend eurer erforderlichen Datenmenge die Werte anpassen. Klickt im Menü Modbus Slave-Kanal ⇒ Kanal hinzufügen… und Ihr seht den nachfolgenden Dialog, mit den oben bereits erwähnten Parametern.

Modbus Slave - Kanal Einstellungen
Modbus Slave – Kanal Einstellungen

Modbus Slave-Konfiguration

Um eine funktionierende Modbus-Kommunikation zu installieren, müssen wir natürlich noch den Slave Konfigurieren. Das werde ich in den nachfolgenden Schritten beschreiben. Auch hier müsst Ihr zunächst (wie beim Master) einen „Ethernet Knoten“ im Gerätebaum einfügen ⇒ Device (rechtsklick) ⇒ Gerät anhängen…

Ethernet Knoten in Gerätebaum einfügen
Ethernet Knoten in Gerätebaum einfügen
Gerät anhängen - Ethernet
Gerät anhängen – Ethernet

Außerdem werden wir gleich den Modbus TCP Slave Gerät mit anfügen und damit, unsere Win Control V3, als Modbus Slave ausweißen ⇒ Ethernet (selektieren) ⇒ rechtsklick ⇒ Gerät anhängen… ⇒ Modbus ⇒ Modbus TCP Slave Device ⇒ Gerät anhängen ⇒ Schließen.

ModbusTCP Slave anhängen
ModbusTCP Slave anhängen

Damit die Modbus-Kommunikation über TCP funktionieren kann, müsst Ihr, wie beim Master, ebenfalls, die Netzwerk Einstellungen im Ethernet Knoten vornehmen ⇒ Ethernet (auswählen) ⇒ Allgemein ⇒ Netzwerkschnittstelle […]

Netzwerkschnittstelle auswählen
Netzwerkschnittstelle auswählen

Ihr erhaltet nun den nachfolgenden Dialog. Dieser unterscheidet sich bei euch natürlich, da Ihr vermutlich andere Hardware Komponenten verbaut habt. Bei meinem PC sieht das Interface wie folgt aus:

Netzwerkadapter auswählen
Netzwerkadapter auswählen

Konfigurierte Parameter

Ebenso wie den Ethernet-Knoten haben wir den Modbus-Slave im vorherigen Schritt schon hinzugefügt. Auch hier sind einige Parameter einzustellen. Das Konfigurationsmenü öffnet Ihr, indem Ihr im Gerätebaum, einen Doppelklick auf den Eintrag des Slaves durchführt.

Der Reiter „Allgemein” hat die folgenden Parameter:

  • Watchdog – die maximale Zeitdauer, die das Slave-Gerät auf einen Schreibzugriff erwartet. Wenn kein Schreibzugriff innerhalb dieser Zeitdauer erfolgt ist, werden alle Ausgänge auf 0 gesetzt.
  • Slave Port – Port-Nummer des Slaves (Default 502)
  • Unit ID – Netzwerk-Adresse des Geräts (nur erforderlich für Modbus RTU)
  • Holding RegistersAnzahl der Holding-Register
  • Input RegistersAnzahl der Eingangsregister
Modbus TCP Slave Parameter
Modbus TCP Slave Parameter

ACHTUNG: Die beiden Zeilen, Holding Registers (%IW) und Input Registers (%QW), legen nicht die Adresse, sondern lediglich die Anzahl, der verwendeten Register, fest.

Während Ihr beim Slave Port und Watchdog hier einfachheitshalber die Standard Werte belassen könnt, müsst Ihr bei der Datenlänge, hier dieselben Werte wie im Master eintragen (hier jeweils 2x WORD).

Datenmodel

Je nachdem, für welches Datenmodel (siehe Kapitel Speicherbereich), Ihr euch entscheidet, müsst Ihr hier die Parameter anpassen. Falls die Speicherblöcken getrennt sind, müsst Ihr für jeden Funktionscode hier unterschiedliche Startadressen (je nach Anordnung und Größe der Sektionen) angeben.

Ich bin eher für die Methode eines gemeinsamen Datenblocks mit überlappendem Zugriff. Dies ist allerdings Geschmackssache. Hier bleiben die Startadressen bei „0“ und das Häkchen bei „Holding- und Input-Register Datenbereich überlagert“ muss gesetzt werden. Damit könnt Ihr nun die einzelnen Funktionscodes verwenden um auf ein WORD oder ein Bit eures Speicherberichs zuzugreifen. Hier empfiehlt es sich in einer externen Tabelle eine Übersicht mit eurem Datenaufbau anzulegen.

E/A-Abbild

Damit unsere Register auch beim Funktionstest übertragen werden, obwohl wir keine SPS Programm geschrieben haben, welches die Register beschreibt, sind noch die nachfolgenden Einstellungen bzgl. Aktuallisierung und Buszyklus-Task erforderlich.

Modbus TCP Slave EA-Abbild Einstellungen
Modbus TCP Slave EA-Abbild Einstellungen

Funktionstest

Die Konfiguration ist nun abgeschlossen. Zeit für einen Funktionstest der Modbus-Kommunikation. Ich habe hierzu einfach beide CODESYS Geräte gleichzeitig geöffnet und werde euch manuell Variablen schreiben um den Übertragungsvorgang zu zeigen.

Modbus-Kommunikation
Funktionstest (Modbus-Kommunikation)

Hier könnt Ihr z.B. sehen, dass meine Werte im Ausgangswort der Win Control V3 als Eingangswerte im CODESYS des Raspberry Pi ausgelesen werden können. Ebenfalls ist es durch das überlagerte Datenmodel möglich auf die Werte als WORD oder als BIT zuzugreifen.

Schlusswort

Mit Hilfe der Modbus-Kommunikation könnt Ihr einfach mehrere Steuerungen untereinander vernetzen. Im Grunde genommen ist das ganz im Sinne von Industrie 4.0. Auch wenn das Modbus-Protokoll mit einem Alter von knapp 40 Jahren zu den Urgesteinen der Kommunikationsprotokolle, für Steuerungssysteme, gehört. Wie Ihr aus den obigen zwei Konfigurationen seht, ist es sehr leicht eine Modbus-Kommunikation zu realisieren. Solltet Ihr dennoch mal Probleme mit dem Verbindungsaufbau haben, so empfehle ich euch, die Kommunikation zum Master und zum Slave separat zu prüfen. Hierzu gibt es eine Reihe von Tools, die eingesetzte werden können. Unter folgendem Link (englisch) findet Ihr eine kleine Auswahl.

4 Kommentare

  1. Hallo Matthias,
    ist es dir einmal gelungen, die IP-Adresse des Elements Modbus_TCP_Slave dynamisch zu ändern, sodass eine Konfiguration zur Laufzeit möglich wird, z.B. über den Webserver der Steuerung? Die Methode Modbus_TCP_Slave.UpdateCommunicationSettings verspricht dies, erfordert wohl aber einen Reconnect der Verbindung, zu dem ich aber keine Dokumentation gefunden habe.
    Ansonsten danke für deine schönen Anleitungen! Da wir auch Modbus, OPC UA und Data Logging nutzen sehr relevant.

    1. Hallo Stefan,

      Ich hatte dies einmal mit einer CODESYS V2.3 Steuerung gemacht. Bisher allerdings noch nicht mit CODESYS V3 probiert. Ich habe leider erst nächste Woche wieder die Möglichkeit, dass an einer Steuerung mit Modbus Slave zu testen. Dann kann ich dir aber auf alle Fälle Feedback geben wie es funktioniert. Eventuell helfen dir allerdings schon diese beiden Methoden weiter.

      Modbus_TCP_Slave.Enable:=FALSE;
      Modbus_TCP_Master.xStop:=TRUE;

      Damit du die Methode Enable beim Slave aufrufen kannst, musst du in deinem Gerät die Diagnose für alle Geräte aktivieren: Device -> PLC Settings -> Additional Settings -> Enable Diagnosis for Devices.

      Ich würde beide Propertys vor der Methode ‘UpdateCommunicationSettings’ bearbeiten. Danach den Master, und anschließend den Slave wieder starten (xStop:=FALSE und Enable:=TRUE). Eventuell musst du auch auf xDone abfragen oder zumindest eine Wartezeit einbauen.

      Ich hoffe die Methoden sind die richtigen. Habe aktuell nur Zugriff mit meinem Smartphone und kann diese leider nicht vorher prüfen. Mit was für einer Steuerung arbeitest du?

      Beste Grüße
      Matthias

    2. Hallo Stefan, ich habe die Konfiguration getestet. Funktioniert super. Ein Beispiel findest du hier, in meinem neusten Artikel.

      Viele Grüße
      Matthias

  2. Super, danke für die ausführliche Anleitung und den Hinweis auf die Diagnosefunktionen! Werde es testen sobald ich wieder an der Hardware sitze.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Diese Website benutzt Cookies und Google Analytics. Wenn du die Website weiter nutzt, gehen wir von deinem Einverständnis aus Weitere Informationen

Die Cookie-Einstellungen auf dieser Website sind auf "Cookies zulassen" eingestellt, um das beste Surferlebnis zu ermöglichen. Wenn du diese Website ohne Änderung der Cookie-Einstellungen verwendest oder auf "Akzeptieren" klickst, erklärst du sich damit einverstanden.

Schließen