Mehrere Real-Zahlen in hex umwandeln und zusammenfügen

egro

Level-1
Beiträge
211
Reaktionspunkte
24
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen

Ich möchte einen FB mit folgenden Funktionen basteln (Codesys 2.3.xx):

Eingang 1: 1.Zahl als Real
Eingang 2: 2.Zahl als Real
Eingang 3: 3.Zahl als Real
(Es kann auch ein anderes Format sein. Ich möchte einfach in der Visu, via Numpad eine Zahl eingeben.)

Ausgang: Die Real-Zahlen zusammen gefügt, umgewandelt in hex, als DWORD.

Beispiel:
Eingang 1 = 77
Eingang 2 = 182
Eingang 3 = 78
Ausgang = 16#4DB64E

Ich suche hier nicht nach der fertigen Lösung, aber nach Hilfe, um mir auf die Sprünge zu helfen.
Mein Lösungsansatz war mit einem String und SHL/SHR. Grundsätzlich scheitere ich aber schon daran eine Real-Zahl, als Hex-Zahl darzustellen.


Vielleicht kann mir jemand einen Tipp geben?

Vielen Dank im Voraus
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Es geht darum einem KNX-ähnlichen Taster eine Adresse zuweisen.
Meine Aufgabenstellung ist nur die Vorstufe.
Ziel ist es nicht jeder einzelnen Taste, die komplette Adresse einzutippen
Eingang 1 ist die Linie, 2 die Nummer und 3 die Tastennummer.
 
Das habe ich jetzt nicht verstanden, ich kenne KNX aber auch nicht.

Aber nur mal so: die Hex-Darstellung ist nur für dich als Programmierer. Eine 16 Bit Integerzahl "1" oder die Hexadezimaldarstellung W#16#0001 sind im Speicher der SPS völlig identisch.
Bei Gleitkommazahlen (REAL) sieht das komplett anders aus, weil die einzelnen Bits des Speicher anders interpretiert werden.
Es kommt nur äußerst selten vor, dass man an die einzelnen Bits einer Gleitkommazahl heran muss (z.B. um von 64 in 32 Bit zu wechseln, wenn die CPU das nicht unterstützt). Darum vermute ich mal, dass du irgendwas anderes machen willst.
 
Nein, ich will nichts anderes machen...
Der Baustein, den ich verwenden will, braucht die Adresse als DWORD in genau der genannten Darstellung.
Statt Real könnte es auch WORD oder USINT sein. Die Adressen gehen nur bis 255.
Im Baustein wird wohl die Adresse wieder in die einzelnen Teile zerlegt.
Das ist nur eine Vermutung, da der Baustein vom Hersteller zur Verfügung gestellt wird.

Das soll kein Lebenswichtiger Baustein geben. Ich will mir nur Arbeit ersparen.
Wenn ich 80 Tasterstellen mit je 4 Tasten habe, muss ich 320x die Liniennummer, 320 die Adresse und 320x die Tasternummer eingeben.
Mit meinem Wunsch-FB müsste ich nur noch 80x die Liniennummer und 80x die Adresse eingeben. Den Rest sollte der FB selber erledigen.
Dieser FB würde mir über 80% Arbeit sparen.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo egro,

ich habe soeben mal schnell einen Code erstellt. Schau dir den mal an. Ist etwas komplizierter, da du ja den Wert in Hex wandeln muss, also durch 16 und Rest ermitteln.

Bei Insert ist fest "2" eingetragen, also die Stelle, an dem dein String zusammengebastelt wird. Evtl. müsstest du ermitteln wie lange dein Teil-String ist und den Wert dann variabel lassen.

Code:
FUNCTION_BLOCK POUT_TEST
VAR_INPUT
    REAL_1 : REAL;
    REAL_2 : REAL;
    REAL_3 : REAL;
END_VAR
    
VAR_OUTPUT
    STRING_    : STRING;     
END_VAR

VAR_STAT
    INT_    : ARRAY [1..3] OF INT;
    HEX     : ARRAY [1..3] OF STRING;
    i         : INT;
    iIN     : INT;
    iDIV    : INT;
    iRest    : INT;
END_VAR

