Number Breakdown

Status
Not open for further replies.

TucsonDon

Member
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
 
Why do you want to convert it to a float?, the original value from the ADC isn't a float, and the display isn't a float - so why?.

You might also consider mentioning what language you're using?. If it's PIC assembler you could check my tutorials.
 
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

Try to avoid float. If you have a 10-bit ADC value (0-1023 counts), and a 5v reference voltage, then I assume you want to display volts.

So if you measure 330 counts, you'd calculate 5 * 330 / 1023 = 1.651 volts. However,
You can also say 5000 * 330 / 1023 = 1651


Then your thousands digit becomes
Int t = result / 1000

Your hundreds becomes
Int h = (result - t * 1000) / 100

Your tens becomes
Int tens = ((result - t * 1000) - 100 * h) / 10

Your ones becomes
Int ones = result % 10

Then you add the decimal point to the first digit.
 
So if you measure 330 counts, you'd calculate 5 * 330 / 1023 = 1.651 volts. However,
You can also say 5000 * 330 / 1023 = 1651
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.
 
nsaspook not sure I understand your point

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; 
}
 
Nigel Goodwin & gophert in am using the ADC to read temperature from a thermistor to a tenth of a degree. Nigel Goodwin I'm using c in MPLab

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
}
 
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.
 
Code:
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.

Tell it you want a 32-bit result...
Code:
total=dat*5000ul;         //multiply by millivolts
 
rjenkinsgb & Pommie thanks for your information but I am reading the ADC through a thermistor for temperature, so not sure how to apply it.

C:
double TempConversion (int TempResult)
{
    double Temp;
    
    Temp = log(10000.0*((1024.0/TempResult-1))); 
//         =log(10000.0/(1024.0/RawADC-1)) // for pull-up configuration
    Temp = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * Temp * Temp ))* Temp );
    Temp -= 273.15;            // Convert Kelvin to Celcius
    return Temp;
}

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.
 

Stop thinking of it as a float. You can display as a string and cram a decimal point anywhere you want.
 
I think with those equations I'd stick to float. To display it, multiply by 10, cast to integer and use the code above.

Mike.
 
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.
 
Do you have a link to the datasheet for the thermistor you're using?

Mike.
 
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…