[MBED] STM32 i SSD1306 – sterowanie dwukolorowym OLED [2]

 

promo

Przedstawiamy drugą część kursu obsługi wyświetlacza OLED za pomocą STM32. Pierwsza część artykułu jest dostępna pod adresem.

Wyświetlacz graficzny doskonale się nadaje do wyświetlania tekstu. W klasycznych wyświetlaczach alfanumerycznych czcionki mają jednakową wielkość zależną od wielkości wyświetlacza i mogą być wyświetlane w ustalonych wierszach. W wyświetlaczu graficznym można definiować czcionki o różnych rozmiarach zależnie od potrzeb i umieszczać je w dowolnym miejscu wyświetlacza – o ile się tam zmieszczą.

Przy adresowaniu Page Addressing Mode jest bardzo łatwo zdefiniować znaki o wysokości 8 pikseli, lub wielokrotności tej wartości: 16, 24, 32 itd. Najprościej definiować znaki np. 8×6 pikseli umieszczając w pamięci generatora znaków 6 kolejnych bajtów – łatwo to sobie wyobrazić patrząc na rysunek 7. W programowych bibliotekach obsługujących wyświetlacze graficzne stosowałem z powodzeniem tę metodę. Mam zdefiniowaną tablice generatora znaków i proste procedury wyświetlania znaku na podstawie jego kodu ASCII. Niestety przy tym wyświetlaczu znaki o wysokości 8 pikseli są praktycznie nieczytelne. Wynika to po prostu z małych wymiarów (przekątnej) matrycy. W naszym przypadku wartością graniczną jest wysokość 12 pikseli, a najlepiej gdyby znaki miały 16 i więcej pikseli.

Do rysowania znaków o dowolnej wielkości najlepiej się nadaje funkcja, która potrafi zapalić lub zgasić jeden piksel o dowolnych współrzędnych x, y niezależnych od trybu adresowania. Taka funkcja została pokazana na listingu 7.

List. 7. Rysowanie punktu o ustalonych współrzędnych

Jak łatwo zauważyć funkcja void DrawPoint() z listingu 7 tylko modyfikuje zawartość dwuwymiarowego bufora DispBuff umieszczonego w pamięci RAM mikrokontrolera Hosta i nie zapisuje modyfikacji do sterownika SSD1306. Jak zobaczymy dalej wszystkie procedury wyświetlania modyfikują tylko ten bufor i aby zobaczyć efekt tych modyfikacji trzeba przepisać całą zawartość DispBuff do pamięci sterownika wywołując funkcję void RefreshRAM(void) pokazaną na listingu 5.

Mając do dyspozycji procedurę potrafiącą zapalać/gasić piksel o konkretnej współrzędnej możemy rysować proste, figury, okręgi, ale też rysować znaki alfanumeryczne o dowolnych wielkościach. Żeby to robić potrzebne są wzorce znaków umieszczone w tablicy zwanej tez generatorem znaków. Ręczne tworzenie wzorców znaków jest możliwe, ale to żmudne zajęcie. Istnieje szereg programów tworzących wzorce o zadanej wielkości znaku. W Internecie można też znaleźć gotowe tablice z wzorcami. Ja skorzystałem z gotowych tablic ze zdefiniowanymi znakami o wielkości 12x6pikseli i 16x8pikseli. Tablice są tak zbudowane, ze kod ASCII znaku adresuje grupę bajtów definiujących ten znak. To znacznie upraszcza procedury wyświetlające łańcuchy znaków (napisy). Na przykład tablica dla znaków o wysokości 12 i szerokości 6 pikseli jest dwuwymiarową tablicą const char c_chFont1206[95][12] i zawiera 95 wzorców znaków. Każdy element wzorca znaków ma 12bajtów i definiuje znak o szerokości 6 pikseli, ale wykorzystuje przestrzeń 12×8 pikseli – listing 8.

List. 8. Fragment tablicy generatora znaków 12×6 pikseli

Dla znaków 16×8 pikseli jest zdefiniowana druga tablica const uint8_t c_chFont1608[95][16].

Mając tablice generatora znaków i procedurę DrawPoint() potrafiącą „zapalać i gasić” bit w buforze pamięci mikrokontrolera odpowiadający zawartości pamięci RAM sterownika, a tym samym odpowiadający pikselowi na matrycy OLED można napisać procedurę „rysującą” znak w pamięci RAM mikrokontrolera. Pamiętamy, że aby ten znak się wyświetlił trzeba przepisać zawartość DispBuff do pamięci RAM wywołując funkcję void RefreshRAM().

Na listingu 9 pokazano procedurę void DisplayChar() z argumentami:

  • x i y – współrzędne początku znaku na ekranie,
  • Chr – kod ASCII wyświetlanego znaku,
  • size – wielkość znaku 12, lub 16 pikseli,
  • mode= 1 wyświetlanie normalne, mode=0 wyświetlanie w negatywie.

Zależnie od wartości argumentu size bajty wzorca są pobierane z tablicy c_chFont1206[95][12] lub z tablicy c_chFont1608[95][16]. Kiedy argument mode jest wyzerowany to dodatkowo wartość pobranego bajtu jest negowana. Potem jest analizowany każdy bit bajtu wzorca i zależnie od jego wartości DrawPoint() zapisuje do bufora DispBuff odpowiednią wartość.

List. 9. Wyświetlenie jednego znaku

Mając procedurę wyświetlania jednego znaku o dowolnych współrzędnych można napisać procedurę wyświetlającą łańcuch znaków od określonej pozycji.

Na listingu 10 pokazano procedurę void DispTxt() z argumentami:

  • x i y – współrzędne początku znaku na ekranie,
  • *txt – wskaźnik na początek bufora z łańcuchem znaków,
  • size – wielkość znaku 12 lub 16 pikseli,
  • mode= 1 wyświetlanie normalne, mode=0 wyświetlanie w negatywie.

List. 10. Procedura wyświetlania ciągów znaków

O autorze

Absolwent Wydziału Elektroniki Politechniki Wrocławskiej, współpracownik miesięcznika Elektronika Praktyczna, autor książek o mikrokontrolerach Microchip i wyświetlaczach graficznych, wydanych nakładem Wydawnictwa BTC.
Zawodowo zajmuje się projektowaniem zaawansowanych systemów mikroprocesorowych.