Wago "Modbus TCP"-Kommunikation mit 750-8100 (Master) und 852 (Slave) unter e!Cockpit

aki09

Level-1
Beiträge
11
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Wago "Modbus TCP"-Kommunikation mit 750-8100 (Master) und 852 (Slave) unter e!Cockpit

Hallo zusammen,

ich versuche gerade eine Modbus TCP Verbindung zwischen dem 750-8100 und dem 750-352 einzubinden, allerdings möchte ich das nicht über den Modbus-Konfigurator (siehe Handbuch) umsetzen, sondern über die Bibliothek "FbMbMasterTcp". Leider stehe ich gerade ein bisschen auf dem Schlauch, wie ich das genau umsetzen muss.

Was habe ich bisher gemacht?
- Funktionsbaustein "WagoAppPlcModbus.FbMbMasterTcp" in PLC_PRG (mit FUP) eingefügt.
- Variablen deklariert (Master-Adresse: 192.168.1.100 / Slave-Adresse: 192.168.1.101)
- Auslesen des PT100
-> Nicht klar, wie ich das umsetzen soll bzw. in welches Register der Wert geschrieben wird und wie man diesen dann ausliest.

WezLfPXgp IAAAAASUVORK5CYIIA


// Konfigurierung Modbus Master
ModbusMaster01: WagoAppPlcModbus.FbMbMasterTcp;

// Input ModbusMaster
xConnect: BOOL := 1;
sHost: STRING := '192.168.1.101'; --> sHost ist die Slave-Adresse?
wPort: WORD := 502;
utKeepAlive: typKeepAlive;
eFrameType: eMbFrameType := ETHERNET;
tTimeOut: TIME := t#5s;
utQuery : typMbQuery := ( bUnitId := 1, // Slaveaddress
bFunctionCode := 16#17, // multiple read/write registers
uiReadAddress := 0, // Startaddress
uiReadQuantity := 10, // Quantity of wanted registers
uiWriteAddress := 512,
uiWriteQuantity := 0,
awWriteData := [124(0)]
)
utResponse: typMbResponse;
xTrigger: BOOL;

// Output ModbusMaster
xIsOpen: BOOL;
xError: BOOL;
oStatus: FbResult;

END_VAR

Ziel:
Auslesen der Temperatur eines PT100 (von 750-352) und Übertragung der Werte auf den Feldbuscontroller (750-8100). Übersteigt die Temperatur einen gewissen Wert, soll ein DO gesetzt werden.Das möchte ich mir gerne erstmal als simples Beispiel aufbauen, um die Kommunikation via Modbus und das Einbinden der Bibliotheken / Schreiben der Register zu verstehen.

Fragen:
- Wie lese ich die Daten vom Feldbuskoppler via Modbus auf dem Controller aus? Die Geschichte mit den Registern ist mir noch nicht so ganz klar.In welches Register werden die Eingangswerte der PT100 geschrieben? (Aufbau Slave "750-452": (1) 750-400, (2) 750-461, (3) 750-492, (4) 750-600)

- Die Variable sHost ist die Slave- oder die Master-Zieladresse? Was ist, wenn ich zwei Master und zwei Slaves habe. Wie kann ich festlegen, welcher Master mit welchem Slave verknüpft ist?Das interessiert mich, weil ich in der Zukunft gerne mehrere dieser Master-Slave Topologien in ein Gesamtnetzwerk aufbauen möchte.

- Gibt es detailliertere Tutorials oder Beispielprojekte für e!Cockpit, mit denen man sich die Einarbeitung erleichtern kann?
Auf YouTube findet man häufig nur sehr oberflächliche Tutorials oder Tutorials mit CodeSys 2.3.

Vielen Dank im Voraus.
 
Zuletzt bearbeitet:
Hallo zusammen,

ich habe mich in den letzten Tagen weiter mit dem Thema beschäftigt, bisher aber keine Lösung des Problems gefunden. Im Anhang habe ich nochmal die Projektdatei (Test123.ecp) angehängt - vielleicht macht das die Sache einfacher.

Was möchte ich umsetzen?
Um mit dem System vertraut zu werden, möchte ich erstmal ein simples Projekt erstellen. Dabei möchte ich einen PT100 Temperatursensor (auf Feldbuskoppler -352, mit Analogeingangskarte „750-492“, Klemme AI1) auslesen und den Temperaturwerts via Modbus TCP auf den Feldbuskoppler -8100 senden.
(!! Nicht mit Modbus-Konfigurator, sondern mit Projektbibliothek „WagoAppPlcModbus Library“ !!)


Was wurde bereits gemacht?
Über e!COCKPIT habe ich bereits eine „Modbus TCP“-Kommunikation mit dem Modbus-Konfigurator aufgebaut. Das Auslesen eines PT100 Sensors vom Feldbuskoppler -352 hat einwandfrei funktioniert. Nun möchte ich aber gerne die Modbus-Konfiguration über die Projektbibliothek einbinden – da scheitere ich aber aktuell an der Umsetzung. Ich möchte die Modbus Kommunikation über die Bibliothek umsetzen, da die Slave-Zieladresse für die Steuerung variieren kann. Der Temperaturwert des PT100 auf Kanal 1 (siehe I/O-Systeme -> HM001 -> 2: _2AI_Pt100_RTD -> AI1) soll ausgelesen und via Modbus vom Feldbuscontroller eingelesen werden.


Programmierung in „PLC_PROG“ (Abbildung, siehe Anhang)
Netzwerk 1: Einlesen des Programmbausteins „PRG_FbMbMasterTCP“
Netzwerk 2: Mappen der Analogeingangskarte „750-492“ auf die Modbus Registeradresse „PRG_FbMbMasterTCP.awInputRegisters_RO[300].1“
(-> Ist das überhaupt das richtige Register für das Einlesen eines AIs? Das Netzwerk 2 gilt nur als Gedankenstütze, wie ich vorgehen soll. Das Auslesen des Analogwertes kann ich natürlich nicht nur eine 1 Bit-Variable deklarieren)

Netzwerk 3: Wertevergleich: Steigt die Temperatur auf größer 30°C -> Schalte digitale Ausgangsklemme auf Feldbuscontroller


PLC_PROG.png


Fragen:
1. Wo stelle ich die Slave-Zieladresse für den Feldbuskoppler ein? Das ist mir aktuell überhaupt nicht klar – auch über die Dokumentation in e!COCKPIT oder die Bibliothek „WagoAppPlcModbus“ konnte ich da keine hilfreichen Details finden. Die Slave Adresse soll über bUnitId_MbServer_Tcp (Standardmäßig „BYTE :=1;“) konfiguriert werden. Meine Zieladresse auf dem Slave ist „196.168.1.101“, der Controller hat die „.100“.

2.
Wie schreibe (vom Feldbuscontroller -> Koppler) bzw. lese ich (vom Koppler -> Feldbuscontroller) Werte aus? Die Begriffe axDiscreteInputs, axCoils, awInputRegisters und awHoldingRegisters im "FbMbSimpleServerTcp"-Baustein, sind die Register in die ich schreiben/lesen kann. Aber wie schreibe ich einen Temperaturwert in das Register und lese es vom Controller wieder aus?


3. Gibt es eine detailliertere Dokumentation zur Konfigurierung von e!COCKPIT mit Modbus TCP, abgesehen von dem e!COCKPIT Handbuch oder der Dokumentation der Projektbibliothek?


