Click here to Skip to main content
Rate this: bad
good
Please Sign up or sign in to vote.
Hi Everyone,
 
I'm trying to interpret some data from an embedded sensor device into a C++ program. The device uses a numerical format called 1.15 fractional format. This means it transmits 2 hex bytes into a value rangle of ~1 < n < -1.
 
A description of the format is given in this document (http://phobos.iet.unipi.it/~pieri/EdT2/2181_Manual/Appendix_C.pdf[^]).
 
I can understand how the format works (for example, negative values have a positive 15th bit) but I'm struggling to implement a convertor in C++ that can identify when the incoming data is negative.
 
So far I have this function, but it outputs incorrect data for negative numbers
 
int Convert(BYTE msg0, BYTE msg1, float Target){
 
	// Combine the 2 bytes 
	unsigned int F = msg0*256 + msg1;
 
	// display the combined hex bytes and the decimal equivilant
	// These values are correct
	printf("\n\n Combined F = 0x%x \t F = %i",F,F);
 
	double Ff = (double)F/(32767); // ((2^15)-1) = 32767 = 0x7FFF

	printf("\n Ff = %f",Ff);
 
	printf("\n Target = %f",Target); 
 
	return 0;
	}
 
The Target values are taken from the sensor documentation. As you can see my Positive outputs are pretty close (but not perfect) yet the negative values are way off.
 
Target______Hex_______Output
0.9999_____0x7FFF____1.000000
0.5_________0x4000____0.500015
-0.5________0xC000____1.500046
-1.0________0x8000____1.000031
 
Any suggestions greatfully recieved, I'm a little out of my depth here!
Posted 22-Oct-12 2:48am
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

A couple of changes I would suggest are,
The largest positive number is 0x7fff / 0x8000. So instead of dividing by 32767, we need to divide by 32768.
Also, change the 'unsigned int F' declaration to 'short'. What this will do is give you the 2's complement negative number which you're looking for. Otherwise you can take the 2's complement yourself and get the correct magnitude for negative numbers (numbers starting with the 0x80 byte).
 
I hope this helps
  Permalink  
Comments
ad_robot at 22-Oct-12 9:31am
   
Fantastic, those small changes solved it perfectly. I'd actually tried both those changes individually but not together! Many Thanks.
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 2

According to the documentation signed numbers are represented in the two's complement format. To convert them you may use this:
// Get the absolute number masking out the sign bit
int n = ((msg0 & 0x7F) << 8) + msg1;
// Get negative number:
//  Input  masked  result
//  0x8000 0x0000  -32768
//  ...
//  0xFFFF 0x7FFF  -1
if (msg0 & 0x80)
    n -= 32768; // 0x8000
// Convert to double according to number of fractional bits
double f = (double)n / ((double)(1 << nFrac)); 
  Permalink  
Comments
ad_robot at 22-Oct-12 9:49am
   
This solution also works excellently. Thank you.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
0 Sergey Alexandrovich Kryukov 555
1 Kornfeld Eliyahu Peter 409
2 Maciej Los 369
3 DamithSL 196
4 OriginalGriff 188
0 OriginalGriff 6,353
1 DamithSL 4,854
2 Maciej Los 4,466
3 Kornfeld Eliyahu Peter 4,058
4 Sergey Alexandrovich Kryukov 3,897


Advertise | Privacy | Mobile
Web02 | 2.8.141220.1 | Last Updated 22 Oct 2012
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100