# e!Cockpit Modbus Abfrage



## Florian Se. (7 August 2018)

Hallo zusammen,

ich habe ein PFC 8204 mit e!Cockpit und versuche zur Zeit mit Modbus einen Stromzähler abzufragen. Ich mache das mit der WagoAPPModbus library. Es gibt dazu ja ein Anwendungsbeispiel bei dem ein Geröt abgefragt wird. Das funktioniert soweit auch super.
Wie gehe ich das technisch an, wenn ich verschiedene Registerbereiche (nicht zusammenhängend) abfragen will, oder ein 2. Gerät am Bus? Wenn ich die Query austausche hab ich den Eindruck, dass sich immer nur alles überschreibt

Muss ich dann jedesmal eine neues Programm schreiben? Ich will am Ende einfach nur 4 Stromzähler direkt hintereinander abfragen. Wie bekomme ich die zeitliche Reihenfolge hin?
Gibt es da auch Beispiele?

Liebe Grüße,
Florian


----------



## wolfi-sps (7 August 2018)

Hallo Florian,

wie willst Du die Zähler auslesen Modbus/TCP oder Modbus/RTU ...?
Es gibt im eCockpit bei der Gerätestruktur/Produktkatalog Sonstige Kommunikationsteilnehmer.
Da sollte was dabei sein.

Wolfgang


----------



## Tobsucht (7 August 2018)

Hallo Florian,

meinst Du die Bibliothek WagoApp*Plc*Modbus? Es gab nämlich auch eine WagoAppModbus.

Für jeden Server würde ich einen Client anlegen. Jeder Client kann dann mehrere Anfragen verwalten. Dazu kann eine Jobliste als Array of Query angelegt werden.
Nach dem Abarbeiten eines Jobs, kann zum nächsten geschaltet werden.

Grüße


----------



## Florian Se. (7 August 2018)

wolfi-sps schrieb:


> Hallo Florian,
> 
> wie willst Du die Zähler auslesen Modbus/TCP oder Modbus/RTU ...?
> Es gibt im eCockpit bei der Gerätestruktur/Produktkatalog Sonstige Kommunikationsteilnehmer.
> ...



Modbus RTU, das ist dann aber die Variante über den Konfigurator oder? Den habe ich nämlich nicht ans laufen bekommen. Da weiß ich auch nicht welchen Datentyp ich einstellen muss. Ich muss 2 Register auslesen, in dem eine Vorzeichenbehaftete Ganzzhal drinsteht.


----------



## Florian Se. (7 August 2018)

Tobsucht schrieb:


> Hallo Florian,
> 
> meinst Du die Bibliothek WagoApp*Plc*Modbus? Es gab nämlich auch eine WagoAppModbus.
> 
> ...



Ich meinte die WagoApp*Plc*Modbus. Es ist eine RTU Kommunikation. Also für jeden Slave einen Master oder? Hab das vergessen zu sagen. Wie stelle ich dann sicher, dass die Master nicht gleichzeitig auf den Bus zugreifen?


----------



## Tobsucht (7 August 2018)

Hallo Florian,

bei Modbus RTU kann es nur eine Masterinstanz geben.
Die serielle Schnittstelle kann nur von einer Instanz genutzt werden. Weitere Instanzen würden melden, dass die Schnittstelle schon verwendet wird.

Das Vorgehen mit der Joblist bleibt, nur dass dort alle Anfrage an alle Slaves abgelegt werden.


Grüße


----------



## Florian Se. (8 August 2018)

Hallo Tobsucht,

ich hab das jetzt mit der Jobliste umgesetzt. Hier im Forum gab es ja ein Beispiel dafür. Allerdings wird da immer so schnell es geht die Jobs direkt hintereinander abgefragt.


```
mySerialMaster( I_Port      := COM1,        // my serial port
                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
```

