Popis použití OLED displeje SSD1306 v projektech na Raspberry Pi Pico a Pico-SDK. Monochromatický OLED displej komunikuje pomocí I2c sběrnice, má velikost 128 bodů na šířku a 32 bodů na výšku. Obvykle se prodává v barvě bílé, žluté a modré. Napájecí napětí displeje je 3.3 V.

C knihovna pro OLED displej umí psát písmenka v kódování UTF-8. K dispozici jsou fonty:

  • Font 9x15

  • Font 10x20 (5205 znaků).

  • Spleen 5x8 (728 znaků — latinka včetně češtiny, braille) — font je velmi malý

  • Spleen 6x12 (676 znaků)

  • Spleen 8x16 (1019 znaků — latinka včetně češtiny, alfabeta, azbuka, braille)

  • Spleen 12x24 (916 znaků)

  • Spleen 16x32 (969 znaků)

  • Spleen 32x64 (969 znaků)

  • Tahoma 8 (450 znaků) — font má proměnnou šířku

  • Tahoma 10 (450 znaků) — font má proměnnou šířku

  • Tahoma 12 (348 znaků)

  • Tahoma 16 (348 znaků)

Jeden displej (SDA 4, SCL 5)

IMG 20260306 150044

Jeden displej (SDA 4, SCL 5)

IMG 20260306 150203

Dva displeje (1. SDA 4, SCL 5; 2. SDA 18, SCL 19)

IMG 20260329 191346

Instalace knihovny

Knihovna ke stažení ssd1306_utf8_lib.tar.gz nebo ssd1306_utf8_lib.zip

Instalace knihovny na Linuxu
cd
wget https://sspvc.lixis.cz/pmp/ssd1306_utf8/ssd1306_utf8_lib.tar.gz
tar xfvz ssd1306_utf8_lib.tar.gz
echo 'export LIB_SSD1306_UTF8_PATH=~/ssd1306_utf8_lib' >>~/.bashrc
source ~/.bashrc
Instalace knihovny na MacOS
cd
wget https://sspvc.lixis.cz/pmp/ssd1306_utf8/ssd1306_utf8_lib.tar.gz
tar xfvz ssd1306_utf8_lib.tar.gz
echo 'export LIB_SSD1306_UTF8_PATH=~/ssd1306_utf8_lib' >>~/.zprofile
source ~/.zprofile

Použití knihovny

Do adresáře vašeho projektu nakopírute soubor pico_lib_ssd1306_utf8_import.cmake a vložte ho direktivou include do vašeho CMakeLists.txt. Do target_include_directories přidejte ${ssd1306_utf8_SOURCE_DIR}/src. Do target_link_libraries přidejte hardware_i2c a ssd1306_utf.

cmake_minimum_required(VERSION 3.13)
include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake)

project(ssd1306_test C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)

pico_sdk_init()
include(pico_lib_ssd1306_utf8_import.cmake)

add_executable(ssd1306_test
    ssd1306_test.c
)

target_include_directories(ssd1306_test PRIVATE
    ${CMAKE_CURRENT_LIST_DIR}
    ${ssd1306_utf8_SOURCE_DIR}/src
)

target_link_libraries(ssd1306_test
    pico_stdlib
    hardware_i2c
    ssd1306_utf8
    )
pico_enable_stdio_usb(ssd1306_test 1)
pico_enable_stdio_uart(ssd1306_test 0)

pico_add_extra_outputs(ssd1306_test)

CMakeLists.txt se dá udělat elegantněji. Soubor pico_lib_ssd1306_utf8_import.cmake si přečteme přímo z adresáře, kam jsme nainstalovali knihovnu. Adresář, kde je knihovna, si vezmeme z proměnné prostředí LIB_SSD1306_UTF8_PATH.

cmake_minimum_required(VERSION 3.13)
include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake)

project(ssd1306_test C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)

pico_sdk_init()
include($ENV{LIB_SSD1306_UTF8_PATH}/pico_lib_ssd1306_utf8_import.cmake)

add_executable(ssd1306_test
    ssd1306_test.c
)

target_include_directories(ssd1306_test PRIVATE
    ${CMAKE_CURRENT_LIST_DIR}
    ${ssd1306_utf8_SOURCE_DIR}/src
)

target_link_libraries(ssd1306_test
    pico_stdlib
    hardware_i2c
    ssd1306_utf8
    )
pico_enable_stdio_usb(ssd1306_test 1)
pico_enable_stdio_uart(ssd1306_test 0)

pico_add_extra_outputs(ssd1306_test)
ssd1306_test.c
#include "pico/stdlib.h"
#include "hardware/i2c.h"
#include "ssd1306.h"
#include "font.h"
#include <stdio.h>
#include <string.h>

// pro OLED displej SSD1306
#define DISPLAY_WIDTH   128			// šířka displeje
#define DISPLAY_HEIGHT  32			// výška displeje
#define I2C_ADDRESS     0x3C		// i2c adresa
#define I2C_FREQ        1000000		// rychlost i2c sběrnice
// rychlost i2c sběrnice může být až 2000000
#define SDA_PIN         4			// datový pin
#define SDC_PIN         5			// hodinový pin
#define I2C             i2c0		// i2c hardware

// struktura pro OLED displej včetně framebufferu
static ssd1306_t disp;

// všechny použité fonty
extern bitmapFONT font_tahoma_10;
extern bitmapFONT font_spleen_16x32;

// nastavení I2C sběrnice
void setup_i2c(void)
{
    i2c_init(I2C, I2C_FREQ);
    gpio_set_function(SDA_PIN, GPIO_FUNC_I2C);
    gpio_set_function(SDC_PIN, GPIO_FUNC_I2C);
    gpio_pull_up(SDA_PIN);
    gpio_pull_up(SDC_PIN);
    // pauza je nutná kvůli displeji. Pokud není displej se někdy nerozsvítí
    sleep_ms(200);
}

void zapnuti_displeje( void )
{
    ssd1306_init(&disp, DISPLAY_WIDTH, DISPLAY_HEIGHT, I2C_ADDRESS, I2C); // inicializace
    ssd1306_poweron(&disp); // zapnutí displeje
    ssd1306_clear(&disp);   // vymazání displeje
    ssd1306_contrast(&disp,0x50);
    ssd1306_show(&disp); // zobrazíme na displeji
}

int main()
{

	// nastavení displeje SSD1306
    setup_i2c();
    zapnuti_displeje();
    sleep_ms(10);
	// vymazání framebufferu
	ssd1306_clear(&disp);
	// nakreslení obdélníka z horního levého x=0,y=0
	// do dolního levého rohu x=127,y=31
    ssd1306_draw_empty_square(&disp, 0, 0, 127, 31);
    ssd1306_draw_empty_square(&disp, 1, 1, 18, 31);
    // řecké písmeno fi fontem spleen 16x32 (horní roh znaku x=3, y=3)
    ssd1306_draw_utf8_char_with_font(&disp, 3, 3, &font_spleen_16x32, 421 );
    // text fontem spleen 6x12 z bodu x=26, y=2
    ssd1306_draw_utf8_string(&disp, 26, 2, &font_tahoma_10, "Maličký ježeček");
    // text fontem tahoma 10 z bodu x=26, y=16
    ssd1306_draw_utf8_string(&disp, 26, 16, &font_tahoma_10, "žere žlutá jablíčka.");
    ssd1306_show(&disp); // zobrazíme písmenka na displeji
    // ukončení práce s displejem (uvolnění paměti framebufferu)
    ssd1306_deinit(&disp);
}

API knihovny

Datové struktury

