SOLVED - Convert Arduino (AVR) float to Microchip float

Hello
I have been working on a project that needs to send floats as 4 bytes to a PIC 18F mcu. I thought it would be simple task until I realized after some head scratching that Microchip use a different format for float representation. I have found info on the differences mainly the location of the sign bit.I found some code on the CCS forum (I own the PICC compiler) that I might be able to use to make the conversion but I just don’t see how to implement it :frowning: I would appreciate some help with this. My result does not seem anywhere like what I would expect. I am using Windows 7 64bit and 1.0.5-r2.

[///From CCs Forum - Ttelmah

float toIEEE(char data[]) { 
    //This is a routine to turn a float from the CCS format to the IEE format 
    union { 
       float value; 
       char bytes[4]; 
       unsigned int words[2]; 
       unsigned long int lword; 
    } block; 
    int sign; 
    //First re-arrange the byte order 
    block.bytes[3]=data[0]; 
    block.bytes[0]=data[3]; 
    block.bytes[1]=data[2]; 
    block.bytes[2]=data[1]; 
    //Now I have to take the sign bit from the top of byte 3, and move it past 
    //the exponent. 
    sign=block.bytes[2] & 128; 
    block.words[1]=(block.words[1] & 0x7F) & ((block.words[1]>>1) & 0x7F80); 
    block.bytes[3]=(block.bytes[3] & 0x7F) | sign; 
    return block.value; 
 } 

 char * toCCS(float value) { 
    //This is a routine to convert from IEEE to CCS. The inverse of the above. 
    static union { 
       float value; 
       char bytes[4]; 
       unsigned int words[2]; 
       unsigned long int lword; 
    } block; 
    int sign; 
    block.value=value; 
    sign=block.bytes[3] & 128; 
    block.words[1]=(block.words[1] & 0x7F) & ((block.words[1]<<1) & 0xFF00); 
    block.bytes[2]=(block.bytes[2] & 0x7F) | sign; 
    block.bytes[3]=block.bytes[0]; 
    block.bytes[0]=block.bytes[3]; 
    block.bytes[1]=block.bytes[2]; 
    block.bytes[2]=block.bytes[1]; 
    return &block.bytes[0]; 
 } 
 
 void setup(){
   Serial.begin(9600);
 }
     
  void loop(){
    float ftTemp; 
    char * b_pointer; 

    ftTemp=14.2; 
    b_pointer=toCCS(ftTemp); 
    Serial.print ("float  -  ");
    Serial.print( (b_pointer[0]),HEX);
    Serial.print( (b_pointer[1]),HEX);
    Serial.print( (b_pointer[2]),HEX);
    Serial.print( (b_pointer[3]),HEX);
    Serial.println();
    delay(2000);
       
     }code]

Avr-gcc uses IEEE-754 which is pretty standard.
What does PIC use?

AVR floats are 4 bytes

Mark

Looking at the IEEE to CCS conversions, to go from, why don't you just use the char * toCCS(float value) { } function and send 4 chars starting at the returned pointer?

The difference is that the CCS sign bit is bit 31 and for IEEE it is bit 23. Conversion is copying the CCS sign bit, shifting bits 23 to 30 left 1 and copying the sign bit to bit 23.

You're grabbing 1 bit off the end, moving the next lower 8 bits up and putting the end bit in the hole from the move.

So why not just use the function you have that does that? It returns a char pointer to the result which is real handy because you write chars to Serial.

Thanks for the replies! Yes I know this code will or should do the job but my problem is how to call the functions and get the result.. I need the convert from IEEE 754 to Microchip so when I send the float to the PIC18f2620 it will be in the format it needs to see. Pointers are hard for me to get in the right syntax. I would like to send 4 bytes to toCCS() and get 4 bytes back that has the microchip float format.

Richard

Then you need to learn arrays and pointers, might take hours.

char buffer[ 12 ]; // allocates 12 bytes as type char, pointed to by char *buffer.

That's right, buffer above is a pointer. Every array name is a pointer (add dimensions and it's a double, etc, pointer).

Syntax

Serial.write(val)
Serial.write(str)
Serial.write(buf, len)

So you want to use the last one.

Serial.write( toCCS(float value), 4 ); // that should probably do it but don't bet the farm

OK I think I have the pointer figured out but the function does not return the expected value. I am not sure that the union is defined properly since I did change some on the data types to Arduino types. Here is the code section and I am sending a float value of 12.5. The output is 048480 and I expected toCCS() to return 82480000 or possibly 00004882 (reverse order).
The IEEE 754 format is seeeeeee-efffffff-ffffffff-ffffffff and Microchip format eeeeeeee-sfffffff-ffffffff-ffffffff .

[/ byte * toCCS(float value) { 
    //This is a routine to convert from IEEE to CCS. The inverse of the above. 
    static union { 
       float value; 
       byte bytes[4]; 
       unsigned int words[2]; 
       unsigned long lword; 
    } block; 
    byte sign; 
    block.value=value; 
    sign=block.bytes[3] & 128; 
    block.words[1]=(block.words[1] & 0x7F) & ((block.words[1]<<1) & 0xFF00); 
    block.bytes[2]=(block.bytes[2] & 0x7F) | sign; 
    block.bytes[3]=block.bytes[0]; 
    block.bytes[0]=block.bytes[3]; 
    block.bytes[1]=block.bytes[2]; 
    block.bytes[2]=block.bytes[1]; 
    return &block.bytes[0]; 
 } 
 
 void setup(){
   Serial.begin(9600);
 }
     
  void loop(){
    float ftTemp; 
    byte * b_pointer; 

    ftTemp=12.5; 
    b_pointer=toCCS(ftTemp); 
    Serial.print ("float  -  ");
    Serial.print( (b_pointer[0]),HEX);
    Serial.print( (b_pointer[1]),HEX);
    Serial.print( (b_pointer[2]),HEX);
    Serial.print( (b_pointer[3]),HEX);
    Serial.println();
    //Serial.write(b_pointer,4);
    delay(2000);
       
     }code]

Well this took a while. As so often the answer was to simplify the code.
Still, see if the result is what Microchip wants!

#include <string.h>

// The IEEE 754 format is seeeeeee-efffffff-ffffffff-ffffffff and Microchip format eeeeeeee-sfffffff-ffffffff-ffffffff .
byte *toCCS( byte *buf, float value ) 
{ 
  //This is a routine to convert from IEEE to CCS. The inverse of the above. 
  byte signBit, switchBit; 
  memcpy( buf, &value, 4 );
  signBit = bitRead( buf[ 3 ], 7 );
  switchBit = bitRead( buf[ 2 ], 7 );
  buf[ 3 ] = ( buf[ 3 ] << 1 ) | switchBit;
  bitWrite( buf[ 2 ], 7, signBit );

  return buf; 
} 


void setup( void )
{
  float test = 12.5;
  byte  buffer[ 5 ];
  byte  *fptr = (byte *) &test; 
  byte  idx;

  Serial.begin( 9600 );

  Serial.println();
  Serial.println( test );

  Serial.println( "\n float bytes in high to low order\n" );
  for ( idx = 0; idx < 4; idx++ )
  {
    if ( *( fptr + 3 - idx ) < 0x10 )
    {
      Serial.print( "0" );
    }
    Serial.print((byte) *( fptr + 3 - idx ), HEX );
  }  

  Serial.println( "\n *** \n" );

  toCCS( buffer, test );
   
  Serial.println( "\n converted bytes in high to low order\n" );
  for ( idx = 0; idx < 4; idx++ )
  {
    if ( buffer[ 3 - idx ] < 0x10 )
    {
      Serial.print( "0" );
    }
    Serial.print( buffer[ 3 - idx ], HEX );
  }  

}

void loop( void )
{
}

GoForSmoke, thanks much! I'm away from my hardware right now but I have a Teensy and it runs the code and the values look dead on. I'll check it out on the PIC_18F2620 when I get back home. This should be helpful to others running cross platforms.
:)Richard

If the byte order isn't right, just send the bytes through Serial in the right order.

all this does is to make [3] and [0] equal whatever [0] was and make [1] and [2] whatever [2] was. 12.5 gets 0's.

    block.bytes[3]=block.bytes[0]; 
    block.bytes[0]=block.bytes[3]; 
    block.bytes[1]=block.bytes[2]; 
    block.bytes[2]=block.bytes[1];

OK to close this out.... I tried out your code on the PIC_18f2620. I did have to reverse the way the bytes were sent, rather than 0,1,2,3 it was 3,2,1,0 but it worked perfectly. Thanks again GoForSmoke !!
Regards
Richard :slight_smile:

    block.bytes[3]=block.bytes[0]; 
    block.bytes[0]=block.bytes[3]; 
    block.bytes[1]=block.bytes[2]; 
    block.bytes[2]=block.bytes[1];

What is this supposed to be doing ? It is not swapping the bytes around, nor reversing their order.

Assigning bytes[0] to bytes [3] and then assigning bytes[3] to bytes[0] results in the original value of bytes[0] now being in both bytes[3] and bytes[0], and the original value of bytes[3] being gone.

ringram2077:
OK to close this out.... I tried out your code on the PIC_18f2620. I did have to reverse the way the bytes were sent, rather than 0,1,2,3 it was 3,2,1,0 but it worked perfectly. Thanks again GoForSmoke !!
Regards
Richard :slight_smile:

If you edit the first post in this thread and change the titled to SOLVED - (etc) then it won't get more help. :wink: