# Modbuskommunikation zwischen 2 Wago Steuerungen



## MW22 (19 April 2022)

Hallo zusammen,

ich versuche gerade, eine Modbuskommunikation zwischen 2 CPU zu verstehen / realisieren. Leider habe ich keine
Wago Controller um dies zu testen. 
Ich würde gerne Daten vom Typ: Time/real/bool/int von den jeweiligen Steuerungen lesen können. 
Mein Ansatz ist:
Auf der CPUA (Master) habe ich den Ethernet_modbusmaster_tcp erstellt.

VAR

    fbMaster_schreiben    :ETHERNET_MODBUSMASTER_TCP;
    xVerbinden_Schreiben    : BOOL:=TRUE;
    strIP_SPS_UPS_A            : STRING := '192.168.2.12';
    typMasterAnSlaveSchreiben: arComCPU;
    dwadrText: DWORD;
    xSendTrigger: BOOL;        (*geht automatisch auf False wenn fertig*)
    tWarteZeit: TIME := t#100ms;
    fbZyklischAbfragen: TON;
    xIstVerbunden: BOOL;
    wError: WORD;
    bID: BYTE;

END_VAR



Dazu habe ich ein Struct erstellt:

TYPE arComCPU :
STRUCT



    xBatteryRelayA                            :BOOL                        ;
    xBatteryRelayB                            :BOOL                        ;

    xDCDBRelayA                                :BOOL                        ;    (* Rückmeldebit *)
    xDCDBRelayB                                :BOOL                        ;    (* Rückmeldebit *)


    rChargerVoltage_A                        :REAL                        ;
    rChargerVoltage_B                        :REAL                        ;
    rLoadCurrent_A                            :REAL                        ;
    rLoadCurrent_B                            :REAL                        ;

    xNextBatteryChange                        :BOOL                        ;

END_STRUCT
END_TYPE

Wenn ich nun auf der Slave Seite das gleiche Struct erstelle kommunizieren die dann schon miteinander?

Die Structvariablen habe ich einerseits auf der A und andererseits auf der B eine feste Adresse gegeben (MX x.y / MD x ).

MfG

MW22


----------



## holgermaik (19 April 2022)

Hallo MW22
bitte beim nächsten mal Controller & Software angeben.
Ich denke mal es handelt sich um Codesys 2.3 und ein 750-8xx Controller.


MW22 schrieb:


> Wenn ich nun auf der Slave Seite das gleiche Struct erstelle kommunizieren die dann schon miteinander?


Dem Master ist es völlig Wurst ob im Slave ein Struct definiert ist.
Dein Programm schreibt in den Slave ab Adresse %MW0 - 9 Worte an Daten aus der VAriable "typMasterAnSlaveSchreiben"
.
PS:
ich würde die einzelnen Bool in einem Wort zusammenfassen.
PSS: die Zyklische Abfrage mit xSendTrigger funktioniert so nicht. Die Variable soll vom FB auf False gesetzt werden um das Ende der Funktion zu kennzeichnen. In deinem Programm schreibst du die Variable im nächsten Zyklus auf False.


----------



## MW22 (19 April 2022)

holgermaik schrieb:


> Ich denke mal es handelt sich um Codesys 2.3 und ein 750-8xx Controller.


Ja genau. codesys 2.3 und 750-890


holgermaik schrieb:


> Dem Master ist es völlig Wurst ob im Slave ein Struct definiert ist.
> Dein Programm schreibt in den Slave ab Adresse %MW0 - 9 Worte an Daten aus der VAriable "typMasterAnSlaveSchreiben"
> .


Das heist: 
Wenn ich im master struct zb xBatteryRelayA :BOOL ; drin habe.
xBatteryRelayA habe ich mit AT %MX81.0 Definiert.
Dann kann ich am Slave unter MX81.0 den wert auslesen? Habe ich das richtig verstanden?


holgermaik schrieb:


> PSS: die Zyklische Abfrage mit xSendTrigger funktioniert so nicht. Die Variable soll vom FB auf False gesetzt werden um das Ende der Funktion zu kennzeichnen. In deinem Programm schreibst du die Variable im nächsten Zyklus auf False.


Ok und wie mache ich das... ?
Den Programmcode habe ich nur kopiert von einer Wagoschulung. Der hatte dies damals so gemacht.


----------



## Tobsucht (19 April 2022)

Die zyklische Abfrage ist sicher.
Der Timer fbZyklischeAbfrage zählt doch nur, wenn keine Anfrage aktiv ist (xSendTrigger = FALSE) denn der Eingang ist negiert.
Zur Sicherheit wurde ich noch xIstVerbunden UND verknüpfen. Eventuell sogar noch negiert den Timer Ausgang. Im ungünstigen Timingfall wird sonst xSendTrigger dauerhaft auf TRUE gesetzt.

Ich würde die Struktur typMasterAnSlaveSchreiben sowohl im Master wie auch im Slave nutzen.
Im Slave die Struktur auf das Merkerwort 0 mappen. Dann werden die Daten 1 zu 1 ausgetauscht und niemand muss sich darum kümmern wo diese liegen.
Dies sollte auch mit diesem Beispiel besprochen worden sein.

Grüße


----------



## holgermaik (19 April 2022)

Tobsucht schrieb:


> Die zyklische Abfrage ist sicher.


Nö

```
xXTrigger = False
-> es läuft die Wartezeit
durch den Ton xTrigger = True
-> das senden wird angestoßen
im selber Zyklus
Bedingung von Ton nicht erfüllt da xTrigger = True (Bedingung negiert)
der Ton setzt xTrigger = False
das löschen des Triggers sollte aber durch den Modbus Bausteine erfolgen
```


----------



## holgermaik (19 April 2022)

Tobsucht schrieb:


> Dann werden die Daten 1 zu 1 ausgetauscht und niemand muss sich darum kümmern wo diese liegen


Auch das ist nur bedingt richtig.
Wenn ich nicht weis wo meine Daten liegen kann ich auch kein vollständiges Abbild senden.
Die Bool werden zu Byte. Mein Real hat 4 Byte.
Damit ist die zu senden Länge viel zu kurz mit 9 Worten
Die Struktur hat zum Senden 21 Byte -> wird aufgefüllt auf 22 Byte.
Damit ist mein vollständiges Abbild 11 Worte groß.


----------



## Tobsucht (19 April 2022)

Ich sehe da nur eine CFC Zeichnung und der Ausgang des Timers setzt das Bit nur. Im Code wird dieses nicht zurückgesetzt.

Und wenn auf dem Master und den Slave die gleiche Struktur verwendet wird muss nichts beachtet werden.
Denn ein BOOL ist dann auf beiden Steuerungen ein Byte groß.
Natürlich muss die ganze Struktur übertragen werden. Dies sollte jedoch schnell auffallen.


----------



## MW22 (20 April 2022)

holgermaik schrieb:


> Damit ist die zu senden Länge viel zu kurz mit 9 Worten
> Die Struktur hat zum Senden 21 Byte -> wird aufgefüllt auf 22 Byte.
> Damit ist mein vollständiges Abbild 11 Worte groß.


Ja solangsam verstehe ich wie es funktioniert. 
Mal ne Dumme Frage:
Könnte ich auch mein Offset bei 12288 anfangen lassen und zb. 200 Worte durchlaufen lassen.
In der Variablenliste deklariere ich:
test1 At%MD0;
test2 At%MD10;
test3 At%MD20;
wenn ich dann zb. in meinen Struct drin stehen habe:
test1
test2
test3

bekomme ich dann in Slave die richtigen werte von MD0/10/20 oder stehen 
die Werte in MD0/1/2 drinne?


----------



## holgermaik (20 April 2022)

MW22 schrieb:


> Könnte ich auch mein Offset bei 12288 anfangen lassen und zb. 200 Worte durchlaufen lassen.


So ganz verstehe ich deine Frage nicht
Dein Slave stellt einen Speicher für externe Geräte zur Verfügung. Dieser beginnt bei Adresse 12288. Damit Codesys auf diesen Speicher zugreifen kann wird er ab %MW0 für Codesys abgebildet.
Mit Modbus ist das Lesen/Schreiben von maximal 125 Worte in einem Aufruf möglich. Wenn du also 200 Worte lesen/schreiben möchstest sind mindestens 2 Aufrufe nötig.

Die einfachste Art der Kommunikation ist wie bereits Tobsucht erwähnt hat einen Struct aufzubauen und diesen auf beiden Steuerungen zu verwenden.

```
TYPE st_Kommunikation :
STRUCT
    rVar1     : REAL;
    rVar2     : REAL;
    diVar1     : DINT;
    iVar1     : INT;
    by_Var1 : BYTE;
    xVar1     : BOOL;
END_STRUCT
END_TYPE
```
Hier ist lediglich zu beachten von großen nach kleinen Datentypen zu definieren um die Erzeugung von Füllbyte zu vermeiden und das Datentypen mit 2 oder mehr Byte nicht auf einem Halbbyte landen.

```
typDatenaustausch AT %MW0 : st_Kommunikation;
```
Deine Variable definierst du auf beiden Steuerungen auf der gleichen Adresse (als Beispiel hier %MW0)
Jetzt kannst du symbolisch oder auch direkt über die Adresse auf die Variablen zugreifen.
Das einzige was du tun musst ist die Länge der Variable berechnen um sie an dem Masterbaustein anzugeben.


----------



## KLM (20 April 2022)

holgermaik schrieb:


> Das einzige was du tun musst ist die Länge der Variable berechnen um sie an dem Masterbaustein anzugeben.


Mit SIZEOF(typDatenaustausch) geht das auch automatisch. Liefert die Größe in Bytes.


----------



## MW22 (21 April 2022)

Ok das habe ich weitgehenst verstanden. Wenn ich also 
typDatenaustausch AT %MW1000 : st_Kommunikation; angebe dann fängt die erste Struct variable bei MW1000
an ohne diese in der Variablentabelle als Test AT% MD500:Real; deklariert zu haben.


----------



## MW22 (21 April 2022)

Ich habe soeben 2 Steuerungen ausgeliehen bekommen. Ich habe nun 2 Projekte erstellt mit versuchsvariablen.

Ich habe nun mal die Variante versucht, über Steuerungsconfig -> Modbusmaster -> slave anlegen und Variablen deklariert welche 
geschrieben und gelesen werden. Gibt es hierfür irgendwelche Nachteile?
Weil das ist ja super einfach und schnell gemacht + mein Baustein wird ja einfach generiert.


----------



## holgermaik (21 April 2022)

MW22 schrieb:


> typDatenaustausch AT %MW1000 : st_Kommunikation; angebe dann fängt die erste Struct variable bei MW1000


genau. Das erste Byte deiner Struktur wird dann auf %MW1000 Low Byte gelegt. Alle anderen Variablen werden danach eingereiht. Im Hintergrund werden schon alle Variablen per AT auf Adressen gemappt. Codesys zeigt es halt nicht an.
Wenn du nur einen symbolischen und keinen absoluten Zugriff im ControllerB bauchst kannst du die Länge auch wie KLM schrieb berechnen lassen.


----------

