Zuviel Werbung? - > Hier kostenlos beim SPS-Forum registrieren

Page 3 of 3 FirstFirst 123
Results 21 to 23 of 23

Thread: 12 Stellige BCD Zahl in DINT wandeln

  1. #21
    Maagic7 is offline Erfahrener Benutzer
    Themenstarter
    Join Date
    03.12.2013
    Location
    Ansbach
    Posts
    228
    Danke
    2
    Erhielt 73 Danke für 44 Beiträge

    Default


    Zuviel Werbung?
    -> Hier kostenlos registrieren
    Habs jetzt nochmal getestet und angepasst!
    Ziffern 11/12, welche bei einem 10-Ziffern DINT eigentlich nur das '-' enthalten können dürfen
    werden vorab geprüft und ein Fehler ausgelöst, wenn da was anders als ein 'F' drinsteht.
    Das lässt sich dann ganz einfach durch auskommentieren der Schleife entfernen.

    Hier geht es wirklich nur um die Fehleranzeige: Da ein 32-DINT nicht mehr als 10 Ziffern enhalten kann,
    kann man getrost abbrechen. Die Frage ist nur will man einen Fehler haben, weil man das vorher nicht
    geteset hat oder will man einfach die BCDs konvertiert haben!

    Mittlerweile sehe ich die Stringversion tatsächlich als die einfachere Version an. Das macht
    programmiertechnisch definitiv weniger Probleme.
    Die Frage bei der Stringversion ist nur, was passiert, wenn man STRING_TO_DINT auf ungültige Werte
    loslässt! Wie reagiert da Step7, TIA, CodeSys

    // hier nochmal der überarbeitete Code
    Code:
    FUNCTION m7_BCDL_TO_DINT : DINT
        TITLE ='Converts Long BCD (10 digits and sign) to a DINT'
    
    // ==============================================================================
    // Converts long BCD value (up to 10 digits and sign) to a DINT
    // The BCD must be provided in an ARRAY[1..] OF BYTE in little endian Format
    // BCD[1] contains the lowes digit
    // each BYTE represents 2 digits of the BCD. 5 Bytes = 10 digits
    // plus the possible minus '-' ('-' is B#16#F in BCD code)
    // the '-' can be anywhere in the BCD. If a '-' is detected the
    // conversion will stop at this position. 
    // For BCD{#0F, #F0) what both is '-0', the FUNCTION returns 0.
    // IF an Error occures ,the Function returns -2147483648 / DW#16#80000000
    //    and FC-ENO := FALSE  // the ok-Flag
    // ELSE it returns the DINT value of the BCD {-2147483647 .. 2147483647}  
    //    and FC-ENO := TRUE;  // the ok-Flag
    // ==============================================================================
    //   
    // AUTHOR: S.Maag
    // DATE: 4/2020
    //
    // CHANGELOG:
    // ------------------------------------------------------------------------------
    // DATE         NAME        DESCRIPTION
    // ------------------------------------------------------------------------------
    // 06.04.2020   S.Maag      Added Error check for digit 11/12 which
    //                          will exceed 32-Bit DINT range. So far digit 11/12
    //                          hve been ignored because they exceed the DINT-range.
    //                          If we want to ignore again, we have to remove
    //                          Err:=TRUE; at Byte6 (digit 11/12) check.
    //                          See comment in the code! 
    // ------------------------------------------------------------------------------
    
        VERSION : '1.0'
        AUTHOR  : 'S.Maag'
        FAMILY  : 'Maagic7'
    
    VAR_INPUT
        inBCDs : ARRAY[1..6] OF BYTE;  // 1:Lo..6:Hi; Array with the BCD digits (with sign max 12 digits)
    END_VAR
    
    VAR_OUTPUT
    
    END_VAR
    
    VAR_TEMP
        I      : DINT;   // LOOP COUNTER
        tmpDI  : DINT;   // Our DINT value
        diBCD  : DINT;   // Value of a 2-digit BCD value
        Err    : BOOL;   // Error (BCD-digit not valid; NOT{0..9})
        negative: BOOL;  // BCD is negative
        dFact  : DINT;   // Factor for BCD_TO_INT (1_digit, 10_digit, 100_digit ...)
    
        BCDhi  : WORD;   // Value of hi BCD digit of a BYTE
        BCDlo  : WORD;   // Value of lo BCD digit of a BYTE
    END_VAR
    
    CONST
       cstReturnValIfError := -2147483648; // -2147483648 / DW#16#80000000  we use the -2147483648 as Error indication
    END_CONST
    
    BEGIN
    
        Err := FALSE;
        negative := FALSE;
        tmpDI := 0;
        dFact := 1;  // Faktor für (1er, 10er),(100er, 1000er) ...
       
        // **********************************************************************
        // ***  A BCD can contain a max. of 10 digits and a '-' to fit into   ***
        // ***  a DINT. (At a 10digit BCD the '-' is in digit 11 of 12)       ***
        // ***  If you want to ignore numbers in digit 11/12, then remove     ***
        // ***  this 1st check for valid digit 11/12.                         ***
        // ***  Removing this 1st check do not affect the processing of the   ***
        // ***  the 'F', BCD '-'                                              ***
        // ***  With this check an Error is fired when digit 11/12 contains   ***
        // ***  digits different from 'F'/'-', without the check              ***
        // ***  only 10 digits & '-' are processed                            ***
        // **********************************************************************
        
        // (*    // remove this 'IF THEN', if you want to ignore numbers in digit 11/12
    
        // check first digit 11/12: If it contains a number, we will exceed DINT range
        BCDhi := BYTE_TO_WORD( SHR(IN:=inBCDs[6], N:=4) );   // Value of hi BCD digit
        BCDlo := BYTE_TO_WORD( inBCDs[6] AND B#16#F);        // Value of lo BCD digit
        IF BCDlo <> W#16#0 AND BCDlo <> W#16#F THEN
            Err := TRUE;
        ELSIF BCDHi <> W#16#0 AND BCDHi <> W#16#F THEN
            Err := TRUE;
        END_IF;
        // **********************************************************************
    
        // *)
        
        I := 0;
        REPEAT 
            I := I + 1;   // inBCDs[1..6]
    
            BCDhi := BYTE_TO_WORD( SHR(IN:=inBCDs[I], N:=4) );   // Value of hi BCD digit
            BCDlo := BYTE_TO_WORD( inBCDs[I] AND B#16#F);        // Value of lo BCD digit
            
            // Caution BCD digits must be checked for correct range {0..9}
            // PLCs may stop if BCD contains invalid digits
        
            IF WORD_TO_INT(BCDhi) > 9 THEN          // IF BCD_DIGIT IS NOT VALID
                IF BCDhi = B#16#F THEN
                    negative := TRUE;
                ELSE
                    Err := TRUE;                    // invalid BCD digit
                END_IF;
                BCDhi := 0;                                   
            END_IF;
      
            IF WORD_TO_INT(BCDlo) > 9 THEN          // IF BCD_DIGIT IS NOT VALID
                IF BCDlo = B#16#F THEN
                    negative := TRUE;
                    BCDHi := 0;                     // ignore BCDhi if BCDlo is the sign '-'
                ELSE
                    Err := TRUE;                    // invalid BCD digit
                END_IF;
                BCDlo := 0;     
            END_IF;
     
            // calculate the DINT value of the 2 BCD digits only up to 10 digits max
            // digit 11..12 is the '-' at 10 digit long BCDs
            IF I<= 5 THEN
                diBCD := INT_TO_DINT(WORD_TO_INT(BCDhi)*10) + INT_TO_DINT(WORD_TO_INT(BCDlo));
      
                IF I = 5 THEN           // Check overflow if 10digit BCD
                    IF diBCD > 21 THEN  // 21-47-48-36-47 = DW#16#7FFFFFFF; maxDINT
                        Err := TRUE;
                    ELSIF diBCD = 21 THEN
                        IF tmpDI > 47483647 THEN ERR := TRUE; END_IF;
                    END_IF;
                END_IF;         
    
                tmpDi := tmpDi + diBCD * dFact;  // add the value of the 2 digits in the right position of the DINT   
                dFact := dFact *100;             // 100 it's ShiftLeftBCD(myBCD,2_digits) as DINT
                // dFact = {1, 100, 10.000, 1.000.000, 100.000.000} fact = 10.000.000.000 will exceed the DINT range 
            END_IF;
        
        UNTIL negative OR Err OR (I = 6)
        END_REPEAT;
       
        IF negative THEN        // add the negative sign to the DINT
            tmpDI := -tmpDI;
        END_IF;                
    
        IF Err THEN
           m7_BCDL_TO_DINT := cstReturnValIfError; // -2147483648; DW#16#80000000
        ELSE
           m7_BCDL_TO_DINT := tmpDI;
        END_IF;
        
        OK := NOT Err;   //  OK-Bit = TRUE if BCD is converted without an Error! If OK is FALSE, the returned DINT is not valid!
        
    END_FUNCTION

  2. #22
    Maagic7 is offline Erfahrener Benutzer
    Themenstarter
    Join Date
    03.12.2013
    Location
    Ansbach
    Posts
    228
    Danke
    2
    Erhielt 73 Danke für 44 Beiträge

    Default

    Und dann verlässt Du Dich darauf, dass nur negative Zahlen drin stehen, damit Du weisst, wo die eine BCD-Zahl aufhört und die nächste anfängt???
    Nein, darauf brauch ich mich nicht verlassen. Insgesamt ist das defintiv nur eine einzige zusammenhängende BCD-Zahl. Entweder negativ oder positiv!
    Die Zahl startet definitiv auf der rechten Seite mit den Einern und geht max. bis 10 Stellen, Stelle 11/12 muss spätestens '-' oder eben 0 enthalten.

    In der Praxis sieht es so aus, dass das '-' immer an Stelle 12 ist, dann ist mit '0'en aufgefüllt, bis die erste wertige Ziffer kommt.
    So ist das beim original Code mit den Stringoperationen interpretiert (eine Fehlerabfrage gibt's im original überhaupt nicht)

    Mein Code akzeptiert das '-' an jeder beliegigen Stelle, was erst mal nicht falsch ist, sondern einfach nur mehr Varianten zulässt, ohne
    nicht mehr zu konvertieren.
    Ich breche in der ersten Version nach 10 Stellen mit der Übersetzung einfach ab und prüfe 11/12 nur noch auf ein '-'
    per Definition des DINT kann 11/12 nur '-' oder eben nichts enhalten!

  3. #23
    Join Date
    27.05.2004
    Location
    Thüringen/Berlin
    Posts
    13,579
    Danke
    721
    Erhielt 3,040 Danke für 2,185 Beiträge

    Default


    Zuviel Werbung?
    -> Hier kostenlos registrieren
    Quote Originally Posted by Maagic7 View Post
    Nein, darauf brauch ich mich nicht verlassen. Insgesamt ist das defintiv nur eine einzige zusammenhängende BCD-Zahl. Entweder negativ oder positiv!
    Die Zahl startet definitiv auf der rechten Seite mit den Einern und geht max. bis 10 Stellen, Stelle 11/12 muss spätestens '-' oder eben 0 enthalten.

    In der Praxis sieht es so aus, dass das '-' immer an Stelle 12 ist, dann ist mit '0'en aufgefüllt, bis die erste wertige Ziffer kommt.
    So ist das beim original Code mit den Stringoperationen interpretiert (eine Fehlerabfrage gibt's im original überhaupt nicht)

    Mein Code akzeptiert das '-' an jeder beliegigen Stelle, was erst mal nicht falsch ist, sondern einfach nur mehr Varianten zulässt, ohne
    nicht mehr zu konvertieren.
    Ich breche in der ersten Version nach 10 Stellen mit der Übersetzung einfach ab und prüfe 11/12 nur noch auf ein '-'
    per Definition des DINT kann 11/12 nur '-' oder eben nichts enhalten!
    Wenn geht, dann hau dem Entwickler einer, dr das verbrohen hat. Ein Trennzeichen war wohl zu schwierig für den Kollegen?
    Gruß
    Ralle

    ... there\'re 10 kinds of people ... those who understand binaries and those who don\'t …
    and the third kinds of people … those who love TIA-Portal

Similar Threads

  1. WinCC Flex Gleitpunkt 3 stellige Zahl mit 2 Kommatstellen
    By litlegerman in forum HMI
    Replies: 7
    Last Post: 24.09.2018, 18:04
  2. Replies: 6
    Last Post: 06.03.2017, 12:48
  3. Replies: 31
    Last Post: 22.02.2012, 13:50
  4. BCD-Zahl in Ganzzahl (16 Bit) wandeln
    By baui in forum Programmierstrategien
    Replies: 3
    Last Post: 05.03.2009, 17:08
  5. 5-stellige ascii zahl in normale zahl umwandeln
    By Anonymous in forum Simatic
    Replies: 3
    Last Post: 04.01.2006, 16:12

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •