OLED displej 128×32 0,91″ SSD1306 I²C a Arduino

OLED displeje se dnes dají koupit v mnoha různých velikostech. Tentokrát se podívám na jednu z nejmenších běžně dostupných variant s úhlopříčkou 0,91 palce a rozlišením 128 × 32 pixelů.

Displej je opravdu drobný a kvůli malé výšce se na něj nevejde příliš mnoho informací. Právě jeho podlouhlý tvar ale může být v některých projektech výhodou. Hodí se například pro zobrazení času, teploty, stavu zařízení, výsledku měření nebo několika položek jednoduchého menu.

Modul komunikuje pomocí sběrnice I²C, takže kromě napájení potřebuje pouze dva vodiče pro komunikaci. Díky tomu se snadno připojuje k Arduinu, ESP nebo dalším vývojovým deskám.

V článku si ukážeme zapojení displeje, instalaci potřebné knihovny a několik programů pro zobrazení textu i jednoduché grafiky.

Jak OLED displej funguje

Zkratka OLED pochází z anglického označení Organic Light-Emitting Diode. Na rozdíl od běžného LCD displeje nepotřebuje OLED samostatné podsvícení. Každý rozsvícený bod totiž vytváří vlastní světlo.

Vypnuté pixely zůstávají černé, zatímco zapnuté pixely u tohoto modulu svítí bíle. Díky tomu má displej výrazný kontrast a zůstává dobře čitelný i při velmi malých rozměrech.

Jednotlivé pixely můžeme ovládat samostatně. Displej proto není omezený pouze na předem připravené znaky, ale dokáže zobrazovat také čáry, rámečky, symboly, jednoduché obrázky nebo malé grafy.

Rozlišení 128 × 32 pixelů

Displej má 128 obrazových bodů na šířku a pouze 32 bodů na výšku. Oproti častějším OLED displejům s rozlišením 128 × 64 pixelů má tedy poloviční výšku.

To je potřeba zohlednit při návrhu obrazovky. Velký text může zabrat téměř celou výšku displeje, zatímco při použití menšího písma lze zobrazit několik krátkých řádků.

Displej se proto nejlépe hodí pro stručné informace, například:

  • Aktuální teplotu nebo vlhkost
  • Čas a datum
  • Stav připojení
  • Napětí akumulátoru
  • Výsledek měření
  • Krátké zprávy
  • Jednoduché menu
  • Malý průběhový graf

Na rozsáhlejší nabídky nebo větší množství textu už je vhodnější displej s rozlišením 128 × 64 pixelů.

Řadič SSD1306

O řízení displeje se stará integrovaný obvod SSD1306. Ten přijímá data z Arduina a podle nich ovládá jednotlivé pixely OLED panelu.

SSD1306 je velmi rozšířený řadič, takže pro něj existuje několik hotových Arduino knihoven. Nemusíme proto ručně vytvářet příkazy pro ovládání jednotlivých pixelů. Knihovna se postará o komunikaci s displejem a nabídne funkce pro vykreslení textu, čar, rámečků nebo obrázků.

V tomto článku použiji knihovnu U8g2, se kterou jsem pracoval také u dalších OLED displejů. Podporuje řadič SSD1306, obsahuje velké množství písem a nabízí jednoduché funkce pro kreslení grafiky.

Komunikace pomocí I²C

Displej komunikuje pomocí sběrnice I²C. Pro přenos dat se používají dva vodiče:

  • SCL – hodinový signál
  • SDA – přenos dat

K nim je potřeba připojit ještě napájení VCC a zem GND. Celý displej tedy používá pouze čtyři vývody.

Výhodou I²C je, že stejné vodiče mohou používat také další moduly. K Arduinu tak můžeme současně připojit například OLED displej, teplotní čidlo a hodiny reálného času, aniž by každý modul potřeboval vlastní dvojici komunikačních pinů.

Jednotlivá zařízení se na společné sběrnici rozlišují pomocí I²C adres. Přesnou adresu konkrétního displeje si později ověříme pomocí jednoduchého I²C scanneru.

Základní parametry

  • Typ displeje: OLED
  • Úhlopříčka: 0,91 palce
  • Rozlišení: 128 × 32 pixelů
  • Barva obrazu: modrá
  • Řadič: SSD1306
  • Komunikační rozhraní: I²C
  • Napájecí napětí: 3,3 až 5 V
  • Počet vývodů: 4

Díky napájecímu rozsahu od 3,3 do 5 V lze modul použít jak s klasickými 5 V deskami Arduino, tak s deskami používajícími 3,3 V.

Vývody modulu

Na modulu jsou vyvedené čtyři piny:

VývodFunkce
GNDZem napájení
VCCNapájecí napětí 3,3 až 5 V
SCK / SCLHodinový signál sběrnice I²C
SDADatový signál sběrnice I²C

Zapojení displeje k Arduinu

Pro první vyzkoušení připojím displej k Arduinu Uno. Protože modul komunikuje pomocí sběrnice I²C, potřebujeme kromě napájení pouze vodiče SDA a SCL.

