[APLIKACJA] STM32 i monochromatyczny wyświetlacz OLED
Przyporządkowanie tak zaadresowanej pamięci obrazu do pikseli na matrycy zostało pokazane na rysunku 5. Jeden bajt w pamięci obrazu odpowiada pionowej linijce o długości 8 pikseli. Najmłodszy bit tego bajtu jest pikselem położonym najwyżej w linijce, a bit najstarszy pikselem położonym najniżej. Położenie linijki w poziomie określa licznik kolumn zmieniający się w zakresie 0…131, a położenie w pionie określa licznik stron zmienia się w zakresie 0…7. Po ustaleniu numeru strony kolejne zapisywane bajty tworzą pasek o szerokości 8 pikseli. Każdy zapis danej powoduje inkrementację licznika kolumn i nowa dana jest zapisywana po kolejna lokację. Kiedy licznik kolumn osiągnie wartość 131, to po następnym zapisie danych jest zerowany. Przepełnienia licznika kolumn nie powoduje inkrementacji licznika stron i jeżeli nie zmodyfikujemy go wykorzystując do tego celu komendę „ustawienie licznika stron”, to kolejne wpisy do pamięci będą nadpisywać dane począwszy od pozycji zerowej (wyzerowanie licznika kolumn).
Wyświetlanie tekstu jest bardzo ważnym elementem tworzenia graficznego interfejsu użytkownika. W odróżnieniu od klasycznych wyświetlaczy alfanumerycznych można sobie definiować czcionki o różnej wielkości i stosować je zależnie od potrzeb. Im mniejszy wyświetlacz tym najprawdopodobniej trzeba będzie definiować większe znaki by były dobrze widoczne. Tablice wzorców dużych znaków zajmują sporo miejsca w pamięci programu mikrokontrolera i dlatego warto definiować tylko te, które są niezbędne. Klasycznym przykładem takiego podejścia jest definiowanie tylko wzorców cyfr 0…9 oraz kilku znaków dodatkowych potrzebnych do wyświetlania wartości cyfrowych.
Przy sterowniku zastosowanym w module modOLED13 wystarczy ustawić adres kolumny i numer strony (listing 8) i wysłać do sterownika kolejnych 6 bajtów, co realizuje program pokazany na listingu 9.
List. 8. Ustalenie pozycji wyświetlania na ekranie
void SetPos(uint8_t x, uint8_t y) { SetColumn(x); SetPage(y); }
List. 9. Wyświetlanie znaku 8×6 pikseli
void WriteChar(char code) { int code_point; code_point=((int)code*6); OledData(rom_gen[code_point++]); OledData(rom_gen[code_point++]); OledData(rom_gen[code_point++]); OledData(rom_gen[code_point++]); OledData(rom_gen[code_point++]); OledData(rom_gen[code_point]); }
Rys. 6. Wygląd okna programu TheDotFactory z przykładowym tekstem konwertowanym do tablicy w C
Definiowanie tablicy wzorców znaków jest zajęciem żmudnym i dlatego warto skorzystać ze specjalnych programów robiących to za nas. W testach wyświetlacza użyłem darmowego programu TheDotFactory autorstwa Erana Duchana (rysunek 6). Program w najnowszej wersji potrafi generować wzorce w konwencji adresowania pamięci stosowanej w sterowniku SH1106. Dodatkowo można zdefiniować tablicę wzorca tylko dla wybranych znaków. Ze względów praktycznych (zajętość pamięci Flash) zdefiniowałem sobie tablice znaków (głównie cyfr) dla „średnich” znaków o będącej wielokrotnością 8 pikseli (1 bajta) wysokości 16 pikseli (2 bajty) i szerokości 10 pikseli oraz „dużych” o wysokości 24 pikseli (3 bajty) i szerokości 15pikseli. Procedura wyświetlania średnich znaków została pokazana na listingu 10, a znaków dużych na listingu 11.
List. 10. Procedura wyświetlania znaku 16×10 pikseli
void CharMedium(uint8_t cyfra, uint8_t x,uint8_t y ){ int i; SetPos(x*10,y*2); for(i=cyfra*20;i < cyfra*20+10;i++) OledData (dig_mid[i]); SetPos(x*10,(y*2)+1); for(i=cyfra*20+10;i < cyfra*20+20;i++) OledData (dig_mid[i]); }
List. 11. Procedura wyświetlania znaku 24x15pikseli
void CharBig(uint8_t cyfra, uint8_t x,uint8_t y ){ int i; SetPos(x*15,y*3); for(i=cyfra*45;i < cyfra*45+15;i++) OledData (dig_big[i]); SetPos(x*15,(y*3)+1); for(i=cyfra*45+15;i < cyfra*45+30;i++) OledData (dig_big[i]); SetPos(x*15,(y*3)+2); for(i=cyfra*45+30;i < cyfra*45+45;i++) OledData (dig_big[i]); }
W przypadku znaku o wymiarach 16×10 pikseli najpierw jest wyświetlana górna połowa znaku, czyli linijka o wysokości 8 pikseli i szerokości 10 pikseli przez wysłanie do sterownika 10 bajtów z tablicy wzorca. Potem ustawiana jest wartość początkowa licznika kolumn, licznik stron jest inkrementowany i do sterownika jest wysłanych kolejnych 10 bajtów z tablicy wzorca. Zasada wyświetlania dużych znaków jest identyczna, z tym, że wysyłane są bajty wzorca w trzech porcjach po 15 bajtów.
Fot. 7. Przykład ilustrujący wyświetlanie znaków alfanumerycznych o różnych wielkościach
Na fotografii 7 pokazano ekran z wyświetlonymi znakami o 3 różnych wielkościach o największej do najmniejszej. Nawet przy tak małym wyświetlaczu i ustawieniu kontrastu na średnią wartość duże znaki są dobrze widoczne i czytelne z odległości do 2 metrów. To zapewne zasługa technologii OLED, bo trudno byłoby uzyskać taki efekt z wyświetlaczem LCD o identycznych wymiarach.
Żeby wyświetlić bitmapę trzeba ją najpierw przekształcić do postaci monochromatycznej, oraz dostosować jej wielkości do rozmiarów matrycy. W naszym przypadku bitmapa musi mieć rozmiar 128×64 pikseli. Tak przygotowana bitmapę trzeba następnie przekonwertować do tablicy w języku C. Tutaj niezbędne jest specjalnego zastosowanie programu, który potrafi to zrobić zgodnie z zasadą powiązania zawartości pamięci programu z wyświetlanymi pikselami na matrycy. Użyłem tu programu bmp2c.exe (do pobrania na dole strony).
Fot. 8. Przykładowa grafika wyświetlana na wyświetlaczu OLED z modułu modOLED13
Program po wczytaniu bitmapy, zaznaczeniu opcji V-8 i kliknięciu na przycisk C generuje tablicę w języku C umieszczoną w schowku systemu Windows. Teraz wyświetlenie bitmapy jest banalnie proste. Wystarczy pobierać dane z tablicy w porcjach po 128 bajtów, a po każdej porcji inkrementować licznik stron. Procedura wyświetlająca pełnowymiarową bitmapę została pokazana na listingu 12, a efekt jej działania na fotografii 8.
List. 12. Procedura wyświetlająca pełnowymiarową bitmapę
void OledBmp(void) { uint16_t i,j,k; SetColumn(0); SetLine(0); SetPage(0); k=0; for(j=0;j<8;j++) { SetPage(j); SetColumn(0); for (i=0; i<128; i++) { OledData(bmp[k++]); } }