DWord in 2x WORD umwandeln

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.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo JarJarBinks,
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:
Code:
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:
DWord_To_Word.jpg
Du siehst, es geht.

Gruß

Oliver
 
Zuletzt bearbeitet:
2x MEMCPY - ala "Wer kennt die umständlichste Variante?" ;) Damit kann man Anfänger natürlich sehr beeindrucken... :ROFLMAO:

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
 
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.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
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.
Code:
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.
 
Hallo,

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

qn5994CmmKtVYQMAkFXM8lTYAABkFbM8FTYAAFnFLE FDQBAVjHLU2EDAJBVzPJU2AAAZBWzPBU2AABZxSxPhQ0AQFYxy1NhAwCQVczyVNgAAGQVszwVNgAAWcUsT4UNAEBWMctTYQMAkFXM8lTYAABkFbM8FTYAAFnFLE FDQBAVjHLU2EDAJBVzPJU2AAAZBWzPBU2AABZxSxPhQ0AQFYxy1NhAwCQVczyVNgAAGQVszwVNgAAWcUsT4UNAEBWMctTYQMAkFXM8lTYAABkFbM8FTYAAFnFLE FDQBAVjHLU2EDAJBVzPJU2AAAZBWzPBU2AABZxSxPhQ0AQFYxy1NhAwCQVczyVNgAAGQVszwVNgAAWcUsT4UNAEBWMctTYQMAkFXM8lTYAABkFbM8FTYAAFnFLE FDQBAVjHLU2EDAJBVzPJU2AAAZBWzPBU2AABZxSxPhQ0AQFYxy1NhAwCQVczyVNgAAGQVszwVNgAAWcUsT4UNAEBWMctTYQMAkFXM8lTYAABkFbM8FTYAAFnFLE FDQBAVjHLU2EDAJBVzPJU2AAAZBWzPBU2AABZxSxPhQ0AQFYxy1NhAwCQVczyVNgAAGQVszwVNgAAWcUsT4UNAEBWMctTYQMAkFXM8lTYAABkFbM8FTYAAFnFLE FDQBAVjHLU2EDAJBVzPJU2AAAZBWzPBU2AABZxSxPhQ0AQFYxy1NhAwCQVczyVNgAAGQVszwVNgAAWcUsT4UNAEBWMctTYQMAkFXM8lTYAABkFbM8FTYAAFnFLE FDQBAVjHLU2EDAJBVzPJU2AAAZBWzPBU2AABZxSxPhQ0AQFYxy1NhAwCQVczyVNgAAGQVszwVNgAAWcUsT4UNAEBWMctTYQMAkFXM8lTYAABkFbM8FTYAAFnFLE FDQBAVjHLU2EDAJBVzPJU2AAAZBWzPBU2AABZxSxPhQ0AQFYxy1NhAwCQVczyVNgAAGQVszwVNgAAWcUsT4UNAEBWMctTYQMAkFXM8lTYAABkFbM8FTYAAFnFLE FDQBAVjHLU2EDAJBVzPJU2AAAZBWzPBU2AABZxSxPhQ0AQFYxy1NhAwCQVczyVNgAAGQVszwVNgAAWcUsT4UNAEBWMctTYQMAkFXM8lTYAABkFbM8FTYAAFnFLE FDQBAVjHLU2EDAJBVzPJU2AAAZBWzPBU2AABZxSxPhQ0AQFYxy1NhAwCQVczyVNgAAGQVszwVNgAAWcUsT4UNAEBWMctTYQMAkFXM8lTYAABkFbM8FTYAAFnFLE FDQBAVjHLU2EDAJBVzPJU2AAAZBWzPBU2AABZxSxPhQ0AQFYxy1NhAwCQVczyVNgAAGQVszwVNgAAWcUsT4UNAEBWMctTYQMAkFXM8lTYAABkFbM8FTYAAFnFLE FDQBAVjHLU2EDAJBVzPJU2AAAZBWzPBU2AABZxSxPhQ0AQFYxy1NhAwCQVczyvLywAQDgHtPL9hyFDQDAIqaX7TkKGwCARUwv23MUNgAAi5hetucobAAAFjG9bM JMg8AAFiDwgYAgJkUNgAAzKSwAQBgJoUNAAAzKWwAAJhJYQMAwEwKGwAAZlLYAAAwk8IGAICZFDYAAMyksAEAYCaFDQAAMylsAACYSWEDAMBMChsAAGZS2AAAMJPCBgCAmRQ2AADMpLABAGAmhQ0AADMpbAAAmElhAwDATAobAABmUtgAADCTwgYAgJkUNgAAzKSwAQBgJoUNAAAzKWwAAJhJYQMAwEwKGwAAZlLYAAAwk8IGAICZFDYAAMyksAEAYCaFDQAAMylsAACYSWEDAMBMChsAAGZS2AAAMJPCBgCAmRQ2AADMpLABAGAmhQ0AADMpbAAAmElhAwDATAobAABmUtgAADCTwgYAgJn H9xeBRsDJCXAAAAAAElFTkSuQmCCAA==


Vielen Dank
 
Zuviel Werbung?
-> Hier kostenlos registrieren
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.
 
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?):
Code:
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));
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];

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

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
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] );
 
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.
 
@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
 

Anhänge

  • Realtowords.png
    Realtowords.png
    264 KB · Aufrufe: 43
  • Screenshot 2022-10-10 144425.png
    Screenshot 2022-10-10 144425.png
    246,8 KB · Aufrufe: 44
  • Screenshot 2022-10-10 144528.png
    Screenshot 2022-10-10 144528.png
    221 KB · Aufrufe: 43
Zuviel Werbung?
-> Hier kostenlos registrieren
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?
 
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?
 
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:
Code:
PT: POINTER TO INT;
var_int1:INT;
var_int2:INT;
pt := ADR(var_int1);
var_int2:=pt^;
1665409446891.png
 
Zurück
Oben