Datentypwandlung Real nach 4 Byte BCD

CNC840D

Level-2
Beiträge
161
Reaktionspunkte
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
 
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
 
: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
 
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
 
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
 
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.
 
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
 
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
Zurück
Oben