Struktura displeje
typedef struct {
    uint8_t width; 		// šířka dispeje
    uint8_t height; 	// výška displeje
    uint8_t pages;		// počet stránek displeje (počítá se při inicializaci)
    uint8_t address; 	// i2c adresa displeje
    i2c_inst_t *i2c_i; 	// i2c sběnice (i2c0 nebo i2c1)
    bool external_vcc; 	// zda používá displej napájení podsvitu z vnějšku (obvykle ne)
    uint8_t *buffer;	// obrazový buffer
    size_t bufsize;		// velikost obrazového bufferu
} ssd1306_t;
Struktura fontu
// struktura bitmapového fontu
typedef struct bitmap_font {
	unsigned char        Width;     // maximální šířka znaku
	unsigned char        Height;    // výška znaku
	unsigned int         Chars;     // počet znaků ve fontu
	const unsigned char *Widths;    // ukazatel na pole šířek jednotlivých znaků
	const uint32_t      *Index;     // pole UTF-8 kódu znaků
	const unsigned char *Bitmap;    // pole bitmap jednotlivých znaků
} bitmapFONT;

Nastavení a ukončení

Počáteční nastavení displeje
// ssd1306_t *p    -- ukazatel na instanci struktury displeje
// uint16_t width  -- šířka displeje
// uint16_t height -- výška displeje
// uint8_t address -- I2C adresa displeje (obvykle 0x3c)
// i2c_inst_t *    -- ukazatel na instanci I2C sběrnice (buď i2c0 nebo i2c1)
bool ssd1306_init(ssd1306_t *p, uint16_t width, uint16_t height, uint8_t address, i2c_inst_t *i2c_instance);
Ukončení práce s displeje
// ssd1306_t *p  -- ukazatel na instanci struktury displeje
void ssd1306_deinit(ssd1306_t *p);

Příklad nastavení displeje a ukončení práce s ním:

  • datový pin SCK displeje je připojen na GPIO5 Pico (I2C0 SCL)

  • hodinový pin SDA displeje je připojen na GPIO4 Pico (I2C0 SDA)

#include "pico/stdlib.h"
#include "hardware/i2c.h"
#include "ssd1306.h"
#include "font.h"
#include <stdio.h>
#include <string.h>

// pro OLED displej SSD1306
#define DISPLAY_WIDTH   128			// šířka displeje
#define DISPLAY_HEIGHT  32			// výška displeje
#define I2C_ADDRESS     0x3C		// i2c adresa
#define I2C_FREQ        1000000		// rychlost i2c sběrnice
#define SDA_PIN         4			// datový pin SDA
#define SDC_PIN         5			// hodinový pin SCK
#define I2C             i2c0		// i2c hardware

// struktura pro OLED displej včetně framebufferu
static ssd1306_t disp;

int main()
{
    // nastavení I2C sběrnice
    i2c_init(I2C, I2C_FREQ);
    gpio_set_function(SDA_PIN, GPIO_FUNC_I2C);
    gpio_set_function(SDC_PIN, GPIO_FUNC_I2C);
    gpio_pull_up(SDA_PIN);
    gpio_pull_up(SDC_PIN);
    // pauza je nutná kvůli displeji. Pokud není, displej se někdy nerozsvítí
    sleep_ms(200);

	// nastavení displeje SSD1306
    ssd1306_init(&disp, DISPLAY_WIDTH, DISPLAY_HEIGHT, I2C_ADDRESS, I2C);

    // ... tady je náš kód

    // ukončení práce s displejem
    ssd1306_deinit(&disp);
}

Ovládání parametrů displeje

Zapnutí displeje
// ssd1306_t *p  -- ukazatel na instanci struktury displeje
void ssd1306_poweron(ssd1306_t *p);
Vypnutí displeje
// ssd1306_t *p  -- ukazatel na instanci struktury displeje
void ssd1306_poweroff(ssd1306_t *p);
Nastavení kontrastu displeje
// ssd1306_t *p  -- ukazatel na instanci struktury displeje
// uint8_t val   -- hodnota kontrastu v procentech od 0 (nic není vidět) do 100 (maximální jas)
void ssd1306_contrast(ssd1306_t *p, uint8_t val);
Prohození barev na displeji (černá se stane bílou a bílá se stane černou)
// ssd1306_t *p  -- ukazatel na instanci struktury displeje
// uint8_t inv   -- je-li inv 0 prohodí se barvy, černý bod se stane bílým a bílý bod se stane černým)
//               -- je-li inv nenulový pak displej zobrazuje normálně
void ssd1306_invert(ssd1306_t *p, uint8_t inv);

Grafické funkce

Přesun dat z framebufferu na displej (změna obrazu na displeji)
// ssd1306_t *p  -- ukazatel na instanci struktury displeje
void ssd1306_show(ssd1306_t *p);
Vymazání framebufferu
// ssd1306_t *p  -- ukazatel na instanci struktury displeje
void ssd1306_clear(ssd1306_t *p);

Tato funkce pouze vynuluje framebuffer. Obraz na displeji se nezmění.

Pokud chceme vymazat obraz na displeji, musíme zavolat potom funkci ssd1306_show():

ssd1306_t disp;

ssd1306_clear(&disp);
ssd1306_show(&disp);
Vymazání bodu v framebufferu (funkce udělá bod o souřadnicích x,y černý)
// ssd1306_t *p  -- ukazatel na instanci struktury displeje
// uint32_t x    -- x souřadnice bodu
// uint32_t y    -- y souřadnice bodu
void ssd1306_clear_pixel(ssd1306_t *p, uint32_t x, uint32_t y);

Souřadnice x=0 a y=0 se nachází v levém horním rohu displeje. Pokud se náhodou stane že x>šířka nebo y>výška, neděje se nic.

Nakreslení bodu v framebufferu (funkce udělá bod o souřadnicích x,y bílý)
// ssd1306_t *p  -- ukazatel na instanci struktury displeje
// uint32_t x    -- x souřadnice bodu
// uint32_t y    -- y souřadnice bodu
void ssd1306_draw_pixel(ssd1306_t *p, uint32_t x, uint32_t y);

Souřadnice x=0 a y=0 se nachází v levém horním rohu displeje. Pokud se náhodou stane že x>šířka nebo y>výška, neděje se nic. Ostatní grafické funkce používají ke kreslení do framebufferu tuto funkci, proto grafické objekty nemohou být rozměrově mimo displej (jsou oříznuty).

Nakreslení úsečky ve framebufferu
// ssd1306_t *p  -- ukazatel na instanci struktury displeje
// int32_t x1    -- souřadnice x počátečního bodu úsečky
// int32_t y1    -- souřadnice y počátečního bodu úsečky
// int32_t x2    -- souřadnice x koncového bodu úsečky
// int32_t y2    -- současnice y koncového bodu úsečky
void ssd1306_draw_line(ssd1306_t *p, int32_t x1, int32_t y1, int32_t x2, int32_t y2);

Pokud jsou souřadnice některého bodu úsečky mimo rozsah displeje, nebudou nakresleny.

Vymazání obdélníka ve framebufferu
// ssd1306_t *p  -- ukazatel na instanci struktury displeje
// uint32_t x    -- souřadnice x levého horního rohu obdélníka
// uint32_t y    -- souřadnice y levého horního rohu obdélníka
// int32_t width -- šířka obdélníka
// int32_t width -- výška obdélníka
void ssd1306_clear_square(ssd1306_t *p, uint32_t x, uint32_t y, uint32_t width, uint32_t height);
Nakreslení obdélníka ve framebufferu
// ssd1306_t *p  -- ukazatel na instanci struktury displeje
// uint32_t x    -- souřadnice x levého horního rohu obdélníka
// uint32_t y    -- souřadnice y levého horního rohu obdélníka
// int32_t width -- šířka obdélníka
// int32_t width -- výška obdélníka
void ssd1306_draw_empty_square(ssd1306_t *p, uint32_t x, uint32_t y, uint32_t width, uint32_t height);
Nakreslení vyplněného obdélníka ve framebufferu
// ssd1306_t *p  -- ukazatel na instanci struktury displeje
// uint32_t x    -- souřadnice x levého horního rohu obdélníka
// uint32_t y    -- souřadnice y levého horního rohu obdélníka
// int32_t width -- šířka obdélníka
// int32_t width -- výška obdélníka
void ssd1306_draw_square(ssd1306_t *p, uint32_t x, uint32_t y, uint32_t width, uint32_t height);
Nakreslení UTF-8 znaku ve framebufferu
// ssd1306_t *p     -- ukazatel na instanci struktury displeje
// uint32_t x       -- souřadnice x levého horního rohu obdélníka kam bude umístěn znak
// uint32_t y       -- souřadnice y levého horního rohu obdélníka kam bude umístěn znak
// bitmapFONT *Font -- ukazatel na strukturu fontu
// uint16_t Index   -- index v poli znaků
// funkce vrací šířku obdélníka v bodech, který ohraničuje daný znak
uint16_t ssd1306_draw_utf8_char_with_font(ssd1306_t *p, uint32_t x, uint32_t y, bitmapFONT *Font, uint16_t Index );
Nakreslení řetězce UTF-8 znaků ve framebufferu
// ssd1306_t *p     -- ukazatel na instanci struktury displeje
// uint32_t Xstart  -- souřadnice x levého horního rohu obdélníka kam bude umístěn řetezec znaků
// uint32_t Ystart  -- souřadnice y levého horního rohu obdélníka kam bude umístěn řetezec znaků
// bitmapFONT *Font -- ukazatel na strukturu fontu
// const char *pString -- ukazatel na řetezec znaků
// funkce vrací šířku obdélníka v bodech, který ohraničuje daný řetezec
uint16_t ssd1306_draw_utf8_string(ssd1306_t *p, uint32_t Xstart, uint32_t Ystart, bitmapFONT *Font, const char *pString );

Pokud se řetezec nevejde šířkou na displej, je zalomen na další řádek.

Příklady

Obdélníky

Kreslení prázdného obdélníka a plného obdélníka.

IMG 20260507 164316

CMakeLists.txt
cmake_minimum_required(VERSION 3.13)
include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake)

project(obdelnik C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)

pico_sdk_init()
include($ENV{LIB_SSD1306_UTF8_PATH}/pico_lib_ssd1306_utf8_import.cmake)

add_executable(obdelnik
    obdelnik.c
)

target_include_directories(obdelnik PRIVATE
    ${CMAKE_CURRENT_LIST_DIR}
    ${ssd1306_utf8_SOURCE_DIR}/src
)

target_link_libraries(obdelnik
    pico_stdlib
    hardware_i2c
    ssd1306_utf8
    )
pico_enable_stdio_usb(obdelnik 1)
pico_enable_stdio_uart(obdelnik 0)

pico_add_extra_outputs(obdelnik)
obdelnik.c
/* obdelnik.c
 * Příklad kreslení obdélníka na OLED displeji ssd1306
 * (c) Jirka Chráska 2026, <jirka@lixis.cz>
 *
 */

#include "pico/stdlib.h"
#include "hardware/i2c.h"
#include "ssd1306.h"
#include "font.h"
#include <stdio.h>
#include <string.h>

// pro OLED displej SSD1306
#define DISPLAY_WIDTH   128			// šířka displeje
#define DISPLAY_HEIGHT  32			// výška displeje
#define I2C_ADDRESS     0x3C		// i2c adresa
#define I2C_FREQ        100000		// rychlost i2c sběrnice
// rychlost i2c sběrnice může být až 2000000
#define SDA_PIN         4			// datový pin
#define SDC_PIN         5			// hodinový pin
#define I2C             i2c0		// i2c hardware

// struktura pro OLED displej včetně framebufferu
static ssd1306_t disp;

// nastavení I2C sběrnice
void setup_i2c(void)
{
    i2c_init(I2C, I2C_FREQ);
    gpio_set_function(SDA_PIN, GPIO_FUNC_I2C);
    gpio_set_function(SDC_PIN, GPIO_FUNC_I2C);
    gpio_pull_up(SDA_PIN);
    gpio_pull_up(SDC_PIN);
    // pauza je nutná kvůli displeji. Pokud není displej se někdy nerozsvítí
    sleep_ms(200);
}

void zapnuti_displeje( void )
{
    ssd1306_init(&disp, DISPLAY_WIDTH, DISPLAY_HEIGHT, I2C_ADDRESS, I2C); // inicializace
    ssd1306_poweron(&disp); // zapnutí displeje
    ssd1306_clear(&disp);   // vymazání displeje
    ssd1306_contrast(&disp,0x50);
    ssd1306_show(&disp); // zobrazíme na displeji
}

int main()
{

	// nastavení displeje SSD1306
    setup_i2c();
    zapnuti_displeje();
    sleep_ms(10);
	// vymazání framebufferu
	ssd1306_clear(&disp);
	// nakreslení obdélníka z horního levého x=0,y=0
	// do dolního levého rohu x=127,y=31
    ssd1306_draw_empty_square(&disp, 0, 0, 127, 31);
    // nakreslení plného obdélníka
    ssd1306_draw_square(&disp, 100, 0, 128, 31);
    ssd1306_show(&disp); // zobrazíme na displeji
    sleep_ms(10000);
    // ukončení práce s displejem (uvolnění paměti framebufferu)
    ssd1306_deinit(&disp);
}

Kreslení pohyblivého obdélníku

/* obdelnik.c
 * Příklad kreslení obdélníka na OLED displeji ssd1306
 * (c) Jirka Chráska 2026, <jirka@lixis.cz>
 *
 */

#include "pico/stdlib.h"
#include "hardware/i2c.h"
#include "ssd1306.h"
#include "font.h"

// pro OLED displej SSD1306
#define DISPLAY_WIDTH   128			// šířka displeje
#define DISPLAY_HEIGHT  32			// výška displeje
#define I2C_ADDRESS     0x3C		// i2c adresa
#define I2C_FREQ        1000000		// rychlost i2c sběrnice
// rychlost i2c sběrnice může být až 2000000
#define SDA_PIN         4			// datový pin
#define SDC_PIN         5			// hodinový pin
#define I2C             i2c0		// i2c hardware

// struktura pro OLED displej včetně framebufferu
static ssd1306_t disp;

// nastavení I2C sběrnice
void setup_i2c(void)
{
    i2c_init(I2C, I2C_FREQ);
    gpio_set_function(SDA_PIN, GPIO_FUNC_I2C);
    gpio_set_function(SDC_PIN, GPIO_FUNC_I2C);
    gpio_pull_up(SDA_PIN);
    gpio_pull_up(SDC_PIN);
    // pauza je nutná kvůli displeji. Pokud není displej se někdy nerozsvítí
    sleep_ms(200);
}

void zapnuti_displeje( void )
{
    ssd1306_init(&disp, DISPLAY_WIDTH, DISPLAY_HEIGHT, I2C_ADDRESS, I2C); // inicializace
    ssd1306_poweron(&disp); // zapnutí displeje
    ssd1306_clear(&disp);   // vymazání displeje
    ssd1306_contrast(&disp,0x50);
    ssd1306_show(&disp); // zobrazíme na displeji
}

int main()
{

	// nastavení displeje SSD1306
    setup_i2c();
    zapnuti_displeje();
    sleep_ms(2000);
	// vymazání framebufferu
	ssd1306_clear(&disp);
	// nakreslení obdélníka z horního levého x=0,y=0
	// do dolního levého rohu x=127,y=31
    ssd1306_draw_empty_square(&disp, 0, 0, 127, 31);
    // nakreslení plného obdélníka
    //ssd1306_draw_square(&disp, 100, 0, 128, 31);
    ssd1306_show(&disp); // zobrazíme na displeji
    sleep_ms(1000);
    for( int i=0; i<127; i++) {
        // kreslení úsečky
        ssd1306_draw_line(&disp, 127-i, 1, 127-i, 30);
        ssd1306_show(&disp);
        sleep_ms(50);
    }
    sleep_ms(1000);
    for( int i=0; i<127; i++) {
        // vymazání obdélníka
        ssd1306_clear_square(&disp, 1, 1, i, 30);
        ssd1306_show(&disp);
        sleep_ms(50);
    }
    sleep_ms(5000);
    ssd1306_poweroff(&disp);
    // ukončení práce s displejem (uvolnění paměti framebufferu)
    ssd1306_deinit(&disp);
}

Zdroje a odkazy

https://github.com/zahash/utf8.c C knihovna pro práci s UTF-8