Datentypwandlung Real nach 4 Byte BCD

CNC840D

Well-known member
Beiträge
145
Punkte Reaktionen
10
Zuviel Werbung?
->Hier kostenlos registrieren
Hallo liebe Foris,

hab hier ein mittelschweres Problem mit einer Datentypwandlung von Real nach 4Byte BCD. :confused:

Gerne auch in SCL.

Das BCD Format ist allerdings nicht ein Standard BCD Format, d.h. das auch Werte über 9 darin vorhaden sind.

Das Format sieht folgendermaßen aus:
B1 E2 34 56 -->entspricht +1.23456 B="+", das "E" enstpricht dem komma
D1 E2 34 56 -->enstpricht -1.23456 D="-" , das "E" enstpricht dem komma
B1 23 4E 56 -->entspricht +1234.56 B="+", das "E" enstpricht dem komma
BE 12 34 56 -->entspricht +0.23456 B="+", das "E" enstpricht dem komma

Das Komma kann also überall in den 4Byte stehen.


Ich hab schon die Realzahl in String gewandelt und anschließend in DINT gewandelt, steh jetzt jedoch total auf dem Schlauch wie ich das Komma wieder in die BCD Zahl bekommen soll.
Evtl. gibt es ja noch bestimmt einen einfacheren Weg.

Wäre schön wenn jemand einen einfacheren Lösungsansatz hätte, da wandlungen nicht unbedingt meine Särken sind.


Viele Grüße und Vielen Dank für Eure Hilfe
:sm24:

Bernd
 

Larry Laffer

Supermoderator
Teammitglied
Beiträge
13.148
Punkte Reaktionen
2.745
Hallo,
SCL ist schon mal ein guter Ansatz ...
Ich würde da (so in etwa) wie folgt vorgehen :
Du maskierst dir immer die höchstwertigsten 4 Bit aus und bewertest die :
- wenn im Wert von 0..9 dann eine Zahl und in einen Zielspeicher (DINT) schreiben
- wenn ein Vorzeichen, dann deinen Faktor entsprechend setzen (-1 oder +1)
- Wenn ein Komma, dann dies als Faktor (zunächst 1) in einen weiteren Zielspeicher (REAL) schreiben
Nun schiebst du deine Quellvariable um 4 Bit nach links und multiplizierst deinen Zielspeicher_1 mit 10 und dividierst den Zielspeicher_2 durch 10 (wenn der <> 0 ist).
Danach wiederholst du die obige Behandlung, bis du alle Stellen ausgewertet hast.
Jetzt Nimmst du den Zielspeicher_1 wandelst ihn in REAL und multiplzierst ihn mit der Faktor und mit dem Zielspeicher_2. Da sollte dann dein Ausgangswert als REAL und für dich greifbare Zahl heraus kommen ...

Bekommst du die Code-Umsetzung meines Vorschlags selber hin ?

Gruß
Larry
 

Larry Laffer

Supermoderator
Teammitglied
Beiträge
13.148
Punkte Reaktionen
2.745
:confused: die "0" wäre doch in dem Fall für eine Interpretation unnötig ... Das könnte also m.E. schon so passen ...

Gruß
Larry
 
OP
C

CNC840D

Well-known member
Beiträge
145
Punkte Reaktionen
10
Das Format ist so wie oben beschrieben...lt. Siemens Anleitung für die HMI der Sinumerik und die zugehörige Werkzeugverwaltungskommunikation via ID- Chips.

@Larry
Danke für dein Angebot..da ich relativer SCL Neuling bin wäre ich Dir für etwas Starthilfe sehr dankbar.

Viele Grüße

Bernd
 

190B

Well-known member
Beiträge
1.124
Punkte Reaktionen
213
Zuviel Werbung?
->Hier kostenlos registrieren
Hallo Larry,

wenn ich den TE richtig verstehe, so will er nicht von "Pseudo-BCD" nach Real wandeln, sondern von Real nach "Pseudo-BCD".
 
OP
C

CNC840D

