News:

PROTON pic BASIC Compilers for PIC, PIC24, dsPIC33

Main Menu

IEEE-745 to VB format conversion

Started by gtvpic, Apr 18, 2021, 07:26 AM

Previous topic - Next topic

gtvpic

Good morning
I am making a small 8 channel data logger that communicates with a PC. The Analog inputs are made by ADS1256 port which each measure occupies 32bit.
For data processing and sending to the PC I use the 4 byte of the variables so that with 32 bits I can send the real value in floating point.
       Case 51    ' Responde 4 Canales de Tension en Voltios
          GoSub Crea_Cabeza_Telegrama_S
          BufferS[3]   = Numero        ' Numero de Telegrama
          BufferS[4]   = 23            ' Largo del Telegrama
          BufferS[5]   = V_CH0.Byte3   ' \                 
          BufferS[6]   = V_CH0.Byte2   '  \Valor en Voltios del Canal 0
          BufferS[7]   = V_CH0.Byte1   '  /                 
          BufferS[8]   = V_CH0.Byte0   ' /                 
          BufferS[9]   = V_CH1.Byte3   ' \                 
          BufferS[10]  = V_CH1.Byte2   '  \Valor en Voltios del Canal 1
          BufferS[11]  = V_CH1.Byte1   '  /                 
          BufferS[12]  = V_CH1.Byte0   ' /                 
          BufferS[13]  = V_CH2.Byte3   ' \                 
          BufferS[14]  = V_CH2.Byte2   '  \Valor en Voltios del Canal 2
          BufferS[15]  = V_CH2.Byte1   '  /                 
          BufferS[16]  = V_CH2.Byte0   ' /                 
          BufferS[17]  = V_CH3.Byte3   ' \                 
          BufferS[18]  = V_CH3.Byte2   '  \Valor en Voltios del Canal 3
          BufferS[19]  = V_CH3.Byte1   '  /                 
          BufferS[20]  = V_CH3.Byte0   ' /                           
          LBufferS     = BufferS[4]- 3 ' Largo Actual del Telegrama
          GoSub Calcula_CRC_Salida     ' Calcula CRC y Envia Telegrama

I have the problem on my PC to recover the value of the 4 byte, for example in the PIC the value 500.00 translates into 0.0.122.135
How do I recompose the value of the variable on the PC starting from these four bytes?
Thank you very much for the help and for the good functioning of the forum

rox

Hi, Maybe that's due to Microchip having different format of IEEE-754, check the proton manual for conversion to the standard.

top204

#2
This was previously discussed on the forum, and I wrote some conversion routines in the thread, but it seems to have disappeared?

There is a mechanism in the compiler manual for the conversion of floating point formats, but I have extended it to "real" usable code for the next upgrade's manual.

This is the code example in the new manual's Floating Point section:
'
' Convert IEEE-754 to Microchip floating point and vice-versa
'
    Device = 18F26K40               ' Select the device to compile for
    Declare Xtal = 16               ' Tell the compiler the device will be operating at 16MHz
'
' Create a variable for the demo
'
    Dim MyFloat As Float = 3.14     ' Create a floating point variable and pre-load it
   
'-------------------------------------------------------------------------------
' Convert the IEEE-754 variable passed, to a Microchip format
' Input     : pVar holds the IEEE-754 format floating point variable
' Output    : pVar will be converted to Microchip format
' Notes     : pVar must be a Float type variable and not a constant value
'
$define IEEE754_MChip(pVar) '
    Rol pVar.Byte1          '
    Rol pVar.Byte0          '
    Ror pVar.Byte1
   
'-------------------------------------------------------------------------------
' Convert the Microchip variable passed, to an IEEE-754 format
' Input     : pVar holds the Microchip format floating point variable
' Output    : pVar will be converted to IEEE-754 format
' Notes     : pVar must be a Float type variable and not a constant value
'
$define MChip_IEEE754(pVar) '
    Rol pVar.Byte1          '
    Ror pVar.Byte0          '
    Ror pVar.Byte1
   
'---------------------------------------------------------------------------------
' Demo to convert Microchip and IEEE-754 floating point formats
'
Main:
    MChip_IEEE754(MyFloat)      ' Convert MyFloat to IEEE-754 format
    IEEE754_MChip(MyFloat)      ' Convert MyFloat back to Microchip format

gtvpic

Perfect, it is already working correctly. :)  :)  :)

