I have a 24-bit signed quantity (from A/D converter LTC2418) and need to convert it to a float (voltage). I'm finding this really hard and not sure where things go wrong. I get the 24-bit A/D data and sign-extend into a 32-bit long:
When you perform a static cast like that, you are basically telling the compiler not to do any form of conversion, just pass the bitpattern from the one variable onto the other variable, and since longs and floats are stored differently, you're going to get garbage data out of the assignment.
If, however, you just perform the assignment without any casting, the compiler will recognize that you are assigning a long value to a float variable, and perform the necessary conversion to retain the value in the new format. IE, just do:
You need to explain your logic here. If the A/D data is 0xC0000000, as a signed value, how do you manage to loose two 0 off the end and get FF on the front, when treating the value as a signed value?
jraskell:
When you perform a static cast like that, you are basically telling the compiler not to do any form of conversion, just pass the bitpattern from the one variable onto the other variable, and since longs and floats are stored differently, you're going to get garbage data out of the assignment.
The LTC2418 24-bit A/D is a real bear to get working ] The conversion data and channel numbering are from Mars. Its output data is "somewhat" 2's complement- there are status bits to tell -ve or +ve over range and I finally have a signed long for the conversion (I will post my sketch in another thread once I get it finished). I need a float to print voltage.
//This code works fine, I get a float with the static(?) cast:
signed long adc_value;
adc_value=getAtoD();
adc_result= (float) adc_value;
adc_result= /838860.8; // R divider 9V max; A/D=2.5Vfsd
Serial.println(adc_result,4);
However, I went to using a union to store the A/D data and it doesn't work properly:
union
{
float v_modem; // Ch. 4 scaled voltage 0-5V
float v_solar; // Ch. 3 scaled voltage 0-5V
float modem_vreg; // Ch. 2 scaled voltage modem vreg 0-9V
float I_monitor; // Ch. 1 scaled current 0-2A
float v_board; // Ch. 0 scaled voltage 0-9V
}
adc;
//--------------------------------------
void mysub() {
signed long adc_value;
adc.v_board = 0.0;
adc.I_monitor = 0.0;
adc.modem_vreg = 0.0;
adc.v_solar = 0.0;
adc.v_modem = 0.0;
adc_value=getAtoD();
adc.v_board = (float)adc_value/838860.8;
Serial.println(adc.v_board,4);
Serial.println(adc.I_monitor,4);
Serial.println(adc.modem_vreg,4);
Serial.println(adc.V_solar,4);
Serial.println(adc.V_modem,4);
}
V_board is correct i.e. 6.0512V but ALL channels in the union have the same value 6.0512V :~
Whichever it returns, that code will convert that return VALUE to a long VALUE which may change the bit representation. So if the input value is "1000.0" then the output value will be "1000".
Then, when you convert adc_value to float, it will simply convert the VALUE back. So if the input value is "1000," the output value will be "1000.0".
This is probably not what you want when you're dealing with floating point values. You want to either scale the long value to the range of floats you want, or you want to do a bit reinterpret cast using memcpy() or a union, depending on what it is you want to accomplish.
Also, the Serial object print/println function that takes two arguments always casts its first argument to long. This means that printing a float like 3.25 will first cast to long -- which is 3 -- then print that in the format you specify -- 0x3 for hex.