简体   繁体   中英

Display floating point numbers on an LCD

How do I get the variable, volts, to display floating point numbers on a LCD?

The LCD only displays floating point values with a lot of decimal places with E at the end. I only need 2 decimal places, so how do I display it?

int main (void){

    adcinit();

    lcd_init();//initializes LCD
    lcd_clear();//clear screen
    lcd_home();


    uint16_t value;
    float volts;
    while(1){
        ADCSRA |= (1<<ADSC);//start ADC conversion
        delay_ms(54);//delay 54 millisecond
        value = ADCW;//assign ADC conversion to value
        volts=(value*5)/1023;
        lcd_goto_xy(0,0);// coordinates of the cursor on LCD Display
        lcd_printf("ADC Value: %d ",value);//display on LCD
        lcd_goto_xy(0,1);// coordinates of the cursor on LCD Display
        lcd_printf("Volts: %f ",volts);//display on LCD
    }
}

I'm answering the question in the LAST sentence of the original post - not the heading. But this is the right answer for your project.

You say "I only need 2 decimal places" - so this should tell you that there's no need for floating point maths. Physicists and engineers need floats to represent very, very small or very, very large quantities, but you need "fixed point" - which means doing integer maths and choosing your units correctly. Fixed point is quicker, more accurate and reduces the size of your compiled binary, as there's no need for the floating point code.

The simplest solution is to use integers and display millivolts, in the same way that the delay() function you've just used takes an argument of an integer number of milliseconds, not a fractional number of seconds.

#define VREF 5000
uint32_t mvolts;
.
.
mvolts=(value*VREF)>>10; // No floats here...
lcd_printf("milliVolts: %d",mvolts); // ...and no casts

If you must display volts, then this does the trick:

lcd_printf("Volts: %d.%02d ",mvolts/1000, (mvolts%1000)/10);

Notice, by the way, that mvolts is a 32 bit integer, because you're now multiplying a 10 bit number by 5000 and that won't fit into 16 bits. This is needed because you need to preserve the accuracy of the value while doing the scaling. I don't think this is heading off-topic, as I take it that you do want to display the correct value or there's no point in displaying those two decimal places.

Unless you're careful, the compiler will work out the value of 5000/1024 - 4.8828125 - and then do integer arithmetic, which cuts off the fractional part and ends up multipliying your ADC result by 4. To guarantee the correct behaviour, multiply by 5000 then divide - 2 separate operations. As 1024 is 2**10, shifting right by ten bits is identical to dividing by 1024.

Finally - don't assume that reading 1023 from the ADC actually means 5.000 volts to 4 significant figures; calibrate against a tested voltmeter by tweaking #define VREF to get the right result.

Try this:

Edit: I just edited displaying of voltage, because value was int. But principe would be same.

int main (void){

    adcinit();

    lcd_init();//initializes LCD
    lcd_clear();//clear screen
    lcd_home();


    uint16_t value;
    float volts;
    while(1){
        ADCSRA |= (1<<ADSC);//start ADC conversion
        delay_ms(54);//delay 54 millisecond
        value = ADCW;//assign ADC conversion to value
        volts=(float)(value*5)/1023;
        lcd_goto_xy(0,0);// coordinates of the cursor on LCD Display
        lcd_printf("ADC Value: %d ",value);//display on LCD
        lcd_goto_xy(0,1);// coordinates of the cursor on LCD Display
        lcd_printf("Volts: %.2f ",volts);//display on LCD
    }
}

If the function lcd_printf() is based to the same library than the function sprintf() for Arduino, the format specifier '%f' is not well managed even when used as '%.2f' .

Step 1: Before proposing alternate solutions, it is necessary to get a well-computed float value from the numerical value read from the Analog-To-Digital Converter.

If the ADC is a 10-bits , the range should be 1024 (instead of 1023).

value = ADCW;//assign ADC conversion to value
volts=((float)value*5.0f)/(1024.0f); 

Step2.1: A first and quick solution to display a 2-decimals fixed float value is to convert it in 2 integers.

lcd_printf("Volts: %d.%02d ",(int)volts, (int)(volts*100)%100));//display on LCD

Instead of

lcd_printf("Volts: %.2f ",volts);//display on LCD

Step 2.2: A more 'official' solution to display a 2-decimals fixed float value is to use the dtostrf() function as proposed in "Arduino sprintf float not formatting" .

char str_volts[15]; // to store the float-to-string converted value
lcd_printf("Volts: %s ",dtostrf(volts, 4, 2, str_volts));//display on LCD
// 4 = minimum number of char ('X.XX'), 2 = number of decimals

Instead of

lcd_printf("Volts: %.2f ",volts);//display on LCD

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM