How to sprintf float numbers with AVR GCC

The float numbers are not recommended to use with smaller 8-bit AVR microcontrollers. The main reason is that the AVR core does not have a floating-point arithmetic unit built-in. The software library emulates the floating-point arithmetic operations. The software library simulates Floating-point arithmetic operations.

However, in real-world applications, you may need to use numbers with floating-point. In some particular cases, you can get away without you declaring variables as float type. If operations are simple like division or multiplying by 2, 4, 8, they can be replaced by the byte shift operation

(byte<<1)=byte*2

Of course, it depends on the different situations and data you are manipulating – sometimes using floats is inevitable. If your code fits into Program memory and execution speed is not critical, use floats or double number formats, as you like.

Let us go through process of including floats to the source code:

#include <stdint.h>
#include <stdio.h>
#include <avr/io.h> 
#include "global.h"     
#include "rprintf.h"
#include "timer.h"
#include "lcd.h"
int main(void){
	char mystr[16];
	double myflt1, myflt2;
	myflt1 = 3.14159;
	myflt2 = myflt1*5.1324;
	sprintf(mystr, "%.5f",
	myflt2);
	lcdInit(); 
	lcdPrintData(mystr, 8);
	return 0;
}

In the example above, I have used LCD routines from the AVRLIB library. The connection diagram is only for representation of how LCD is wired to the microcontroller.

LCD connected to AVR using 8 bit interface

In the code, we declare a char buffer:

char mystr[16];

We are going to convert the float number to a string and store it in this buffer named mystr. Then we declare floating-point variables:

double myflt1, myflt2;

Let us attach some numbers and perform basic math operation with floating numbers:

myflt1 = 3.14159;
myflt2 = myflt1*5.1324;

Now we can convert floating number to a string and save it to the buffer as follows:

sprintf(mystr, "%.5f", myflt2);

The program may not work because we need to tell the linker to use floating-point library libprintf_flt.a and libm.a. Additionally, we need to add linker options -Wl,-u,vfprintf.

To make things easier, process can be automated if you use Mfile generator with template:

make file generator for AVR gnu tools

 This operation adds required linker options:

#---------------- Library Options ----------------
PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min
# Floating point printf version (requires MATH_LIB = -lm below)
PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt
# If this is left blank, then it will use the Standard printf version.
PRINTF_LIB = $(PRINTF_LIB_FLOAT)
#PRINTF_LIB = $(PRINTF_LIB_MIN)
#PRINTF_LIB = $(PRINTF_LIB_FLOAT)

With AtmelStudio settings is even simpler, because makefile is generated automatically.

In AtmelStudio, go to Project -> Properties ->Toolchain->AVR/GNU linker->General setup dialog. Then select linker options, and then add the -Wl,-u,vfprintf

AtmelStudio settings. Add float support


This should be enough.

The sprintf function is generic and requires a significant program space. Other option would be to use dtostre() or dtostrf() as they are more lightweight than floating-point sprintf(). Or use rprintfFloat(char numDigits, double x) function from AVRLIB library (rprintf.h).

Leave a Reply