Zapojení bude následující:

OLED displejArduino Uno
GNDGND
VCC5 V
SCL / SCKA5
SDAA4
připojení k Arduino UNO

Piny A4 a A5 jsou u Arduina Uno určené pro komunikaci I²C. U novějších verzí desky jsou signály SDA a SCL vyvedené také na samostatných pinech vedle AREF. Elektricky jsou ale propojené se stejnými piny A4 a A5.

Displej lze napájet také napětím 3,3 V. To se hodí při použití s deskami ESP nebo Raspberry Pi. U každé vývojové desky je ale potřeba ověřit, na kterých pinech má vyvedenou sběrnici I²C.

Kontrola I²C adresy

Každé zařízení připojené ke sběrnici I²C má vlastní adresu. Arduino podle této adresy pozná, se kterým modulem právě komunikuje.

U OLED displejů s řadičem SSD1306 se často používá adresa 0x3C. Nelze ale spoléhat na to, že ji mají všechny vyráběné varianty stejnou. Proto je dobré adresu před prvním spuštěním ověřit pomocí programu I²C scanner.

Program postupně vyzkouší všechny možné adresy a nalezená zařízení vypíše do sériového monitoru.

///////////////////////I2C scanner fw v.0.1 /////////////////////////////////
///////////////////////14.7.2026 ///////////////////////////////////////////
///////////////////////www.michaluvbrloh.cz//////////////////////////////////

#include <Wire.h>       //komunikace po sběrnici I2C

byte chyba = 0;         //výsledek pokusu o komunikaci
byte adresa = 0;        //právě testovaná I2C adresa
byte pocet = 0;         //počet nalezených zařízení

/////////////////////////////po spuštění///////////////////////////////////////////////////////////////////////////////////////
void setup()
  {
    Wire.begin();                     //start sběrnice I2C
    Serial.begin(9600);               //start sériové linky

    delay(1000);                      //krátká pauza po spuštění

    Serial.println(F("I2C scanner"));
    Serial.println(F("Hledam zarizeni..."));
  }

/////////////////////////////hlavní smyčka/////////////////////////////////////////////////////////////////////////////////////
void loop()
  {
    hledatZarizeni();                 //prohledej I2C sběrnici

    delay(5000);                      //další kontrola za 5 sekund
  }

/////////////////////////////hledání zařízení//////////////////////////////////////////////////////////////////////////////////
void hledatZarizeni()
  {
    pocet = 0;                        //vynuluj počet zařízení

    for(adresa = 1; adresa < 127; adresa++)
      {
        Wire.beginTransmission(adresa);       //zkus zahájit komunikaci
        chyba = Wire.endTransmission();       //ukonči komunikaci a načti výsledek

        if(chyba == 0)                        //pokud zařízení odpovědělo
          {
            Serial.print(F("Nalezeno zarizeni na adrese 0x"));

            if(adresa < 16)                   //doplň úvodní nulu
              {
                Serial.print(F("0"));
              }

            Serial.println(adresa, HEX);      //vypiš adresu
            pocet++;                          //zvyš počet zařízení
          }
      }

    if(pocet == 0)                            //pokud nebylo nic nalezeno
      {
        Serial.println(F("Zadne I2C zarizeni nebylo nalezeno"));
      }
    else                                      //pokud bylo zařízení nalezeno
      {
        Serial.print(F("Pocet nalezenych zarizeni: "));
        Serial.println(pocet);
      }

    Serial.println();
  }

Po nahrání programu otevřeme sériový monitor a nastavíme rychlost 9600 baudů. Pokud je displej správně zapojený, měla by se objevit nalezená adresa.

nalezený displej

Pokud program žádné zařízení nenajde, je potřeba zkontrolovat napájení, propojení země a vodiče SDA a SCL. Častou chybou bývá právě prohození datového a hodinového vodiče.

Instalace knihovny U8g2

Pro ovládání displeje použiju knihovnu U8g2. Je to univerzální knihovna pro spoustu monochromatických displejů a podporuje i řadič SSD1306.

Instalace v Arduino IDE:

  1. Otevřít Manažéra knihoven
  2. Vyhledat U8g2
  3. Nainstalovat knihovnu U8g2 od oliver
  4. Restartovat Arduino IDE, pokud by se příklady nebo knihovna nenačetly správně

Knihovna obsahuje velké množství konstruktorů pro různé typy displejů. Pro tento modul s řadičem SSD1306, rozlišením 128 × 32 pixelů a hardwarovou komunikací I²C použijeme:

U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C displej(U8G2_R0, U8X8_PIN_NONE);

Označení jednotlivých částí konstruktoru znamená:

  • SSD1306 – použitý řadič displeje
  • 128X32 – rozlišení displeje
  • UNIVISION – varianta zapojení displeje
  • F – použití celé obrazové paměti
  • HW_I2C – hardwarová komunikace I²C

Varianta s celou obrazovou pamětí umožňuje nejprve připravit celý obraz v paměti Arduina a potom ho najednou odeslat na displej. Pro obraz o rozlišení 128 × 32 pixelů je potřeba 512 bajtů paměti.

