Creating custom fonts for u8glib

The U8glib library includes a fairly large number of basic fonts, but they are not always enough.

The general essence of the algorithm

Among the fonts already registered in the library, they support little the Cyrillic alphabet, that is, the Russian alphabet, and in some projects unique characters are needed. And what to do in such a situation? Create a font yourself.

The author of the library himself offers us a special program – a converter. She is from the one given to her .bdf file with font data will create a ready-made data array, which we just need to insert into the library data file.

The first thing we need to do is create a font and save its data in .bdf format. To do this, you can use the programs

Fontforge (for Windows)

Fony (for Windows)

Fontlab (for Windows and Mac)

Bdfeditor (for Linux)

Creating the font itself

It takes a long time to draw the whole font, and I’m not an artist either, so for example, let’s create a simple font in Fony to display the clock (it will include only numbers and the “:” symbol to separate them).

Work at fony

If you are familiar with another program, skip this block.

Follow the link above, download and extract the archive.

Launch fony.

File -> New (or Ctrl + N)

Ascent here is the height in pixels above the baseline.

When calculating this parameter, it is necessary to take into account that there may be other lines above the symbol and it should not touch them.

So, if we want a font of a character with a height of 20 pixels, the Ascent parameter must be taken with a margin of distance between lines, for example, 24 pixels. Height – the overall height (Ascent + the descender height). It is also necessary to indicate which symbols we are going to draw. According to the ASCII code table.

We create a font starting at “0” and ending with “:”. “0” has number 48, we write it into the First char parameter, and “:” – 58, we write it into the Last char.

Click OK.

We see such a window:

The baseline is the red line.

And then we remember that we did not indicate the width of the character, it needs to be entered in the field above.

It should also be remembered that the characters should not touch their neighbors and take the width with a margin, for example 14.

Pencil tools – 1, line – 2, fill – 3, allow you to fill in the pixels, and the box – 4 changes their scale.

Arrows 5 and 6 move filled pixels left and right, and arrows 7 and 8 up and down. The panel is used to select and display the drawn symbol, and the field on the left for preview.

Now we draw our symbols from “0” to “:”.

Now you can see how the text will look in the drawn font, for example 12:58.

After we have finished drawing, click:

File -> Export -> BDF Font

Let’s call the created font Clock_font.

We save.

Converting font data file to code

Ok, now we have a bdf file that needs to be converted into a format that the U8glib library can handle. To do this, its author suggests using the bdf2u8g_101 program.

Make sure bdf2u8g_101.exe and your font file are in the same folder.

Now you need to run the conversion program using the command line.

Win + R -> cmd -> OK -> cd “path to the folder where the files are located”

Terminal example:

Now we enter the following command

start bdf2u8g.exe "опции" "полное название файла шрифта" "название шрифта для вызова" "полное название выходного файла"


[-b num] start at number num from ASCII table. Range num: 0..255.

[-e num] end with num from ASCII table. Range num: 0..255.

[-l page] and [-u page] take the range of characters from the ASCII table from 0 to 512. page = 0 selects the range 0..127, page = 1 selects the range 128..255, and so on.

To create a font conversion Clock_font, enter the following command:

start bdf2u8g.exe -b 48 -e 58 Clock_font.bdf clock_font Clock_font.c

and press Enter.

A date file has now appeared in the folder.

We open it. I use the Visual Studio Code editor, but any text editor up to notepad will work.

Now you need to insert this piece of code into the library data files.

To do this, go to the clib folder. It lies at:

“path where U8glib is stored” U8glib src

In this directory you need to find and open the file u8g_font_data.c

Now copy the text from Clock_font.c to u8g_font_data.c and, of course, save it.

But that’s not all. We also find and open the u8g.h file there.

In this file, scroll to the start of the font declaration.

We copy only the declaration of our font here, adding extern to the beginning, and also save it.

Congratulations, on this the custom font has been successfully integrated into the library.

Test sketch

Let’s write a simple sketch showing the time to test the font’s functionality.

#include "U8glib.h"

U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE | U8G_I2C_OPT_DEV_0); // I2C / TWI

byte _hour = 0, _minet = 0; // переменные, хранящие время. Часы и минуты
long long last_millis = 0;  // переменная хранящая предыдущее значение числа миллисекунд
long delay_time = 1000;      // задержка по истечению котрой наступит следующя минута. Устанавливается в миллисекундах.

void setup(void) {
  // u8g.setRot180(); // поворот экрана, если нужен

void loop(void) {
  if (millis() - last_millis > delay_time) {    // если пришло время следующей минуты
    last_millis = millis();
    _minet ++;                                  // увеличиваем число минут
    if (_minet > 59) _minet = 0, _hour ++;      // если это уже следующий час, увеличиваем число часов, а минуты сбрасываем в 0
    if (_hour > 23) _minet = 0, _hour = 0;      // если это уже следующий день, сбрасываем в 0 часы и минуты
    u8g.firstPage();              // начало цикла отрисовки
    do {
      u8g.setFont(clock_font);      // устанавливаем свой шрифт
      u8g.setPrintPos(30, 40);      // устанавливаем позицию печати
      u8g.print(_hour);             // печатаем часы
      u8g.print(':');               // печатаем разделяющий знак
      u8g.print(_minet);            // печатаем минуты
    } while ( u8g.nextPage() );   // конец цикла отрисовки

For delay_time I set it to 1000 so that the minutes are updated once a second.

If you want a real update rate, set it to 60,000 (if you want absolute accuracy, then calculate this parameter based on the test run time and the frequency of the microcontroller. There will be a couple of tens of milliseconds more).

About: Morozov Dmitry

My specialisation is software engineer. I am 35 years old and have been working in the IT field for over 15 years. I have accumulated experience in programming, project management, training and administration.