Może i Tobie, tak jak i ranie znudziło się przetwarzanie programu lak, aby na wyświetlaczu wciąż widzieć to samo. Niezależnie od tego jakie wymyślne znaki zostaną wypisane -wciąż będzie to nieruchomy obraz. Może nadszedł więc czas, by coś w tym miejscu zmienić?
Rys. 23 Porównanie zużycia pamięci
Skoro praktycznie nie musimy już zajmować się ciągłym odświeżaniem wyświetlacza - dzięki przerwaniom będzie działo się to niejako całkowicie niezależnie - możemy wykorzystać pętlę główną do tworzenia animacji. Najprościej będzie wyświetlać kolejne liczby. Okazuje się także, że bardzo łatwo tworzy się funkcję wyświetlającą liczby w kodzie hcksadecymalnym.
Myślę, że po poznaniu wszystkich informacji, jakie do tej pory przedstawiłem, jesteś już w stanie mniej więcej wyobrazić sobie, jak będą wyglądały poszczególne działania. Cały program można by napisać w funkcji maili. Takie przyzwyczajenia niektórzy mogli wynieść z BASCOM-a - lam opis działania najczęściej zawierało się w' jednym ciągu. Twór taki jak funkcja był nieco sztuczny.
Jeśli podzielasz takie właśnie myślenie, chciałbym, abyś zaczął przyzwyczajać się do czegoś zupełnie innego. Troszkę innej jakości. W C wykorzystanie funkcji staje się całkowicie naturalne. Program praktycznie zawsze powinien składać się z zespołu funkcji wywoływanych z poziomu programu głównego. Nawet bardziej rozbudowana obsługa przerwania może korzystać z innych funkcji. Mam nadzieję, że przekonasz się, że takie myślenie jest bardzo wygodne. Dzięki temu, że skomplikowane działanie można rozbić na więcej prostych program pisze się łatwiej i bardziej intuicyjnie. Ważne jest także to, że raz utworzoną funkcję można wykorzystać w wielu miejscach - co zmniejsza objętość kodu. Wyprzedzając trochę dzisiejszy zakres materiału, wspomną tylko o bardzo wygodnej właściwości funkcji, którą jest, całkowicie naturalna, możliwość tworzenia zmiennych lokalnych praktycznie nieistniejących poza funkcją. Zobaczysz już niedługo, jak wygodny jest brak konieczności zastanawiania się, czy gdzieś indziej nie wykorzystuję tej właśnie zmiennej.
Jednak kończąc zachwalać to, co dopiero
przedstawię w przyszłości, przechodzę do rzeczy. Dziś przedstawiam całkowite podstawy, umożliwiające stworzenie programu dokładnie takiego, jak chcieliśmy: liczącego i wyświetlającego kolejne liczby w kodzie heksadecymalnym. Jak zwykle proponuję zapoznanie się z ramką zawierającą odpowiednie informacje. Tym razem jest to ramka z informacjami o podstawach tworzenia oraz korzystania z funkcji.
Pamiętasz może moje pytanie na końcu poprzedniej części? Jeśli podjąłeś wtedy wyzwanie i stworzyłeś tablicę zawierającą wygląd wszystkich cyfr kodu szesnastkowego, masz teraz okazję porównać swoje dzieło z moją propozycją. Ze względu na objętość pełnego kodu źródłowego oraz na to, że wiele elementów wciąż się nie zmienia, nic przedstawiam go w całości. Myślę, że jeśli opiszę krok po kroku wprowadzane zmiany - nic będziesz miał problemów z przerobieniem poprzedniego programu, a dodatkowo łatwiej przyjdzie zrozumienie nowego kodu.
Na początek zajmiemy się stworzeniem tablicy zawierającej wygląd poszczególnych znaków na wyświetlaczu. Ja umieściłem ją
nerająea definicję wyglądu poszczególnych znaków SzórCyfr[if] =
I «LŁD_E !«LED_C «t,r:n :
1«LED_C i«LED_E :«LED t!
i «LED_F | : «LED_G) , . 1«LED_F) , / / C •«:.SD_E | 1 «T,FC o) , , «LED_? | l«LED_G) , '
ABC... C
Wykorzystanie pamięci programu w AVR-GCC
Oddzielna przestrzeń adresowa dla danych i programu to kolejny element, który nie jest zgodny z ANSIC. Trzeba liczyć się z tym, że w innym kompilatorze problem ten może być rozwiązany zupel-
Nąjwygodniejszym sposobem posługiwania się pamięcią programu jest wykorzystanie nagłówka <avr\pgmspace.h>. Definiuje on wszystko, czego potrzeba do umieszczenia „zmiennych” w obszarze programu oraz do dostępu do nich.
Pamiętaj - jeśli chcesz wykorzystać w praktyce informacje z tej ramki — koniecznie dołącz wspomniany plik do swojego programu za pomocą dyrektywy Hinclude.
Jak tworzyć „zmienne”:
Wspomniany wyżej nagłówek daje dwie możliwości poinformowania kompilatora o naszym życzeniu specjalnego potraktowania zdeklarowanej właśnie zmiennej. Jednym z nich jest wykorzystanie słowa kluczowego PROGMEM. W takim przypadku deklaracja naszej tablicy wyglądałaby następująco:
uint8 t q DaneCom[4] PROGMEM =
{- (1«C0M1) (...)};
Słowo kluczowe PROGMEM umieszcza się za deklaracją „zmiennej”, ale przed jej inicjacją.
Drugą możliwością jest wykorzystanie jednego ze specjalnych typów zmiennych, jakie deklaruje dołączenie pliku pgmspace.h. Pojawiają się tutaj wszystkie typy zdeklarowane w pliku inttypes.h (przypominam, zmienne w formie [u)intN_t -część 2 kursu), jednak poprzedzone dodatkowo przedrostkiem prog_. Jak zwykle wszystko najlepiej tłumaczy przykład:
prog_uinCS_t. g_DaneCom[H] =
{~(1«com1) (...));
To, który sposób wyda Ci się wygodniejszy i bardziej czytelny, zależy tylko i wyłącznie od Twojego gustu. Ja praktycznie wykorzystuję obie możliwości naprzemiennie.
Niezmienne zmienne?
Zauważ pewną bardzo ważną rzecz: jeśli tworzymy twór laki jak „zmienna” w pamięci programu -nic mamy możliwości zapisania do niej danych, możemy z niej tylko czytać. Nie ma znaczenia to, że niektóre z procesorów pozwalają na pisanie do pamięci programu - to jest zupełnie inna historia. Z punktu widzenia kompilatora zmienna w pamięci programu zawsze jest TYLKO DO ODCZYTU. Aby z tworu takiego mieć jakikolwiek użytek, konieczne jest początkowe przypisanie mu war-(ciąg dalszy w następnej ramce...)
Lipiec2005 Elektronika dla Wszystkich