Ich habe das Gefühl, dass die SPS damit sehr stark belastet wird oder das generell nicht richtig funktioniert. (Busüberlastung oder so?)
Kann man das auch so programmieren, dass alle 500ms die Jobliste einmal abgearbeitet wird. Ich hab eher C programmiert und muss mich erst noch in die Programmierung mit einer SPS einarbeten.

Also ich könnte mir vorstellen, dass man einen Task mit 500 ms laufen lässt und dann in einer While Schleife all Jobs abarbeiten lässt??


----------



## Thruser (8 August 2018)

Hallo;


Florian Se. schrieb:


> Ich habe das Gefühl, dass die SPS damit sehr stark belastet wird oder das generell nicht richtig funktioniert. (Busüberlastung oder so?)
> Kann man das auch so programmieren, dass alle 500ms die Jobliste einmal abgearbeitet wird. Ich hab eher C programmiert und muss mich erst noch in die Programmierung mit einer SPS einarbeten.
> 
> Also ich könnte mir vorstellen, dass man einen Task mit 500 ms laufen lässt und dann in einer While Schleife all Jobs abarbeiten lässt??



Hier e!Cockpit Modbus-TCP findest Du ein Beispiel mit Timer.

Gruß


----------



## Florian Se. (8 August 2018)

Hallo Thruser,

danke für die Info. Ist das dabei aber nicht so, dass nur die Zeit zwischen den Jobs eine bestimmte Dauer hat?

Ich würde gerne möglichst kurz hintereinander 4 Jobs ausführen im Zylus von 500ms...

LG Florian


----------



## Thruser (8 August 2018)

HALLO





Florian Se. schrieb:


> Hallo Thruser,
> 
> danke für die Info. Ist das dabei aber nicht so, dass nur die Zeit zwischen den Jobs eine bestimmte Dauer hat?
> 
> ...



Du könntest jetzt die Zeit auf 125ms setzen, dann wäre die Belastung schön verteilt.

Oder versuche mal folgendes (ungetestet):

```
mySerialMaster( I_Port      := COM1,        // my serial port
                utQuery:=Jobliste[iJobCounter], 
                xTrigger:=xTrigger, 
                utResponse:=Responseliste[iJobCounter]
              );
              


FB_F_Trig (clk:=xTrigger);


IF FB_F_Trigger.Q THEN
    iJobCounter := (iJobCounter+1) MOD iMaxJobs;
    IF iJobCounter=0 THEN
        xTimer:=TRUE;
    ELSE
        xTrigger:=TRUE;
    END_IF
END_IF


delay(IN := xTimer, PT := T#500MS); // TON


IF delay.Q THEN
    xTimer:=FALSE;
    xTrigger:=TRUE;
END_IF
```

Da sollte jetzt zwischen zwei Ausführungen der Jobliste eine Pause von 500ms liegen.

Eine weitere Möglichkeit (auch ungetestet):

```
IF xTrigger & (iJobCounter=0) THEN
    xTimer:=True;
END_IF


delay(IN := xTimer; PT := T#500MS); //TON


mySerialMaster( I_Port      := COM1,        // my serial port
                utQuery:=Jobliste[iJobCounter], 
                xTrigger:=xTrigger, 
                utResponse:=Responseliste[iJobCounter]
              );
              


FB_F_Trig (clk:=xTrigger);


IF FB_F_Trigger.Q THEN
    iJobCounter := iJobCounter+1);
    IF NOT (iJobCounter=iMaxJobs) THEN
        xTrigger:=TRUE;
    END_IF
END_IF


IF delay.Q & (iJobCounter=iMaxJobs) THEN
    xTrigger:=TRUE;
    xTIMER:=FALSE;
    iJobCounter:=0;
END_IF
```

Hier sollte der Durchlauf der Jobliste jetzt alle 500ms gestartet werden.

Also im ersten Beispiel kommt zu den 500ms noch die Abarbeitungszeit der Jobliste dazu. Im zweiten Beispiel sollte, mit Jitter, alle 500ms die Abarbeitung gestartet werden.

Zusätzliche Variablen, FB müssen noch deklariert werden. Darauf habe ich jetzt verzichtet.

Gruß


----------



## Florian Se. (9 August 2018)

Hi,

ich hab noch ein paar kleine Typos rausgeholt, aber er funktioniert nicht der Code. Zumindest hab ich den Eindruck.
 Im Debugger kann ich das sauch nicht wirklich nachvollziehen, da der Timer asynchron hochzählt oder?



```
IF (xTrigger AND (iJobCounter=0)) THEN
    xTimer:=True;
END_IF


delay(IN := xTimer, PT := T#500MS); //TON
delay.ET;

mySerialMaster( I_Port      := COM1,        // my serial port
                utQuery:=Jobliste[iJobCounter], 
                xTrigger:=xTrigger, 
                
                utResponse:=Responseliste[iJobCounter]
              );
              


FB_F_Trigger (clk:=xTrigger);


IF FB_F_Trigger.Q THEN
    iJobCounter := (iJobCounter+1);
    IF NOT (iJobCounter=iMaxJobs) THEN
        xTrigger:=TRUE;
    END_IF
END_IF


IF delay.Q AND  (iJobCounter=iMaxJobs) THEN
    xTrigger:=TRUE;
    xTIMER:=FALSE;
    iJobCounter:=0;
END_IF
```


----------



## Thruser (9 August 2018)

Hallo,





Florian Se. schrieb:


> Hi,
> 
> ich hab noch ein paar kleine Typos rausgeholt, aber er funktioniert nicht der Code. Zumindest hab ich den Eindruck.
> Im Debugger kann ich das sauch nicht wirklich nachvollziehen, da der Timer asynchron hochzählt oder?



ja da habe ich mit dem Timer Mist gebaut. Der läuft nur einmal durch, da er keinen Flankenwechsel erkennt.

So müßte es gehen:

```
IF (xTrigger AND (iJobCounter=0)) THEN
    xTimer:=True;
END_IF




mySerialMaster( I_Port      := COM1,        // my serial port
                utQuery:=Jobliste[iJobCounter], 
                xTrigger:=xTrigger, 
                
                utResponse:=Responseliste[iJobCounter]
              );
              


FB_F_Trigger (clk:=xTrigger);


IF FB_F_Trigger.Q THEN
    iJobCounter := (iJobCounter+1);
    IF NOT (iJobCounter=iMaxJobs) THEN
        xTrigger:=TRUE;
    END_IF
END_IF


IF delay.Q AND  (iJobCounter=iMaxJobs) THEN
    xTrigger:=TRUE;
    xTIMER:=FALSE;
    iJobCounter:=0;
END_IF


delay(IN := xTimer, PT := T#500MS); //TON
delay.ET; // So funktioniert das nicht. Entweder einer Dummy Variablen zuweisen oder den Deklarationsteil im Onlinemodus ansehen.
```
Dadurch ergibt sich jetzt ein Jitter von mindestens einer Zykluszeit. Sonst  könnte man den delay Timer auch zweimal aufrufen, einmal oben und einmal unten.

Gruß


----------



## Florian Se. (14 August 2018)

Hallo,

irgendwie bin ich mit dem Code nicht wirklich klar gekommen. Habe jetzt mal selbst was versucht. Im Sekundentakt werden die Jobs ausgeführt. Stimmt das so?

```
Timer(IN := NOT (Timer.Q), PT := T#500MS); //TP Timer
Timer.ET;//nur für live ansicht

FB_R_Trigger (clk:=Timer.Q);
//Es wird ein 1 Sekundentakt erkannt
IF FB_R_Trigger.Q THEN
    xTrigger := TRUE;
    iJobCounter := 0;
END_IF


mySerialMaster( I_Port      := COM1,        // my serial port
                utQuery:=Jobliste[iJobCounter], 
                xTrigger:=xTrigger,                 
                utResponse:=Responseliste[iJobCounter]
              );
              
//Jobende erfolgt, nächsten Job starten
IF xTrigger = FALSE AND iJobCounter < (iMaxJobs -1)  THEN 
  iJobCounter := iJobCounter +1;
  xTrigger := TRUE;
END_IF
```


Viele Grüße


----------



## Florian Se. (14 August 2018)

Also Hintergrund ist, dass ich oft die gleichen Werte habe. So 10 sek. lang und ich glaube, dass er die Werte nicht richtig abruft, weil bei einem Stromzähler so oft die gleichen Werte ist ja unwarscheinlich. Entweder weil das Skript nicht läuft oder weil sonst was passiert. TimeOut oder so.
Kann man das irgendwo sehen?


----------



## Thruser (14 August 2018)

Hallo,


Florian Se. schrieb:


> Also Hintergrund ist, dass ich oft die gleichen Werte habe. So 10 sek. lang und ich glaube, dass er die Werte nicht richtig abruft, weil bei einem Stromzähler so oft die gleichen Werte ist ja unwarscheinlich. Entweder weil das Skript nicht läuft oder weil sonst was passiert. TimeOut oder so.
> Kann man das irgendwo sehen?



ich schau mir das mal die Woche an. Muß eh noch etwas anderes ausprobieren.

Hast Du die 500ms mal verlängert? Ich weiß ja jetzt nicht mit wieviel b/s Du arbeitest, aber da kann schon mal etwas an Zeit zusammenkommen bei der seriellen Kommunikation.

Gib mir mal Deine Kommunikationsparameter der Schnittstelle und am besten auch die Modbusadressen oder verlinke auf das Handbuch zu Deinem Zähler.

Bei einem Zähler von Saia steht z.B. im Handbuch auch, daß die Werte nur alle 10s aktualisiert werden.

Gruß


----------



## Thruser (16 August 2018)

So,

ich habe mal was getestet. Die Timerfunktion arbeitet so wie sie soll. Hier mal mein Beispiel, den Modbusbaustein habe ich durch einen Dummy ersetzt, der alle 10 Aufrufe xTrigger zurücksetzt.


```
PROGRAM PLC_PRG
VAR
    FB_Dummy:FB_TEST;
    FB_F_Trigger: F_Trig;
    delay: TON;
    
    xTrigger: BOOL := TRUE;
    xTimer: BOOL;
    
    iJobCounter: INT;
    iMaxJobs: INT := 4;
    iCounter:INT;
    tTime:TIME;
END_VAR
```


```
IF (xTrigger AND (iJobCounter=0)) THEN
    xTimer:=True;
END_IF

FB_Dummy (xTrigger:=xTrigger, iCounter=>iCounter);

FB_F_Trigger (clk:=xTrigger);

IF FB_F_Trigger.Q THEN
    iJobCounter := (iJobCounter+1);
    IF NOT (iJobCounter=iMaxJobs) THEN
        xTrigger:=TRUE;
    END_IF
END_IF

IF delay.Q AND  (iJobCounter=iMaxJobs) THEN
    xTrigger:=TRUE;
    xTIMER:=FALSE;
    iJobCounter:=0;
END_IF

delay(IN := xTimer, PT := T#10000MS, ET => tTime); //TON
```
und hier die Dummyfunktion

```
FUNCTION_BLOCK FB_TEST
VAR_OUTPUT
    iCounter:INT;
END_VAR
VAR_IN_OUT
    xTrigger:BOOL;    
END_VAR
```


```
IF xTrigger THEN
    iCounter:=iCounter+1;
    IF iCounter=10 THEN
        iCounter := 0;
        xTrigger := FALSE;
    END_IF
END_IF
```





Gruß


----------



## Sugarman (15 Februar 2019)

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


----------

