I have a ADC result that I am converting to a float. I want to display on a 4 digit 7 segment display via a BCD decoder. How do I break the float into 100’s, 10’s, 1’s and 10th’s to convert to BCD for the decoder
I have a ADC result that I am converting to a float. I want to display on a 4 digit 7 segment display via a BCD decoder. How do I break the float into 100’s, 10’s, 1’s and 10th’s to convert to BCD for the decoder
Not to be too picky, but I think maybe your calculator needs a new battery.
Also two things... technically you should be dividing by 1024, not 1023,
and you must make sure that 5000 * ADREADING doesn't overflow the data type you're using.
I have a ADC result that I am converting to a float. I want to display on a 4 digit 7 segment display via a BCD decoder. How do I break the float into 100’s, 10’s, 1’s and 10th’s to convert to BCD for the decoder
Don't be afraid to to use floats sparingly if the system has the resources, timing is not critical and fractional scaling is a requirement to make a standard internal data integer storage type (10th's of X parameter) for later processing.
A quick example with made-up numbers:
Read your ADC at some calibrated temp, offset and scale that binary result to a calibrated float (1234.0 10th's of) of the required decimal reading of the needed temperature standard. You can use that float directly or convert it to a properly sized integer to extract the 100’s, 10’s, 1’s and 10th’s to convert to BCD using the modulus operator.
C:
#include <stdio.h>
int main()
{
int n = 7569;
int th,h,t,u; // Thousands,hundreds,tens,units
u=n%10;
t=(n/10)%10;
h=(n/100)%10;
th=n/1000;
printf("Thousands = %d , Hundreds = %d , Tens = %d , Units = %d\n",th,h,t,u);
return 0;
}
So no need whatever for floats - which are MUCH slower, take MUCH more memory (neither of which are really a problem in your case) and also less accurate - just do it in integers and manually add a decimal point in the display routine - as in my assembler tutorial routines.
Here's a little clip of how I do it in C - the 4 digit number is split into the four separate digits and printed to the LCD in turn, adding the decimal point in the right place. LCD_charD simply converts the number to ASCII
C:
LCD_charD(Thou);
LCD_charD(Hund);
LCD_charD(Tens);
LCD_char(46); //decimal point
LCD_charD(Ones);
void LCD_charD(unsigned char ch)
{
ch+=0x30;
LCD_char(ch); // convert to ascii
}
All integers with 7 or fewer decimal digits, and any 2n for a whole number −149 ≤ n ≤ 127, can be converted exactly into an IEEE 754 single-precision floating-point value.
I did this recently and it's practically identical to nsaspook's, slightly modified to meet your needs,
Code:
/*
* assuming the value is to be converted to 5V
* with 1 decimal place
*/
void showADC(uint16_t dat){
uint32_t total;
uint8_t tenths,units,tens,hund;
total=dat*5000; //multiply by millivolts
total>>=10; //divide by ADC resolution (1024)
tenths=total%10+0x30;
total/=10;
units=total%10+0x30;
total/=10;
tens=total%10+0x30;
total/=10;
hund=total+0x30;
}
Mike.
Edit, just realized the above will give the ascii character. For the individual numbers delete the 0x30 on each line.
That's pretty much how I'd do it; the only change I would suggest is using another variable, an INT or unsigned int (16 bit value) to store the result of the ten bit shift, and for the maths from then on;
eg. Pommie's code, tweaked slightly:
C:
/*
* assuming the value is to be converted to 5V
* with 1 decimal place
*/
void showADC(uint16_t dat){
uint32_t total;
unit16_t totint;
uint8_t tenths,units,tens,hund;
total=dat*5000; //multiply by millivolts
totint = total >> 10; //divide by ADC resolution (1024)
tenths=totint%10+0x30;
totint/=10;
units=totint%10+0x30;
totint/=10;
tens=totint%10+0x30;
totint/=10;
hund=totint+0x30;
}
The number being worked on is back into a suitable range for 16 bit maths after the bit shift, so avoiding the 32 bit calculations should make it rather faster and the code more compact.
uint32_t total;
uint16_t dat;
total=dat*5000; //multiply by millivolts
With most 8-bit C compilers that isn't going to give you a (correct) 32-bit result... it'll do a 16x16 multiply to get a 16-bit result and then promote that to 32-bit.
I am taking the result and type casting to a float to display remotely on a LCD and locally on a four digit 7 segment(that I'm driving w/ a BCD decoder) display to the tenth of a degree.
I am taking the result and type casting to a float to display remotely on a LCD and locally on a four digit 7 segment(that I'm driving w/ a BCD decoder) display to the tenth of a degree.
If you have a device with more than 2K program memory spare, pre-calculate the result for each of the 1024 possible ADC results using a program on a PC or a spreadsheet etc., to give a four digit result in 10ths of a degree for every value.
Save those as four BCD digits per 16 bit word in a look-up table array.
(I format look-up tables in a header file I can include - I use them for such as sine tables or other conversions that have a finite input range that's not too large, fonts etc).
Then in the device program, just use the ADC result as an index in to the table and display the four digits from that word location with a decimal point before the last.
No longs, floats or complex maths in the device at all.