První program

První program pouze inicializuje displej a zobrazí na něm dva řádky textu. Tím jednoduše ověříme, že je správně zapojený a že jsme zvolili vhodný konstruktor knihovny.

///////////////////////OLED 128x32 fw v.0.1 /////////////////////////////////
///////////////////////14.7.2026 ///////////////////////////////////////////
///////////////////////www.michaluvbrloh.cz//////////////////////////////////

#include <Wire.h>       //komunikace po sběrnici I2C
#include <U8g2lib.h>    //ovládání OLED displeje

//OLED displej SSD1306 128x32 připojený pomocí hardwarové I2C
U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C displej(U8G2_R0, U8X8_PIN_NONE);

/////////////////////////////po spuštění///////////////////////////////////////////////////////////////////////////////////////
void setup()
  {
    displej.begin();                  //spusť OLED displej

    vypisUvod();                      //zobraz úvodní text
  }

/////////////////////////////hlavní smyčka/////////////////////////////////////////////////////////////////////////////////////
void loop()
  {
    //obraz zůstává na displeji, hlavní smyčka nemusí nic dělat
  }

/////////////////////////////výpis úvodního textu/////////////////////////////////////////////////////////////////////////////
void vypisUvod()
  {
    displej.clearBuffer();                            //vymaž obrazovou paměť

    displej.setFont(u8g2_font_6x12_tf);               //nastav písmo
    displej.drawStr(0, 12, "Michaluv brloh");         //první řádek
    displej.drawStr(0, 28, "OLED 128x32");            //druhý řádek

    displej.sendBuffer();                             //odešli obraz na displej
  }
výsledek prvního programu

Po zapnutí programu se nejprve pomocí příkazu displej.begin() inicializuje displej. Funkce vypisUvod() potom připraví celý obraz a odešle ho na OLED.

Příkaz:

displej.clearBuffer();

vymaže obrazovou paměť. Bez jeho použití by v ní mohly zůstat části předchozího obrazu.

Následující řádek nastaví použité písmo:

displej.setFont(u8g2_font_6x12_tf);

Písmo u8g2_font_6x12_tf má přibližnou velikost 6 × 12 pixelů a na malý displej se dobře hodí.

Text vykreslíme pomocí funkce:

displej.drawStr(0, 12, "Michaluv brloh");

První číslo určuje vodorovnou souřadnici, druhé číslo svislou souřadnici a posledním parametrem je zobrazovaný text.

Souřadnice [0, 0] se nachází v levém horním rohu displeje. U funkce drawStr() ale svislá souřadnice neurčuje horní okraj znaků, nýbrž základní linku textu. Proto první řádek nezačíná na souřadnici Y rovné nule.

Nakonec je potřeba připravený obraz skutečně odeslat na displej:

displej.sendBuffer();

Dokud tuto funkci nezavoláme, změny provedené v obrazové paměti se na displeji neprojeví.

Obnovování obrazu

V prvním programu se obraz vykreslí pouze jednou ve funkci setup(). To stačí pro neměnný text, který má zůstat na displeji po celou dobu provozu.

Pokud chceme zobrazovat měnící se hodnoty, například teplotu nebo čas, musíme celý obraz pravidelně překreslovat.

Postup je vždy stejný:

  1. Vymazat obrazovou paměť
  2. Nakreslit nový obsah
  3. Odeslat obraz na displej

Základ překreslování může vypadat například takto:

displej.clearBuffer();       //vymaž starý obraz

//sem přijde vykreslení nového obsahu

displej.sendBuffer();        //zobraz nový obraz

Vymazání paměti je důležité hlavně při zobrazování čísel. Kdybychom například změnili hodnotu 100 na 99 bez smazání starého obrazu, mohla by na displeji zůstat část poslední číslice.

OLED displej nepotřebuje neustálé obnovování jako některé jiné zobrazovací technologie. Jakmile obraz odešleme, zůstane zobrazený až do další změny nebo vypnutí napájení.

Výběr písma

Knihovna U8g2 obsahuje velké množství písem různých velikostí. Na displeji s výškou pouze 32 pixelů je ale potřeba vybírat opatrně. Příliš velké písmo se může na obrazovku vejít jen částečně.

Písmo nastavíme příkazem:

displej.setFont(u8g2_font_6x12_tf);

Použité písmo zůstává nastavené, dokud ho nezměníme dalším příkazem setFont().

Pro malý displej se mohou hodit například tato písma:

displej.setFont(u8g2_font_5x7_tf); //malé písmo


displej.setFont(u8g2_font_6x12_tf); //dobře čitelné písmo



displej.setFont(u8g2_font_9x15_tf); //větší písmo



displej.setFont(u8g2_font_logisoso24_tf); //velké číslice

Názvy písem mohou na první pohled působit nepřehledně. Část názvu obvykle napovídá přibližnou velikost nebo vzhled písma.

Přehled dostupných písem je součástí dokumentace knihovny U8g2. Nejjednodušší je ale několik vhodných písem vyzkoušet přímo na displeji.

Zarovnání textu na střed

Funkce drawStr() vykresluje text od zadané vodorovné souřadnice směrem doprava. Pokud chceme text umístit doprostřed displeje, musíme nejprve zjistit jeho šířku.

K tomu slouží funkce:

displej.getStrWidth(text);

Vodorovnou souřadnici potom vypočítáme takto:

x = (128 - sirkaTextu) / 2;

Od celkové šířky displeje odečteme šířku textu a zbývající prostor rozdělíme na dvě poloviny.

Následující program zobrazí oba řádky přesně uprostřed displeje:

///////////////////////OLED zarovnani textu fw v.0.1 ////////////////////////
///////////////////////14.7.2026 ///////////////////////////////////////////
///////////////////////www.michaluvbrloh.cz//////////////////////////////////

#include <Wire.h>       //komunikace po sběrnici I2C
#include <U8g2lib.h>    //ovládání OLED displeje

//OLED displej SSD1306 128x32 připojený pomocí hardwarové I2C
U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C displej(U8G2_R0, U8X8_PIN_NONE);

const char text1[] = "Michaluv brloh";     //text prvního řádku
const char text2[] = "OLED 128x32";        //text druhého řádku

/////////////////////////////po spuštění///////////////////////////////////////////////////////////////////////////////////////
void setup()
  {
    displej.begin();                  //spusť OLED displej

    vypisText();                      //zobraz text
  }

/////////////////////////////hlavní smyčka/////////////////////////////////////////////////////////////////////////////////////
void loop()
  {
    //obraz se nemění
  }

/////////////////////////////výpis textu///////////////////////////////////////////////////////////////////////////////////////
void vypisText()
  {
    int x1;                           //pozice prvního textu
    int x2;                           //pozice druhého textu

    displej.clearBuffer();            //vymaž obrazovou paměť
    displej.setFont(u8g2_font_6x12_tf); //nastav písmo

    x1 = (128 - displej.getStrWidth(text1)) / 2;   //vypočítej střed
    x2 = (128 - displej.getStrWidth(text2)) / 2;   //vypočítej střed

    displej.drawStr(x1, 12, text1);   //zobraz první řádek
    displej.drawStr(x2, 28, text2);   //zobraz druhý řádek

    displej.sendBuffer();             //odešli obraz na displej
  }
výsledek druhého programu

Tento způsob funguje pro libovolně dlouhý text, pokud se samozřejmě celý vejde na displej.

Zobrazení proměnné

Při praktickém použití většinou nezobrazujeme pouze pevný text, ale také hodnoty uložené v proměnných. Může jít například o teplotu, napětí, počet impulzů nebo stav počítadla.

Funkce drawStr() ale očekává textový řetězec. Číselnou hodnotu proto musíme nejprve převést na text.

Pro převod celého čísla lze použít funkci snprintf():

snprintf(text, sizeof(text), "%d", hodnota);

Proměnná hodnota se převede na text a uloží do znakového pole text.

Velká hodnota na displeji

Následující program zobrazuje velké počítadlo, které se každou sekundu zvýší o jedničku. Nad hodnotou je menším písmem zobrazený popisek.

Program zároveň ukazuje, jak lze během jednoho vykreslení použít dvě různá písma.

///////////////////////OLED pocitadlo fw v.0.1 //////////////////////////////
///////////////////////14.7.2026 ///////////////////////////////////////////
///////////////////////www.michaluvbrloh.cz//////////////////////////////////

#include <Wire.h>       //komunikace po sběrnici I2C
#include <U8g2lib.h>    //ovládání OLED displeje

//OLED displej SSD1306 128x32 připojený pomocí hardwarové I2C
U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C displej(U8G2_R0, U8X8_PIN_NONE);

unsigned int pocitadlo = 0;       //aktuální hodnota počítadla
char textHodnoty[10];             //textová podoba hodnoty

/////////////////////////////po spuštění///////////////////////////////////////////////////////////////////////////////////////
void setup()
  {
    displej.begin();                  //spusť OLED displej
  }

/////////////////////////////hlavní smyčka/////////////////////////////////////////////////////////////////////////////////////
void loop()
  {
    vypisHodnotu();                   //zobraz aktuální hodnotu

    pocitadlo++;                      //zvyš počítadlo
    delay(1000);                      //počkej jednu sekundu
  }

/////////////////////////////výpis hodnoty/////////////////////////////////////////////////////////////////////////////////////
void vypisHodnotu()
  {
    int x;                            //vodorovná pozice hodnoty

    snprintf(textHodnoty, sizeof(textHodnoty), "%u", pocitadlo); //převeď číslo na text

    displej.clearBuffer();            //vymaž obrazovou paměť

    displej.setFont(u8g2_font_5x7_tf);        //nastav malé písmo
    displej.drawStr(0, 7, "Pocitadlo");       //zobraz popisek

    displej.setFont(u8g2_font_logisoso24_tf); //nastav velké písmo
    x = (128 - displej.getStrWidth(textHodnoty)) / 2; //vypočítej střed
    displej.drawStr(x, 32, textHodnoty);      //zobraz hodnotu

    displej.sendBuffer();             //odešli obraz na displej
  }

Velké číslice využijí téměř celou výšku displeje. Malý popisek se ještě vejde do horní části obrazovky.

video z třetího programu

Při větším počtu číslic je potřeba počítat s tím, že se hodnota nemusí vejít na displej. V takovém případě můžeme použít menší písmo nebo zobrazovanou hodnotu upravit.

Kreslení jednoduché grafiky

Knihovna U8g2 neumí pouze text. Nabízí také funkce pro kreslení základních geometrických tvarů.

Mezi nejčastěji používané patří:

displej.drawPixel(x, y);          //nakreslí jeden pixel
displej.drawLine(x1, y1, x2, y2); //nakreslí čáru
displej.drawFrame(x, y, w, h);    //nakreslí obrys obdélníku
displej.drawBox(x, y, w, h);      //nakreslí vyplněný obdélník
displej.drawCircle(x, y, r);      //nakreslí kružnici
displej.drawDisc(x, y, r);        //nakreslí vyplněný kruh

Souřadnice [0, 0] se nachází v levém horním rohu displeje. Hodnota X se zvětšuje směrem doprava a hodnota Y směrem dolů.

Poslední viditelný pixel má souřadnici:

X = 127
Y = 31

Při kreslení je tedy potřeba hlídat, aby objekty nepřesahovaly mimo plochu displeje.

Ukázka jednoduché grafiky

Následující program nakreslí rámeček kolem displeje, oddělovací čáru, kružnici a několik vyplněných obdélníků.

///////////////////////OLED grafika fw v.0.1 ////////////////////////////////
///////////////////////14.7.2026 ///////////////////////////////////////////
///////////////////////www.michaluvbrloh.cz//////////////////////////////////

#include <Wire.h>       //komunikace po sběrnici I2C
#include <U8g2lib.h>    //ovládání OLED displeje

//OLED displej SSD1306 128x32 připojený pomocí hardwarové I2C
U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C displej(U8G2_R0, U8X8_PIN_NONE);

/////////////////////////////po spuštění///////////////////////////////////////////////////////////////////////////////////////
void setup()
  {
    displej.begin();                  //spusť OLED displej

    nakresliGrafiku();                //zobraz ukázkovou grafiku
  }

/////////////////////////////hlavní smyčka/////////////////////////////////////////////////////////////////////////////////////
void loop()
  {
    //obraz se nemění
  }

/////////////////////////////vykreslení grafiky///////////////////////////////////////////////////////////////////////////////
void nakresliGrafiku()
  {
    displej.clearBuffer();            //vymaž obrazovou paměť

    displej.drawFrame(0, 0, 128, 32); //rámeček kolem displeje
    displej.drawLine(63, 1, 63, 30);  //svislá oddělovací čára

    displej.drawCircle(31, 16, 10);   //nakresli kružnici
    displej.drawDisc(31, 16, 3);      //nakresli střed kružnice

    displej.drawBox(73, 23, 8, 6);    //první sloupec
    displej.drawBox(85, 18, 8, 11);   //druhý sloupec
    displej.drawBox(97, 12, 8, 17);   //třetí sloupec
    displej.drawBox(109, 6, 8, 23);   //čtvrtý sloupec

    displej.sendBuffer();             //odešli obraz na displej
  }
výsledek čtvrtého programu

Grafické funkce se hodí například pro tvorbu ikon, ukazatelů stavu, jednoduchých grafů nebo vlastního uživatelského rozhraní.

Ukazatel průběhu

Jednoduchý ukazatel průběhu můžeme vytvořit kombinací obrysu a vyplněného obdélníku.

Nejprve nakreslíme rámeček:

displej.drawFrame(4, 18, 120, 12);

Do něj potom vložíme vyplněnou část:

displej.drawBox(6, 20, sirka, 8);

Šířku vyplněné části lze vypočítat z hodnoty v procentech:

sirka = map(procenta, 0, 100, 0, 116);

Funkce map() převede rozsah od 0 do 100 procent na šířku od 0 do 116 pixelů.

Praktický ukazatel v procentech

Následující program zobrazuje procentuální hodnotu a pod ní jednoduchý ukazatel průběhu. Hodnota postupně roste od 0 do 100 procent a potom začne znovu od začátku.

///////////////////////OLED ukazatel fw v.0.1 ///////////////////////////////
///////////////////////14.7.2026 ///////////////////////////////////////////
///////////////////////www.michaluvbrloh.cz//////////////////////////////////

#include <Wire.h>       //komunikace po sběrnici I2C
#include <U8g2lib.h>    //ovládání OLED displeje

//OLED displej SSD1306 128x32 připojený pomocí hardwarové I2C
U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C displej(U8G2_R0, U8X8_PIN_NONE);

byte procenta = 0;          //aktuální hodnota v procentech
char textProcent[8];        //textová podoba hodnoty

