CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

4 Hex bytes To Float - exponent and mantissa [SOLVED]

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Gabriel



Joined: 03 Aug 2009
Posts: 1067
Location: Panama

View user's profile Send private message

4 Hex bytes To Float - exponent and mantissa [SOLVED]
PostPosted: Sun Nov 19, 2017 6:36 pm     Reply with quote

Hi all,

I have tried this:

Code:
float test=0x41200000;

Which obviously does not work as in reality its 4 separate bytes 0x41,0x20,0x00,0x00 in a bad attempt to build a float.

i understand there is a sign, exponent and mantissa to this... but is there an easier way than bit testing and elevating each bit to the corresponding power and adding and signing?

the resulting float for this should be "10.0"

thanks,

G.
_________________
CCS PCM 5.078 & CCS PCH 5.093


Last edited by Gabriel on Mon Nov 20, 2017 4:37 pm; edited 1 time in total
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Nov 19, 2017 7:39 pm     Reply with quote

Download this zip to your Windows desktop.
http://www.piclist.com/images/floatconv10.zip
Open it, and drag floatconv.exe onto your desktop.
Run it. You can select the float format. CCS uses
"Microchip 32-bit" format for the PCM and PCH compilers.
You can enter the 4 bytes, then click the Convert to Float
button, and it will show you the decimal floating point number.
Gabriel



Joined: 03 Aug 2009
Posts: 1067
Location: Panama

View user's profile Send private message

PostPosted: Sun Nov 19, 2017 8:12 pm     Reply with quote

Hi PCM, thank you for your quick reply.

In retrospect i dont think I asked the right question so i will further explain.

I am reading a Modbus device from my PIC, the device has the data i need as a 4 hex bytes that add up to a float which is the device's sensor reading.

I want to display the sensor value to terminal as a float number that any human can understand.

Just to be clear This is not a modbus question.... its a how to convert data to float question.

is there any function to do this? how do i build the float from those bytes in code?

Edit:
Just for reference my modbus device seems to be using IEEE754 according to your app and the example provided on the original post.

Thanks.
G.
_________________
CCS PCM 5.078 & CCS PCH 5.093
Gabriel



Joined: 03 Aug 2009
Posts: 1067
Location: Panama

View user's profile Send private message

PostPosted: Sun Nov 19, 2017 8:24 pm     Reply with quote

Hi PCM...

I'm looking at the code of that little app... seems like i can get the conversion code from the .H files...

I'll let you know if run into any problems.

Thanks!
_________________
CCS PCM 5.078 & CCS PCH 5.093
Gabriel



Joined: 03 Aug 2009
Posts: 1067
Location: Panama

View user's profile Send private message

PostPosted: Sun Nov 19, 2017 10:34 pm     Reply with quote

For those interested in this below is my "working" code.

Works fine for numbers ending in .0 or .5 but its always a bit off for other decimals for reasons i dont yet understand.



Code:

float Bytes_to_Float(int Byte1,int Byte2,int Byte3,int Byte4)
{
   int Exponent=0;
   int32 Mantissa=0;
   
   if((Byte1+Byte2+Byte3+Byte4)==0) return(0.00);   //Handle Exception

   Exponent = ((Byte1 & 0x7F) << 1) + ((Byte2 & 0x80) >> 7); // Exponent is biased at this point
   Exponent-=127;   //Exponent is unbiased

   Mantissa =(Byte2 & 0x7F);
   Mantissa<<=16;
   Mantissa +=(Byte3 << 8);
   Mantissa +=Byte4;

   fprintf(lcd_putc"Mantissa: %1.4f\r\n",((Mantissa/8388608.00)+1.00));   //Debug

   if (Byte1 & 0x80) return(((pwr(2,Exponent))*((Mantissa/8388608.00)+1.00))*-1.0); //mantissa is fixed 23 bit so no point in using Pow(2,23)
                 else return((pwr(2,Exponent))*((Mantissa/8388608.00)+1.00));
}

_________________
CCS PCM 5.078 & CCS PCH 5.093
Jerson



Joined: 31 Jul 2009
Posts: 125
Location: Bombay, India

View user's profile Send private message Visit poster's website

PostPosted: Sun Nov 19, 2017 11:02 pm     Reply with quote

I would think the right way to approach this is to make a union to which you assign the individual bytes. Then read the union as a float.

union {
float f;
int8 bytes[4];
} Float_bytes;

Only, you will need to identify which byte is MSB and which is LSB and do the stuffing accordingly.
Ttelmah



Joined: 11 Mar 2010
Posts: 19518

View user's profile Send private message

PostPosted: Mon Nov 20, 2017 12:15 am     Reply with quote

Jerson's answer is right if this was a CCS float.
There is though a caveat. The data being sent is in IEEE format, not CCS. With the compiler there is a library 'ieefloat.c'. This contains the routines to convert to/from an int32 containing the bytes, to a float (and vice versa).
So:
Code:

//your includes etc.
#include <ieeefloat.c>;

//Then retrieve the data (with the same comment about byte order).
//Use 'make32' to make the four bytes into an int32 'ifloat' say

   float f_value;
   f_value=f_IEEEtoPIC(ifloat);


This is several orders of magnitude smaller and faster than recreating the values using floating point maths (ugh...), since all it does is move the correct parts of the data to the locations required by the Microchip float format.

This actually depends on you using PCM or PCH (which the first post implies, since all the chips mentioned are PIC16/18). On PCD, the chip already works directly in the IEEE format.

The 'reason' the PIC uses a different format is historical and hardware. When the PIC first launched, the IEEE format didn't exist. Microchip designed their own 4byte float, optimising the layout to be the most efficient possible for the chip. CCS when it started, wrote their maths routines to use the same format. It saves a little time on each maths operation. When IEEE was launched, users posted here routines to convert, and a little later CCS added the library to do this.
Gabriel



Joined: 03 Aug 2009
Posts: 1067
Location: Panama

View user's profile Send private message

PostPosted: Mon Nov 20, 2017 4:37 pm     Reply with quote

Well this worked like a charm! Thanks Mr. T.

Now I'm left with an itch cause i don't know why my attempt was failing with the decimal precision.

Thanks
G.
_________________
CCS PCM 5.078 & CCS PCH 5.093
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Nov 20, 2017 10:02 pm     Reply with quote

Gabriel wrote:

i don't know why my attempt was failing with the decimal precision.

You are shifting Byte3 left by 8, without casting it to an int16 first.
CCS doesn't automatically do this. You have to cast it.
Add the section shown in bold below:
Quote:

Mantissa =(Byte2 & 0x7F);
Mantissa<<=16;
Mantissa +=((int16)Byte3 << 8);
Mantissa +=(Byte3 << 8);
Gabriel



Joined: 03 Aug 2009
Posts: 1067
Location: Panama

View user's profile Send private message

PostPosted: Tue Nov 21, 2017 5:44 am     Reply with quote

Huh... i thought i was shifting INTO "Mantissa" and thus the shifting byte size did not matter.

Thanks for clearing that up!
No wonder i was losing all decimal presicion!

Thank you.
G.
_________________
CCS PCM 5.078 & CCS PCH 5.093
Ttelmah



Joined: 11 Mar 2010
Posts: 19518

View user's profile Send private message

PostPosted: Tue Nov 21, 2017 6:01 am     Reply with quote

No.
That is a general C thing. All arithmetic sizes are based on the size of the sources not the destination. The result is put into the destination, but not till after the maths is done.

So two int8 values (say 130 and 150 in 'a' and 'b'). Destination int16 (say 'c'). Add them together as:

c=a+b;

or multiply etc., and the maths will overflow.

However if one source is larger this size will be used for the maths. So:

c=a+150L; //here the '150' is declared as a 'long'

or:

c=(int16)a+b; //convert 'a' to int16 before the arithmetic.

Will both use int16 arithmetic.

On some chips (for example the Intel processors particularly when using the hardware maths processor), the arithmetic will automatically be handled using a larger type, but this is specific behaviour to these chips, not how C defines this to be done....
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Tue Nov 21, 2017 6:10 am     Reply with quote

Gabriel wrote:
Huh... i thought i was shifting INTO "Mantissa" and thus the shifting byte size did not matter.


The definition of C is clear on this point: the type of left hand side of an assignment has no effect on the right hand side. There are two sequential processes involved in an assignment: the evaluation of the right hand expression and the setting of the left hand side, with any required type conversions/casts.

Put another way, it doesn't matter what you are "shifting into", it is what you are shifting that gets shifted, and the type of what you shift must be big enough to take whatever it is you are shifting. So, if the result of a shift is expected to need 16 bits you must cast it to a suitable (normally unsigned) type, e.g. Uint16, and then shift that.

The same applies with any arithmetic operation. If a multiply of an 8 bit integer is expected to give a sixteen bit result, then it should be cast to 16 bit first and then multiplied.

It is possible in assembler to implement more efficient operations on known smaller values, for example 8 * 8 bit multiples to get 16 bit results, 12 * 4 bit multiplies and so on. I have done may over the years. But you have to realise that C doesn't have such special cases and only implements generic 8 by 8 = 8, 16 by 16 = 16, etc. , operations. CCS C does provide some special case routines, such as _mul( ) which does optimised 8 * 8 = 16 and 16 * 16 = 32 multiplies. Also stdlib provides div() and ldiv() which provide the quotient and remainder in one division rather than two as would normally be the case.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group