///////////////////////////////////////////////////////////////////////////////////////////////


//REAL IN WORD WANDELN
INT_[1] := REAL_TO_INT(REAL_1);
INT_[2] := REAL_TO_INT(REAL_2);
INT_[3] := REAL_TO_INT(REAL_3);


//INDEX INITIALISIEREN
IF i = 0 THEN
    i := 1;
END_IF

//AUS DEZIMAL HEX ERMITTELN
iIN:=INT_[i];
HEX[i] := '';

//SCHLEIFE FÜR UMRECHUNG IN HEX
WHILE TRUE DO
         iDiv:=iIN/16;
         iRest:=iIN-iDiv*16;
    IF iDiv=0 THEN
         iRest:=iIN;
    ELSE
         iIN:=iDiv;
    END_IF
        
    CASE iRest OF
         10: HEX[i]:=INSERT(HEX[i],'A',0);
         11: HEX[i]:=INSERT(HEX[i],'B',0);
         12: HEX[i]:=INSERT(HEX[i],'C',0);
         13: HEX[i]:=INSERT(HEX[i],'D',0);
         14: HEX[i]:=INSERT(HEX[i],'E',0);
         15: HEX[i]:=INSERT(HEX[i],'F',0);
    ELSE
         HEX[i]:=INSERT(HEX[i],INT_TO_STRING(iRest),0);
    END_CASE
    
    IF iDiv=0 THEN 
        IF i < 3 THEN
            i := i +1;
        ELSE
            i := 1;
        END_IF
        EXIT; 
    END_IF
END_WHILE; 


//ALS STRING ZUSAMMENSTELLEN
STRING_ := INSERT (HEX[1], HEX[2], 2); 
STRING_ := INSERT (STRING_,HEX[3],  4);


Ob du allerdings mit dem String was anfangen kannst, kann ich nicht beurteilen.

Übrigens werden die Nachkommastellen abgeschnitten. (Was auch immer die bei einer Adresse für einen Sinn machen würden).
 
Zuletzt bearbeitet:
Wenn du nicht Real genannt hättest, dann wäre das auch durchaus möglich. Bei Real-Zahlen könnte jemand aber auch 0.1 eingeben, und wenn du das Bitmuster auf ein DWORD kopierst, kann damit später keiner etwas anfangen. Zumindest nicht wenn er nicht weiß, dass er das Bitmuster auch als Real-Zahl zu interpretieren hat.

Wenn der Wertebereich aber nur 0..255 abdecken soll, dann kannst du am HMI als Eingabewert eine BYTE oder USINT-Variable verwenden, und dann mit:
dwVar := DINT_TO_DWORD(INT_TO_DINT(BYTE_TO_INT(eingabwert)))

in eine Dword Variable ausgeben.
Ich vermute aber das kennst du schon.
 
Ja, ich hätte erwähnen sollen, dass es nur um ganze Zahlen geht.

Kurz zur Erklärung:
Unter meinem Benutzernahmen steht "Erfahrener Benutzer"... Das ist eine Lüge!!!

Ich programmiere erst seit ein paar Jahren mit Codesys 2.3. aufgewachsen bin ich mit Eaton Easy.
Darum schreibe ich noch immer alles im CFC!!! Ich weiss, das ist für richtige "Erfahrene Benutzer" unverständlich, aber ich bin Elektriker und will sehen, was, wie und bis wo funktioniert.
Wie früher bei den Schützensteuerungen.
Ich kann mit ST ein wenig verstehen, aber nur begrenzt.
Allgemein sind meine Codesys-Kenntnisse begrenzt, aber wenn ich damit jemandem hier helfen kann, mache ich das gerne.
Daher ist mein "Erfahrener Benutzer" mit Vorsicht zu geniessen...

@Thomas:
Die Typenkonvertierung kenne ich. Aber gibt es eine andere Art, das ganze in HEX umzuwandeln, als das vom "Münchnerjunge"?
Ich denke, dass ich zuerst einen String zusammensetzen muss und diesen dann irgendwie zu einem DWORD machen muss?
Der Baustein will die zusammengesetzte Adresse als DWORD.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Du meinst in etwa sowas:
Code:
VAR_INPUT
    Zahl_1 : BYTE;
    Zahl_2 : BYTE;
    Zahl_3 : BYTE;
    Zahl_4 : BYTE;
END_VAR

VAR_OUTPUT
    ZahlZusammen : DWORD;
END_VAR

BEGIN
ZahlZusammen := BYTE_TO_DWORD(Zahl_1) OR 
                SHL(IN := BYTE_TO_DWORD(Zahl_2), N := 8) OR
                SHL(IN := BYTE_TO_DWORD(Zahl_3), N := 16) OR
                SHL(IN := BYTE_TO_DWORD(Zahl_4), N := 24);

D.h. du gibst an deinem Panel die Zahlen Zahl_1 bis Zahl_4 ein, und bekommst einen zusammengesetzten Wert an ZahlZusammen.
Wenn du eine andere Reihenfolge benötigst, dann musst du beim zusammen-verodern die Reihenfolge tauschen.

Das kannst du auch in CFC programmieren.
 
Genau.

3 Zahlen reichen aber...

Das Problem ist leider immer noch das der sch... Baustein, die Zahlen im HEX-Format braucht.
Beispiel:
Eingang 1 = 77 (z.B: BYTE)
Eingang 2 = 182
Eingang 3 = 78
Ausgang = 16#4DB64E (DWORD)
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Genau.

3 Zahlen reichen aber...

Das Problem ist leider immer noch das der sch... Baustein, die Zahlen im HEX-Format braucht.
Beispiel:
Eingang 1 = 77 (z.B: BYTE)
Eingang 2 = 182
Eingang 3 = 78
Ausgang = 16#4DB64E (DWORD)

Also 77 = hex 4D, 182 = hx B6 und 78 = hex4E

Also Eingang 1 um 24 Bit links schieben, Eingang 2 um 16 Bit nach links schieben und dann alle 3 Eingangsvariablen mit Oder verknüpfen.
Das müsste in Codesys sogar in CFC gehen ... Hab nur keins gerade da zum testen.

Gruß
Blockmove
 
Also das ganze läuft so ab:
Ein kleiner Hersteller hat ein Produkt auf den Markt gebracht, dass ähnlich wie KNX funktioniert. Nur sind die Komponenten viel günstiger.
Da ich viel mit Gebäude-Automation arbeite, benutze ich hauptsächlich die Taster-Bausteine.
Das sind kleine Platinen (diese Platinen haben eine Adresse), auf die ein handelsüblicher Taster verdrahtet wird. Diese Platinen werden dann über eine Busleitung (RS485) miteinander und der SPS verkabelt.

Im Codesys gibt es dann verschiedene FB's, die das Signal auswerten.
Den FB, den ich am meisten verwende, hat einen Eingang für die Adresse.
Der Eingang muss vom Typ DWORD sein und heisst zum Beispiel 16#4DB64E.
So weiss der FB, dass ich die Linie Nr.77, die Platine Nr.182 und den Taster Nr.78 meine.
Am Ausgang, des FB, bekomme ich dann ein BOOL-Signal, wie von einem Digitalen Eingang.

Mein Beispiel oben ist nur theoretisch, da es nie 77 Linien geben wird (das wären dann über 19000 Platinen).
Es gibt auch keine Platinen mit 78 Tasteranschlüssen!
Im Normalfall gibt es 1-3 Linien und 4 Taster. Das heisst ich müsste eigentlich nur die zweite Zahl als HEX darstellen
(1 bis 9 ist ja dezimal gleich, wie Hex.).

Also noch einmal ein reales Beispiel:
Ich habe auf der Linie 1, die Platine mit der Adresse 182 und will den Taster Nr. 3 auswerten.
Dann muss ich dem FB die Adresse 16#01B603 (vom Typ DWORD) mitteilen.
Da ich aber Projekte mit über 100 solcher Platinen (mit bis zu vier Tastern) habe, muss ich das für jeden Taster eingeben.

Jetzt möchte ich einen FB machen, bei dem ich nur noch die Liniennummer und die Adresse (als BYTE) eingeben kann. Im Baustein sind dann vier der oben genannten FB's drin.
Jeder der vier FB's bekommt dann die richtige Adresse, bei der sich nur die letzte Ziffer ändert.


