Każdy, kto zajmuje się konstruowaniem i budową urządzeń, wcześniej czy później jest zmuszony zaprezentować parametry pracy urządzenia na wyświetlaczu. Mogą to być ustawienia menu, wskazania parametrów pracy lub logo firmy. Na rynku mamy bardzo duży wybór różnych wyświetlaczy. Wszystkie do prawidłowej pracy potrzebują algorytmów inicjalizacji i obsługi w kodzie programu. Zajmuje to dość dużo cennej pamięci, co ma szczególnie znaczenie dla tanich mikrokontrolerów wyposażonych w skromne zasoby. Obsługa interfejsu fizycznego wyświetlacza może wiązać się z koniecznością użycia dużej liczby wyprowadzeń lub zastosowania układów pośredniczących. Wyświetlacze Avago są bardzo ciekawą alternatywą, ponieważ prezentują informacje w czytelny sposób, również przy jasnym oświetleniu słonecznym.
Zaglądając do noty katalogowej układu, widzimy, że wyświetlacz komunikuje się z mikrokontrolerem za pomocą interfejsu SPI. W dalszej kolejności musimy zwrócić uwagę na to, jakie wyprowadzenia układu będą nam jeszcze potrzebne do sterowania. Na rysunku 1 zamieszczono zaczerpnięty z dokumentacji opis wyprowadzeń. W podstawowej konfiguracji nie wszystkie są używane:
- RESET powinno być dołączone do mikrokontrolera.
- DATA IN to wejście danych do układu (do MOSI mikrokontrolera).
- DATA OUT jest wyjściem dołączanym danych do kolejnego układu. Służy do szeregowego łączenia układów wyświetlaczy.
- CLOCK wejście sygnału zegarowego interfejsu danych (do SCK mikrokontrolera).
- RS doprowadzenie sterujące zapisem danych do rejestru diod lub rejestrów kontrolnych.
- CE wejście sterujące zapisem danych. Zapis następuje, gdy wejście CE jest wyzerowane. Narastające zbocze CE powoduje zapamiętanie danych w rejestrach.
- SEL jest wejściem sygnału służącego do wyboru wewnętrznego lub zewnętrznego oscylatora. Dołączenie do napięcia +5 V (poziomu wysokiego) spowoduje wybór oscylatora wewnętrznego.
- BLANK wejście służące do wyłączenia wyświetlacza. Aktywne, gdy jest ustawione. Podczas normalnej pracy powinno być wyzerowane.
Pozostałe piny to masa i zasilanie, przy czym możemy korzystać z oddzielnych źródeł napięcia dla logiki i driverów diodo.
Wiemy już, co i jak przyłączyć - czas na realizację. Na listingu 1 zamieszczono plik hcms.h, w którym dla wygody przygotowano makra służące do obsługi układu wyświetlacza. Oprócz makr dla poszczególnych pinów widzimy deklarację potrzebnych funkcji, bufora tekstowego oraz definiujemy liczbę połączonych modułów. Najważniejsze funkcje, oprócz inicjalizacji modułu SPI, to funkcje narzędziowe do inicjalizacji, zerowania i czyszczenia wyświetlaczy.
Na listingu 2 pokazano funkcje użyteczne przy sterowaniu wyświetlaczem. W funkcji Display_init oprócz ustawienia potrzebnych pinów dokonujemy zerowania wyświetlacza. Sama funkcja Reset_display sprowadza się do zmiany poziomu na dedykowanym wyprowadzeniu mikrokontrolera. Funkcja Clear_display za pomocą pętli for wpisuje do rejestru diod same 0, co powoduje wyłączenie wyświet-
lacza. Liczba powtórzeń pętli jest wyznaczana makrem display_len. Oczywiście, wpisanie do wysłania wartości 0xFF spowoduje zaświecenie wszystkich diod w matrycach.
Funkcje SPI_init oraz Send_SPI nie wymagają omawiania. Interfejs SPI działa w trybie MODE 0. Można zrezygnować z włączenia bitu SPI2X. W testach zegar kontrolera pracował z zewnętrznym oscylatorem kwarcowym o częstotliwości 16 MHz, więc szybkość zegara SPI to 8 MHz przy włączonym bicie SPI2X. Jedyne, na co pragnę zwrócić uwagę w funkcji Send_SPI, to kolejność ustawiania pinu CE inaczej niż w typowych rejestrach przesuwnych.
Mamy zainicjalizowany wyświetlacz. Czas na funkcje pozwalające na wyświetlenie komunikatu lub zmiennej. Podstawową będzie funkcja wyświetlająca pojedynczy znak. Można by było napisać funkcję wyświetlającą pojedynczy piksel, ale ze względu na specyfikę tych wyświetlaczy nie będziemy na nich tworzyć grafik, więc ograniczymy się do wyświetlenia znaku zdefiniowanego w pliku fonty.h. Funkcja putChar wypełnia bufor odpowiednimi bitami, odwołując się do wspomnianego pliku z definicjami fontów. Funkcja niczego nie wyświetla, a jedynie wypełnia bufor odpowiednimi kombinacjami bitów. Jeżeli chcielibyśmy za jej pomocą wyświetlić pojedynczy znak, to musimy dodać pętlę, która prześle dane 5 kolumn z bufora na wyświetlacz.
Kolejne dwie funkcje to putString i putStringP. Obydwie umożliwiają wyświetlenie łańcucha znaków zapisanego w pamięci danych RAM lub programu Flash. Funkcje różnią się tylko odwołaniem do miejsca pobierania znaku. Następnie wypełniamy bufor i za pomocą krótkiej pętli for przesyłamy dane z bufora do wyświetlacza. Oczywiście - każdy znak osobno.
Pozostała jeszcze do omówienia funkcja wyświetlająca wartość liczbową, to jest putInt(). Dodano w niej parametr pozwalający na pozycjonowanie wyświetlanej wartości. Wyświetlając łańcuch, możemy do pozycjonowania użyć znaków odstępu, natomiast w wypadku wyświetlania wartości temperatury takiej możliwości nie mamy. Dlatego dodałem argument pozwalający na taką czynność. Pierwszy argument to właśnie pozycja na wyświetlaczu. Drugi to zmienna do wyświetlenia, przy czym mamy tu dowolność typu. Podstawowy, użyty w funkcji to 8-bitowy ze znakiem, ale w zależności od potrzeb możemy to zmienić. Funkcja zamienia wartość liczbową na znak ASCII, a następnie za pomocą putString wypełnia bufor tekstowy, który potem jest wysyłany do wyświetlacza. W funkcji widać jeszcze jedną pętlę, która ma za zadanie pozycjonowanie łańcucha na wyświetlaczu. Bufor tekstowy jest wypełniany znakiem spacji w liczbie wskazanej przez pierwszy argument funkcji pomniejszony o jeden, ponieważ procesor liczy od 0.
Testując wyświetlacze, ograniczyłem się do kilku podstawowych funkcji, mając na uwadze to, że najważniejsze jest uruchomienie układu, a dalsze zabawy, na przykład z przewijaniem czy miganiem napisu pozostawiam czytelnikom. Przykładowy test wyświetlacza pokazano na listingu 3.
Na początku są dołączane potrzebne biblioteki. Definiujemy zmienną licznik do testów oraz komunikat w pamięci Flash. Inicjalizujemy wyświetlacz oraz interfejs SPI, czyścimy wyświetlacz i za pomocą funkcji putStringP wyświetlamy wcześniej zdefiniowany napis. Następnie musimy zająć się rejestrami kontrolnymi wyświetlacza, ponieważ bez tego nic nie zobaczymy.
Wyświetlacz ma dwa rejestry kontrolne indeksowane 0 i 1. W pierwszym bezwzględnie musimy ustawić bit na pozycji szóstej. Odpowiada on za tryb sleep wyświetlacza i jeżeli jest wyzerowany, to wyświetlacz pozostaje ciemny (wyłączony). Należy wspomnieć o tym, że w trybie uśpienia wyświetlacz pobiera prąd o natężeniu jedynie 50 mA, co można wykorzystać przy zasilaniu bateryjnym. Pozostałe bity 0…5 rejestru decydują o jasności świecenia. Po szczegóły odsyłam do noty aplikacyjnej. Rejestr o indeksie 1 wykorzystujemy tylko przy kaskadowym połączeniu wyświetlaczy. Ustawienie bitu 0 spowoduje, że na pinie DATAOUT wyświetlacza otrzymamy dane dla kolejnych modułów. W pętli głównej migamy diodą oraz wyświetlamy co sekundę zmienną licznik.
Na koniec zachęcam czytelników do dzielenia się pomysłami na stronach forum "Elektroniki Praktycznej", gdzie można zastosować te wyświetlacze.
Marek Rębecki
marekrebecki@wp.pl