Well-known member
Beiträge
145
Punkte Reaktionen
10
Hallo 190B,

ich brauche eigentlich beides habe mich aber mal auf "Real nach Pseudo-BCD" für den Anfang beschränkt.

Viele Grüße

Bernd
 
OP
C

CNC840D

Well-known member
Beiträge
145
Punkte Reaktionen
10
So ich hab nun mal etwas rumexperimentiert und bin zu angehängter Lösung gekommen.
Allerdings geht das bestimmt auch wesentlich einfacher. Bitte gebt mir ein paar Ratschläge wie man das besser macht.

Danke

:sm24:

Bernd


Anhang anzeigen REAL_BCD.txt
 

Thomas_v2.1

Well-known member
Beiträge
8.811
Punkte Reaktionen
2.700
Zuviel Werbung?
->Hier kostenlos registrieren
Wenn es mit den Strings funktioniert ist es ja gut. Meine Idee wäre ja die schon vorhandenen BCD-Funktionen zu nutzen und um eine Auswertung in Vor- und Nachkommastellen zu ergänzen. Dann muss man die beiden BCD Werte nur noch in deine vier Bytes einmaskieren.

Sähe bei mir so aus
Code:
FUNCTION_BLOCK FB999
VAR_INPUT
    E_REAL      :REAL;
END_VAR

VAR_OUTPUT
    _1_Byte:BYTE;
    _2_Byte:BYTE;
    _3_Byte:BYTE;
    _4_Byte:BYTE;
END_VAR

VAR_TEMP
    vk : DINT;
    nk : DINT;
    bb : DWORD;
    at_bb AT bb : ARRAY[1..4] OF BYTE;
    nstellen_vk : INT;
    i : INT;    
    vk_bcd : DWORD;
    nk_bcd : DWORD;
    mask : DWORD;
END_VAR

BEGIN
// Auf Grenzen prüfen, max. 7 Stellen ohne Komma
IF E_REAL > 9999999 THEN
    bb := 16#B9999999;
ELSIF E_REAL < -9999999 THEN
    bb := 16#D9999999;
ELSE
    // Init
    bb := 16#B0000000;
    // Vorzeichen
    IF E_REAL < 0.0 THEN
       bb := 16#D0000000;
    END_IF;
    
    // Vor und Nachkommastellen
    E_REAL := ABS(E_REAL);  // Vorzeichen wurde schon abgearbeitet
    nstellen_vk := DINT_TO_INT(TRUNC(LOG(E_REAL))) +1;
    vk := REAL_TO_DINT(TRUNC(E_REAL));    
    nk := REAL_TO_DINT((E_REAL - vk) * 10000000);
    
    vk_bcd := DINT_TO_BCD_DWORD(vk);
    nk_bcd := DINT_TO_BCD_DWORD(nk);
    
    // Vorkommastellen Nibbles einbauen
    vk_bcd := SHL(IN := vk_bcd, N := (7 - nstellen_vk) * 4);
    mask := 16#0F000000;
    FOR i := 1 TO nstellen_vk DO 
        bb := bb OR (mask AND vk_bcd);
        mask := SHR(IN := mask, N := 4);
    END_FOR;
    
    // Komma einbauen
    bb := bb OR (mask AND 16#EEEEEEEE);
    mask := SHR(IN := mask, N := 4);

    // Nachkommastellen Nibbles passend schieben
    nk_bcd := SHR(IN := nk_bcd, N := (nstellen_vk + 1) * 4);
    // Nachkommastellen einbauen
    FOR i := nstellen_vk TO 8 DO 
        bb := bb OR (mask AND nk_bcd);
        mask := SHR(IN := mask, N := 4);
    END_FOR;
END_IF;

_1_Byte := at_bb[1];
_2_Byte := at_bb[2];
_3_Byte := at_bb[3];
_4_Byte := at_bb[4];

END_FUNCTION_BLOCK

Es ist dabei immer ein Vorzeichen vorhanden. Bei 7 Vorkommastellen gibt es kein Komma mehr, ich weiß nicht wie deine Spezifikation aussieht.
 
OP
C

CNC840D

Well-known member
Beiträge
145
Punkte Reaktionen
10
Hallo Thomas,

vielen Dank für Deinen Code....hab doch gewußt das es kleiner geht.:)

Soweit funktioniert die Sache auch, beim testen ist mir allerdings aufgefallen das die 0 bzw. das E vor dem Komma verschwindet sobald der Wert kleiner +0.1 bzw. -0.1 ist, die 0 wird jedoch benötigt.
Hab versucht den Code von Dir noch dahingehend abzuändern bin aber leider gescheitert.

So sieht 0.1 bei deinem Code aus BE 10 00 00
So solte er aussehen B0 E1 00 00

Das Problem tritt wie gesagt nur bei gleich kleiner +0.1/-0.1.

Wäre toll wenn du mir noch einen Tipp hättest

Vielen Dank

Bernd
So sollte er aussehen
 

Thomas_v2.1

Well-known member
Beiträge
8.811
Punkte Reaktionen
2.700
Stimmt, kleine Zahlen habe ich gepflegt ignoriert ;-)
Ist aber nicht schwer, man braucht nur zu sagen dass es immer eine Vorkommastelle gibt.
Die For-Schleifen braucht man auch nicht mehr.
Code:
FUNCTION_BLOCK FB999
VAR_INPUT
    E_REAL      :REAL;
END_VAR

VAR_OUTPUT
    _1_Byte:BYTE;
    _2_Byte:BYTE;
    _3_Byte:BYTE;
    _4_Byte:BYTE;
END_VAR

VAR_TEMP
    vk : DINT;
    nk : DINT;
    bb : DWORD;
    at_bb AT bb : ARRAY[1..4] OF BYTE;
    nstellen_vk : INT;
    i : INT;    
    vk_bcd : DWORD;
    nk_bcd : DWORD;
    mask : DWORD;
    n : INT;
END_VAR

BEGIN
// Auf Grenzen prüfen, max. 7 Stellen ohne Komma
IF E_REAL > 9999999 THEN
    bb := 16#B9999999;
ELSIF E_REAL < -9999999 THEN
    bb := 16#D9999999;
ELSE
    // Init
    bb := 16#B0000000;
    // Vorzeichen
    IF E_REAL < 0.0 THEN
       bb := 16#D0000000;
    END_IF;
    
    // Vor und Nachkommastellen
    E_REAL := ABS(E_REAL);  // Vorzeichen wurde schon abgearbeitet
    IF E_REAL >= 1.0 THEN
        nstellen_vk := DINT_TO_INT(TRUNC(LOG(E_REAL))) +1;
    ELSE
        nstellen_vk := 1;   // Eine Stelle für führende Null
    END_IF;
    vk := REAL_TO_DINT(TRUNC(E_REAL));    
    nk := REAL_TO_DINT((E_REAL - vk) * 10000000);
    
    vk_bcd := DINT_TO_BCD_DWORD(vk);
    nk_bcd := DINT_TO_BCD_DWORD(nk);
    
    // Vorkommastellen einbauen
    n := (7 - nstellen_vk) * 4;
    vk_bcd := SHL(IN := vk_bcd, N := n);
    mask := SHL(IN := 16#0FFFFFFF, N := n);
    bb := bb OR (mask AND vk_bcd);
    // Komma
    n := (nstellen_vk + 1) * 4;
    mask := SHR(IN := 16#E0000000, N := n);
    bb := bb OR mask;
    // Nachkommastellen einbauen
    nk_bcd := SHR(IN := nk_bcd, N := n);
    mask := SHR(IN := 16#0FFFFFFF, N := n - 4);
    bb := bb OR (mask AND nk_bcd);
END_IF;

_1_Byte := at_bb[1];
_2_Byte := at_bb[2];
_3_Byte := at_bb[3];
_4_Byte := at_bb[4];

END_FUNCTION_BLOCK
 

Similar threads

A
Antworten
2
Aufrufe
4K
Anonymous
A
Oben