Thank you very much Les and many thanks to the forum for working so well.

I am waiting for the new version of the compiler and its manuals to be available to buy it. I imagine it will be shortly.

Do you have any idea of the release date?

trastikata

Or this is the VB function if you want conversion on the PC, code is taken from here:

    'Will return 250.25
    Dim MyString As String
    MyString = ConvertHexToSingle("437A4000").ToString

    Private Function ConvertHexToSingle(ByVal hexValue As String) As Single
        Try
            Dim iInputIndex As Integer = 0
            Dim iOutputIndex As Integer = 0
            Dim bArray(3) As Byte

            For iInputIndex = 0 To hexValue.Length - 1 Step 2
                bArray(iOutputIndex) = Byte.Parse(hexValue.Chars(iInputIndex) & hexValue.Chars(iInputIndex + 1), Globalization.NumberStyles.HexNumber)
                iOutputIndex += 1
            Next

            Array.Reverse(bArray)

            Return BitConverter.ToSingle(bArray, 0)
        Catch ex As Exception
            Throw New FormatException("The supplied hex value is either empty or in an incorrect format. Use the following format: 00000000", ex)
        End Try
    End Function

towlerg

@trastikata Note comment in post #1 re. Microchip variation.

Yasin

Quote from: gtvpic on Apr 18, 2021, 10:00 AMPerfect, it is already working correctly. :)  :)  :)

Thank you very much Les and many thanks to the forum for working so well.

I am waiting for the new version of the compiler and its manuals to be available to buy it. I imagine it will be shortly.

Do you have any idea of the release date?

Les's solution is very practical, but rarely can give different results.

Test for values less than 2. For example, like 1.88 or 0.96. I have encountered the problem before. I think the bits gets cleared accidentally while spinning. I solved the problem by temporarily hiding pExponent.7 and pMantissa0.7.

OG

Quote from: top204 on Apr 18, 2021, 09:14 AMThis was previously discussed on the forum, and I wrote some conversion routines in the thread, but it seems to have disappeared?

Discussed in the old forum.
I haven't saved all of them.


--------------


Default serious problem with 4 bytes float

    I am building simple project that send float 4 bytes via serial from 16F690 to esp8266

    so the problem is on 16F690 side float value is 0X8111999A

    so when read this value from esp8266 then it is not correct and result is -0.00

    as arduino float must be as IEEE754

    so how to fix this problem?

    Last edited by hassawfaa; 25th September 2019 at 18:29.

------------


Default Re: serious problem with 4 bytes float

    Convert the float in the Pic device or in the ESP (I'll bet a tidy sum it's easier in Proton).

    See the page of the manual headed "Floating point mathematics. At the bottom it show the method to convert either way, in your case Microchip to IEEE-754. You can access the individual bytes as Variablename.Byte4 or whatever.

    George.

---------

Re: serious problem with 4 bytes float

    As George stated, page 21 of the compiler's manual shows how to convert from the Microchip format to the IEEE754 format using a few rotates.

    However, it can be done with a procedure to do the conversion, which make the program tidier:

    Code:

    '----------------------------------------------------
    ' Convert a Proton (Microchip) 32-bit float into an IEEE754
    ' Input    : pValue holds the floating point value to convert
    ' Output    : Returns a Dword carrying the 4 bytes in correct order for IEEE754
    ' Notes    : None
    '
    Proc FloatToIEEE(pValue As Float), Dword
        Result.Byte0 = pValue.Byte3        ' \
        Result.Byte1 = pValue.Byte2        ' |
        Result.Byte2 = pValue.Byte1        ' | Transfer the Float parameter to the Dword result without IntToFloat conversion
        Result.Byte3 = pValue.Byte0        ' / 
        Dim Exponent As Result.Byte3              ' Create an alias for the floating point's exponent byte
        Dim Mant0    As Result.Byte2              ' Create an alias for the floating point's mantissa0 byte   

        Rol Mant0                        ' Rotate the LSB of Mantissa0 into the Carry flag
        Ror Exponent                          ' Rotate the Carry into the MSB of Exponent and its LSB into Carry
        Ror Mant0                        ' Rotate the Carry into MSB of Mantissa 0
    EndProc
   
    '--------------------------------------------------------------------
    Main: 
        Dim IEEEConv As Dword
       
        IEEEConv = FloatToIEEE(1234)   
        HRSOut Dec IEEEConv
        Stop

    I learned my lesson when I created Proton24 and used IEEE754 standard format for both 32-bit and 64-bit floating point variables in it, but remember, I created the 8-bit Proton back in 2003 and I added floating point to it only a few years later, and there were very few microcontroller compilers that had floating point variables, so I went to the obvious place for inspiration and information, and that was Microchip! Unfortunately, they used a screwed up format but I wasn't 100% in the know about float formatting, just how it worked, so I used their format. I learned over the years never to rely on Microchip for exact information, and NEVER, NEVER, take it for granted what they recommend or write is accurate, or even correct!

    But changing the 8-bits compiler's float format to IEEE would probably have caused problems with people's code, so I had to leave the format in Proton alone when I created Proton24 as well.

    Last edited by top204; 25th September 2019 at 20:07.

---------


Default Re: serious problem with 4 bytes float

    Main:
    SerData = 4.55
    SerOut PORTA.2, 396, [SerData]

    Print At 1,1, Dec SerData
    Print At 2,1, Hex SerData
    DelayMS 2000
    Cls
    GoTo Main

    End

    the result is


    the hex value for 4.55 that sent from pic is 0X8111999A
    then when esp receive the serial data it show -0.00
    could you please help me to find solution?

-----------


Default Re: serious problem with 4 bytes float

    The solution is just prior your post. Haven't you tried out ?

----------

Re: serious problem with 4 bytes float

    I am using 12F675, I have an issue I tried the code then can not compile the code :

    Error: Not enough RAM for all the variables. Reduce the amount, or switch to a larger device

    so my project is so small I do not want to use larger device

    is there any solution?

------------


Default Re: serious problem with 4 bytes float

    Post your code and some kind member of this forum might be able to reduce it in size or point you in the right direction.

    Charlie

------------

Re: serious problem with 4 bytes float

    hassawfaa - I doubt that you can run the code that Les posted on a 12F675. But you definatly can run the code on the manual.

    BTW when you say that your project is small, is that physical size or price or indeed some other parameter. If it's price, then larger more popular devices are probably cheaper.

    George.

--------

Re: serious problem with 4 bytes float

    As George stated, simply use the Rol and Ror commands on teh variable itself to move it into the correct format for IEEE. However, with a standard 14-bit core device, you should not be using floating point because they are old devices with little RAM and are now very much out of date, so floating point takes up the RAM and code space.

------------

serious problem with 4 bytes float

    it is impossible to compile the code using 12F675 it takes more than 64 variable bytes
    I have to make conversion to IEEE754 at ESP side
    by the way, what device you recommend to use I just use two analog inputs and two IO for serial communication

    Last edited by hassawfaa; 2nd October 2019 at 17:51.

-------

Re: serious problem with 4 bytes float

    All the info required is within the Procedure code, but here's a piec of code that will do the same inline an no extra RAM used:

    Code:

        Dim MyFloat As Float = 1234

        Swap MyFloat.Byte3, MyFloat.Byte0          ' \ Swap the bytes around within MyFloat
        Swap MyFloat.Byte2, MyFloat.Byte1          ' /

        Rol MyFloat.Byte2                          ' Rotate the LSB of Mantissa0 into the Carry flag
        Ror MyFloat.Byte3                          ' Rotate the Carry into the MSB of Exponent and its LSB into Carry
        Ror MyFloat.Byte2                          ' Rotate the Carry into MSB of Mantissa 0

        HRSOut MyFloat                            ' This will transmit the 4 bytes in IEEE format

    .

    Last edited by top204; 2nd October 2019 at 18:51.

------------


Default Re: serious problem with 4 bytes float

    I think it's the rest of OP code that heats up all the 64 bytes of RAM.
    So it would be less expensive to go for a 12F1522 which has as much as 4 times fold of 12F675, and license free.

------------

top204

Many thanks OG. I thought it was on this forum, and did find it unusual for it to disappear.

Unfortunately, my memory is not what it used to be since my injury. :-(


John Drew

Another idea is to send the float value out as a string then convert it back to a number at the other end. Proton will do it and so will Delphi but not sure about VB. It probably will.

Another way is to convert the float to a dword by multiplying by say a 1000, send the integer and at the other end convert it to a float and divide by 1000. I have used the latter way many times.
John

top204

I agree with John.

Whenever I have been sending floating point from a microcontroller to a PC, I have always used a String method, then convert the String into the floating point format that the PC application is using, because there are quite a few different formats for floating point and not all of them use the IEEE-754 format, and if they do, it can be big-endian or little-endian. So a few element String with the value held in it, bypasses all of this and "any" PC application can see and convert the value.


gtvpic

In this application the measurements are from -1000.0Vdc to + 1000.0Vdc so that the range is very large, I also have 4 voltage measurements and four intensity measurements so if we put 4 decimal places to each of the eight measurements and digits are 64 characters in total (Each measure would be VVVVDDDD x 8 measures = 64 Characters). On the other hand, if I send the FLOAT it is 4 bytes per measure and I can obtain more values than with the option of sending the string.
On previous occasions, I used the send string with a fixed number of decimal places.
Thank you very much for the help.

trastikata

It was mentioned earlier:
 - multiply by 10000
 - send as SDword (4 bytes)
 - receive 4 bytes as integer
 - divide by 10000

No information will be lost and you will have another 32 bytes to fill with usable information as you require.

gtvpic

I understand, if I multiply the float by 10000 and store it in an SDWORD it will occupy 4 bytes, the same as a FLOAT.
For the shipment it will be the same but in the PIC I will have one more operation for each of the measurements, which takes time to execute and takes up program memory.

It is another solution but currently I opted to send the FLOAT divided into 4 byte so that on the PC I reconcile the BYTES and I get a SINGLE. I have the PC application made in VB2019 and the code used is the following:
            Case 51     ' Valores de los Canales de Tension en Voltios
                If P_Valor = (UBound(Valor) - 1) Then
                    Array.Copy(Valor, 1, Valor, 0, UBound(Valor) - 1)
                Else
                    ' Incrementa el Valor del Registro
                    P_Valor = P_Valor + 1
                End If
                '       Canal 0
                ' Recupera los BYTES
                B3 = Telegrama(5)
                B2 = Telegrama(6)
                B1 = Telegrama(7)
                B0 = Telegrama(8)
                ' Forma el Texto del Hexadecimal
                Ayuda = Right("00" & Hex(B0), 2)
                Ayuda &= Right("00" & Hex(B1), 2)
                Ayuda &= Right("00" & Hex(B2), 2)
                Ayuda &= Right("00" & Hex(B3), 2)
                ' Calcula el Valor
                Valor(P_Valor).Canal(0).Tension = HextoFloatIEEE(Ayuda)

Normally I like to do new things and see how they work, in this way I try to optimize the operation of the applications for future versions or improvements of the current ones.

Thanks for the help and I will consider your suggestions for future applications

As I comment more times on the PROSITRON compiler, I have used it for more than 10 years and every day I learn something new about it and its application, also in the forum very good ideas and suggestions are provided so that I am always trying to optimize the code more and be more efficient, although the resources of the PICs are increasing.

I am looking forward to seeing the new version of positron and its manuals, which will surely be incorporating new examples of all these particularities.

tumbleweed

You just need to be aware that as Les pointed out, different compilers and applications represent data differently on the PC side.

That may work with VB2019 on a win PC, but that might be it.

trastikata

I looked through MC's AN575 and it seems it is matter of simple bit swap, so I wrote a small VB.NET function for direct conversion from Microchip's 32b floating point 4 byte's array, not the most elegant but should work.

       'Example how to use:

        Dim MySingle As Single
       
        'This will return 500
        MySingle = MC32bFloatToIEEE754(135, 122, 0, 0)
       


Private Function MC32bFloatToIEEE754(ByVal byte3 As Byte, ByVal byte2 As Byte, ByVal byte1 As Byte, ByVal byte0 As Byte)
        Dim bytes(4) As Byte
        Dim tempBit As Boolean

        'Load the Byte array with the FP values
        bytes(3) = byte3
        bytes(2) = byte2
        bytes(1) = byte1
        bytes(0) = byte0

        'Convert to a Bit array
        Dim bitArray As New BitArray(bytes)

        'Convert from MC's 32b floating point to IEEE754
        tempBit = bitArray.Item(23)
        For i As Integer = 23 To 30
            bitArray.Item(i) = bitArray.Item(i + 1)
        Next
        bitArray.Item(31) = tempBit

        'Convert the Bit array to byte
        bitArray.CopyTo(bytes, 0)

        'Return converted floating point as Single
        Return BitConverter.ToSingle(bytes, 0)
    End Function