Nazwa wskaźnika. Jest to nazwo tworzonej zmiennej. Nic ma nic wspólEego z nazwą funkcji
ABC... C
wskaźnik na funkcję
Mimo tego, że już kolejny raz posłużymy się wskaźnikami, nie przedstawiam jeszcze pełnego opisu zagadnienia. Omówienie wskaźników nie jest jednak konieczne przy sposobie, w jaki z nich korzystamy. Teraz chcę jedynie, żebyś oswoił się z samą ideą zmiennej, która po prostu przechowuje adres, pod którym w pamięci znajduje się inna zmienna lub, co ciekawa, także funkcja. Wskaźnik na funkcję od strony czysto maszynowej jest 16-bitową liczbą przechowującą adres, pod jakim znajduje się dana procedura. Tworząc taki wskaźnik, musimy poinformować kompilator, jakie parametry musi poumieszczać w rejestrach przed wykonaniem skoku w odpowiednie miejsce.
Zmienna typu wskaźnikowego jest deklarowana przez dodanie znaku gwiazdki między jej nazwą a typem. Na przykład: int* wskaznik_na_ir.t;
Wskaźnik na funkcję tworzymy według następującego przepisu:
Przypisanie takiemu wskaźnikowi odpowiedniej wartości jest dziecinnie proste. W tym celu posługujemy się nazwą wybranej funkcji. Na przykład:
VOid(*proc)Cuintl6_t); proc = WyswietlDECJ Funkcja musi mieć identyczny zestaw parametrów oraz identyczny typ zwracanej wartoś-Inaczej kompilator zgłosi błąd.
Jeśli już przypisaliśmy takiemu wskaźnikowi odpowiednią wartość, wywołanie wskazywanej przez niego funkcji jest intuicyjne i proste: void(*proe)(uintl6_t); proc = WyswietlDEC; proc(lOO);
Uważaj. Przy tworzeniu wskaźnika na funkcję wszystkie te „nadużyte” nawiasy są konieczne. C był już za to krytykowany. Zabawność sytuacji polega na tym, że: int *funkcja(void) to funkcja zwracająca wskaźnik do int, z kolei: int (*funkcja)(void) to wskaźnik na funkcję zwracającą int.
Listing 18
Funkcje odpowiedzi na naciśnięcie przycisku.
void piusfyoid)
{
++g Licznik;
WyswietlDEC(g_Licznik);
>
void Minus (void)
{
—g_LicznikJ WyswietlDEC(g_Licznik)J
}
Listing 19
Modyjikacju pętli głównej.
WyswietlDEC(g_Licznik); for(;;)
{
ObslozFrzycisk(l«SWl, Plus) ; 0bslozPrzycisk(l<<SW2, Minus);
}
' JStAwm
^ ^ ELECTRONICS v
SPUZKDM CZĘŚCI ELEKTRONICZNYCH
01- 985 Warszawa, ul. Dzieramiowska 9A
02- 585 Warszawa, Al. Niepodległości 84
jak to ma miejsce w wygodnej procedurze DEBOUNCE, umożliwić przesłanie informacji, jaką funkcję należy wywołać przy naciśnięciu klawisza, konieczne będzie poznanie informacji na temat wskaźników na funkcje. Odpowiednie informacje znajdziesz w ostatniej ramce ABC... C. W aktualnym kodzie możesz całkowicie usunąć zawartość pętli głównej programu - przybierze zupełnie inną postać. Na listingu 17 przedstawiam funkcję, która zajmie się obsługą naciśnięcia i przytrzymania przycisku. Zauważ, że jest ona ograniczona o tyle, że wszystkie przyciski muszą znajdować się na jednym wybranym porcie - tak jest u nas w istocie. Umożliwia za to wybranie dowolnego wyprowadzenia danego portu. Podana jako parametr funkcja będzie wywoływana raz, gdy przycisk zostanie naciśnięty, a następnie za każdym razem gdy „będzie powtarzany” przy przytrzymaniu.
Zauważ, że we wnętrzu wykorzystałem pętlę do-while, zamiast while. W tym przypadku, od teoretycznej strony, nie ma to znaczenia, jednak okazuje się, że przy takiej składni program zajął nieco mniej miejsca w pamięci.
Zajmijmy się teraz napisaniem funkcji odpowiedzialnych za odpowiedź na naciśnięcie klawisza pierwszego i drugiego. Pokazuje je listing 18 i myślę, że ich działanie nie wymaga komentarza. Pamiętaj jedynie, aby umieścić ich definicje powyżej miejsca wykorzystania — inaczej konieczna będzie ich deklaracja. W tym przypadku umieszczamy je powyżej funkcji main. Nie ma znaczenia, że naprawdę wywoływać je będziemy z poziomu funkcji ObslozPrzycisk. Funkcja ta odwołuje się do swojego zdefiniowanego wskaźnika funkcji, zupełnie nie interesując się tym, do czego on się z kolei odwołuje.
Mamy już wszystkie potrzebne elementy. Możemy połączyć je w całość, co oczywiście odbędzie się w pętli głównej. Zmianę pokazuje listing 19. Zauważ, że przy takiej konstrukcji funkcja WyswietlDEC jest wywoływana tylko wtedy, gdy jest to konieczne, nic tak jak poprzednio, gdzie jej wywołania były nadmiarowe. Ponadto, po kompilacji przekonasz się, żc program zajmuje mniej miejsca w pamięci programu. Udało się to dzięki temu, że usunęliśmy, wspomniany wcześniej, powtarzający się fragment kodu.
Dziś zapoznaliśmy się z pętlami, zmiennymi lokalnymi, zaczęliśmy obsługiwać klawiaturę, co wiązało się z odczytem danych z portów mikrokontrolera. Poznałeś także sposób wykorzystania wskaźników na funkcje, co z reguły jest uznawane za zagadnienie dla zaawansowanych - świat mikrokontrolerów jednak rządzi się innymi zasadami niż świat dużych maszyn typu PC i tutaj będziemy korzystać z tej przydatnej możliwości dość często, czasem nawet w prostych programach.
Zgodnie z obietnicą zamykamy już wyświetlacz multipleksowany. W następnej części zajmiemy się prostą obsługą wyświetlacza alfanumerycznego LCD. Poznamy makra oraz, koniecznie, zajmiemy się obsługą łańcuchów znakowych — czyli napisów. Będzie to ostatnia część kursu prowadzona z wykorzystaniem BASCOM-owej płytki testowej. W przygotowaniu jest już sterownik który da nam znacznie większe możliwości.
Radosław Koppel
02-620 Warszawa, ul. Puławska 132 KUf:.x: 0...22 84S 44 95. tel.: 0...22 844 44 43 40-032 Katowice, ul. Dąbrowskiego 1 tel.: 0...32 251 24 25. BL/fas; 0...32 251 58 44
Sprzedaż wysyłkowa. PEŁNA OFERTA W INTERNECIE
4G Wrzesień2005 Elektronika dla Wszystkich