Search code examples
catmega

How to print a float via serial?


So far I am able to send strings, numbers etc via uart. The code below runs on an embedded device (atmega328p) and sends data to my laptop on which putty runs:

void main(void)
{
    /* Works fine */
    int16_t a = 132;
    char data[100] = {0};

    sprintf(data, "%"PRId16, a);
    libuart_send("a: ", strlen("a: "));  
    libuart_send(data, strlen(data)); //works fine

    /* Below doesn't work */
    double l_data = 132.34;
    char data[100] = {0};

    sprintf(data, "%f", l_data);
    libuart_send("f: ", strlen("f: "));  
    libuart_send(data, strlen(data)); //doesnt work
}

void libuart_send(void *p_data, int p_data_size)
{
    assert(p_data != NULL);
    assert(p_data_size > 0);

    for(int i = 0; i < p_data_size; i++)
    {
        /* Wait for empty transmit buffer. */
        while ( !( UCSR0A & (1<<UDRE0)) );

        /* Put data into buffer, sends the data. */
        UDR0 = *(((signed char*)(p_data)) + i);
    }
}

When sending the float to my putty terminal I see a question mark instead of the actual float value. Why?

Thanks

EDIT: This is a pdf version of the datasheet which explains what inter alia UDR0 does (see page 195/452): https://www.sparkfun.com/datasheets/Components/SMD/ATMega328.pdf


Solution

  • The AVR port does not link any float support by default (BTW many ARM implementations also) because of the size of the functions. Remember that float math support + printf floats may take up to 15k of your 32k program memory!!

    you need to add the correct options to print float numbers.

    -Wl,-u,vfprintf -lprintf_flt -lm and it will print.

    BTW try to avoid floats as a plaque. Below you have the table with multiplication operation benchmark (results in cycles)

    uint8 22

    uint16 98

    uint32 102

    int8 22

    int16 92

    int32 108

    float 2986

    on 1MHz you can only perform 300 float multiplications per second comparing to 10000 int32. Have it always in your maind