# S7 FB für MODBUS TCP



## Lars Weiß (3 März 2008)

Hallo Gemeinde,

ich hab da mal ein Problem. Ich habe heute mehr oder weniger erfolgreich einen FB für Modbus/TCP zusammgezirkelt.
Funktioniert auch soweit. Mit dem Testprogramm ModScan32 von WinTech spreche ich die SPS an.
Funktionscode 03h, n Register lesen, SPS antwortet, passt.

Jetzt das Problem: Ich wollte den Empfangpuffer für AG_SEND so groß wählen, das wenn ModScan mit den Funktionscode 10h, n Register schreiben kommt mein Baustein auf jeden Fall alles im Puffer hat. Funzt nicht.

Weil:

Für den Funktioncode 3h ist das Kommandotelegramm 12Byte lang (6B Header + 1B Slave-Adresse + 1B Funktionscode + 2B Register Offset + 2B Anzahl Register). Gebe ich am AG_RECIEVE für den Empfangbereich 12 Byte an wird korrekt übertragen, ist er grösser werden die 12Byte wie in einem Ringspeicher angehängt, also nicht mehr vernünftig auszuwerten.

Also, wie stelle ich das an, ich kann ja nicht wissen wie viele Bytes der Partner mir senden will. Funktionscode 6h reicht hier nicht aus, da Real-Werte in meinem Anwendungsfall damit nicht übertragen werden können.

Wieso macht der AG_RECIEVE so einen Müll ?


----------



## Grubba (3 März 2008)

Wenn Du anhand Deines Headers auf die Datenlänge schliessen kannst, ist folgendes möglich:

Lies in einen AG_Rec Aufruf deinen Header ein (die Länge sollte schon konstant sein)

Durch diesen Header ermittelst Du die Länge Deiner Nutzdaten. Diese kannst Du dann in einem weiteren Empfangsauftrag dann längengenau abholen.


----------



## Lars Weiß (3 März 2008)

Du meinst einen AG_Recieve mit konstanter Länge und direkt darunter einen zweiten Aufruf wo ich die Länge anpasse ? Ich werde es morgen mal versuchen, danke für den Tipp.


----------



## Grubba (3 März 2008)

Exakt. Der 1. Empfangsbaustein liest Deinen festen Header aus und "leert" somit schonmal den Empfangspuffer um Deine eingestellte Empfangslänge.
Der Aufruf danach holt dann nur noch Deine Nutzdaten ab. 
Schreib doch mal, obs geklappt hat. Hab das schon mal auf diese Weise gemacht, funktioniert eigentlich einwandfrei.
Siemens empfielt für variable Empfangslängen auch diese Vorgehensweise.


----------



## Kieler (3 März 2008)

Sag mal Bescheid, wenn Du es hinbekommen hast und erkläre doch bitte kurz den Aufbau. In meinem nächsten Projekt, muss ich mir auch eine solche Kopplung basteln.

Gruß aus Kiel


----------



## Lars Weiß (4 März 2008)

Also, do sieht mein Versuch der variablen Empfangslänge aus:


```
CALL  "AG_RECV"
       ID    :=1
       LADDR :=W#16#100
       RECV  :=P#DB2.DBX0.0 BYTE 6
       NDR   :=#ndr1
       ERROR :=#error
       STATUS:=#status
       LEN   :=#len
      UN    #ndr1
      SPB   m002
// ANY-Pointer zusammensetzen
      LAR1  P##Pointer_VAR
      L     B#16#10                     // Syntax-ID
      T     LB [AR1,P#0.0]
      L     B#16#2                      // Datentyp Byte
      T     LB [AR1,P#1.0]
      L     "RECV_BUFFER".LENGHT_LOW    // Anzahl Bytes
      T     LW [AR1,P#2.0]
      L     2                           // Quell-DB
      T     LW [AR1,P#4.0]
      L     P#DBX 6.0                   // Byte Offset
      T     LD [AR1,P#6.0]
 
      CALL  "AG_RECV"
       ID    :=1
       LADDR :=W#16#100
       RECV  :=#Pointer_VAR
       NDR   :=#ndr1
       ERROR :=#error
       STATUS:=#status
       LEN   :=#len
m002: BE
```
 
Das passt so leider auch nicht, da ModScan 12 Bytes schickt und so im ersten Aufruf von AG_Recieve die 6 Bytes überschrieben werden.


----------



## Grubba (4 März 2008)

Wenn Du also immer mindestens 12 Bytes empfängst, hol doch im ersten Auftrag erstmal diese 12 Bytes ab. Den Rest dieses Telegramms (sofern es denn dann noch einen gibt) kannst Du doch dann immer noch nach belieben abholen.


----------



## Lars Weiß (4 März 2008)

Wenn ich 12 Bytes in meinen 12Byte Empfangspuffer schreibe passt es, kommen 14 Bytes werden mir die ersten beiden wieder übschrieben. 

Ich könnte kotzen ...


----------



## Grubba (4 März 2008)

Von welchem Aufruf werden die ersten Bytes überschrieben, vom 1. oder 2. Aufruf?

Ansonsten probier doch mal, dass überspringen des 2. Aufrufs wegzulassen. Es könnte sein, das Du das NDR erst dann bekommst, wenn der FC alle Bytes umkopiert hat. (Bin mir da aber nicht ganz sicher) Wenn das der Fall wäre, würde der 2. Aufruf nichts mehr vorfinden, da der 1. ja schon alles umkopiert hat. (evtl auch in mehreren Zyklen)


----------



## Lars Weiß (4 März 2008)

Die Bytes werden schon im ersten Aufruf überschrieben​


----------



## Grubba (4 März 2008)

Weglassen des Sprungbefehl bringt auch nichts?

Dann weiß ich leider auch nicht mehr weiter.


----------



## Grubba (4 März 2008)

Doch noch was zwecks Fehlersuche:

Was sagt denn der 1. Aufruf am Parameter Len?

Sagt der 14? Würde mich doch sehr wundern, da Dein Pointer ja nur auf 12 Byte zeigt. In einem Mal dürfte der dann keine 14 Byte umkopieren, denn sonst müßtest Du eigentlich am Status 8185h anliegen haben. (-> Zielpuffer zu klein)


----------



## Grubba (4 März 2008)

Zum Schluß noch einen Link zu Siemens mit der gleichen Problematik: 

(machen das Ganze im Prinzip aber auch nicht viel anders, aber vielleicht hilfts ja... )

http://support.automation.siemens.c...objaction=csopen&extranet=standard&viewreg=WW


----------



## Lars Weiß (4 März 2008)

So, Problem erkannt, Problem gebannt.Die beiden Recieve-Aufrufe müssen gegeneinander verriegelt sein. Wenn der erste sein NDR auf true setzt darf der Zweite loslegen und den ersten sperren, kommt der zweite NDR darf der erste wieder ...


----------



## Mojo (4 März 2008)

Könntest du deinen FB online stellen? Wäre echt toll!


----------



## Lars Weiß (5 März 2008)

Und, hast du schon getestet ?


----------



## Mojo (5 März 2008)

Habe leider noch keine Mail bekommen?!


----------

