38347 Image96 (4)

38347 Image96 (4)



Programowanie ■

Programowanie ■

Listing J OJ modyf ikacjo funkcji h» led GetSpec

Sta tlić uintSj IcdGetSpcc(uint8_t s_indcx)

{

// Zabezpieczenie 1f (lar.gsys GctSpccO *=» NULL) return 0x20;

(...)

// Nic nie znaleziono

return pgm ivad_byie(&(langsys_GetSpeeO[s_index] .cAlt)) ;


Listing 102 modyfikacja funkcji >v IcdUpdatcCGkAM


void led UpdatcC GRAM(voi d)

// Zabezpieczenie i f (langsys GetSpec O =* NULL) return;

(...)

■for(a—0; a<LLEMS(lcd_5pcc) J a-t-f)

{

// 0xff oznacza koniec danych if(led_spcc[a] — Oxff) break;

U wskaźnik na początek danych wyglądu znaku uint8_t* pdata = langsys GetSpec() [led spec [a] J .ntatrix; (...)


Ta funkcja zwraca wskaźnik na tabłoę struktur.

Traktujomy Ją jako zmienną Z powodu togo zap«u, między Innymi, możemy powtedźtoć, ża funkcja Jasi typu LCD_LOCAL_PGhT


jest więcej niż języków. Problemem automatycznej inicjacji rozmiaru tablicy jeszcze się zajmiemy.

Zgodnie z ramką o idei naszego programu, utworzymy teraz funkcje manipulujące językiem. Spójrz na listing 98. Zwróć szczególną uwagę na sposób odczytu danych z naszej tablicy w funkcji langsysGetLangMame. Dostęp wygląda dość skomplikowanie niestety nie możemy czytać bezpośrednio danych z tablicy umieszczonej w pamięci programu. Makro pgm_read_won!_near odczytuje szesnastobi-tową liczbę z pamięci programu. Ponieważ my wiemy, że w tym miejscu znajduje się wskaźnik i wskaźnika oczekujemy, musimy wykonać rzutowanie, aby odczytana wartość mogła być prawidłowo wykorzystana. Korzystając z makra pgmread word near zakładamy jednocześnie, że nasze wskaźniki me mają więcej niż 16 bitów - zwykle będzie to prawdą. Należałoby jedynie zweryfikować poprawność tego założenia w przypadku wykorzystania procesora o pamięci programu większej niż 64KB przy wykorzystaniu bardzo dużej ilości stałych.

Ostatnie dwie funkcje modułu langsys pokazuje listing 99. Zwracają one wskaźnik na znaki specjalne (jeśli w danym języku znaki specjalne nic występują, zwracana jest wartość NULL) oraz tekst o podanym identyfikatorze.

W tym miejscu plik źródłowy mamy zakończony. Pozostaje nam jeszcze stworzenie pliku nagłówkowego widocznego na listingu 100. Umieszczamy w nim deklaracje funkcji oraz symboliczne oznaczenia identy-

Listing 100 plik langsys .h

0ifndef LANGSYS_H_INCLUDED frdefine langsys_h_INCLJDED

U-

// Funkcje interfejsu iniine uintfcj langsys_GetNumOfLangs(void); inlir.e void langsys_Select(uint8_t index); iniine uint$_t langsys GetSelected(void); prog ehur* langsys GclUmgName(uint8_t index); LCDJjOCAL PGM * langsys GctSpcc (voi d) ; próg char* langsys GetText(uim8 i indcx);

//__

// Indeksy dla poszczególnych nap'sów enun {

IDS..LANGNAME,

IDS Start

#endif //langsys_h_includcD

ABC... C

Funkcja traktowana jak zmienna

Rozmawialiśmy już o tym, jak wygcdr.ą własnością C est możliwość wykonywania złożonych obliczeń w jednej linii. Do wygody tej przyczynia się także możliwość traktowania jako zmiennej każdej funkcji, która zwraca jakąś wartość. Co zrozumiałe, będzie to zmienna tylko do odczytu. Kompilator zawsze zadba o to, aby potrzebne funkcje zostały wywołane we właściwym momencie, a zwracana prze/, nie wartość wzięta do obliczeń.

O ile sprawa wydaje się oczywista w przypadku prostych operacji arytmetycznych, zauważ, że daje to znacznie szersze możliwości. Znakomitym przykładem są listingi 101 oraz 102. W tym miejscu funkcja langsysjGdSpec zwraca wskaźnik, który natychmiast jest obsługiwany jako tablica. Można by skorzystać ze zmiennej pomocniczej, do której zostałaby zapisana wartość zwracana przez funkcje, a następnie dostawalibyśmy się do tablicy, tak jak robiliśmy to do tej pory, jednak nic nut potrzeby rozbijania przedstawionego działania.

fikatorów. Identyfikatory moglibyśmy tworzyć za pomocą poznanych do tej pory dyrektyw ttdefine. Jednak dla większej ilości napisów działanie takie jest dość uciążliwe i łatwo o pomyłkę. Zamiast tego wykorzystamy dziś typ wyliczeniowy (ramka). Dzięki temu, jeśli tylko zachowamy kolejność identyfikatorów' zgodną z kolejnością zapisania wskaźników w tablicy, identyfikatory zostaną prawidłowo wygenerowane automatycznie. Przy identyfikatorach napisów przyjmijmy zasadę, aby zaczynać je zawsze dużymi literami IDS_ a reszta nazwy zgodna była z nazwą zmiennej łańcuchowej bez liter F.Nv'PL_str. Ułatw'i to orientację w kodzie oraz tworzenie wyliczenia - wystarczy skopiować dane inicjujące jeden język w tablicy langsysstr Table i dokonać zmian komendą Edi(-> Repluce. Wyjątkiem od tej reguły są identyfikatory o specjalnym znaczeniu, pisane w całości dużymi literami (aktualnie jedynie JDS LANGNAMF).

I ważaj: Standard nie definiuje w takim przypadku, w jakiej kolejności funkcje zostaną wywołane. Może okazać się nawet, że pewne funkcje r ie zesłana w ogóle wywołane, jeśli kompilator stwierdzi, że ich wartość nie ma znaczenia dla wyniku obliczeń. Mogą one być wywoływane zgodnie z kolejnością, w jakiej wykonywane są działania, ale mogą także być wywołane przed rozpoczęciem jakichkolwiek obliczeń. Jeśli zależy Ci na kolejności wywołania funkcji, nie obejdzie się bez zmiennych pomocniczych konieczne jest wtedy „ręczne” wywołanie funkcji oraz zapisanie ich wyników.

langoya_G«tSpecO [o_ir.dcx3. cAlt

Normalny dcetęp do toWcy

Dostęp oo składowej struktury

Przykłady listingi 101 oraz i02

Dostosowanie modułu led

Moduł ledy z którego chcemy serzystać, zakładał występowanie w programie modułu local i korzystał z umieszczonej w nim informacji o znakach specjalnych. W stosunk i do tej sytuacji pojawiają się aktuulnie trzy różnice:

1.    Nie ma modułu iocal.

2.    Nie ma możliwości bezpośredniego dostępu do tablicy z danymi lokalnymi należ} korzystać z funkcji langsys GetSpcc.

3.    Istnieje możliwość, że tablica danych lokalnych dla danego języka nie istnieje - należy zabezpieczyć się przed próbą czytania spod adresu NULL.

Otwórz poprzednio napisany plik Icd.c i korzystając z komendy Edil->Find, znajdz wszystkie wystąpienia słowa local . Zauważysz, że zc wspomnianego modułu korzystamy jedynie w dwóch miejscach. Nie będziemy więc mieli dużo pracy.

W pierwszej kolejności dołączenie #include „local.h ” zmieniamy na tfinelude „ langsys. h ’. Resztę koniecznych zmian możesz zobaczyć na listingach 101 oraz 102. Dodane lub zmodyfikowane fragmenty oznaczam kolorem

Test

Wszystkie moduły są już gotowe, pora na ich połączenie oraz napisanie funkcji głównej programu. Utwórz plik main.c. Jeśli korzystasz z makefde z poprzedniej części, powinien on być już tam dodany. Propozycję prostego testu przedstawia listing 103. Funkcja obsługi przycisków została

Elektronika dla Wszystkich Czerwiec 2006 45


Wyszukiwarka

Podobne podstrony:
Poznaj C++ w$ godziny0125 Zaawansowane sterowanie programem Listing 8.6. Pomijanie pętli while 1:
cz2 Programowanie Listing 7 Poprawa programu (...) COMPORT = LEDPORT = (l«COMl) ; (1«LED_B
cz5 3 Programowanie Listing 22 LCD: komendy sterujące U Komendy sterujące wyświetlaczem #define
cz5 6 Programowanie Programowanie listing 29 Pisanie na LCD. LCDstr("W-jtaj!");
cz7 Programowanie Listing 57— wykorzystanie funkcji printf int main(void) l ■int a - 1234; int b
cz8 Programowanie I Listing 68 ■ fcheat_iPodsumowanie rozwiązania Możesz uznać teraz, że C jest str
79181 Image95 (3) ■ Programowanie Tabela 11 Znaczenie sekcji .initO-9 Sekcja Znaczenia .initO Jeś
42173 Image97 (3) ProgramowanieABC... GCC Pisanie funkcji w pełnym asemblerze WinAV R umożliwia

więcej podobnych podstron