Vielen Dank im Voraus.
 

Anhänge

  • Test123.rar
    73,5 KB · Aufrufe: 107
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

ich kapier zwar nicht warum Du da alles zu Fuß machen willst und nicht mit dem Konfigurator.

Habe nur mal kurz in das Projekt geschaut. Du verwendest dort den falschen Baustein. Der Baustein FbMbSimpleServerTcp ist für einen Modbus Slave, daher kannst Du dort auch keine Adresse vorgeben. Bei Modbus spricht man normalerweise nicht von Master und Slave, sondern von Server (Slave) und Client (Master). Bei Wago haben die jetzt beides gemischt in der Biliothek. Wenn Du richtig schaust, siehst Du, daß FbMbSimpleServerTcp unter der Kategorie '30 Simple Modbus Slave' eingetragen ist. In der Dokumentation zum Baustein steht auch: This function block provides Modbus TCP Slave functionality
Du mußt FbMbMasterTcp nehmen und die Struktur typMbQuery entsprechend füllen

Auf welcher Adresse jetzt die einzelnen Eingänge liegen mußt Du aus dem Handbuch zum 352 rauslesen, Stichwort Modbus Register Mapping. Zum Testen der Adressen kannst Du ja auch erst einmal einen Windowsrechner nehmen und z.B. qmodmaster. Damit kann man mal schnell etwas von einem Modbus Slave/Server abfragen und testen.

Deine erste Temperatur müßtest Du aber über Funktionscode 4, Adresse 0 lesen können (%IW0). Die zweite Temperatur ist dann auf Adresse 1, der erste Stromeingang Adresse 2 und der 2. auf 4.
Die beiden digitalen Eingänge liest Du über die Coil Funktionen ein (Funktionscode 2)

Gruß
 
Hallo,

ich kapier zwar nicht warum Du da alles zu Fuß machen willst und nicht mit dem Konfigurator.

Ich möchte im weiteren Verlauf ein Netzwerk aus mehreren Feldcontrollern (z.B. 5) mit je einem Feldbuskoppler aufbauen. Ein System aus Feldbuscontroller (Client) und Koppler (Server) ist die Standard Konfiguration. Diese Systemkonfiguration soll standardmäßig laufen. Nun soll es aber möglich sein, dass man z.B. folgendes tut:
- 5 Systeme (jeweils 1x Controller (Client) + 1x Koppler (Server)) laufen
- 2 Systeme werden gestoppt und sollen umkonfiguriert werden, die anderen 3 Systeme sollen davon aber unberührt bleiben und weiter laufen
- Neue Systemkonfiguration: 2 Feldbuscontroller (ein Controller parametriert als Client, einer als Server) + 1 Koppler (Server) kommunizieren jetzt miteinander (2. Koppler ist nicht im System)

Das alles möchte ich später über eine visualisierte Bedieneroberfläche parametrierbar machen - die Slave-Zieladressen der Clients über die Weboberfläche neu konfigurieren.


Habe nur mal kurz in das Projekt geschaut. Du verwendest dort den falschen Baustein. Der Baustein FbMbSimpleServerTcp ist für einen Modbus Slave, daher kannst Du dort auch keine Adresse vorgeben. Bei Modbus spricht man normalerweise nicht von Master und Slave, sondern von Server (Slave) und Client (Master). Bei Wago haben die jetzt beides gemischt in der Biliothek. Wenn Du richtig schaust, siehst Du, dass FbMbSimpleServerTcp unter der Kategorie '30 Simple Modbus Slave' eingetragen ist. In der Dokumentation zum Baustein steht auch: This function block provides Modbus TCP Slave functionality

Danke für den Hinweis - funktioniert jetzt zumindest mal ohne Fehler. Als sHost muss ich dann aber meinen Client (192.168.1.100) angeben, richtig? Den FbMbSimpleServerTcp Baustein benötige ich also nur, wenn ich einen Feldbuscontroller als Slave parametrieren möchte?


Du musst FbMbMasterTcp nehmen und die Struktur typMbQuery entsprechend füllen

Und genau an dem Punkt hänge ich gerade. Folgende Einstellungen habe ich hier vorgenommen:
utQuery : typMbQuery := ( bUnitId := 0, // Slaveaddress -> Was muss hier hin? Slave Adresse ist: 192.168.1.101
bFunctionCode := 16#04, // Read Input Registers
-> Das entspricht FC4. Und wie konfiguriere ich die Zeilen, wenn ich z.B. sowohl FC16 (Write Multiple Registers) und FC4 (Read Input registers) nutzen möchte?
uiReadAddress := 0, // Startaddress := %IW0
uiReadQuantity := 10, // Quantity of wanted registers -> Anzahl der IWs, also Anzahl der benötigen Register, die auf meinem Koppler ausgelesen werden müssen?!
uiWriteAddress := 512, // not needed for FC4
uiWriteQuantity := 10, // not needed for FC4
awWriteData := [124(0)] // not needed for FC4

Mein Programm läuft jetzt ohne Fehlermeldung (allerdings ohne das ich Werte auslesen kann) und ich habe vermutet, dass die Werte meiner Eingangskarte (PT100, %IW0) unter utresponse -> awData (ARRAY[0..124] -> ARRAY[0]) liegen. Da finde ich aber nur Null (ist auch mit awWriteData := [124(0)] initialisiert worden)!


Deine erste Temperatur müßtest Du aber über Funktionscode 4, Adresse 0 lesen können (%IW0). Die zweite Temperatur ist dann auf Adresse 1, der erste Stromeingang Adresse 2 und der 2. auf 4.
Die beiden digitalen Eingänge liest Du über die Coil Funktionen ein (Funktionscode 2)

Mir ist leider nicht ganz klar, wie ich Modbus-Nachrichten unter dem typMbQuery konfiguriere. Klar ist mir, dass Analog vor Digital kommt und Eingang vor Ausgang und das abhängig von der Hardwarereihenfolge, in die Register geschrieben wird. Leider fehlt mir aber das Verständnis wie ich genau eine Modbus-Nachricht vom Server auslese (Wert vom PT100) und einen Ausgang auf dem Client schreibe (z.B. AO). Auch Anwendungsbeispiele konnte ich dazu nicht in der Dokumentation finden.

Mein überarbeites Projekt habe ich nochmal im Anhang beigefügt.

Beste Grüße und danke schon für die Starthilfe.
 

Anhänge

  • Testprojekt_20180328.rar
    71,2 KB · Aufrufe: 72
Hi,


Danke für den Hinweis - funktioniert jetzt zumindest mal ohne Fehler. Als sHost muss ich dann aber meinen Client (192.168.1.100) angeben, richtig?
Nein, sHost ist der Server/Slave, also der Koppler 352 (Master=Client=PFC100; Slave=Server=352).


Den FbMbSimpleServerTcp Baustein benötige ich also nur, wenn ich einen Feldbuscontroller als Slave parametrieren möchte?
Sieht so aus, aber wahrscheinlich wäre es leichter dies in der Gerätestruktur über den Modbus Slave Tab einzustellen.


Und genau an dem Punkt hänge ich gerade. Folgende Einstellungen habe ich hier vorgenommen:
utQuery : typMbQuery := ( bUnitId := 0, // Slaveaddress -> Was muss hier hin? Slave Adresse ist: 192.168.1.101
Sollte bei TCP/UDP Verbindung egal sein, wird normalerweise nur bei RTU verwendet. Die Slaveadresse wird wie schon oben geschrieben bei sHost angegeben.
bFunctionCode := 16#04, // Read Input Registers
-> Das entspricht FC4.
OK
uiReadAddress := 0, // Startaddress := %IW0
OK, also Start mit dem ersten Register (erster analoger Kanal)
uiReadQuantity := 10, // Quantity of wanted registers -> Anzahl der IWs, also Anzahl der benötigen Register, die auf meinem Koppler ausgelesen werden müssen?!
Versuch erst einmal mit einem Register. Dann langsam steigern. Bei 10 Registern müßte es auch einen Fehler geben, btw. darauf solltest Du auch auswerten. Bei Dir dürften da zur Zeit max. nur 5 Register ansprechbar sein: 0 und 1 die beiden Kanäle der Temperaturkarte, 2 und 3 die 4-20mA KArte und 4 dann noch zusätzlich die digitale Eingangskarte. Wenn ich es richtig lese werden die dig. Ein-/Ausgänge nämlich auch nochmal als Register hinten drangehangen, sodaß an auch über die Registerfunktionen und nicht nur über die Coilfunktionen darauf zugreifen kann.
uiWriteAddress := 512, // not needed for FC4
OK, aber vielleicht besser auf 0 setzen.
uiWriteQuantity := 10, // not needed for FC4
OK, aber vielleicht besser auf 0 setzen.
awWriteData := [124(0)] // not needed for FC4
OK
Mein Programm läuft jetzt ohne Fehlermeldung (allerdings ohne das ich Werte auslesen kann) und ich habe vermutet, dass die Werte meiner Eingangskarte (PT100, %IW0) unter utresponse -> awData (ARRAY[0..124] -> ARRAY[0]) liegen. Da finde ich aber nur Null (ist auch mit awWriteData := [124(0)] initialisiert worden)!
Eigentlich sollten die Daten dort liegen. Meldet den xlsOpen True und xError wirklich False?

Ich weiß nicht ob die Pt100 Karte noch speziell über I/O Check konfiguriert wird, wurde das gemacht?

Versuche sonst mal mit dem Programm qModMaster (https://sourceforge.net/projects/qmodmaster/) unter Windows auf den Koppler zuzugreifen. Damit kann man schnell mal die verschiedenen Adressen ausprobieren und man sieht auch wann es Fehlermeldungen gibt.


Ansonsten versuch auch erst mal die Adresse 16#2000 (8192) mit Anzahl 9 Registern zu lesen. Als Antwort solltest Du folgendes erhalten:
16#0000
16#FFFF
16#1234
16#AAAA
16#5555
16#7FFF
16#8000
16#3FFF
16#4000


siehe auch Handbuch Kapitel 11.2.5.6 Konstantenregister


Und wie konfiguriere ich die Zeilen, wenn ich z.B. sowohl FC16 (Write Multiple Registers) und FC4 (Read Input registers) nutzen möchte?
Du mußt mehrere Query Strukturen ausführen und die dann nacheinander abarbeiten.


Mir ist leider nicht ganz klar, wie ich Modbus-Nachrichten unter dem typMbQuery konfiguriere. Klar ist mir, dass Analog vor Digital kommt und Eingang vor Ausgang und das abhängig von der Hardwarereihenfolge, in die Register geschrieben wird. Leider fehlt mir aber das Verständnis wie ich genau eine Modbus-Nachricht vom Server auslese (Wert vom PT100) und einen Ausgang auf dem Client schreibe (z.B. AO). Auch Anwendungsbeispiele konnte ich dazu nicht in der Dokumentation finden.
Wie gesagt, Du mußt mehrere Query Strukturen erstellen. Am besten über ein Array. Nennen wir das mal eine Jobliste. Zusätzlich wird dann eine dazugehörige Antwortliste benötigt
Code:
Joblist: ARRAY[0..1] of typMbResponse :=  //JOB 0 Konstantenregister lesen
                                          (bUnit := 0,
                                           bFunctionCode := 16#04,
                                           uiReadAddress := 16#2000,
                                           uiReadQuantity := 9,
                                           uiWriteAddress := 0,
                                           uiWriteQuantity := 0,
                                           awWriteData := [124(0)]
                                          ), //JOB 1 MAC Adresse lesen
                                          (bUnit := 0,
                                           bFunctionCode := 16#04,
                                           uiReadAddress := 16#1031,
                                           uiReadQuantity := 3,
                                           uiWriteAddress := 0,
                                           uiWriteQuantity := 0,
                                           awWriteData := [124(0)]
                                           )
                                          ;
ResponseList: ARRAY[0..1] of typMbResponse;


Dazu benötigst Du dann eine Zahlvariable, z.B. i, dann rufst Du den Baustein mit Joblist als utQuery und ResponseList als utResponse auf. Zusätzlich mußt Du dann die Variable i nach erfolgreichem Ausführen des Bausteins (fallende Flanke xTrigger) inkrementieren und dann wenn alle Jobs durch sind wieder auf 0 setzen.


So müßte das klappen, habe meine Controller gerade nicht aufegbaut um das zu testen. Hatte vorletzte Woche nur mit einem 352 und qModMaster etwas rumgespielt.


Gruß

/EDIT: Array Initialisierung berichtigt
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo nochmal,

@Thruser: Deine Anleitung hat super funktioniert und somit konnte ich die Temperaturwerte vom Feldbuskoppler bereits einlesen. Wie das funktioniert habe ich nun auch verstanden.
Nun habe ich mich in den letzten 2 Wochen mit anderen Themen auseinandersetzen müssen und somit konnte ich erst seit gestern wieder weitermachen. Zur Zeit versuche ich die Ausgangsklemmen
meines Feldbuskopplers anzusteuern. Dafür habe ich eine DO-Klemme hinzugefügt - die Umsetzung hat aber bisher überhaupt nicht funktioniert.

Ansonsten versuch auch erst mal die Adresse 16#2000 (8192) mit Anzahl 9 Registern zu lesen. Als Antwort solltest Du folgendes erhalten:
16#0000
16#FFFF
16#1234
16#AAAA
16#5555
16#7FFF
16#8000
16#3FFF
16#4000

siehe auch Handbuch Kapitel 11.2.5.6 Konstantenregister

Check!

Mir ist leider nicht ganz klar, wie ich Modbus-Nachrichten unter dem typMbQuery konfiguriere. Klar ist mir, dass Analog vor Digital kommt und Eingang vor Ausgang und das abhängig von der Hardwarereihenfolge, in die Register geschrieben wird. Leider fehlt mir aber das Verständnis wie ich genau eine Modbus-Nachricht vom Server auslese (Wert vom PT100) und einen Ausgang auf dem Client schreibe (z.B. AO). Auch Anwendungsbeispiele konnte ich dazu nicht in der Dokumentation finden.
Wie gesagt, Du mußt mehrere Query Strukturen erstellen. Am besten über ein Array. Nennen wir das mal eine Jobliste. Zusätzlich wird dann eine dazugehörige Antwortliste benötigt

Die grundsätzliche Idee habe ich verstanden. Es gibt Konstantenregister und andere feste Register (z.B. MAC Adresse lesen o.Ä.), die feste HEX Werte zurückgeben (mit QModmaster probiert - hat geklappt!).
Wie ich den Aufbau der Job- und Responselist aufbauen soll, ist mir aber unklar.

Meine Fragen dazu:
1. bFunctionCode := 16#04 ist ein Eingangsregister, bei dem man eine Anzahl von Eingangsworten lesen kann (d.h. Analogeingänge! Oder auch Digitaleingänge?!).
Die Funktion 01 liest Ein- und Ausgangsbits. Entsprechend lediglich Digitalein- und Ausgänge? Habe ich das so richtig verstanden?

2. uiReadAddress: Wenn ich keine Konstantregister oder MAC-Adressen auslesen will (wie in deinem Beispiel) - muss ich hier die Adressen meiner Eingangskarten (Digital-/Analogeingänge) festlegen, die ich später über die Funktion auslesen will?

3. uiWriteAddress: Muss bei Funktionscode, bei denen nur Eingangsregister eingelesen werden, mit 0 deklariert werden!?

4. Du meintest, dass ich je ein Array "Joblist" und "ReponseList" erstellen sollte und dann mittels Laufvariable den Baustein aufrufen soll.
Das Array Joblist muss ich also an den Baustein utQuery vom Masterbaustein - das Array Responselist entsprechend an utResponse des Bausteins deklarieren?

5. Was ich grundsätzlich nicht verstehe ist, dass ich die Werte für die Analogwerte wirklich einfach auslesen kann (über PRG_FbMbMasterTCP.utResponse.awData[0] für Kanal 1 bzw. awData[0] für Kanal 2 der 1. Analogeingangskarte). Jetzt habe ich auf dem Feldbuskoppler eine DO Karte. Ich habe versucht mit Kanal 1 der Digital-Ausgangskarte versucht das Register RG_FbMbMasterTCP.awWriteData[512].0 auf 1 zu setzen (Kanal 1 sollte eingeschaltet werden, Startadresse des Schreibregisters habe ich mit 512 angegeben). Das funktioniert aber nicht (Fehlermeldung: utQuery ist kein Eingang von 'PRG_FbMbMasterTCP'). Was mache ich falsch?

6. Ich habe ein Problem mit der Firmware zwischen Projekt- und Controller. Jedes mal, wenn ich das Projekt neu öffne, muss ich die Firmware unter den Gerätedaten des Controllers wieder auf 20(09) ändern (siehe Anhang). Wie kann ich das Problem beheben?


Wieder eine Menge an Fragen, die sich angesammelt haben. Ich hoffe trotzdem verständlich. :p
 

Anhänge

  • FirmwareVersionProblem.png
    FirmwareVersionProblem.png
    25,7 KB · Aufrufe: 76
Zuletzt bearbeitet:
HAllo,
Hallo nochmal,


@Thruser: Deine Anleitung hat super funktioniert und somit konnte ich die Temperaturwerte vom Feldbuskoppler bereits einlesen. Wie das funktioniert habe ich nun auch verstanden.
schön zu lesen.

Die grundsätzliche Idee habe ich verstanden. Es gibt Konstantenregister und andere feste Register (z.B. MAC Adresse lesen o.Ä.), die feste HEX Werte zurückgeben (mit QModmaster probiert - hat geklappt!).
Wie ich den Aufbau der Job- und Responselist aufbauen soll, ist mir aber unklar.
Ich versuch mal etwas fertig zu machen. Sehe aber auch gerade das ich da oben ein Fehler gemacht habe. Die Joblist muß natürlich als typMbQuery angelegt werden, nicht als typMbResponse.


Meine Fragen dazu:
1. bFunctionCode := 16#04 ist ein Eingangsregister, bei dem man eine Anzahl von Eingangsworten lesen kann (d.h. Analogeingänge! Oder auch Digitaleingänge?!).
Die Funktion 01 liest Ein- und Ausgangsbits. Entsprechend lediglich Digitalein- und Ausgänge? Habe ich das so richtig verstanden?
Ich habe es jetzt einmal ausprobiert, mit der Funktion lassen sich sowohl die Analog- und Digitaleingänge lesen. Als erstes kommen die komplexen (unter anderen analogen) Eingänge, dahinter dann die digitalen. Es ist egal ob man FC 3 oder FC 4 nimmt, s.a. Handbuch, mit beiden Funktionscodes werden dieselben Daten gelesen.


Ich habe hier jetzt einen Aufbau: 750-352 (Koppler), 750-602 (Einspeiseklemme), 750-400 (2 DI), 750-501 (2 DO), 750-472 (2 AI), 750-600 (Endklemme)

Mit FC 3/FC 4, Adresse 0 und Länge 3 Register bekommt man an Adresse 0 den ersten Kanal von der 472 (IW0), an Adresse 1 den zweiten Kanal (IW1) und an Adresse 2 dann die beiden digitalen Eingänge von der 400 (IW2). Der erste digitale Eingang liegt da auf Bit 0 der zweite auf Bit 1.
Auch den Zustand der Ausgänge läßt sich mit den beiden Funktionscodes auslesen. Die 501 liegt auf Adresse 512 (QW0).


Zusätzlich kann man die digitalen Ein- und Ausgänge noch über die Coil- (Bitzugriff-) Funktionen ansprechen. So kann man die Eingänge der 400 über FC 1/FC 2 ab Adresse 0 lesen. Adresse 0 ist der erste digitaler Eingang, Adresse 1 der zweite. Auch die Ausgänge lassen sich lesen, die 501 liegt auf den Adressen 512 und 513.


Ähnliches gilt für die Ausgänge. Die digitalen Ausgänge können über FC 6/FC 16 (Registerzugriff, 501 auf Adresse 512) und FC 5/FC 15 (Bitzugriff, Adresse 0 und 1) gesetzt werden.


Kannst Du auch schön mit qModMaster ausprobieren.


2. uiReadAddress: Wenn ich keine Konstantregister oder MAC-Adressen auslesen will (wie in deinem Beispiel) - muss ich hier die Adressen meiner Eingangskarten (Digital-/Analogeingänge) festlegen, die ich später über die Funktion auslesen will?
Ja, wie oben beschrieben. Der erste analoge (komplexe) Kanal liegt auf Adresse 0.

3. uiWriteAddress: Muss bei Funktionscode, bei denen nur Eingangsregister eingelesen werden, mit 0 deklariert werden!?
Wahrscheinlich nicht, wäre aber vielleicht besser. Mußt Du ausprobieren.

4. Du meintest, dass ich je ein Array "Joblist" und "ReponseList" erstellen sollte und dann mittels Laufvariable den Baustein aufrufen soll.
Das Array Joblist muss ich also an den Baustein utQuery vom Masterbaustein - das Array Responselist entsprechend an utResponse des Bausteins deklarieren?
Fast richtig. Nicht das ganze Array, sondern nur ein ein Element davon. Daher die Zählvariable.

5. Was ich grundsätzlich nicht verstehe ist, dass ich die Werte für die Analogwerte wirklich einfach auslesen kann (über PRG_FbMbMasterTCP.utResponse.awData[0] für Kanal 1 bzw. awData[0] für Kanal 2 der 1. Analogeingangskarte).
OK, schon mal gut.

Jetzt habe ich auf dem Feldbuskoppler eine DO Karte. Ich habe versucht mit Kanal 1 der Digital-Ausgangskarte versucht das Register RG_FbMbMasterTCP.awWriteData[512].0 auf 1 zu setzen (Kanal 1 sollte eingeschaltet werden, Startadresse des Schreibregisters habe ich mit 512 angegeben). Das funktioniert aber nicht (Fehlermeldung: utQuery ist kein Eingang von 'PRG_FbMbMasterTCP'). Was mache ich falsch?
Da ist jetzt im Text etwas durcheinander geraten.
Du hast eine Variable utQuery vom Typ typMbQuery und eine Variable utResponse vom Typ typMbResponse erstellt? Die mußt Du dann den jeweiligen Eingängen vom FbMbMasterTCP zuweisen.


Wenn Du als Adresse 512 angibst (sollte die richtige sein für den Registerzugriff), dann mußt Du das Bit utQuery.awWriteData[0].0 setzen. Nicht awWriteData[512].0.


Jetzt kommt es noch darauf an, über welchen Funktionscode Du den Ausgang ansprechen willst. Bit- oder Registerzugriff, ein oder mehrere Zugriffe mit einem Auftrag. Gerade bei den Bitzugriffen mußt Du das mal ausprobieren wo Du welche Daten reichschreiben mußt, da ich gerade nicht weiß wie Wago da die Daten im awWriteData organisiert. Beim Funktionscode 15 müssen die Daten nämlich Byteweise organsisiert werden. D.h. bis 8 Coils wird nur 1 Byte gesendet, bis 16 Coils 2 Byte also 1 Word, 24 Coils dann 3 Byte (1,5 Word) etc. Wago hat das Array aber auf Word aufgebaut, so daß man mal ausprobieren muß wo denn jetzt das Bit für den ersten Kanal abgelegt werden muß im unteren Teil awWriteData[0].0 oder im oberen awWriteData[0].8. Das müßte man aber auch aus der Antwort von mehreren Coils lesen ableiten können.

6. Ich habe ein Problem mit der Firmware zwischen Projekt- und Controller. Jedes mal, wenn ich das Projekt neu öffne, muss ich die Firmware unter den Gerätedaten des Controllers wieder auf 20(09) ändern (siehe Anhang). Wie kann ich das Problem beheben?
Da kann ich jetzt nicht helfen. Aber Du könntest auch die neue Firmware auf den Controller aufspielen. Die kannst Du beim Wago Support anfordern.


Ich hoffe das hilft erst einmal. Wenn ich dazu komme versuche ich die Woche mal selbst ein Beispielprogramm zu schreiben und hier dann einfügen.


Gruß
 
Hallo Thruser,

vielen Dank nochmal für deine schnelle Antwort und die ganzen detaillierten Antworten auf meine Fragen.

Ich habe es jetzt einmal ausprobiert, mit der Funktion lassen sich sowohl die Analog- und Digitaleingänge lesen. Als erstes kommen die komplexen (unter anderen analogen) Eingänge, dahinter dann die digitalen. Es ist egal ob man FC 3 oder FC 4 nimmt, s.a. Handbuch, mit beiden Funktionscodes werden dieselben Daten gelesen.


Ich habe hier jetzt einen Aufbau: 750-352 (Koppler), 750-602 (Einspeiseklemme), 750-400 (2 DI), 750-501 (2 DO), 750-472 (2 AI), 750-600 (Endklemme)

Mit FC 3/FC 4, Adresse 0 und Länge 3 Register bekommt man an Adresse 0 den ersten Kanal von der 472 (IW0), an Adresse 1 den zweiten Kanal (IW1) und an Adresse 2 dann die beiden digitalen Eingänge von der 400 (IW2). Der erste digitale Eingang liegt da auf Bit 0 der zweite auf Bit 1.
Auch den Zustand der Ausgänge läßt sich mit den beiden Funktionscodes auslesen. Die 501 liegt auf Adresse 512 (QW0).


Zusätzlich kann man die digitalen Ein- und Ausgänge noch über die Coil- (Bitzugriff-) Funktionen ansprechen. So kann man die Eingänge der 400 über FC 1/FC 2 ab Adresse 0 lesen. Adresse 0 ist der erste digitaler Eingang, Adresse 1 der zweite. Auch die Ausgänge lassen sich lesen, die 501 liegt auf den Adressen 512 und 513.


Ähnliches gilt für die Ausgänge. Die digitalen Ausgänge können über FC 6/FC 16 (Registerzugriff, 501 auf Adresse 512) und FC 5/FC 15 (Bitzugriff, Adresse 0 und 1) gesetzt werden.

Dann bin ich zumindestens nicht ganz auf dem Holzweg. Verstanden, check!

Kannst Du auch schön mit qModMaster ausprobieren.

Ausprobiert, verstanden, check! ;)


Ich habe jetzt folgendes im Quellcode implementiert:

FOR-Schleife für Zählvariable
// Ausprobiert, bei fallender Flanke geht iIncrement aber nicht auf TRUE. Der Rest soll den 1. Ansatz zeigen.

FOR iCounter := 0 TO 1 BY 1 DO
FTRIG_0 (CLK:= xTxTrigger);
iIncrement := FTRIG_0.Q
IF iIncrement := TRUE THEN

utQuery := Joblist ; // Hier muss ich utQuery mit dem jeweiligen Array von Joblist ([0] oder [1]) initialisieren, richtig?
Responselist := utResponse; // Rückmeldung wird ins Array Responselist geschrieben
iCounter := iCounter + 1;
END_IF;
END_FOR;
iCounter := 0; // Nach Schleifendurchlauf, starte bei iCounter = 0



Initialisierung von Joblist und Responselist
// Da erscheint einiges an Fehlermeldungen. Das soll aber mein aktuelles Verständnis zeigen
Joblist : ARRAY[0..1] OF typMbQuery := ( bUnitId := 0, // Slaveaddress
bFunctionCode := 16#04, // Read Input Registers
uiReadAddress := 0, // Startaddress
uiReadQuantity := 5, // Quantity of wanted registers --> 2x Analogeingänge mit IW0-4, 1x Digitaleingang IW5
uiWriteAddress := 0, // not needed for FC4
uiWriteQuantity := 0, // not needed for FC4
awWriteData := [124(0)] // not needed for FC4
),
(
bUnitId := 0, // Slaveaddress
bFunctionCode := 16#05, // Read Input Registers
uiReadAddress := 0, // Startaddress
uiReadQuantity := 0, // Quantity of wanted registers
uiWriteAddress := 512, // not needed for FC4
uiWriteQuantity := 1, // not needed for FC4 --> 1x Digitalausgang IW0
awWriteData := [124(0)] // not needed for FC4
);
Responselist : ARRAY[0..1] OF typMbResponse;


Ich weiß nicht ob ich einfach nur ein schlechter Programmierer bin, mir die Erfahrung mit der Feldbuskommunikation fehlt oder ich das auf die fehlenden Anwendungsbeispiele für die Kommunikation über e!COCKPIT schieben soll. Vielleicht auch alles zusammen! Aktuell schaffe ich es zumindest nicht, mir aus dem Netz nützliche Informationen zu schnappen, trotz durchwälzen von Datenblättern usw.Die Hilfe hier ist auf jeden Fall gerade gold Wert.Beste Grüße,
aki09
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Hi,
Hallo Thruser,

vielen Dank nochmal für deine schnelle Antwort und die ganzen detaillierten Antworten auf meine Fragen.


Dann bin ich zumindestens nicht ganz auf dem Holzweg. Verstanden, check!

Ausprobiert, verstanden, check!
dann lohnt sich der Aufwand wenigstens ;)

FOR-Schleife für Zählvariable
// Ausprobiert, bei fallender Flanke geht iIncrement aber nicht auf TRUE. Der Rest soll den 1. Ansatz zeigen.

FOR iCounter := 0 TO 1 BY 1 DO
FTRIG_0 (CLK:= xTxTrigger);
iIncrement := FTRIG_0.Q
IF iIncrement := TRUE THEN
utQuery := Joblist ; // Hier muss ich utQuery mit dem jeweiligen Array von Joblist ([0] oder [1]) initialisieren, richtig?
Responselist := utResponse; // Rückmeldung wird ins Array Responselist geschrieben
iCounter := iCounter + 1;
END_IF;
END_FOR;
iCounter := 0; // Nach Schleifendurchlauf, starte bei iCounter = 0
gleich mehrere Fehler!

Code am besten in CODE Tags (der Knop mit der Raute #) schreiben wegen der Darstellung. Die kursive Darstellung hilft aber auch schon einmal.

Dann die for Schleife zu verwenden ist falsch. Die wird in jedem Zyklus komplett abgearbeitet. Dazu kommt, daß das inkrementieren von iCounter so nicht notwendig ist, da der Wert autoinkrementiert wird durch die 'BY 1' Anweisung. So wird gleich von 0 auf 2 hochgezählt, die for Schleife wird also sogar nur einmal durchlaufen. Auch muß am Ende iCounter nicht unbedingt explizit auf 0 gesetzt werden, das passiert bereits bei der Initialisierung der Schleife, außer Du verwendest sie noch einmal.

Beim If statement machst Du auch eine Zuweisung und keinen Vergleich iIncrement = TRUE wäre richtig. Ich vermute jetzt aber auch noch, daß Du iIncrement als Integer deklariert hast, wegen des kleinen i am Anfang. Verwenden tust Du die Variable aber als bool.

Code:
FTRIG_0 (CLK:= xTxTrigger);       //auf fallende Flanke warten
IF FTRIG_0 THEN                   //wenn fallende Flanke kommt
  iCounter = iCounter +1;         //Jobcounter erhöhen
  IF iCounter > maxJobs THEN      //alle Jobs durch, dann wieder beim ersten anfangen
    iCounter := 0;
  END_IF
  xTxTrigger := TRUE;             //nächste Anfrage/Job starten
END_IF

FbMbMasterTCP Bausteinaufruf (utQuery=>Joblist[iCounter], utResponse=>Responselist[iCounter], ...) //genauen Aufruf mußt Du gucken
versuch das mal so. Als maxJobs mußt Du die höchste Zahl der Jobs verwenden, hier in dem Beispiel 1. Man könnte auch mit Modulo arbeiten, dann fällt da die weitere If Abfrage weg.

Initialisierung von Joblist und Responselist
// Da erscheint einiges an Fehlermeldungen. Das soll aber mein aktuelles Verständnis zeigen
Joblist : ARRAY[0..1] OF typMbQuery := ( bUnitId := 0, // Slaveaddress
bFunctionCode := 16#04, // Read Input Registers
uiReadAddress := 0, // Startaddress
uiReadQuantity := 5, // Quantity of wanted registers --> 2x Analogeingänge mit IW0-4, 1x Digitaleingang IW5
uiWriteAddress := 0, // not needed for FC4
uiWriteQuantity := 0, // not needed for FC4
awWriteData := [124(0)] // not needed for FC4
),
(
bUnitId := 0, // Slaveaddress
bFunctionCode := 16#05, // Read Input Registers
uiReadAddress := 0, // Startaddress
uiReadQuantity := 0, // Quantity of wanted registers
uiWriteAddress := 512, // not needed for FC4
uiWriteQuantity := 1, // not needed for FC4 --> 1x Digitalausgang IW0
awWriteData := [124(0)] // not needed for FC4
);
Responselist : ARRAY[0..1] OF typMbResponse;
Muß ich mal selbst aufbauen am System, kann ich aber erst heute abend. awWriteData kommt mir noch etwas komisch vor.

Ich weiß nicht ob ich einfach nur ein schlechter Programmierer bin, mir die Erfahrung mit der Feldbuskommunikation fehlt oder ich das auf die fehlenden Anwendungsbeispiele für die Kommunikation über e!COCKPIT schieben soll. Vielleicht auch alles zusammen! Aktuell schaffe ich es zumindest nicht, mir aus dem Netz nützliche Informationen zu schnappen, trotz durchwälzen von Datenblättern usw.Die Hilfe hier ist auf jeden Fall gerade gold Wert.Beste Grüße,
aki09

Sagen wir mal fehlende Erfahrung, obwohl mit der for Schleife hast Du Dich ziemlich vertan. Rest ist einfach daß man Erfahrung benötigt wie man mit Aktionen arbeitet, die über mehrere Zyklen gehen. Zusätzlick kommt hier jetzt noch dazu wie man die verschiedenen Baugruppen am entfernten Knoten anspricht.

Gruß
 
So,

habe etwas Zeit gefunden das jetzt mal umzusetzen.

Meine Kofiguration (Module) ist noch die gleiche wie oben. Mein Master ist eine 750-8204, mit der 750-8101 sollte es aber keinen Unterschied machen. Ich schreibe das jetzt mal direkt hier in ST rein, anstatt es als Projekt hochzuladen.

PLC_PRG:
Code:
PROGRAM PLC_PRG
VAR
    Ain1:WORD;
    Ain2:WORD;
    Din1:BOOL;
    Din2:BOOL;
    Din:WORD;
    
END_VAR

// Unterprogramm ModbusMaster aufrufen
ModbusMaster();

//Antworten der Eingänge auf lokale Variable kopieren
Ain1:=ModbusMaster.Responseliste[0].awData[0];
Ain2:=ModbusMaster.Responseliste[0].awData[1];
Din:=ModbusMaster.Responseliste[0].awData[2];
Din1:=ModbusMaster.Responseliste[0].awData[2].0;
Din2:=ModbusMaster.Responseliste[0].awData[2].1;

//Setzen von Ausgängen am entfernten Knoten
//um mehrere Ausgänge zu setzen etwas rumgespiele:
//beide digitalen Eingänge = 0 (0) -> erster Ausgang = 1, zweiter = 0 (1)
//erster dig. Eingang =1, zweiter = 0 (1) -> erster Ausgang = 0, zweiter = 1 (2)
//erster dig. Eingang =1, zweiter = 1 (3) -> erster Ausgang = 0, zweiter = 0 (4->0)
//erster dig. Eingang =0, zweiter = 1 (2) -> erster Ausgang = 1, zweiter = 1 (3)

ModbusMaster.Jobliste[1].awWriteData[0]:=Din+1;

ModbusMaster (PRG)
Code:
PROGRAM ModbusMaster
VAR_INPUT
    Jobliste: ARRAY [0..1] OF typMbQuery := [ 
        ( //JOB 0, Eingänge lesen (Registerzugriff, inklusive digitale Eingänge)
            bUnitId:= 1, 
            bFunctionCode:= 4, 
            uiReadAddress:= 0, 
            uiReadQuantity:= 3, 
            uiWriteAddress:= 0, 
            uiWriteQuantity:= 0, 
            awWriteData:= [125(0)]
        ),
        ( //JOB 1, Ausgänge schreiben (Registerzugriff)
            bUnitId:= 1, 
            bFunctionCode:= 16, 
            uiReadAddress:= 0, 
            uiReadQuantity:= 0, 
            uiWriteAddress:= 512, 
            uiWriteQuantity:= 1, 
            awWriteData:= [125(0)]
        )];
END_VAR
VAR
    iJobCounter:INT:=0;
    xTrigger:BOOL:=TRUE;
    FB_F_Trig:F_Trig;
    
    Responseliste:ARRAY [0..1] OF typMbResponse;
            
    FB_ModbusMasterTCP:FbMbMasterTcp;
END_VAR

//Aufruf des Kommunikationsbausteins
FB_ModbusMasterTCP (xConnect:=TRUE, 
                    sHost:='192.168.12.114', 
                    wPort:=502, 
                    eFrameType:=eMbFrameType.Ethernet, 
                    tTimeOut:=T#2S, 
                    utQuery:=Jobliste[iJobCounter], 
                    xTrigger:=xTrigger, 
                    utResponse:=Responseliste[iJobCounter]);

//Auf Jobende warten
FB_F_Trig (clk:=xTrigger);

//Jobende erfolgt, nächsten Job starten
IF FB_F_Trig.Q THEN
    xTrigger :=TRUE;
    iJobCounter := (iJobCounter+1) MOD 2;
END_IF

Um die Daten in das ModbusMaster Programm schreiben zu können mußte ich die Jobliste als Input deklarieren. Für den JobCounter wollte ich keine If Abfrage nehmen, daher der Modulo. Bei mehr Jobs muß der Moduloteiler entsprechend angepaßt werden.

Da läßt sich noch so einiges verbessern, gerade auch mit den zuweisen der Daten, aber so hast Du jetzt mal ein Anhaltspunkt.

Wie Du siehst habe ich weiter oben auch ein Fehler mit dem Jobliste Array gemacht. Das ganze mußte mit in die eckigen Klammern. So läuft es aber bei mir.

Gruß
 
Hallo Thruser,

vielen Dank für die ganze Mühe, die du dir hier gemacht hast. Ich habe mir deine Programmierung mal angesehen und auf meine Steuerung übertragen - funktioniert einwandfrei.
Mit dem Grundkonzept bin ich zumindest jetzt auf einem Stand, um eigenständig daran weiterarbeiten zu können.

Vielen Dank dafür und ein schönes Wochenende! :)
 
Hallo nochmal,

mittlerweile bin ich schon ein paar Schritte weiter. Die Kommunikation zwischen Feldbuscontroller und Koppler läuft und ist soweit programmiert. Jetzt möchte ich eine weitere Modbus Verbindung zwischen einem "Nicht-Wago"-Modbusteilnehmer und dem Controller aufbauen und dafür die Eingänge und Ausgänge des Controllers schreiben / lesen.

Dafür habe ich den Baustein "mySimpleTCPServer" verwendet in denen die folgenden Variablen initialisiert werden:
Code:
// Programm: ModbusSlave
    //------------------------------------------------------------------------------------
    myDiscreteInputs    :   ARRAY[0..20] OF BOOL;       // Modbus bit address 0 .. 20
    myCoils             :   ARRAY[0..20] OF BOOL;       // Modbus bit address 0 .. 20
    myInputRegisters    :   ARRAY[0..20] OF WORD;    // Modbus word address 0 .. 20
    myHoldingRegisters  :   ARRAY[0..20] OF WORD;       // Modbus word address   0 .. 20
    //------------------------------------------------------------------------------------

Soweit ich verstanden habe, kann ich die Klemmen des Controllers mit den 4 Registern (DiscreteInputs, Coils, InputRegisters, HoldRegisters) deklarieren. Dafür habe ich folgenden Code geschrieben:

Code:
// Digitale Ausgänge
IoConfig_Globals_Mapping.xOut11 := ModbusSlave.myCoils[0];
IoConfig_Globals_Mapping.xOut12 := ModbusSlave.myCoils[1];
IoConfig_Globals_Mapping.xOut21 := ModbusSlave.myCoils[2];
IoConfig_Globals_Mapping.xOut22 := ModbusSlave.myCoils[3];

// Analoge Eingänge
xTemp11 := INT_TO_WORD(IoConfig_Globals_Mapping.xTemp11);     --> hab versucht mir das "zurechtzufuschen", aber auch das klappt nicht :eek:
ModbusSlave.myInputRegisters[0] := IoConfig_Globals_Mapping.xTemp11;

1. Die digitalen Ausgänge kann ich damit schreiben (-> OK). Ist diese Art der Initialisierung denn auch so vorgesehen, dass ich das myCoil[0..3] mit je einem Digitalausgang der Klemmen verknüpfe?
2. Beim Auslesen der Temperaturen ist die Klemmenvariable "IoConfig_Globals_Mapping.xTemp11" als INT deklariert (vorzeichenbehaftet, Klemme ist ein AI für Temperatur TYP K Messung), das Register "ModbusSlave.myInputRegisters[0]" aber als WORD. Ich kann mir beim besten Willen nicht vorstellen, dass man die Klemmen mit den Registern auf diese Art und Weise deklariert. Zudem funktioniert das Auslesen der Temperatureingänge mit diesem Programmcode auch nicht. Fehler: "PLC_PRG: C0037: 'myInputRegisters' ist kein Eingang von 'ModbusSlave' (-> NOK)

Beste Grüße
 
Zuletzt bearbeitet:
Hallo,

groß weiterhelfen kann ich Dir da jetzt auch erst einmal nicht. Das müßte ich mir auche erst einmal ansehen. Habe sowieso noch nicht viel mit e!cockpit gemacht.

Sehe ich das richtig, daß Du jetzt von einem anderen Gerät per Modbus auf den Controller zugreifen willst? Der Controller jetzt also als Slave/Server arbeiten soll?

Ich würd da jetzt mal den entsprechenden Teil des Konfigurator nehmen.

Ansonsten kann ich mir das erst zum Ende nächster Wocheansehen.

Zudem funktioniert das Auslesen der Temperatureingänge mit diesem Programmcode auch nicht. Fehler: "PLC_PRG: C0037: 'myInputRegisters' ist kein Eingang von 'ModbusSlave' (-> NOK)
Du hast myInputRegisters wahrscheinlich nicht als VAR_INPUT deklariert. Das hatte ich damals auch bei der Jobliste.

Gruß
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen,

mittlerweile bin ich ein paar Schritte weitergekommen. Jetzt fehlt mir aber noch ein Punkt, für die ich noch keine Lösung gefunden habe.

Rückfrage zum gleichzeitigen Schreiben/Lesen von Modbus Registern
Ich benötige ein Feedback für die digitalen/analogen Ausgänge von meinem externen Endgerät. Hintergrund ist, dass ich sowohl vom Endgerät, als auch vom PFC die Ausgänge steuern möchte und dafür ein Feedback ("Ist der Ausgang jetzt an oder aus?!") benötige. Im Handbuch habe ich dafür folgenden Hinweis gefunden:

Hinweis: „Lesen und Schreiben der Ausgänge bei FC1 bis FC4 auch durch Hinzuaddieren eines Offsets möglich! Bei den Lesefunktionen (FC1 ... FC4) können Sie zusätzlich die Ausgänge schreiben und zurücklesen, indem Sie für Adressen in dem Bereich [0 hex ... FF hex] ein Offset von 200hex (0x0200) und für Adressen in dem Bereich [6000 hex ... 62FChex] ein Offset von 1000hex (0x1000) zu der MODBUS-Adresse hinzu addieren“

Meine Frage:
Wie schaffe ich es, dass ich auf ein Modbus Register sowohl lesen, als auch schreiben kann? Wie ist das mit dem Offset genau gemeint? Mein Lösungsansatz, bei dem ich aber ab Adresse 0 schreibe und ab Adresse 512 lese (=> Offset von 0 + 512 = 512?):

Code:
PROGRAM ModbusMaster
VAR
FB_ModbusMasterTCP:FbMbMasterTcp;
       Jobliste: ARRAY [0..1] OF typMbQuery := [ 
        ( //JOB 0, Eingänge lesen (Registerzugriff, inklusive digitale Eingänge)
            bUnitId:= 1, 
            bFunctionCode:= 4,   // FC4 'Read Input Registers' -> Lesen der digitalen und analogen Eingänge
            uiReadAddress:= 0, 
            uiReadQuantity:= 3, 
            uiWriteAddress:= 0, 
            uiWriteQuantity:= 0, 
            awWriteData:= [125(0)]
        ),
        ( //JOB 1, Ausgänge schreiben/lesen (Registerzugriff)
            bUnitId:= 1, 
            bFunctionCode:= 1,     // FC1 'Force Multiple Coils' -> Schreiben & Lesen der Register
            uiReadAddress:= 512, 
            uiReadQuantity:= 4, 
            uiWriteAddress:= 0, 
            uiWriteQuantity:= 4, 
            awWriteData:= [125(0)]
        )];
        Responseliste:ARRAY [0..1] OF typMbResponse;
    
        // Um Array "Jobliste" und "Responseliste" zu triggern     
        iJobCounter:INT:=0;
        xTrigger:BOOL:=TRUE;
        FB_F_Trig:F_Trig;
END_VAR

Bei der Modbus Verbindung zwischen meinem externen Endgerät und einem 352 lässt sich das alles in einem Register (schreiben/lesen) umsetzen. Von meinem externen Endgerät wird das auch sofort erkannt, wenn der Zustand sich ändert. Was muss ich dafür beim PFC tun, damit ich das Feedback dort auch bekomme?
 
Zuletzt bearbeitet:
Ich sehe da aktuell ein Problem beim Aufbau des Netzwerks, wodurch ich Probleme mit dem "Feedback" der digitalen und analogen Ausgänge bekomme. Ich vermute, dass ich bei dem derzeitigen Programmaufbau grundlegend etwas falsch gemacht habe und ich da erstmal ansetzen muss.

Was habe ich gemacht?
3 POUs habe ich derzeit eingebunden (PLC_PRG, ModbusMaster mit dem ModbusMasterTCP-Funktionsbaustein, ModbusSlave mit dem SimpleTCPServer-Funktionsbaustein).

Folgende Idee steckt dahinter:
- Externes Endgerät soll als Master gegenüber PFC und FC arbeiten
- PFC soll als Slave zum externen Endgerät arbeiten und als Master zum Koppler
- Sowohl PFC, als auch Endgerät sollen Ausgänge steuern (Endgerät ist höher priorisiert!)

Was funktioniert und was nicht?
- Das Lesen der digitalen/analogen Eingänge funktioniert einwandfrei -> OK
- Das Schreiben der digitalen/analogen Ausgänge (auf PFC) funktioniert, wenn ich vom Endgerät aus schreibe und/oder vom PFC (über e!COCKPIT). In e!COCKPIT sehe ich auch die Zustandsänderung des Ausgangs, wenn ich vom Endgerät aus schalte. -> OK
- Auf externem Endgerät sehe ich keine Zustandsänderung, wenn ich von e!COCKPIT die Ausgänge ansteuere. Weder bei den Ausgängen des PFCs, noch bei den des FCs (Feedback fehlt!). -> NOK
- Das Schreiben vom Endgerät auf FC funktioniert prinzipiell, allerdings setzt mein Programm den Ausgang direkt wieder zurück. Ich habe keine Ahnung, wie ich das verhindern kann. -> NOK

Ich verzweifle gerade wirklich an diesem fehlendem Feedback und das ich vom externen Endgerät nicht die Ausgänge des FCs vernünftig anteuern kann.

Ansatz zur Problemlösung
Ich würde versuchen vom Endgerät in Zukunft in die Merker-Register zu schreiben (als Ausgänge deklariert), die über e!COCKPIT auszulesen und dann von dort aus in die Modbus-Prozessabbilder zu schreiben? Am Montag möchte ich das mal versuchen. Beim FC fängt MX0 bei 0x3000 bzw 12288 an. Wieso finde ich das im Manual vom PFC nicht?
 
Zuletzt bearbeitet:
Problem gelöst:
Externes Endgerät als Master und PFC als Slave konfiguriert. Verbindung zwischen generischem Modbus Master (externem Endgerät) via Feldbuskonfigurator machen (mit Linie verbinden).
Über SimpleServerTCP lassen sich die Modbus Adressen, je nach Deklarierung der Arrays (InputRegister[0..10] = Modbusadresse 0..10) in die passenden Adressregister schreiben.

Mein Beispiel Code:
Code:
[I]// Deklarierung von Modbus Telegrammen (von externem Endgerät) in Merker-Register (Adressbereich 0..20)[/I]
[I]// Eingehende Modbus Telegramme von MSE (Master)[/I]
[I]Merker1_IN_REG := ModbusSlave.myHoldingRegisters[0];[/I]
[I]Merker2_IN_REG := ModbusSlave.myHoldingRegisters[1];[/I]
[I]Merker3_IN_COIL := ModbusSlave.myCoils[0];[/I]
[I]Merker4_IN_COIL := ModbusSlave.myCoils[1];[/I]
 
[I]// Deklarierung von Modbus Telegrammen (von Endgerät) in Merker-Register (Adressbereich 0..20)[/I]
[I]// Ausgehende Modbus Telegramme von PFC (Slave), Anfrage von MSE (Master)[/I]
[I]ModbusSlave.myInputRegisters[0] := Merker1_OUT_REG;[/I]
[I]ModbusSlave.myInputRegisters[1] := Merker2_OUT_REG;[/I]
[I]ModbusSlave.myDiscreteInputs[0] := Merker3_OUT_COIL;[/I]
[I]ModbusSlave.myDiscreteInputs[1] := Merker4_OUT_COIL;[/I]
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Servus,
es passt zwar nicht ganz zu der ersten Frage, aber habe ein ähnliches Problem mit der PFC 200.

Habe ein Problem mit der Modbusauslesung von digitalen Werten.

Habe eine CPU 750-8202 und mehrere Feldbuskoppler 750-352.



Die analogen Werte können über Modbus TCP oder UDP ausgelesen werden, die digitalen Werte können nicht abgefragt werden.



Habe den Koppler 750-342 mit dem 750-352 ausgetauscht und es funktioniert.



Habe den selben Versuch mit Codesys V2.3 gestartet, und ich kann alles lesen.

Alle Eingänge können gelesen werden und Ausgänge kann ich über die Koppler schreiben.



Sobald ich die Koppler mit E-Cockpit auslesen möchte kommen nur die Zustände von dem Koppler 342.

Die Koppler 352 zeigen mir alle Zustände über IO-Check an, aber im Programm werden keine Zustände angezeigt.


Die einzelnen Variablen sind über den Modbus Konfigurator veröffentlicht und sind als Read Only deklariert.


Das kann doch nicht sein?

Worin liegt der Fehler?

Danke im Voraus, Tom
 
Zurück
Oben