Modbus TCP: REAL-Werte in WORDs übertragen

brice

Level-1
Beiträge
5
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

ich bin neu in der SPS Programmierung und ich bitte um Ihre Hilfe.

Ich nutze die Funktion fbWriteRegs von Twincat3, um die Ausgangsregister über Modbus zu schreiben zu schreiben. Die Variabe, die schreiben will ist ein REAL und geht von -1000000 ..+1000000. Da Modbus nur WORD überträgt, möchte ich meine Variable in 2 WORDs konvertieren und gleichzeit sowohl positive und negative Werte übertragen.

Vielen Dank im Voraus,
Brice
 
Benutze eine UNION, um einen REAL mit 2 WORD zu überlagern, da kannst Du den REAL-Wert hinein laden und das Bitmuster als 2 WORD herausladen.

PS: oder hier eine Function, die mittels Pointer den REAL in 2 WORD zerlegt
Code:
FUNCTION_BLOCK REAL_TO_2WORDS_V2
VAR_INPUT
  Input_Real : REAL;
END_VAR
VAR_OUTPUT
  Lo_Word : WORD;
  Hi_Word : WORD;
END_VAR
VAR_TEMP
  wArr : ARRAY [0..1] OF WORD;
  pReal : POINTER TO REAL;
END_VAR

pReal := ADR(wArr);   //Pointer auf Anfangsadresse des Word-Array setzen
pReal^:= Input_Real;  //REAL-Wert in das Word-Array speichern
Lo_Word := wArr[0];
Hi_Word := wArr[1];

Harald
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Harald,

vielen Dank für deine schnelle Antwort.
Soweit ich weiß, können nur DWORD bzw WORD positive Zahlen enthalten. wie soll ich mit dem negativen Wert umgehen?

MfG, Brice
 
Augen zu und durch ohne drüber nachdenken. Alles gut. ;)
DWORD und WORD enthalten eigentlich überhaupt keine Zahlen (*) sondern Bitmuster ("Bitstring"). Den WORDs ist es egal ob der REAL ein positives oder negatives Vorzeichen hat oder ob das ein NaN oder sonstwas ist. Die beiden WORDs enthalten einfach das 32-Bit-Bitmuster des REAL. Völlig ohne irgendwelche Konvertierung oder Interpretation des Inhalts. PS: der Empfänger der beiden WORD muß einfach nur die zwei mal 16 Bit in der richtigen Reihenfolge wieder zu 32 Bit zusammensetzen und hat dann wieder das originale Bitmuster des ursprünglichen REAL.

(*) In der Codesys-Anfangszeit wurde leider abweichend von Standards innovativ festgelegt, daß WORD/DWORD wie unsigned INT/unsigned DINT interpretiert werden ... und Siemens hat diesen "Quatsch" nun auch in TIA eingeführt.

Harald
 
Zuletzt bearbeitet:
In Siemens S7 --->
You may need conversion function to convert a real number into DINT.
It is simply conversion a value with fraction to an integer.The process
is also known as rounding.Possible functions:

RND+
RND-
RND
TRUNC

regards
 
Zuviel Werbung?
-> Hier kostenlos registrieren
In Siemens S7 --->
You may need conversion function to convert a real number into DINT.
:roll:
Hier in diesem Thema soll nichts konvertiert werden, sondern lediglich ein 32-Bit-REAL zerlegt als 2x 16-Bit-WORD per Modbus übertragen werden. Und das würde man auch bei S7 ohne Konvertierung machen.

Harald
 
Zuletzt bearbeitet:
Ich nutze die Funktion fbWriteRegs [...] Die Variabe, die schreiben will ist ein REAL [...] Da Modbus nur WORD überträgt, möchte ich meine Variable in 2 WORDs konvertieren.
Wenn ich die Beschreibung zu FB_MBWriteRegs richtig verstehe, dann muß Du Dich gar nicht um die Zerlegung des REAL in mehrere WORD kümmern, sondern kannst dem fbWriteRegs direkt die Adresse der REAL-Variable übergeben. Für Schreiben einer REAL-Variable mußt Du den fbWriteRegs u.A. mit diesen Werten beschalten:

nQuantity := 2
cbLength := 4
pSrcAddr := ADR(myRealVar)


Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich habe mehrere Datenpunkte, die ich schreiben moechte. Diese Datenpunkte sind normalerweise Real-Werte. Aber der Empfaenger hat fuer jeden Datenpunkt eine "Resolution" definiert. z.B Statt 50,122345 will er 5012 empfangen. Deswegen verschiebe ich zuerst das Komma auf die gewünschte Position (in dem Fall *100). Das mache ich fuer jeden Datenpunkt nach geforderter Resolution. Dann benutze ich TRUNC, um eine Ganzzahl fuer jeden Datenpunkt zu haben (wie der Empfaenger moechte). Ich speichere das ganze in einem Array of DINT. Mit FB_WriteRegs schreibe ich das Array beim Empfaenger. Der FB kuermmert sich um die Zerlegung in mehreren WORD.

Meine Frage ist: uebertraegt der FB auch richtig die negative Zahl? wie soll der Empfaenger aus empfangenen WORD negative und position Zahl unterscheiden? Denn WORD kann nur positiv Zahl
 
Beispiel

Zum Schluß steht in myDint der Wert, das geht
sowohl für die positiven, als auch für die negativen Werte, kann also
immer so verwendet werden.


//Code:

VAR
myDInt : DInt;
ptrWordArray : POINTER TO ARRAY[0..1] OF
Word;
END_VAR


ptrWordArray := ADR(myDInt);

ptrWordArray^[0] := MW1002;
ptrWordArray^[1] := MW1003;


 
Meine Frage ist: uebertraegt der FB auch richtig die negative Zahl? wie soll der Empfaenger aus empfangenen WORD negative und position Zahl unterscheiden? Denn WORD kann nur positiv Zahl
Der FB_MBWriteRegs überträgt die Zahlen automatisch richtig, weil er gar nicht weiß was er da überträgt und auch nicht versucht das zu interpretieren. Er weiß nur daß das ein langer Bitstring ist, dessen 16 Bit große Teilstücken (WORDs) bei Bedarf einzeln adressiert werden können.

Die Aussage, daß in einem WORD nur positive Zahlen enthalten sein können, ist falsch. Wie ich in #4 schon schrieb, enthalten WORDs keine Zahlen sondern Bitmuster. Den WORDs ist es egal wo die Bitmuster herkommen und was sie bedeuten. Ob da auch ein Bit dabei ist, was bei irgendeinem Datentyp das Vorzeichenbit ist und ob das 1 oder 0 ist, ist dem WORD herzlich egal. Es wird erst interessant wenn jemand versucht, das Bitmuster in dem WORD als Zahl zu interpretieren, um z.B. damit zu rechnen, was eigentlich nicht zulässig sein sollte, in Codesys aber dummerweise erlaubt wurde unter der Bedingung, daß das Bitmuster in WORDs beim Rechnen als unsigned INT interpretiert wird. Der saubere Weg wäre, das WORD in eine INT- oder UINT-Variable zu kopieren und dann mit der INT-/UINT-Variable zu rechnen. So können auch negative Zahlen über WORD-Speicherplätze transportiert werden.

Erstelle einfach ein STRUCT (oder ARRAY), so wie der Empfänger die Daten haben möchte (im Idealfall nur 1 zusammenhängender Bereich):
Code:
SendData : STRUCT
  rVar_1 : REAL;
  aWerte : ARRAY [0..9] OF DINT;
  rVar_2 : REAL;
END_STRUCT;
In die Variablen dieser STRUCT kopiere Deine positiven und negativen und skalierten und sonstigen Werte.

Dann übergib die Anfangsadresse des STRUCT an den FB_MBWriteRegs:
nMBAddr := xxx
nQuantity := 24
cbLength := 48
pSrcAddr := ADR(SendData)


FB_MBWriteRegs kopiert den Speicherbereich des STRUCT SendData in die WORD-Register des Modbus-Servers.

Wenn der Empfänger sich einen genau so strukturierten STRUCT RecvData anlegt und z.B. mit FB_MBReadRegs mit
nMBAddr := xxx
nQuantity := 24
cbLength := 48
pDestAddr := ADR(RecvData)

die 24 WORDs in seine STRUCT holt, dann hat er wunderbarerweise genau Deine Werte in seiner STRUCT - auch negative Werte! ganz ohne Konvertieren und Zerlegen und Zusammenbasteln.

Harald
 
Sollte man REAL nicht im IEEE754 Format übertragen? So hab ich es bis jetzt zumindest immer gemacht.
 
Sollte man REAL nicht im IEEE754 Format übertragen? So hab ich es bis jetzt zumindest immer gemacht.
Hast Du das auch schon mal über Modbus gemacht?

REAL werden auch bei Modbus im IEEE754 Format übertragen, allerdings zerlegt in zwei aufeinanderfolgenden 16-Bit-Registern (WORD). Bei Modbus gibt es nur einzelne Bits und 16-Bit-Register.

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Code:
Hallo Harald,

Ich habe z.B mit [COLOR=#333333]FB_MBWriteRegs den DINT (-25) geschrieben. Der FB hat in WORD [B]65511[/B] geschrieben.

Danach habe ich mit [/COLOR][COLOR=#333333]FB_MBReadRegs den Wert gelesen und in einem DINT gespeichert. Ergebnis: [B]65511[/B]

[/COLOR][COLOR=#333333]Wie kann ich den negativen Wert wieder haben? Gibt es einen Formel dafür?[/COLOR]
 
Ich habe z.B mit FB_MBWriteRegs den DINT (-25) geschrieben. Der FB hat in WORD 65511 geschrieben.
Danach habe ich mit
FB_MBReadRegs den Wert gelesen und in einem DINT gespeichert. Ergebnis: 65511
Wie kann ich den negativen Wert wieder haben?
Du hast anscheinend nur 1 Wort von DINT geschrieben (das niederwertige) und das höherwertige unter den Teppich gekehrt bzw. gelöscht.
Wolltest Du nicht ursprünglich eine 32 Bit grosse Info "scheibchenweise" - aber inhaltlich unverändert - in ein 32 Bit grosses Ziel befördern?
Sind wir noch beim selben Thema?

Gruss, Heinileini
 
@brice
Wenn Du einen DINT (oder anderen 32-Bit-Datentyp) über Modbus schreiben oder lesen willst, dann mußt Du "nQuantity := 2" angeben für 2 Register (2 mal 16 Bit)

Harald
 
Zurück
Oben