# DWord in 2x WORD umwandeln



## JarJarBinks (16 Dezember 2016)

Hallo zusammen,

Codesys Beckhoff,

ich möchte ein DWORD 32 bit in 2 Variabeln umwandeln.
HIWORD 16 bit
LOWWORD 16 bit
Ich kann im Netz keine Hilfe dazu finden.

Danke


----------



## oliver.tonn (16 Dezember 2016)

Such mal nach MEMCPY
Den Befehl führst Du 2 mal aus und fertig.

Von irgendwas mit Internetzugang gesendet.


----------



## PN/DP (16 Dezember 2016)

Ausmaskieren, etwa so:

```
Lo_Word := DWord AND 16#FFFF
Hi_Word := SHR(DWord, 16) AND 16#FFFF
```

Harald


----------



## JarJarBinks (16 Dezember 2016)

Hab ich schon nachgelesen, nicht das was ich suche.

Beschreibung Beckhoff:

Mit der Funktion MEMCPY können Werte der SPS-Variablen von einem Speicherbereich in einen anderen kopiert werden.


----------



## Hack (16 Dezember 2016)

Hallo,

MEMCPY funktioniert sicher.

In TwinCAT3 kannst du eine Union verwenden!

Grüße


----------



## oliver.tonn (16 Dezember 2016)

Hallo JarJarBinks,


JarJarBinks schrieb:


> Hab ich schon nachgelesen, nicht das was ich suche.


ich denke mal, dass Du SPS-Anfänger bist, darum hier mal ein klein wenig Nachhilfe. Eine Variable belegt im Speicher der SPS, je nach Variablentyp, unterschiedlich viel Platz. Im Falle eines DWORD sind dies 4 Bytes, im Falle eines Words 2 Bytes. Du möchtest eine DWORD Variable in zwei WORD Variablen umkopieren, also einen 4 Bytes großen Speicherbereich auf 2 x 2 Bytes große Speicherbereiche. Genau dafür ist MEMCPY da. Hier mal ein Beispiel:

```
PROGRAM MAIN
VAR
 dwVarLong : DWORD;
 wLowWord :WORD;
 wHighWord :WORD;
END_VAR

dwVarLong := 16#ABCD4321;
MEMCPY(ADR(wLowWord), ADR(dwVarLong), 2);
MEMCPY(ADR(wHighWord), ADR(dwVarLong) + 2, 2);
```
Und ein Screenshot vom Ergebnis:


Du siehst, es geht.

Gruß

Oliver


----------



## PN/DP (16 Dezember 2016)

2x MEMCPY - ala "Wer kennt die umständlichste Variante?"  Damit kann man Anfänger natürlich sehr beeindrucken... 

Bei MEMCPY ist ja schon alleine der Aufruf der Funktion ein vielfaches aufwändiger als das DWord einfach auf eine Union von 2 Words zu laden. Oder "AT" zu benutzen. Oder per Pointer im Speicher rumzupeeken.

Harald


----------



## oliver.tonn (16 Dezember 2016)

War gerade von Alzenau auf dem Weg nach Bückeburg (Jetzt sucht er erstmal) und hatte kurz Pause gemacht, da kam mir nur das auf die Schnelle in den Sinn. Das mit dem Ausmaskieren ist für nen Anfänger vielleicht etwas einfacher zu durchschauen.  

Von irgendwas mit Internetzugang gesendet.


----------



## oliver.tonn (17 Dezember 2016)

TwinCAT 2 lässt leider keine automatische Umwandlung von DWORD zu WORD zu, daher würde Haralds Lösung zu einer Fehlermeldung führen. Hier mal ein Beispiel basierend auf Haralds Vorschlag.

```
PROGRAM MAIN
VAR
 dwVarLong : DWORD;
 wLowWord :WORD;
 wHighWord :WORD;
END_VAR

dwVarLong := 16#ABCD4321;
wLowWord := DWORD_TO_WORD(dwVarLong);
wHighWord := DWORD_TO_WORD(SHR(dwVarLong, 16));
```

Das Ausmaskieren ( AND 16#FFFF) braucht man dabei nicht.


----------



## JarJarBinks (17 Dezember 2016)

Hallo,

vielen Dank, hab 2 Möglichkeiten ausprobiert und in einen FB gepackt.
Variante 1 ist wohl am kürzesten.







Vielen Dank


----------



## JarJarBinks (17 Dezember 2016)

*Bild*



Hier der Screen


----------



## Caroli (19 Dezember 2016)

Hallo, JarJarBinks!

Du kannst den Real Wert auch gleich in das Word Array schieben.

MEMCPY(ADR(mb_Input_Registers[8]), ADR(rZaehWert), 4);

Kannst Du natürlich auch grafisch im CFC zusammenstellen.


----------



## JarJarBinks (19 Dezember 2016)

Vielen Dank


----------



## PN/DP (19 Dezember 2016)

JarJarBinks schrieb:


> Anhang anzeigen 35218
> 
> Hier der Screen


Du hättest uns auch gleich mitteilen können, daß Du nicht ein DWORD sondern einen REAL in 2 Words zerlegen willst. Weil das nämlich in Codesys nicht das selbe ist und auch nicht durch REAL_TO_DWORD einfach angepasst werden kann.

Vorsicht: REAL_TO_DWORD - hat das in Twincat auch diesen Designfehler wie in Codesys, daß dabei der REAL-Wert in eine Ganzzahl gerundet wird, weil konvertiert wird?

Ich kenne TwinCat nicht, doch ich meine, Deine Aufgabe kann nur gelöst werden über zunächst Umspeichern des REAL-Wertes in DWord- oder Word-Variablen. Allerdings muß man dafür nicht aufwändig MEMCPY bemühen sondern kann mit Pointern arbeiten, etwa so (enthält eventuell Syntaxfehler?):

```
FUNCTION_BLOCK REAL_TO_2WORDS_V1
VAR_INPUT
  Input_Real : REAL;
END_VAR
VAR_OUTPUT
  Lo_Word : WORD;
  Hi_Word : WORD;
END_VAR
VAR_TEMP
  dwVar : DWORD;
  pReal : POINTER TO REAL;
END_VAR

pReal := ADR(dwVar);  //Pointer auf das DWord setzen
pReal^:= Input_Real;  //REAL-Wert in das DWord speichern
Lo_Word := DWORD_TO_WORD(dwVar);
Hi_Word := DWORD_TO_WORD(SHR(dwVar, 16));
```


```
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];
```

In TwinCAT 3 könnte man das ganze auch schick mit einer UNION lösen.

Harald


----------



## manoj (20 April 2020)

Hi,

You can use this function to convert a DWORD into 2 WORDS.
For this function to work 'Util' library should be added to library manager.
Note: Works for only positive values

FUNCTION DW_TO_2W : ARRAY [0..1] OF WORD
VAR_INPUT

DW  : DWORD;


END_VAR


VAR
	Bits : ARRAY [0..31] OF BOOL;
	DT2W : DWORD_AS_BIT;
	BTW  : BIT_AS_WORD;
END_VAR

DT2W(
	X:=DW , 
	B00=>Bits[0], 
	B01=>Bits[1], 
	B02=>Bits[2], 
	B03=>Bits[3], 
	B04=>Bits[4], 
	B05=>Bits[5], 
	B06=>Bits[6], 
	B07=>Bits[7] , 
	B08=>Bits[8] , 
	B09=>Bits[9] , 
	B10=>Bits[10] , 
	B11=>Bits[11] , 
	B12=>Bits[12] , 
	B13=>Bits[13] , 
	B14=>Bits[14] , 
	B15=>Bits[15] , 
	B16=>Bits[16] , 
	B17=>Bits[17], 
	B18=>Bits[18] , 
	B19=> Bits[19], 
	B20=> Bits[20], 
	B21=> Bits[21], 
	B22=> Bits[22], 
	B23=> Bits[23], 
	B24=> Bits[24], 
	B25=> Bits[25], 
	B26=> Bits[26], 
	B27=> Bits[27], 
	B28=> Bits[28], 
	B29=> Bits[29], 
	B30=> Bits[30], 
	B31=> Bits[31]);

	BTW(
	B00:=Bits[0] , 
	B01:=Bits[1] , 
	B02:=Bits[2] , 
	B03:=Bits[3] , 
	B04:=Bits[4] , 
	B05:=Bits[5] , 
	B06:=Bits[6] , 
	B07:=Bits[7] , 
	B08:=Bits[8] , 
	B09:=Bits[9] , 
	B10:=Bits[10] , 
	B11:=Bits[11] , 
	B12:=Bits[12] , 
	B13:=Bits[13] , 
	B14:=Bits[14] , 
	B15:=Bits[15] , 
	W=>DW_TO_2W[0] );

	BTW(
	B00:=Bits[16] , 
	B01:=Bits[17] , 
	B02:=Bits[18] , 
	B03:=Bits[19] , 
	B04:=Bits[20] , 
	B05:=Bits[21] , 
	B06:=Bits[22] , 
	B07:=Bits[23] , 
	B08:=Bits[24] , 
	B09:=Bits[25] , 
	B10:=Bits[26] , 
	B11:=Bits[27] , 
	B12:=Bits[28] , 
	B13:=Bits[29] , 
	B14:=Bits[30] , 
	B15:=Bits[31] , 
	W=>DW_TO_2W[1] );


----------



## oliver.tonn (20 April 2020)

Hello manoj,
are you aware, that the thread is nearly four years old? Hopefully the author already found a solution.
And by the way, after a while it gets clear, that a REAL value should be split into two words and not a DWORD.


----------



## TimSchu (10 Oktober 2022)

@PN/DP 

Hallo Harald,
zunächst einmal dankeschön für deinen Beitrag. Ich hatte deinen Quellcode versucht (siehe Bilder). Ich möchte die Position 200000 an einen Schrittmotor über Modbus senden. Dazu benötige ich zwei Register mit jeweils einem Word. Also versuchte ich mit deiner Lösung einen Real-Wert in zwei Wörter zu splitten, nun ist die Position jedoch bei rund 1 Milliarde.
Hast du eine Lösung um das zu beheben? Ich habe erst vor Kurzem angefangen mit ST zu arbeiten und frage mich auch was das Zeichen "^" bedeuten soll. Allerdings habe ich auch kein TwinCat, sondern Codesys auf dem Raspberry Pi. 
Vielen Dank


----------



## DeltaMikeAir (10 Oktober 2022)

Hat deine Position auch Kommastellen? Wenn nein, warum nutzt du eine REAL-Variable?
Eine REAL-Variable "stupide" in zwei WORD´s zu teilen kann natürlich nicht funktionieren.

PS:
In welchem Format muss denn die Sollposition auf dem Regler ankommen?


----------



## TimSchu (10 Oktober 2022)

Ok danke. Ich habe es nun mit DINT versucht und das hat geklappt.
Das "^" im Code würde mich aber noch interessieren was es heisst. Weisst du das?


----------



## DeltaMikeAir (10 Oktober 2022)

TimSchu schrieb:


> Das "^" im Code würde mich aber noch interessieren was es heisst. Weisst du das?


So genau weiß ich es tatsächlich nicht, ich habe das auch noch nie gesehen. Aber im Handbuch steht:



> Inhaltsoperator
> Die Dereferenzierung eines Pointers erfolgt über den Inhaltsoperator "^" nach dem Pointerbezeichner.
> Beispiel in ST:




```
PT: POINTER TO INT;
var_int1:INT;
var_int2:INT;
pt := ADR(var_int1);
var_int2:=pt^;
```


----------



## oliver.tonn (10 Oktober 2022)

TimSchu schrieb:


> Ok danke. Ich habe es nun mit DINT versucht und das hat geklappt.
> Das "^" im Code würde mich aber noch interessieren was es heisst. Weisst du das?


@DeltaMikeAir hat mit seinem Handbuch Auszug eigentlich schon die Lösung geliefert, trotzdem gebe ich noch meinen Senf dazu.
Wenn Du mit Pointern arbeitest enthalten diese ja "nur" die Adresse auf die eigentlichen Daten. Wenn Du jetzt aber auf die an der Adresse liegenden Daten zugreifen möchtest musst dazu den sogenannten Dereferenzierer nutzen. Bei Nutzung des Dereferenzierers ist es übrigens sehr wichtig bei der Deklaration des Pointers den richtigen Variablentyp anzugeben auf den er Zeigt, weil sonst der Dereferenzierer die "falschen" Daten liefert.
Ich muss aber gestehen, dass ich es noch nie gesehen habe, dass man den Dereferenzierer auch vor dem := nutzen kann. Ich kannte es bisher immer nur so, dass man Ihn so nutzt:

```
uiVar01 := puiPointer01^;
```
Tja, wieder was gelernt.
Es gibt übrigens auch den umgekehrten Fall, eine Funktion oder ein FB braucht die Adresse zu einer Variablen, dann nutzt man die Funktion ADR.


----------



## holgermaik (10 Oktober 2022)

Hallo TimSchuh
da du schreibst, das du neu in ST bist möchte ich Harald seinen Code mal interpretieren.


> pReal := ADR(dwVar);  //Pointer auf das DWord setzen
> pReal^:= Input_Real;  //REAL-Wert in das DWord speichern
> Lo_Word := DWORD_TO_WORD(dwVar);
> Hi_Word := DWORD_TO_WORD(SHR(dwVar, 16));





> pReal := ADR(wArr); Hier wird die Speicheradresse der Variable "wArr" ermittelt, Der Speicherblock ist 32bit groß





> pReal^:= Input_Real; pReal^ ist ein Zeiger auf die ermittelte Speicheradresse. Die Variable "Input_Real" wird an die ermittelte Speicheradresse geschrieben





> Lo_Word := DWORD_TO_WORD(dwVar);
> Hi_Word := DWORD_TO_WORD(SHR(dwVar, 16)); entnahme der 2 Word aus der Variable dwVar



Diese Möglichkeit hat Nachteile. 
Bei OnLine Change kann es fehlerhafte Zugriffe auf den Speicher geben, da Speicherbereiche verschoben werden.
Pointer sollten m.M.n. nur bei unbedingt nötigen Zugriffen verwendet werden.

In deinem Fall wäre eine Lösung mit einer Union wesentlich besser geeignet.


----------



## Oberchefe (10 Oktober 2022)

> Bei OnLine Change kann es fehlerhafte Zugriffe auf den Speicher geben, da Speicherbereiche verschoben werden.


Aber nur dann wenn du mehrere Zyklen brauchst um etwas auszuwerten oder aber die Adresse nur einmalig ermittelt wird und dann in Folge "blind" mit dieser ermittelten Adresse gearbeitet wird. Solange immer erst die Adresse ermittelt wird und dann anschließend im gleichen Zyklus mit dieser Adresse gearbeitet wird, passiert bei Online-Changes nichts.


----------



## R_Grabichler (11 Oktober 2022)

Nur zur Vollstaendigkeit, da Union immer genannt wurde.


Hier eine Union definiert und eine Struct mit dem erwarteten Ergebnis.
Schaut dann so aus


Das Schöne daran, es ist beliebig erweiterbar, man könnte eine Structur mit Bits, Strings oder ähnlichem machen,
und die Zahlen werden automatisch immer umgewandelt.

Für genauere Interpretationen des Real Werts von 200000 zu DINT und DWORD sollen die Profis was sagen.



EDIT: Unpräzise bzw. falsch ausgedrückt, ich meinte die Darstellung von unterschiedlichen Datentypen wird eben im spezifischen Datentyp dargestellt.
Wie erwähnt, ist die Magie dahinter die zugrundeliegende Darstellung der Zahl im Speicher,
worauf jeder Datentyp zugreift und eben entsprechend interpretiert.


----------



## PN/DP (11 Oktober 2022)

PN/DP schrieb:


> UNION gibt es ab Codesys/TwinCat 3 (...). Etwa so:
> 
> ```
> TYPE VAR32 : UNION
> ...


----------



## PN/DP (11 Oktober 2022)

R_Grabichler schrieb:


> Das Schöne daran, es ist beliebig erweiterbar, man könnte eine Structur mit Bits, Strings oder ähnlichem machen,
> und die Zahlen werden automatisch immer umgewandelt.


Das Schöne daran ist, daß Zahlen NICHT umgewandelt werden. Es wird immer nur das in der Speicherstelle liegende Bitmuster OHNE Umwandlung als Zahl des betreffenden Datentyps interpretiert.


----------