Es geht nur um die roten Rechtecke.Unbenannt.jpg
 
Oh man ... Du hast schon ein seltsames Talent einfache Sachverhalte kompliziert darzustellen
Du übergibst die Adresse des 1.Tasters 01B601.
Dann addierst einfach eine 1 dazu und hast die Adresse des 2. Tasters. Nochmal eine 1 dazu und du hast die Adresse des nächsten Tasters.

Gruß
Blockmove
 
Zuviel Werbung?
-> Hier kostenlos registrieren
@Blockmove
Das weiss ich auch, aber es geht um die Adresse davor!!!

Wie kann ich aus dem BYTE-Werte, beim Eingang Adresse, die Hex-Darstellung machen und in die Adresse des Hersteller-FB einfügen
Schau dir bitte nochmal das Bild an.
 
Vergiss einfach mal deine Hex-Darstellung. Bei der Programmierung relevant sind Datentypen.
D.h. welchen Datentyp verlangt der Baustein deines Herstellers, und welche Funktion besitzen die Daten darin.

Wahrscheinlich macht meine Funktion damit genau das was du brauchst, denn dort kommt eine DWORD Variable heraus. Evtl. muss du noch die Reihenfolge der Werte anpassen.


Nochmal kurz was zu deiner Hex-Darstellung:
Eine DWORD Variable besitzt 32 Bits.
Das Bitmuster:
10001001000100011001101000100

entspricht in Hexadezimaldarstellung 16#11223344.
Wenn du dieses Bitmuster als DINT (also Ganzzahlig) interpretierst, dann ergibt das 287454020. Die Bits im Speicher der SPS sind dabei völlig identisch.
Hexadezimal ist also nur eine Darstellungsart für dich als Programmierer, das ist sozusagen ein Bitstrom, eine Aneinanderreihung von einzelnen Bits. Die SPS kennt das überhaupt nicht, denn rechnen kann sie nur mit Ganzzahlen oder mit Gleitkommazahlen.
 
Ja, das ist mir alles fast klar.
Aber wenn ich zum Beispiel die Adresse 16#012001 eingebe, ist das für den Hersteller-FB nicht die Adresse 20, sondern die 14 (20 dec=14hex).
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Wenn Du 16#012001 eingibst ist das für den Hersteller Linie 1 (Hex und Dez), Adresse 20 (Hex und 36 Dez) und Schalter 1 (Dez und Hex), denn 16# kennzeichnet eine Hex-Zahl. Wenn der Hersteller was anderes sieht macht er was falsch.

Von irgendwas mit Internetzugang gesendet.
 
Zuletzt bearbeitet:
Dann passt es doch genau so wie es meine Funktion oben macht.
Wenn du bei einer Zahl eine 14 (dezimal) eingibst, siehst du an der entsprechenden Stelle im DWORD eine hexadezimale 20.

Die Herstellerfunktion extrahiert sich mittels schieben und maskieren wahrscheinlich aus dem DWORD die einzelnen Bytes wieder umgekehrt heraus

Eingang : DWORD

Wert1 := DWORD_TO_BYTE(Eingang);
Wert2 := DWORD_TO_BYTE(SHR(IN := Eingang, N := 8));
usw.
 
Am einfachsten deklarierest Du Deine Eingänge gleich als DWORD, ansonsten müsstest Du Sie im Baustein jeweils in eins umkopieren. Den Eingang der Linie verschiebst Du um 16Bit nach links, den der Adresse um 8Bit, beides mit oder in einer Variable kombinieren. An den Ausgängen addierst Du jeweils zu diesem Wert die Tasternummer dazu, fertig. Diesen kannst Du nun übergeben. Ob Du diesen Wert nun als Hex darstellst, weil so Linie, Adresse und Schalter besser auseinander zu halten sind oder Dezimal oder Binär ist egal, wenn der Hersteller wirklich ein DWORD erwartet kommt das immer aufs Selbe raus, da es sich, wie schon mehrfach erwähnt, lediglich um eine Anzeigeform handelt.

Von irgendwas mit Internetzugang gesendet.
 
Zurück
Oben