/////////////////////////////po spuštění///////////////////////////////////////////////////////////////////////////////////////
void setup()
  {
    displej.begin();                  //spusť OLED displej
  }

/////////////////////////////hlavní smyčka/////////////////////////////////////////////////////////////////////////////////////
void loop()
  {
    vypisUkazatel();                  //zobraz hodnotu a ukazatel

    procenta += 1;                    //zvyš hodnotu

    if(procenta > 100)                //pokud hodnota překročila 100 %
      {
        procenta = 0;                 //začni znovu od nuly
      }

    delay(150);                       //krátká pauza
  }

/////////////////////////////výpis ukazatele///////////////////////////////////////////////////////////////////////////////////
void vypisUkazatel()
  {
    byte sirka;                       //šířka vyplněné části
    int x;                            //vodorovná pozice textu

    snprintf(textProcent, sizeof(textProcent), "%u %%", procenta); //vytvoř text
    sirka = map(procenta, 0, 100, 0, 116); //přepočítej procenta na pixely

    displej.clearBuffer();            //vymaž obrazovou paměť

    displej.setFont(u8g2_font_6x12_tf); //nastav písmo
    x = (128 - displej.getStrWidth(textProcent)) / 2; //vypočítej střed
    displej.drawStr(x, 11, textProcent); //zobraz procenta

    displej.drawFrame(4, 18, 120, 12);  //nakresli obrys ukazatele

    if(sirka > 0)                       //pokud je co vykreslit
      {
        displej.drawBox(6, 20, sirka, 8); //nakresli vyplněnou část
      }

    displej.sendBuffer();             //odešli obraz na displej
  }
video z pátého programu

Podobný ukazatel lze použít například pro stav nabití akumulátoru, sílu signálu, naplnění zásobníku nebo průběh dlouhé operace.

Jednoduchá animace

OLED displej dokáže obraz překreslovat dostatečně rychle také pro jednoduché animace. Princip je stále stejný. Nejprve vymažeme obrazovou paměť, nakreslíme objekt na nové pozici a celý obraz odešleme na displej.

Následující program zobrazuje malou tečku, která se pohybuje zleva doprava a po dosažení okraje se vrátí zpět.

///////////////////////OLED animace fw v.0.1 ////////////////////////////////
///////////////////////14.7.2026 ///////////////////////////////////////////
///////////////////////www.michaluvbrloh.cz//////////////////////////////////

#include <Wire.h>       //komunikace po sběrnici I2C
#include <U8g2lib.h>    //ovládání OLED displeje

//OLED displej SSD1306 128x32 připojený pomocí hardwarové I2C
U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C displej(U8G2_R0, U8X8_PIN_NONE);

int poziceX = 3;                    //vodorovná pozice tečky
int smer = 1;                       //směr pohybu
unsigned long posledniPohyb = 0;    //čas posledního překreslení

/////////////////////////////po spuštění///////////////////////////////////////////////////////////////////////////////////////
void setup()
  {
    displej.begin();                //spusť OLED displej
  }

/////////////////////////////hlavní smyčka/////////////////////////////////////////////////////////////////////////////////////
void loop()
  {
    animace();                      //obsluhuj animaci
  }

/////////////////////////////animace///////////////////////////////////////////////////////////////////////////////////////////
void animace()
  {
    if(millis() - posledniPohyb >= 20)       //pokud uplynulo 20 ms
      {
        posledniPohyb = millis();            //ulož čas překreslení

        displej.clearBuffer();                //vymaž obrazovou paměť

        displej.drawFrame(0, 0, 128, 32);     //nakresli rámeček
        displej.drawDisc(poziceX, 16, 3);     //nakresli pohybující se tečku

        displej.sendBuffer();                 //odešli obraz na displej

        poziceX = poziceX + smer;             //posuň tečku

        if(poziceX >= 124)                    //pokud dorazila doprava
          {
            smer = -1;                        //změň směr doleva
          }

        if(poziceX <= 3)                      //pokud dorazila doleva
          {
            smer = 1;                         //změň směr doprava
          }
      }
  }
video z šestého programu

Časování je v tomto případě řešené pomocí funkce millis(). Program proto nemusí čekat v blokujícím příkazu delay() a během animace může současně obsluhovat tlačítka, měřit senzory nebo komunikovat s dalšími moduly.

Interval 20 ms odpovídá teoreticky až 50 překreslením za sekundu. Skutečná rychlost ale závisí také na době potřebné k odeslání celé obrazové paměti po sběrnici I²C.

U jednoduchých animací není potřeba používat maximální možnou rychlost. Příliš časté překreslování zbytečně zatěžuje Arduino i sběrnici. Pro stavové symboly nebo pomalejší pohyb často stačí interval 50 až 200 ms.

Zobrazení vlastního obrázku

Kromě textu a základních geometrických tvarů můžeme na displeji zobrazit také vlastní obrázek.

Protože jde o monochromatický displej, každý pixel může být pouze zapnutý nebo vypnutý. Obrázek tedy neobsahuje odstíny šedi ani barvy. Musí být předem převedený na černobílou bitmapu.

Knihovna U8g2 dokáže pracovat například s formátem XBM. Obrazová data jsou uložená přímo v programu jako pole bajtů.

Následující ukázka obsahuje jednoduchou ikonu akumulátoru o velikosti 16 × 16 pixelů.

///////////////////////OLED bitmapa fw v.0.1 ////////////////////////////////
///////////////////////14.7.2026 ///////////////////////////////////////////
///////////////////////www.michaluvbrloh.cz//////////////////////////////////

#include <Wire.h>       //komunikace po sběrnici I2C
#include <U8g2lib.h>    //ovládání OLED displeje

//OLED displej SSD1306 128x32 připojený pomocí hardwarové I2C
U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C displej(U8G2_R0, U8X8_PIN_NONE);

//ikona akumulátoru 16x16 pixelů
static const unsigned char baterie_bits[] U8X8_PROGMEM =
  {
    0x00, 0x00,
    0x00, 0x00,
    0x00, 0x00,
    0xFE, 0x3F,
    0x02, 0x20,
    0xFA, 0x27,
    0xFA, 0xE7,
    0xFA, 0xE7,
    0xFA, 0xE7,
    0xFA, 0xE7,
    0xFA, 0x27,
    0x02, 0x20,
    0xFE, 0x3F,
    0x00, 0x00,
    0x00, 0x00,
    0x00, 0x00
  };

/////////////////////////////po spuštění///////////////////////////////////////////////////////////////////////////////////////
void setup()
  {
    displej.begin();                  //spusť OLED displej

    vypisBaterii();                   //zobraz ikonu a hodnotu
  }

/////////////////////////////hlavní smyčka/////////////////////////////////////////////////////////////////////////////////////
void loop()
  {
    //obraz se nemění
  }

/////////////////////////////výpis stavu baterie//////////////////////////////////////////////////////////////////////////////
void vypisBaterii()
  {
    displej.clearBuffer();            //vymaž obrazovou paměť

    displej.drawXBMP(4, 8, 16, 16, baterie_bits); //zobraz ikonu baterie

    displej.setFont(u8g2_font_9x15_tf);           //nastav větší písmo
    displej.drawStr(28, 21, "75 %");              //zobraz stav baterie

    displej.sendBuffer();             //odešli obraz na displej
  }
výsledek sedmého programu

Funkce pro zobrazení bitmapy má následující tvar:

displej.drawXBMP(x, y, sirka, vyska, obrazovaData);

První dvě hodnoty určují pozici levého horního rohu obrázku. Následuje jeho šířka, výška a název pole obsahujícího obrazová data.

V tomto příkladu se ikona vykreslí na souřadnici [4, 8]:

displej.drawXBMP(4, 8, 16, 16, baterie_bits);

Obrázek zabírá plochu 16 × 16 pixelů a vedle něj zůstává dost prostoru pro zobrazení textové hodnoty.

Příprava vlastní bitmapy

Vlastní obrázek lze připravit v grafickém programu nebo pomocí převodníku bitmap do formátu vhodného pro Arduino.

Při přípravě je potřeba dodržet několik pravidel:

  • Obrázek musí být černobílý
  • Jeho rozměry nesmí překročit 128 × 32 pixelů
  • Jednoduché tvary bývají na malém displeji čitelnější
  • Tenké čáry mohou při zmenšení zaniknout
  • Velká bitmapa zabere více paměti programu

Celá obrazovka o rozlišení 128 × 32 pixelů potřebuje:

128 × 32 ÷ 8 = 512 bajtů

Jeden bajt obsahuje stav osmi pixelů. Malé ikony proto zabírají pouze několik desítek bajtů, zatímco obrázek přes celou obrazovku potřebuje přibližně půl kilobajtu paměti programu.

U klasického Arduina Uno nebo Nano není jedna bitmapa problém. Pokud bychom ale do programu vložili velké množství obrázků nebo jednotlivé snímky animace, mohla by se rychle zaplnit paměť programu.

Animace z několika obrázků

Jednoduchou animaci lze vytvořit také střídáním několika bitmap. Každá bitmapa představuje jeden snímek.

Program postupně zobrazí například:

displej.drawXBMP(0, 0, 128, 32, obrazek1);
displej.sendBuffer();

delay(100);

displej.clearBuffer();
displej.drawXBMP(0, 0, 128, 32, obrazek2);
displej.sendBuffer();

Tento způsob se hodí pro malé symboly, blikající ikony nebo krátké úvodní animace. U většího počtu snímků je ale potřeba hlídat velikost programu.

Pro plynulý pohyb jednoduchých objektů je většinou výhodnější měnit jejich souřadnice než ukládat každý snímek jako samostatný obrázek.

Nastavení kontrastu

Jas displeje lze částečně ovlivnit nastavením kontrastu. K tomu slouží funkce:

displej.setContrast(100);

Použitá hodnota může být v rozsahu od 0 do 255. Vyšší číslo zpravidla znamená jasnější obraz.

Nastavení kontrastu můžeme provést po spuštění displeje:

displej.begin();          //spusť OLED displej
displej.setContrast(100); //nastav nižší kontrast

Nejnižší hodnota nemusí znamenat úplně zhasnutý displej. Konkrétní výsledek se může mírně lišit podle použitého panelu.

Při použití v místnosti většinou není potřeba nastavovat maximální jas. Nižší kontrast může být příjemnější na pohled a zároveň omezí zatěžování OLED pixelů.

Vypnutí displeje

Pokud zařízení displej delší dobu nepotřebuje, můžeme ho softwarově vypnout:

displej.setPowerSave(1);      //vypni displej

Opětovné zapnutí provedeme příkazem:

displej.setPowerSave(0);      //zapni displej

Obsah obrazové paměti Arduina tím není automaticky vymazaný. Po zapnutí se proto může znovu objevit předchozí obraz.

Tato funkce se hodí například u zařízení napájených z akumulátoru nebo u displeje, který se má rozsvítit pouze po stisknutí tlačítka.

Spotřeba OLED displeje

Spotřeba OLED displeje závisí také na tom, kolik pixelů právě svítí. Obrazovka s několika malými znaky proto obvykle odebírá méně než plocha vyplněná velkým bílým obdélníkem.

Při bateriovém napájení je proto výhodné:

  • Používat pouze potřebné množství svítících pixelů
  • Nenastavovat zbytečně vysoký kontrast
  • Displej při nečinnosti vypnout
  • Nezobrazovat velké vyplněné bílé plochy

Samotné snížení rychlosti překreslování nemusí výrazně snížit spotřebu OLED panelu. Rozsvícené pixely totiž odebírají proud i v době, kdy obraz právě neměníme.

Dlouhodobé zobrazování stejného obrazu

Jednotlivé OLED pixely se během provozu postupně opotřebovávají. Pokud bude displej dlouhodobě zobrazovat stále stejný obsah, mohou se nejčastěji používané pixely opotřebovat rychleji než okolní plocha.

Po delší době se pak může objevit nerovnoměrný jas nebo slabě viditelný zbytek původního obrazu.

U běžných domácích projektů se tento problém nemusí projevit rychle. Přesto je vhodné hlavně u zařízení pracujících nepřetržitě dodržet několik jednoduchých pravidel:

  • Vypínat displej, když není potřeba
  • Nepoužívat zbytečně maximální kontrast
  • Občas změnit polohu statických údajů
  • Vyhnout se dlouhodobému zobrazení velkých bílých ploch
  • Použít automatické zhasnutí po určité době

OLED je proto výborný pro zařízení, na kterém se hodnoty průběžně mění nebo které se zapíná pouze při používání. Pro nepřetržité zobrazování stejného obrazu po mnoho měsíců mohou být vhodnější jiné zobrazovací technologie.

Výhody a omezení malého displeje

Hlavní výhodou tohoto modulu jsou jeho malé rozměry. Displej se vejde i do drobné krabičky a díky komunikaci I²C nezabere mnoho vývodů mikrokontroléru.

Mezi jeho výhody patří:

  • Malé rozměry
  • Dobře čitelný obraz
  • Vysoký kontrast
  • Jednoduché připojení pomocí I²C
  • Napájení 3,3 až 5 V
  • Možnost zobrazovat text i grafiku
  • Rozšířený řadič SSD1306
  • Velký výběr hotových knihoven

Největším omezením je výška pouhých 32 pixelů. Na displej se nevejde velké množství informací a při návrhu obrazovky je potřeba dobře využít dostupné místo.

Mezi omezení patří:

  • Malá zobrazovací plocha
  • Omezený počet řádků textu
  • Pouze jedna barva pixelů
  • Postupné opotřebovávání OLED panelu
  • Vyšší spotřeba při velkém počtu rozsvícených pixelů
  • Horší vhodnost pro dlouhodobě neměnný obraz

Displej se nejlépe uplatní tam, kde potřebujeme zobrazit jednu nebo několik důležitých hodnot a zároveň chceme zachovat malé rozměry celého zařízení.

Závěr

Malý OLED displej s rozlišením 128 × 32 pixelů sice nenabízí mnoho prostoru, ale při rozumném návrhu obrazovky dokáže přehledně zobrazit hlavní hodnotu, krátký stav, jednoduchou ikonu nebo několik položek menu. Díky komunikaci přes I²C navíc zabere pouze dva komunikační piny a snadno se přidá i k zařízení s dalšími moduly.

Knihovna U8g2 umožňuje kromě textu kreslit také základní grafiku, bitmapy a jednoduché animace. Při dlouhodobém provozu je jen potřeba počítat se spotřebou svítících pixelů a nenechávat zbytečně dlouho zobrazený stejný obraz při maximálním jasu. Pro malé měřáky, stavové panely a kompaktní zařízení je ale tento displej velmi dobře použitelný.

Různé druhy OLED displejů zakoupíte na Laskakit.cz, přímý odkaz je ZDE.

Další díly ze začátečnické série o modulech najdete ZDE.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *