Implementacja obsługi wyświetlacza LCD Spis treści
Transkrypt
Implementacja obsługi wyświetlacza LCD Spis treści
Zespół: CZ/N/15 Wrocław, dn. 29 stycznia 2009 Karol Wrótniak, 156566 Ocena: Marcin Załuski, 156571 Oddano: Implementacja obsługi wyświetlacza LCD sprawozdanie z projektu przedmiotu „Architektura Komputerów” Rok akad. 2008/2009, kierunek: INF, specjalność: - PROWADZĄCY: dr inż. Piotr Patronik Spis treści 1 Cel projektu 3 2 Realizacja sprzętowa 3 3 Protokół transmisyjny 5 4 Obsługa portu LPT 7 5 Narzędzia pomocnicze 7 6 Funkcje podstawowe 8 6.1 Funkcja setb . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 6.2 Funkcja clrb . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 6.3 Funkcja writeB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 6.4 Funkcja clear . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 6.5 Funkcja setPerm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 6.6 Funkcja init . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 6.7 Funkcja off . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 6.8 Funkcja normColors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 6.9 Funkcja invColors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 6.10 Funkcja putStr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 6.11 Funkcja setXY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 7 Obsługa grafiki oraz animacji 12 7.1 Funkcja anim . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 7.2 Funkcja readGif . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 7.3 Funkcja playMovie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 7.4 Funkcja getImage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 7.5 Funkcja getFrameDuration . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 7.6 Funkcja displayImage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 8 Interfejs użytkownika 14 9 Podsumowanie i wnioski 15 Bibliografia 16 2 1 Cel projektu Celem tego projektu było zaimplementowanie sterowania i obsługi z poziomu komputera PC wyświetlacza LCD telefonu Nokia 3310. Jest to ekran monochromatyczny o wielkości 84x48 pikseli. Sprzęt ten został wybrany ze względu na nieskomplikowany protokół transmisyjny, a także łatwość realizacji części sprzętowej oraz niską cenę elementów niezbędnych do jego działania. Połączenie z komputerem PC odbywa się przy pomocy portu równoległego LPT. Obsługa LCD obejmuje wyświetlanie liter alfabetu łacińskiego oraz wyświetlanie obrazków w tym prostych animacji. Kod źródłowy napisany jest w języku asemblera, w składni AT&T i przeznaczony dla systemu Linux x86/x86 64. 2 Realizacja sprzętowa Głównym elementem układu jest wyświetlacz LCD wyposażony w kontroler Philips PCD8544 (szczegółowa specyfikacja dostępna w [1]). Tego typu ekrany występujące w popularnych Nokiach 3310 (także 3210 i podobnych) obudowane są metalową maskownicą, która zabezpiecza LCD przed uszkodzeniami i zwiększa jego trwałość. Odmiana występująca w większości modeli 3310 ma jeszcze jedną zaletę – metalowe styki kontaktowe umożliwiające bezpośrednie przylutowanie kabli i taki właśnie wyświetlacz zastosowaliśmy. Na rynku dostępna jest też wersja z gumką przewodzącą, która wymaga użycia odpowiedniej płytki drukowanej w celu podłączenia. Przystosowanie go do podłączenia do portu LPT wymaga skonstruowania układu składającego elementów pasywnych, który ma za zadanie zapewnienie odpowiednich parametrów prądowo-napięciowych oraz stabilności działania. Nasz układ zbudowaliśmy w oparciu o schemat z [2] wprowadzając pewne modyfikacje. Wyświetlacz wymaga napięcia w zakresie od 2,7V do 3,3V, a więc nie powinien być podłączony bezpośrednio do portu równoległego, na którego liniach w zależności od płyty głównej może występować napięcie aż do 5V. Żeby uzyskać pożądany poziom sygnału użyte zostały diody Zenera 3V3 dla każdej z linii (zasilania i sterowania). Dzięki temu napięcie między liniami LCD, a masą nie powinno przekroczyć 3,3V. W celu zabezpieczenia 3 portu przed przeciążeniem należy ograniczyć maksymalne natężenie prądu płynące przez linie danych portu. Zadanie to realizują rezystory włączone szeregowo w linie portu. W układzie występują, też kondensatory elektrolityczne między masą i liniami zasilającymi. Ich zadaniem jest stabilizacja napięć, a co za tym idzie, wyświetlanego na LCD obrazu. O ile w przypadku diod Zenera, sprawa doboru ich parametrów jest oczywista, to dla rezystorów stanowi większy problem. Na początku zlutowaliśmy układ w oparciu o rezystory wartości 1,2 kΩ (wg przyjętego wcześniej schematu), jednak napięcie na wyjściu (ok. 2,4V) okazało się wtedy zbyt niskie dla prawidłowej pracy LCD i wyświetlana była tylko jedna linia. W związku z tym zmniejszyliśmy opory rezystorów do 330Ω (tak jak w schemacie na [3]). Po tej operacji napięcie na wyjściu mieściło się w normie i wyświetlacz zaczął działać prawidłowo. Pojemności kondensatorów okazały się dobrane poprawnie, dzięki czemu obraz był stabilny. Ostateczny schemat naszego układu przedstawia rys. 1. 1 14 330Ω D0 SCK D1 SDIN D2 RES D3 SCE D4 D/C D5 VDD LPT VOUT 1μF 3V3 GND GND 13 LCD 2,2μF 25 Rysunek 1: Schemat układu służącego do podłączenia wyświetlacza z komputerem 4 Kolejnym, z pozoru błahym problemem, było wykonanie połączenia między wtyczką a wyświetlaczem. Początkowo użyliśmy żyłek ze skrętki telefonicznej, jednak okazały się one zbyt sztywne i powodowały zrywanie lutów nawet przy delikatnych ruchach. Zdecydowaliśmy się więc na użycie kawałka kabla (taśmy) od napędu dyskietek, ponieważ jest on elastyczny, więc nie powodował takich problemów jak poprzednie rozwiązanie. Kabel od FDD wygląda też bardziej estetycznie. Jak się jednak okazało, przy lutowaniu od strony LCD trzeba było zwracać szczególną uwagę, aby taśma i wyświetlacz były ustawione idealnie w osi. Niewielkie odchylenie przy rozpoczęciu lutowania od pinów z jednej strony w kierunku drugiej powodowało, że ostatnie żyły znajdowały się już zbyt daleko od styków. Rozwiązaniem było przylutowanie najpierw skrajnych pinów – co prawda pogarsza to dostęp do tych znajdujących się w środku, ale ostatecznie zastosowaliśmy ten sposób. Końcówki wszystkich elementów zostały przylutowane bezpośrednio do wtyczki LPT. Odwrotne ich umiejscowienie było by kłopotliwe ze względu na małe odległości między pinami wyprowadzonymi z LCD i większą podatność na uszkodzenia. Miejsce styków zostało owinięte taśmą izolacyjną, co zabezpieczyło styki przed zwarciami jak i przed zerwaniem lutów. Wygląd kompletnego układu wraz z wyświetlaczem przedstawia rys. 2. Rysunek 2: Wyświetlacz gotowy do podłączenia 5 3 Protokół transmisyjny Chociaż wyświetlacz podłączany jest przez port równoległy i wykorzystuje kilka linii, to transmisja danych odbywa się w rzeczywistości w sposób szeregowy, synchroniczny po jednej linii. Po tej samej linii przesyłane są komendy. Na zewnątrz LCD wyprowadzone są następujące połączenia: • SCK – sygnał zegarowy (synchronizacji) • VOUT – stabilizacja napięć wewnętrznych • GND – masa • SDIN – słowa danych/komend • RES – sygnał resetujący • SCE – sygnał aktywacji (określa czy sygnały na SCK i SDIN są ważne) • D/C – wybór danych/komend (określa czy wysyłamy dane czy komendę) • VDD - zasilanie Sterowanie wyświetlaczem polega na podawaniu kolejnych bitów przez linię SDIN w takt sygnału zegarowego przesyłanego przez SCK (odczyt stanu ma miejsce przy rosnącym zboczu), jeśli na SCE jest stan niski (w przeciwnym razie sygnały zegarowe są ignorowane). Bity zgrupowane są w bajty, które mogą oznaczać dane (kolejne bity określają stan pikseli, ustawiony bit oznacza zapalony piksel) lub polecenia (np. przesuwanie kursora), jeśli na na linii D/C panuje wtedy stan wysoki, to przebieg jest interpretowany jako dane. Reakcja wyświetlacza następuje po wysłaniu całego bajta, oraz zmianie stanu SCE, lub po kolejnym takcie zegara (wysłanie pierwszego bitu z kolejnego bajta). Najbardziej znaczący bit danych/komendy przesyłany jest jako pierwszy. Linia RES służy do restartowania wyświetlacza, stan aktywny jest niski, przy czym restart nie powoduje zmiany zawartości pamięci DDRAM (Display Data RAM) - stan pikseli nie zmienia się. Sygnał resetu jest 6 niezbędny w celu inicjalizacji LCD, lecz może być też użyty do przerywania transmisji (pierwszy przesłany bit po zresetowaniu traktowany jest jako początek nowego bajta). Przykładowe przebiegi na liniach używanych przez wyświetlacz obrazuje rys. 3, przedstawia on pocztąek inicjalizacji wyświetlacza, a dokładnie resetowanie oraz przesłanie pierwszej komendy (aktywacja i ustawienie rozszerzonego zakresu instrukcji). Na rysunku pominięto linie zasilania (VDD musi by w stanie wysokim, aby kontroler działał) oraz masy, która jak VOUT nie jest sterowalna. 105 ms SCE D/C RES SCLK SDIN DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 writeB Rysunek 3: Przebiegi sygnałów na początku inicjalizacji Ze względu na brak możliwości zakodowania wszystkich poleceń wraz z ich parametrami na jedynie ośmiu bitach (niewystarczająca liczba kodów) zostały one podzielone na dwa zestawy: podstawowy i rozszerzony. Ten sam kod może oznaczać różne polecenia 7 w zależności od zestawu instrukcji, który jest w danym momencie aktywny. Do wyboru zestawu służy specjalne polecenie, które ma zawsze identyczny kod, ustawia ono także tryb pracy kontrolera (włączony lub oszczędzanie energii) i tryb adresowania (poziomy lub pionowy). Standardowy zestaw obejmuje najczęściej używane polecenia, czyli ustawianie kursora i zmianę trybu wyświetlania (normalny, negatyw, zapalenie/zgaszenie wszystkich pikseli). Natomiast rozszerzony w ogólności zawiera polecenia ustawiające napięcia wewnętrzne LCD, co ma wpływ na kontrast obrazu. Szczegółowy opis wszystkich poleceń można znaleźć w specyfikacji kontrolera LCD. 4 Obsługa portu LPT Realizację kodu programu rozpoczęliśmy od obsługi portu LPT. Do ustawiania rejestru danych portu używana jest asemblerowa komenda outb, której użycie wymaga nadania odpowiednich uprawnień dostępu do portu za pomocą funkcji systemowej ioperm [4]. Tylko użytkownik root może ją wywoływać - próba zapisu do portu bez przyznanych uprawnień powoduje naruszenie ochrony pamięci, o czym mieliśmy okazję się przekonać. Adres portu ustawiony jest w kodzie jako stała globalna na 0x378, co jest wartością domyślną, którą można czasami zmienić w BIOS -ie podczas startu komputera. Funkcje wymagające adresu portu odwołują się do etykiety tej stałej. Zrezygnowaliśmy z próby automatycznego rozpoznawania adresu portu (np. przez parsowanie pliku /proc/ioports) czy pytania się o to użytkownika, ze względu na to, że rzadko kiedy adres portu nie jest domyślny. Niemniej jednak wprowadzenie takiej opcji nie spowoduje konieczności zmian w funkcjach potrzebujących adresu portu i może rozważymy to w terminie późniejszym. 5 Narzędzia pomocnicze W trakcie tworzenia programu używaliśmy narzędzia lptmanager[6], monitora portu LPT, który niestety nie jest już rozwijany, ale swoje zadanie spełnia bardzo dobrze. Umożliwia on wygodne sprawdzenie, czy stan rejestru portu po wykonaniu jakiegoś fragmentu 8 jest zgodny z oczekiwanym, bądź podgląd na bieżąco, przy krokowym debugowaniu programu. Kolejnym pomocnym narzędziem okazał się testserdisp, wchodzący w skład pakietu serdisplib[7]. Stanowi on zbiór bibliotek umożliwiających obsługę różnych wyświetlaczy podłączanych do PC. Wywołanie testserdisp -n PCD8544 -o‘‘WIRING=5‘‘ pozwala na obsługę naszego układu. Program ten był przydatny głównie przy pisaniu podstawowych funkcji jak inicjalizacja, czy przesyłanie poleceń i umożliwiał np. szybkie zresetowanie oraz wyczyszczenie wyświetlacza. Wykonanie tych operacji byłoby bardzo uciążliwe, gdy nie mieliśmy jeszcze w pełni gotowych naszych funkcji. Innego rodzaju udogodnieniem było użycie systemu kontroli wersji Subversion (SVN[8]), dzięki czemu łatwo mogliśmy udostępniać sobie nawzajem i uaktualniać pliki wchodzące w skład projektu. SVN uniemożliwia wystąpienie ew. konfliktów wersji plików oraz pozwala korzystać z zasobów na dowolnym komputerze podłączonym do internetu. 6 Funkcje podstawowe Funkcje zapewniające obsługę wyświetlacza na najniższym poziomie zostały umiesz- czone w pliku set.s, który zawiera także definicje stałych używanych przez nie, takich jak maski bitów portu, tablica znaków oraz numery funkcji systemowych i ich parametry. Ponieważ nie ma potrzeby ich modyfikacji przez program, całość znajduje się w sekcji text. Tylko niektóre funkcje tego modułu dostępne są z zewnątrz. Założyliśmy, że podstawowy zestaw instrukcji jest domyślny, a więc funkcje operujące tylko na poleceniach z niego, nie muszą go ustawiać. Jeśli wymagana jest instrukcja z rozszerzonego zestawu, to funkcja jej potrzebująca go aktywuje, a przed zakończeniem wraca do podstawowego. Jeśli nie jest napisane inaczej, to funkcje nie zwracają żadnych wartości i nie są dostępne na zewnątrz. Wybrane funkcje zostały oznaczone dyrektywą global, co umożliwia wykorzystanie ich przez inne moduły. Taka enkapsulacja spełnia podobną rolę, jak modyfikatory dostępu w klasach języków wysokiego poziomu, ograniczając możliwość błędnego użycia niektórych funkcji. 9 6.1 Funkcja setb Służy do ustawiania konkretnego bitu w rejestrze danych portu. Przyjmuje jako argument 1-bajtową maskę z ustawionym bitem. Jej działanie polega na odczytaniu stanu portu do rejestru procesora, ustawieniu w nim bitu zgodnie z maską i wpisaniu wyniku do portu LPT. 6.2 Funkcja clrb Działa analogicznie jak poprzednia, z tym że zeruje bit ustawiony w masce. 6.3 Funkcja writeB Wysyła bajt podany jako pierwszy argument do wyświetlacza. Drugim argumentem jest flaga określająca czy dany bajt jest komendą czy danymi. Na początku zależnie od drugiego argumentu ustawiany jest stan linii D/C, po czym ustawiane są stany początkowe linii SCE i SCK, do czego służą dwie poprzednio omówione funkcje. Następnie kolejne bity umieszczane są na linii SDIN, równolegle z generowaniem sygnału zegarowego. Najbardziej znaczący bit transmitowany jest jako pierwszy. Po przesłaniu ostatniego bitu stan SCE zmienia się na wysoki, co powoduje reakcję wyświetlacza na właśnie przesłany bajt. Żadna wartość nie jest zwracana. 6.4 Funkcja clear Nie wymaga parametrów, służy do czyszczenia pamięci DDRAM, a więc i zawartości wyświetlacza. Jej działanie polega na ustawieniu kursora na początek wyświetlacza, punkt o współrzędnych (0,0) i wysłaniu na wyświetlacz 4032 (liczba pikseli) bitów o wartości zero w trybie ciągłym. Po tej operacji kursor znajduje się na początku wyświetlacza, ponieważ jest przesuwany automatycznie w miarę napływu danych. 10 6.5 Funkcja setPerm Nie posiada żadnych parametrów, służy do ustawiania uprawnień dla portu zdefiniowanego w zmiennej globalnej port. Jej działanie polega wyłącznie na wywołaniu funkcji systemowej ioperm. Zwraca 0, gdy operacja ustawienia uprawnień zakończy się sukcesem albo -1, gdy nastąpi błąd, co może mieć miejsce np. przy próbie uruchomienia programu przez zwykłego użytkownika (UID!=0). 6.6 Funkcja init Nie przyjmuje żadnych parametrów, zajmuje się inicjalizacją wyświetlacza. Powinna być wywołana przed rozpoczęciem jakichkolwiek działań na LCD. Jej działanie polega na załączeniu napięcia zasilającego i resetowaniu kontrolera przez czas określony w strukturze waitTime, który u nas wynosi 105ms (wg specyfikacji minimalny czas resetowania w czasie inicjalizacji to 100ms). W tym celu użyta jest funkcja systemowa sleep[5]. Następnie wysyłane są kolejno polecenia nakazujące aktywację chipa, wybór rozszerzonego zestawu instrukcji, ustawienie poziomego trybu adresowania, napięcia, biasu i współczynnika temperaturowego. Wartości tych parametrów zostały dobrane doświadczalnie tak, aby uzyskać jak najlepszy kontrast. Kolejnym krokiem jest aktywacja standardowego zestawu instrukcji i włączenie normalnego trybu wyświetlania. Zawartość pamięci DDRAM jest w tym momencie niezdefiniowana, wywoływana jest więc tu funkcja clear, co kończy inicjalizację. 6.7 Funkcja off Nie przyjmuje żadnych parametrów, a służy do wyłączania wyświetlacza, co jest osiągane poprzez ustawienie stanu niskiego wszystkich używanych linii na porcie LPT. 6.8 Funkcja normColors Nie ma żadnych argumentów. Służy do ustawiania normalnego trybu wyświetlania (zapalone piksele na zgaszonym tle), jeśli przed wywołaniem tryb jest już ustawiony na 11 normalny, to na wyświetlaczu nic się nie dzieje. 6.9 Funkcja invColors Działa analogicznie do poprzedniej, z tym że ustawia tryb odwróconych kolorów (zgaszone piksele na czarnym tle). 6.10 Funkcja putStr Przyjmuje argument w postaci adresu początku ciągu ASCIIZ, który później wysyła na ekran LCD. Pojedynczy znak jest wielkości 5x8 pikseli, tak więc na wyświetlaczu zmieści się 6 linii po 14 znaków każda, co daje w sumie 84 znaki. Każdy znak dający się wpisać bezpośrednio z klawiatury (znak o kodzie ASCII od 32 do 126) zawiera swój wpis w tablicy znaków (aby oszczędzić sobie trudu samodzielnego jej tworzenia, za pomocą polecenia substitute edytora Vim, dostosowaliśmy znalezioną na [9]). Wiersz tablicy składa się z 5 bajtów, które odpowiadają za wygląd danego znaku na ekranie, pierwszy bit w bajcie oznacza najwyżej znajdujący się piksel. Po wyświetleniu znaku wstawiany jest odstęp o szerokości jednego piksela (bajt składający się z samych zer), spacja składa się z 6 pikseli odstępu. Adres znaku do wyświetlenia jest inkrementowany w pętli, a kursor przesuwany jest automatycznie przez kontroler miarę wyświetlania kolejnych znaków, które kończy się w momencie napotkania na znak o kodzie poniżej 0x20. Jeśli tekst nie zmieści się na wyświetlaczu to nadpisuje on jego zawartość zaczynając od początku. 6.11 Funkcja setXY Przyjmuje jako argumenty numer kolumny (od 0 do 84) oraz numer wiersza (od 0 do 5) i ustawia odpowiednio kursor (miejsce, od którego zacznie się potem wyświetlanie), gdy któraś z wartości jest poza zakresem, to funkcja nic nie robi. Nalżey zwrócić uwagę, że niemożliwe jest zaadresowanie w ten sposób każdego piksela bezpośrednio. Przestrzeń adresowalna podzielona jest na linie o wysokości 8 pikseli, a numer wiersza i kolumny 12 odnosi się właśnie do takiej linii. Żeby sterować poszczególnymi pikselami należy wysłać odpowiedni bajt danych. 7 Obsługa grafiki oraz animacji Głównym zadaniem na drugą część projektu była implementacja obsługi wyświetlania animacji. Pomysł stworzenia własnego sposobu zapisu grafiki został zarzucony na rzecz popularnego formatu GIF [11] [12], który obsługuje także obrazy animowane. Kod odpowiedzialny za obsługę grafiki został umieszczony w pliku lcdplib.s. Do odczytu i dekompresji plików została wykorzystane funkcje DGifOpenFileName oraz DGifSlurp DGifCloseFile z biblioteki GIFLIB [13]. Implementacja interakcji z użytkownikiem w zakresie wczytywania nazwy pliku i wyświetlania komunikatów o błędach również znajduje się w tym pliku. Ze względu na, to że funkcje biblioteki GIFLIB korzystają ze struktur typu GifFileType oraz SavedImage, to na początku zostały zadeklarowane offsety poszczególnych ich pól, aby można było łatwo się do nich odwoływać. Funkcje biblioteczne zwracają wartość 0 oznaczoną oryginalnie jako GIF ERROR w razie napotkania problemów w dalszym działaniu, ze względu na przejrzystość kodu używamy tej stałej jako globalnej. Natomiast stała globalna bmMaxsize określa nam maksymalny rozmiar obrazka obsługiwany przez wyświetlacz. Ponieważ projekt nie miał na celu implementacji pełnej obsługi formatu GIF oraz wszystkich jego rozszerzeń, w związku z tym narzucono dodatkowe ograniczenia na plik wejściowy: • paleta jednobitowa • brak kanału alpha • każdy obrazek w pliku o wymiarze 48px x 84px 13 7.1 Funkcja anim Jako jedyna z modułu dostępna jest z zewnątrz. Odpowiada ona za wyświetlenie znaku zachęty do wczytania nazwy pliku i wczytuje ją ze standardwego wejścia i przekształca odpowiednio dla funkcji czytającej plik (poprzez usunięcie znaku końca linii). Następnie wywołuje pozostałe funkcje odpowiedzialne za obsługę grafiki tj. wczytanie pliku i wyświetlenie animacji, wywołuje również zmiany trybu adresowania wyświetlacza z wierszowego (poziomego - używanego do wyświetlania tekstu) na kolumnowe (pionowe - naturalne w przypadku wyświetlania grafiki) przed wyświetleniem obrazka oraz odwrotnie po zakończeniu jego wyświetlania. W celu możliwośći przerwania zapętlonej animacji w dowolnym momencie, użyta została funkcja systemowa FORK i KILL. Na końcu, w przypadku prawidłowego otwarcia i odczytu pliku wywoływana jest funkcja DGifCloseFile zwalniająca zasoby przydzielone przez inne funkcje biblioteczne. 7.2 Funkcja readGif Służy do odczytu pliku GIF o nazwie podanej jako argument. Wywołuje biblioteczną funkcję DGifOpenFileName otwierającą plik, a w przypadku, gdy ta zakończy się poprawnie (zwróci wartość różną od 0, a więc poprawny wskaźnik na strukturę GifFileType) wywoływane jest DGifSlurp wczytujące obrazek do pamięci. W przypadku, gdy obie te funkcje zakończą się bez błędów, to zwracany jest uzyskany wcześniej wskaźnik na GifFileType. Natomiast w razie wystąpienia problemów wyśiwetlane są komunikaty o błędach i ewentualnie plik jest zamykany oraz funkcja zwraca wartość 0. 7.3 Funkcja playMovie Przyjmuje wskaźnik na strukturę GifFileType pliku do wyświetlenia. W ogólności odpowiada za wyśiwetlenie na LCD animacji. Wywołuje w pętli (aż do wyczerpania klatek) funkcje odpowiedzialne za wyświetlenie i synchronizację kolejnych klatek animacji. 14 7.4 Funkcja getImage Pobiera ona obrazek ze stuktury SavedImage(na którą wskaźnik został podany w pierwszym argumencie), dokonuje odpowiedniej konwersji (obrót o 90◦ , tak aby mógł on być prawidłowo wyświetlony na LCD) i zapisuje go jako ciąg bitów (w miejsce wskazywane przez drugi argument). Ze względu na konieczność dokonywania wielu dość operacji związanych z przekodowaniem obrazka z formatu dostarczanego przez funkcje z GIFLIB do nadającego się do wysłania na LCD, funkcja ta jest jedną z najbardziej rozbudowanych w całym projekcie. 7.5 Funkcja getFrameDuration Funkcja ta odczytuje i zwraca czas trwania danej klatki w animacji z informacji zawartych w strukturze SavedImage, do której wskaźnik podawany jest jako argument. Wartość zwracna podana jest w setnych częściach sekundy, gdy nie uda się jej odczytać zwracane jest 0. 7.6 Funkcja displayImage Funkcja ta odpowiada za wyświetlanie na LCD obrazka poprzez wywoływanie w pętli funkcji writeB z modułu set.s. Przyjmuje jako argument wskaźnik na ciąg bitów opisujący obrazek w formacie odpowiednim do wyświetlenia na LCD (pozyskany poprzez getImage). Pętla biegnie dopóbki nie zostanie wyświetlony cały obrazek. 8 Interfejs użytkownika W ramach części zadania przeznaczonej na sprawozdanie połówkowe został zaimplemen- towany interfejs umożliwiający wypisywanie znaków ASCII na LCD, który później został rozszerzony o opcje dotyczące grafiki i animacji. Program znajdujący się w pliku menu.s zawiera proste tekstowe menu, które udostępnia podstawowe metody kontroli wyświetlacza, takie jak inicjalizacja, czyszczenie, odwracanie kolorów, wysłanie tekstu, wyświetlenie 15 animacji oraz wyłączanie LCD. Działają one w oparciu o funkcje opisane w poprzednich rozdziałach. Wybranie opcji powoduje zwykle jedynie wywołanie odpowiedniej z tych funkcji, czasami podejmowane są dodatkowe działania np. wczytanie ciągu znaków. Menu wyświetla się ciągle w pętli, aż do momentu wybrania opcji zakończenia programu. Wybór opcji wysyłania tekstu powoduje wczytanie ciągu o długości maksimum 85 znaków, co stanowi 84 znaki drukowalne oraz znak końca linii, niewyświetlany. Wysyłanie dłuższego ciągu nie ma sensu ponieważ zacznie on nadpisywać początek ekranu zanim zdąży się zauważyć poprzedni tekst. Na początku program podejmuje próbę ustawienia dostępu do portu, jeśli się ona nie powiedzie, to dalsze działanie jest bezcelowe, a więc wyświetlany jest tylko komunikat o błędzie i następuje zakończenie programu. Menu zostało przedstawione na rys. 4 Wybierz opcje: 1 - Inicjalizacja LCD 2 - Dopisanie tekstu 3 - Negatyw 4 - Pozytyw 5 - Wylacz LCD 6 - Czyszczenie ekranu 7 - Wyswietlenie GIFa 8 - Koniec >> Rysunek 4: Menu programu 9 Podsumowanie i wnioski Realizacja tego projektu pozwoliła nam na poznanie języka asemblera od strony bardziej praktycznej, niż miało to miejsce wcześniej. Efekty naszej pracy były widoczne na żywo na 16 sprzęcie, a więc były bardziej namacalne, niż tylko obraz na monitorze komputera, w przypadku pisania ”zwykłych“ programów, co było niewątpliwie bardzo interesujące zwłaszcza jeśli chodzi o wyświetlanie animacji. Należy zwrócić uwagę na nienajlepszą dokumentację biblioteki giflib, co jednak rekomensowane jest otwartością kodu źródłowego. Okazało się to pomocne przy pisaniu funkcji wykorzystujących tę bibliotekę Samodzielne lutowanie elementów było również ciekawym doświadczeniem, pokazało nam, że skonstruowanie nawet prostego działającego układu nie jest zadaniem trywialnym i może być bardzo czasoi praco-chłonne. Przekonaliśmy się także, jakie znaczenie mają dodatkowe narzędzia, jak np. monitor portu LPT, bez którego zadanie było by praktycznie niewykonalne, zwłaszcza w zakresie funkcji operujących bezpośrednio na rejestrze portu równoległego, a także o znaczeniu aspektów nieistniejących przy zadaniach czysto programowych (jak np. konieczność odpowiedniego ułożenia elementów elektronicznych, tak aby nie było zwarć). Był to nasz pierwszy, tak duży projekt, zrealizowany w asemblerze. Było by go ciężko zrealizować bez sprawnej współpracy, którą ułatwiał system kontroli wersji i udostępniania kodu. Literatura [1] http://www.nxp.com/acrobat_download/datasheets/PCD8544_1.pdf, Specyfikacja kontrolera LCD Philips PCD8544 [2] http://www.mod-planet.com/index.php?module=subjects&func= viewpage&pageid=196, Jak podłączyć LCD z Nokii do PC [3] http://www.night-modders.com/index.php?module=subjects&func= viewpage&pageid=226, Podłączanie LCD Nokia 3310 [4] info ioperm, dokumentacja info funkcji systemowej ioperm [5] info nanosleep, dokumentacja info funkcji systemowej nanosleep [6] http://lptman.sourceforge.net/, Strona domowa LPT Manager 17 [7] http://serdisplib.sourceforge.net/, Strona domowa serdisplib [8] http://subversion.tigris.org/, Strona domowa systemu kontroli wersji SVN [9] http://www.microchip.su/showthread.php?t=3245, źródło tablicy znaków [10] http://download.savannah.gnu.org/releases/pgubook/ ProgrammingGroundUp-1-0-booksize.pdf, Jonathan Bartlett, Programming from the Ground Up [11] www.w3.org/Graphics/GIF/spec-gif89a.txt, Cover Sheet for the GIF89a Specification [12] http://en.wikipedia.org/wiki/Graphics_Interchange_Format, Graphics Interchange Format - Wikipedia, the free encyclopedia [13] http://sourceforge.net/projects/giflib/, Introduction to GIFLIB – A library for processing GIFs 18