Modbus TCP/IP mit Beckhoff BX9000

Draco Malfoy

Well-known member
Beiträge
1.168
Punkte Reaktionen
80
Zuviel Werbung?
->Hier kostenlos registrieren
Hallo Forum!

Ich habe derzeit ein folgendes DICKES Problem, daß ich versuche den Aufbau von Modbus TCP/IP Verbindung aus folgendem Beckhoff Beispiel (Modbus Client, zum Download am Ende des Artikels) http://infosys.beckhoff.com/index.p...tcplccontrol/html/tcplcctrl_editorcfc.htm&id= zu entknobeln. Leider, absolut erfolglos, wobei mir scheint, daß die "coolen und lässigen" Beckhof-Programmierer dieses Ergebnis auch so beabsichtigt haben.

Ich verstehe in diesem Programmcode rein GAR NICHTS. Mangels IRGENDWELCHER Kommentare, muss man hier wohl jeden einzelnen Byte raten und back-ingeneeren. Mich kotzt das absolut an, daß diese besch* Beckhoff-Informatiker sich nicht einmal die Mühe gegeben haben, ihren Gekritzel wenigstens mit vernünftigen Kommentaren zu versehen. Ich raffe es nicht, was hier passiert. Kann mir das jemand erklären, wie der Aufbau einer Modbus TCP/IP Verbindung unter Beckhoff TwinCat funktioniert ?

Ein Koststück, aus dem Code:

IF NOT bBusy AND fb_Flanke.Q THEN
bBusy:=TRUE;
bError:=FALSE;
nErrId:=0;
cbRead:=0;
i:=10;
ReqBuf[0]:=nUnitID;
ReqBuf[1]:=23;
ReqBuf[3]:=WORD_TO_BYTE(nMBReadAddr AND 16#FF);
ReqBuf[2]:=WORD_TO_BYTE(ROR(nMBReadAddr,8) AND 16#FF);
ReqBuf[5]:=WORD_TO_BYTE(nReadQuantity AND 16#FF);
ReqBuf[4]:=WORD_TO_BYTE(ROR(nReadQuantity,8) AND 16#FF);
ReqBuf[7]:=WORD_TO_BYTE(nMBWriteAddr AND 16#FF);
ReqBuf[6]:=WORD_TO_BYTE(ROR(nMBWriteAddr,8) AND 16#FF);
ReqBuf[9]:=WORD_TO_BYTE(nWriteQuantity AND 16#FF);
ReqBuf[8]:=WORD_TO_BYTE(ROR(nWriteQuantity,8) AND 16#FF);
ReqBuf[10]:=WORD_TO_BYTE(nWriteQuantity*2);
Result:=MEMCPY(ADR(ReqBuf[11]),pSrcAddr, cbSrcLength);
IF SwapWORD THEN
FOR Swap:=0 TO ReqBuf[10]-1 BY 2 DO
Merker:=ReqBuf[11+Swap];
ReqBuf[11+Swap]:=ReqBuf[12+Swap];
ReqBuf[12+Swap]:=Merker;
END_FOR
END_IF
END_IF

Was machen diese verdammten schleifen hier ? Welchen Sinn hat es, was die tun ??
WARUM schreibe ich in den Request Buffer irgendwelche Angaben über Länge und Adresse der Daten, wenn der Funktionsbaustein es gar nicht fordert ??

Kurzum: ich KOTZE und hoffe, daß irgenjemand es mir in vernünftiger Form erklären kann, was die Beckhoff-Informatiker sich da dabei gedacht haben, und WRAUM IN ALLER WELT es nicht einfach so gehen kann, daß ich den die Funktionsbausteine laut deren Spezifikation benutzen kann, ohne irgendwelche IF Schleifen zu fahren, deren Sinn sich mir vollkommen entzieht, und drei verschiedene Funktioonen zu benutzen (fb_Modbus_23, fb_Modbus_4, fb_Modbus_16), von denen nicht einmal für eine einzige erklärt ist, WAS sie denn GENAU tut !

Wäre für jede vernünftige Hilfe dankbar ich komme hier wie gesagt nicht weiter!
 
Zuletzt bearbeitet:
OP
Draco Malfoy

Draco Malfoy

Well-known member
Beiträge
1.168
Punkte Reaktionen
80
Grundsätzlich, mich kotzt das Informationsmanagement von Beckhoff zutiefst an. Alles lieblos zusammengewürfelt, und in einer herablassenden, undurchsichtigen Form, mit RECHTSCHREIBFEHLERN zusammengeschrieben.
Zitat hier aus: http://infosys.beckhoff.com/index.p...0/html/bt_bx_examples_bx9000_overview.htm&id=

Der Baustein FB_MBGENERICREQ ermöglicht das Senden und Empfangen beliebiger ModbusTCP Funktionen. Mit steigender Flanke von bExecute wird der Baustein aktive, das bBusy wird gesetzt und er sendet seine Daten, die im pReqBuff enthalten sind. Die Länge der zu senden Daten entnimmt der Baustein der Variable cbReqLen. Die Variable nHandle muss mit der Variable aus dem Baustein FB_MBOpen nHandle verbunden werden. Die Antwort des ModbusTCP-Servers (Slave) wird in dem pResBuff abgelegt. Die Größe der Variable sollte groß genug gewählt werden, damit alle Daten eines ModbusTCP Telegramms empfangen werden. Empfängt der ModbusClient innerhalb der tTimeout Zeit keine Antwort, so wird das bBusy auf FALSE gesetzt und das bError gesetzt. In der Variable nErrId findet man den Fehlercode. In cbResponse ist die Anzahl der Empfangenden Bytes enthalten. Diese können mit der Puffergröße der cdResLen verglichen werden. Ist cbResponse größer als dResLen gehen Daten verloren und Buffer muss größer gewählt werden.

Ah ja, interessant. Die zu sendenden Daten, angeblich enthalten in pReqBuff. Was genau ist jetzt dort enthalten, wenn diese Variable als DWORD deklariert ist ?? Die Daten ?? Oder wohl doch ein Pointer auf die Daten ??
Nicht mal die wichtigsten Sachen schaffen diese Witzbolde sauber hinzuschreiben.

Noch weitere spannende Stellen:
Die Variable nHandle muss mit der Variable aus dem Baustein FB_MBOpen nHandle verbunden werden.

Schön. Ein einziges kleines Problemchen: der Baustein FB_MBOpen ist überhaupt nirgendswo erklärt !!! Und kommt auch in deren charmantem Beispiel nicht ein einziges Mal vor !!!

Was soll ich jetzt tun ?? Try & error an einer industriellen Steuerung im laufenden Betrieb ausprobieren ?? Beckhoff direkt kontaktieren ?? Wenn die Leute am Telefon genau so kompetent und auskunftsfreundlich wie die Verfasser der Dokumentation sind, dann ist mir wohl nicht viel geholfen damit ?
 
Zuletzt bearbeitet:

Oberchefe

Well-known member
Beiträge
2.665
Punkte Reaktionen
479
Zuviel Werbung?
->Hier kostenlos registrieren
Was machen diese verdammten schleifen hier ? Welchen Sinn hat es, was die tun ??
der Begriff "Swap" sollte eigentlich Erklärung genug sein

pReqBuff. Was genau ist jetzt dort enthalten, wenn diese Variable als DWORD deklariert ist ?? Die Daten ?? Oder wohl doch ein Pointer auf die Daten ??
Ungarische Notation ein Begriff?

Schön. Ein einziges kleines Problemchen: der Baustein FB_MBOpen ist überhaupt nirgendswo erklärt !!! Und kommt auch in deren charmantem Beispiel nicht ein einziges Mal vor !!!

Mit ein klein wenig Phantasie aus dem "FB_MBOpen" ein "FB_MBConnect" machen

Ich verstehe in diesem Programmcode rein GAR NICHTS
kann das auch daran liegen dass Du keine Ahnung von Modbus hast?

WARUM schreibe ich in den Request Buffer irgendwelche Angaben über Länge und Adresse der Daten, wenn der Funktionsbaustein es gar nicht fordert ??

siehe oben, woher soll der Modbus Teilnehmer wissen was Du gelesen haben willst wenn Du es nicht in den Request reinschreiben willst?

und drei verschiedene Funktioonen zu benutzen (fb_Modbus_23, fb_Modbus_4, fb_Modbus_16), von denen nicht einmal für eine einzige erklärt ist, WAS sie denn GENAU tut !
ich finde jetzt auf die Schnelle nicht wo Du das her hast (Dein erster Link führt zu was anderem), ich finde diese 3 Bausteine (sehr wohl mit Erklärung was sie machen):
Der FB_MBConnect verbindet den BX9000 über ModbusTCP mit einem anderen Teilnehmer.
Der Baustein FB_MBGENERICREQ ermöglicht das Senden und Empfangen beliebiger ModbusTCP Funktionen.
Der Baustein FB_MBCLOSE ermöglicht das Schließen einer TCP/IP Verbindung.
 
OP
Draco Malfoy

Draco Malfoy

Well-known member
Beiträge
1.168
Punkte Reaktionen
80
der Begriff "Swap" sollte eigentlich Erklärung genug sein
Nein, ist mir nicht. Ich bin kein Informatiker.
Ungarische Notation ein Begriff?
Muss man dafür etwa ungarisch können ? Oder, vielleicht, eine andere nichtwestliche Muttersprache der Beckhoff-Informatiker beherrschen ?
Mit ein klein wenig Phantasie aus dem "FB_MBOpen" ein "FB_MBConnect" machen
Sorry, habe ich mich gerade vielleicht verhört oder verlesen ?
Wir reden hier von einer industriellen Steuerung, die 40t Stahl durch die Gegend bewegen muss, und die zusammen mit den Klemmen eine vierstellige Summe Geld kostet. Übrigens, von einem der führenden Hersteller.
Und die Beckhoff-Programmierer erwarten jetzt also von mir, daß ich hier Funktionsbausteine rate und wild herumphantasiere ? Ist es jetzt ein besonderer Beckhoff-Witz, den ich ich irgendwie nicht verstehe ?
kann das auch daran liegen dass Du keine Ahnung von Modbus hast?
Schwachsinn ich habe schon in einer anderen Steuerung erfolgreich Modbus implementiert. Dort gab es aber vorgefertigte Bausteine, wie zum Beispiel "Read Holding Registers". Ich habe von Schleifen und Pointern wenig Ahnung, weil ich kein Informatiker bin sondern Elektrotechniker.
ch finde jetzt auf die Schnelle nicht wo Du das her hast (Dein erster Link führt zu was anderem)
Mein Link weist exact zu dem Beispiel hin. Das gibt es am Ende der Page zum Download. Wenn Du es so nicht findest, such bitte in Beckhoff Infosys nach Programmierung / Bibliotheken /ModbusTCP Client.

Danke & Gruß, Igor
 
Zuletzt bearbeitet:
OP
Draco Malfoy

Draco Malfoy

Well-known member
Beiträge
1.168
Punkte Reaktionen
80
Ich will ja wenigstens wissen, in welchem Adressbereich ich die Daten in der BX9000 ablegen muss, sodaß sie über read holding registers von einer übergeordneten Steuerung gelesen werden können....
Gibt ja keine einizige Mapping Tabelle !!
 

Oberchefe

Well-known member
Beiträge
2.665
Punkte Reaktionen
479
Zuviel Werbung?
->Hier kostenlos registrieren
sodaß sie über read holding registers von einer übergeordneten Steuerung gelesen werden können....

das wäre ein Fall für einen Modbus-Slave(bei Beckhoff modbus TCP Server bezeichnet), die o.a. Bausteine sind aber für Modbus Master (bei Beckhoff modbus TCP Client bezeichnet)!

Programmieren braucht man da vermutlich gar nichts (zumindest ist das bei Wago so), die Variablendeklaration reicht, folgendes aus dem Beckhoff Beispielprojekt:

Code:
VAR
    M_Test1 AT %MB0:INT;
    M_Test2 AT %MB2:INT;
    M_Test3 AT %MB4:INT;
    M_Test4 AT %MB6:INT;
    (* Client write data *)
    M_Test5 AT %MB10:ARRAY[0..2] OF INT;
END_VAR

Möglicherweise muss man unter Zielsystemeinstellungen bzw. in der Steuerungskonfiguration oder in der Weboberfläche (falls er das hat) das Modbus/TCP Protokoll anhaken.
 

uncle_tom

Well-known member
Beiträge
627
Punkte Reaktionen
161
Im Infosystem gibt´s z.B. zum BX9000 eine Dokumentation.
Schaut man dann im Unterordner Ethernet nach, dann findet man dort noch einen Unterordner "Modbus_TCP".
Hier gibt´s dann ein Dokument Namens "Interface":

http://infosys.beckhoff.com/content/1031/bx9000/html/bt_ethernet modbus image.htm?id=3310

Da drin steht dann z.B., dass man den Merkerbereich des BX9000 (also %MB...) über die Modbusadressen 0x4000 - 0x47FF ansprechen kann.

Das übergeordnetete System kann also via Modbus Function Code 3 bzw. 16 über die Adressen 0x4000- 0x47FF auf die Merkeradressen 0 - 2047 zugreifen.
Du musst lediglich deine Variablen in den Merkerbereich adressieren - sonst muss nichts weiter eingestellt bzw. parametriert werden - der BX9000 hat einen fest eingebauten Modbus-Server bzw. Modbus-Slave.

Die Beschreibung zu den Modbus-Master bzw. Modbus-Client Bausteinen für den BX9000 ist wirklich nicht besonders glücklich ausgefallen.
Das hängt aber auch damit zusammen, dass es sich beim BX9000 auch "nur" um einen Busklemmen-Controller und um keine richtige Steuerung handelt.

Für die Windows-basierten Systeme (also CX und PC) gibt es einen ordentlichen Treiber, der dann auch für die einzelnen Modbus-Funktionscodes eigene Bausteine bereitstellt:
http://infosys.beckhoff.com/content/1031/tcmodbussrv/html/tcmodbussrv_client_overview.htm?id=20782
 
Zuletzt bearbeitet:
OP
Draco Malfoy

Draco Malfoy

Well-known member
Beiträge
1.168
Punkte Reaktionen
80
Zuviel Werbung?
->Hier kostenlos registrieren
Ok, sehr vielen Dank für eure Beiträge!
Damit komme ich bestimmt schon mal weiter.

Meine Idee war ja ursprünglich, die Kommunikation von BX9000 aus zu starten, also den BX als Master zu benutzen. Nachdem ich allerdings gesehen habe, wie fehlerträchtig und aufwändig hier die Implementierung ausfällt, bin ich zu dem Entschluss gekommen, das lieber von der anderen Seite zu machen, wo es mittels vorprogrammierter Funktionsbausteine ja deutlich einfacher geht.

Daher, kommt es mir gelegen, daß man die Variablen einfach direkt in den Merker-Bereich positionieren kann und gut ist. Ein Paar zusätzliche Fragen hätte ich allerdings noch, und zwar:
- Die Funktion "read holding registers" holt die Daten ja in WORDs ab, soweit ich weiß. Was ist aber, wenn ich dort boolsche Werte eintrage, und zwar mittels Direktadressierung, also Data1 AT%MX0.0, Data2 AT%MX0.1 und so weiter ?
Kann ich einfach davon ausgehen, daß je 16 Werte ein WORD bilden und dieses auch so übertragen wird ?

- Muss ich irgendwie programmmäßig ein TCP/IP Socket aufsetzen, eine IP-Adresse und SubnetMask vergeben, oder reicht hier das, was per Defaul für die Startkonfiguration eingestellt wird ? Ich meine, verwendet der Controller für die Kommunikation mit dem TwinCAT und den Config-Zugang nicht irgendwie eine andere Adresse, als für den Modbus ?

Würde mich über die Beantwortung der Fragen freuen,

Danke & Gruß

Igor
 

uncle_tom

Well-known member
Beiträge
627
Punkte Reaktionen
161
Hallo nochmal,

ich hab mit den BX´n bisher auch noch nicht gearbeitet (nur CX´n bzw. PC´s in Verbindung mit BK´s).

Bzgl. Byte-Alignment hilft wohl im Zweifelsfall nur ein Test.
Ich würde die Bitmeldungen evtl. mittels Bitzugriff in Wort-Variablen ablegen, und nur die Wortvariablen adressieren.

Also z.B. so:

Code:
WortVariable.0 := Bitmeldung_1;
WortVariable.1 := Bitmeldung_2;
...
WortVariable.15 := Bitmeldung_16;

Das ganze dann z.B. noch in eine Funktion verpackt, kann man einen evtl. Byte-Versatz schnell anpassen.

Bzgl. Einstellungen IP-Adressen, etc.:
Es muss nichts weiter programmtechnisch aufgesetzt werden.

Eine IP-Adresse musst du ja sowieso einstellen:
http://infosys.beckhoff.com/content/1031/bx9000/html/bt_bx9000_ipaddressoverview.htm?id=3160

Die IP-Adresse gilt dann auch für den Modbus-Zugriff.

Der Modbus-TCP Port ist fest auf 502 eingestellt.

Die Modbus-Slave Adresse bzw. Unit kann laut Doku nicht eingestellt werden, und ist nicht relevant - ich vermute mal der BX9000 antwortet auf alle Anfragen, unabhängig welche Slave-Adresse im Telegramm hinterlegt ist.
 
Oben