Wielopoziomowe menu w C.pdf

(114 KB) Pobierz
Wielopoziomowe menu w C
K U  R S
Wielopoziomowe menu w C
Opisane w†artykule funkcje wykona-
³em jako demonstracjÍ sposobu imple-
mentacji menu. Nie s¹ one zwi¹zane
z†øadnym konkretnym urz¹dzeniem. Do
ich uruchomienia uøy³em p³ytki ekspe-
rymentalnej w³asnej konstrukcji, zbliøo-
nej funkcjonalnie do AVR Starter Kit
i†zawieraj¹cej mikrokontroler AT89S8252,
programator oraz z³¹cza doprowadzaj¹ce
sygna³ do wyprowadzeÒ mikrokontrole-
ra. Do p³ytki pod³¹czy³em wyúwietlacz
LCD (pracuje z†interfejsem 4-bitowym)
oraz klawiaturÍ wykonan¹ jako matrycÍ
3†wierszy i†4†kolumn (w sumie 12 kla-
wiszy). Port P2, do ktÛrego pod³¹czy-
³em klawiaturÍ, dodatkowo wyposaøy³em
w†rezystory pull-up o†wartoúci 47 k
Jednym z†najwiÍkszych ìpoøeraczyî czasu i†energii
programisty, obok uruchomienia programu, jest tak zwany
interfejs uøytkownika. Mikrokontroler nie potrzebuje do pracy
wyúwietlacza, klawiatury, diod úwiec¹cych LED i†temu
podobnych elementÛw, o†ile nie jest to úciúle zwi¹zane
z†operacjami zapisu lub odczytu danych. Wszystkie te
drobiazgi s¹ potrzebne nam, ludziom, abyúmy mogli
wprowadzaÊ parametry i†poznaÊ rezultat wykonania przez
mikrokontroler okreúlonego programu.
W†artykule przedstawiÍ sposoby tworzenia jedno-
i†dwupoziomowych menu, wyúwietlanych na typowym
wyúwietlaczu LCD 4†linie po 20 znakÛw.
numer 0†argumentu (argument wywo³a-
nia np. 0xFE), drugiej bitu numer
1†itd. W†pliku nag³Ûwkowym KBD3X4.H
za pomoc¹ dyrektywy #define zdefinio-
wano w³aúciwe wartoúci argumentu wy-
wo³ania funkcji KBD _ Read ( Co-
lumn_1...3 ), ktÛre pÛüniej uøywane s¹
przez funkcjÍ Key _ Number .
SposÛb funkcjonowania KBD_Read
jest nastÍpuj¹cy: argument column jest
zapisywany do portu klawiatury i†tym
samym linia ktÛrejú z†kolumn przyjmu-
je stan niski. Na skutek przyciúniÍcia
(zwarcia) klawisza linia wiersza - bÍ-
d¹ca normalnie w†stanie wysokim -
przejdzie w†wymuszony stan niski. Stan
ten jest dwukrotnie odczytywany przez
mikrokontroler: za drugim razem po 50
milisekundach. Zrobi³em tak, aby
upewniÊ siÍ, øe klawisz zosta³ naciú-
niÍty celowo i†by³o to zamiarem uøyt-
kownika. Jest to rÛwnieø bardzo prosty
filtr zak³ÛceÒ mog¹cych pojawiÊ siÍ na
doprowadzeniu portu.
Aby zapobiec wp³ywowi na wynik
dzia³ania funkcji bitÛw innych niø przy-
porz¹dkowane wierszom klawiatury, s¹
one maskowane (ustawiane w†stan nis-
ki) poleceniem curr &= Row_mask (ilo-
czyn bitowy). WartoúÊ maski rÛwnieø
zdefiniowana zosta³a w†pliku nag³Ûwko-
wym. Bit aktywny przyjmuje stan niski.
W†zwi¹zku z†tym, øe ³atwiej jest porÛw-
nywaÊ bity znajduj¹ce siÍ w†stanie wy-
sokim, wartoúÊ zwracanej zmiennej jest
negowana (polecenie return(~curr) , ì~î
to operator dope³nienia jedynkowego).
Funkcja Key_Number przyporz¹dko-
wuje kombinacjom bitÛw odczytanych
z†portu mikrokontrolera okreúlone kody.
Konstrukcja programu zbliøona jest do
budowy klawiatury. Warunki if tworz¹
rodzaj matrycy, na ktÛrej przeciÍciach
znajduj¹ siÍ kody klawiszy. Wartoúci
Row_1...4 rÛwnieø predefiniowane s¹
w†pliku nag³Ûwkowym. Jedynka na po-
zycji bitu wiersza odpowiada wciúniÍ-
ciu klawisza. W†przypadku, gdy øaden
z†klawiszy nie jest naciúniÍty, funkcja
zwraca wartoúÊ 0.
Odczyt klawiatury
Funkcje odczytuj¹ce klawiaturÍ za-
deklarowa³em jako zewnÍtrzne funkcje
biblioteczne i†umieúci³em w†module
o†nazwie KBD3X4. Pierwsza z†nich char
KBD_Read(char column) s³uøy†do obs³u-
gi klawiatury na poziomie sprzÍtu, ope-
ruj¹c na portach mikrokontrolera. Dru-
ga - char Key_Number(void) - przydzie-
la klawiszom odpowiednie kody.
Funkcja KBD_Read w†wyniku dzia-
³ania zwraca unikatow¹ dla kaødego
z†wciúniÍtych klawiszy, odpowiadaj¹c¹
mu wartoúÊ lub 0†- jeúli øaden z†kla-
wiszy nie jest wciúniÍty. Nie pracuje
ona poprawnie, jeúli wciúniÍto wiÍcej
niø jeden klawisz. Zawsze zwracana
jest jako pierwsza kombinacja klawiszy
z†kolumny bÍd¹cej pierwsz¹ odczytan¹.
Jako argument wywo³ania spodziewane
jest wyzerowanie bitu odpowiadaj¹cego
odczytywanej kolumnie. W†zwi¹zku
z†tym, øe kolumna pierwsza klawiatury
pod³¹czona jest do P2.0, druga do P2.1
a†trzecia do P2.2, odczytowi pierwszej
kolumny odpowiada wyzerowanie bitu
Menu jednopoziomowe
Najprostszym rodzajem menu jest me-
nu jednopoziomowe. Charakteryzuje siÍ
ono tym, øe po wybraniu opcji nastÍpu-
je bezpoúrednie wywo³anie akcji. Menu
takie jest ³atwe do wykonania, jeúli
w†ca³oúci mieúci siÍ na ekranie LCD.
Znacznie gorzej jest, gdy ma ono na
przyk³ad 8†pozycji, a†na ekranie mamy
do dyspozycji 2†czy 4†linie. WÛwczas
musimy nie tylko okreúliÊ nazwy po-
szczegÛlnych opcji, ale rÛwnieø sposÛb
wyúwietlania menu po przekroczeniu roz-
miaru ekranu. Wyliczenie tych wszyst-
kich zmiennych zajmuje duøo pamiÍci
programu oraz czasu mikrokontrolera.
Pocz¹tek programu (czÍúÊ deklara-
cyjna zmiennych) zawiera definicjÍ ty-
pu o†nazwie menuitem . Jest to struktu-
ra pojedynczego rekordu opisuj¹cego li-
niÍ menu. Rekordy te s¹ nastÍpnie
zgrupowane w†tabeli menus , tam teø
nadawana jest im wartoúÊ. Kilku s³Ûw
omÛwienia wymaga rola poszczegÛlnych
pÛl rekordu.
Tab. 1. Przypisanie funkcji wyprowadzeniom mikrokontrolera
Nazwa portu
Oznaczenie Funkcja
Funkcja
!"#!$%
!"#&'$%
!"&(')%&$%
)
)*+$%
)
) *+$%
)
),*+$%
,
),
)-*+$%
Elektronika Praktyczna 9/2003
77
.
Uøy³em ich ze wzglÍdu na d³ugie kable
³¹cz¹ce klawiaturÍ z†portem mikrokont-
rolera. W† tab. 1 i†na rys. 1 zawarto
opis po³¹czeÒ elektrycznych.
Nazwa portu
Nazwa portu Oznaczenie
Oznaczenie
39646619.008.png
K U  R S
Rys. 1. Schemat klawiatury matrycowej 3 (kolumny) x 4 (wiersze) wykorzystywanej
w modelu
menu pos³ugujÍ siÍ zmienn¹ globaln¹
o†nazwie actpos . Jest to zmienna typu
signed char (z zakresu od -128...127).
Jej wartoúÊ ulega zmianie po naciúniÍ-
ciu klawiszy umownie przyjÍtych jako
kierunek dÛ³ (8) lub gÛra (2). Dodatko-
wo wartoúÊ tej zmiennej porÛwnywana
jest z†liczbami okreúlaj¹cymi jej maksi-
mum i†minimum. W†przypadku przekro-
czenia maksimum, zmiennej actpos na-
dawana jest wartoúÊ minimum i†vice
versa: gdy jej wartoúÊ jest mniejsza niø
wartoúÊ minimalna, zmiennej nadawana
jest wartoúÊ maksimum. Tu jedna uwa-
ga: wartoúÊ maksymaln¹ stanowi liczba
elementÛw tablicy menus . Jej elementy
numerowane s¹ od 0. W†zwi¹zku z†tym
numer ostatniego elementy tablicy to
rozmiar-1 , a†pierwszego to 0. Na sku-
tek tak przyjÍtej konwencji rÛwnieø
i†zmiennej actpos naleøy w†przypadku
dolnej granicy zakresu nadaÊ wartoúÊ
maksymalnej liczby opcji pomniejszon¹
o†1. Odpowiada za to polecenie if (--
actpos < 0) actpos=maxoptions-1. Po-
dobnie jest w†przypadku gÛrnej grani-
cy. Wskaünik adresuje obszar leø¹cy
poza tablic¹ juø wÛwczas, gdy przyj-
muje wartoúÊ jej rozmiaru. Z†mojej
praktyki wynika, øe mimo faktycznie
zachodz¹cej rÛwnoúci, w†takiej sytuacji
bezpieczniej jest uøyÊ znaku ìwiÍksze
lub rÛwneî. W†zwi¹zku z†tym linia
programu przyjmuje postaÊ if (++actpos
>= maxoptions) actpos=0.
Program g³Ûwny wykonuje czynnoú-
ci zwi¹zane z†obs³ug¹ wyúwietlacza
(inicjalizacja trybu 4-bitowego oraz de-
finicja znakÛw uøytkownika), a†nastÍp-
nie wywo³uje funkcjÍ obs³ugi menu.
Zwracana przez tÍ funkcjÍ wartoúÊ roz-
patrywana jest nastÍpnie przez wyraøe-
nie switch - case . Oczywiúcie moøna
uøyÊ instrukcji if lub chociaøby zbudo-
waÊ tablicÍ z†wykazem wywo³ywanych
funkcji, a†zwrÛcon¹ w†wyniku dzia³ania
wartoúÊ potraktowaÊ jako offset lub
wskaünik do tejøe tablicy.
Pole o†nazwie name to ³aÒcuch
znakÛw wyúwietlany na ekranie i†sta-
nowi¹cy nazwÍ (etykietÍ) danej pozy-
cji menu. Jest on widziany przez uøyt-
kownika dokonuj¹cego wyboru opcji.
Pole ptr to offset dodawany do adre-
su pocz¹tku tablicy - wykazu menu.
Jego rola polega na wskazaniu miejs-
ca, od ktÛrego maj¹ byÊ wyúwietlane
etykiety menu. I†tak dla przyk³adu
ptr=4 spowoduje, øe w†linii numer
1†wyúwietlacza LCD znajdzie siÍ ety-
kieta menu spod adresu menus+4 . Ko-
lejne pole - y0 - to numer linii,
w†ktÛrej ma siÍ znajdowaÊ znak wy-
boru w†momencie, gdy wskaünik aktu-
alnej pozycji w†tabeli-wykazie wskazu-
je na rekord zwi¹zany z†tym paramet-
rem. Kombinacja dwÛch ostatnich pa-
rametrÛw umoøliwia efektywne i†czy-
telne wyúwietlanie zawartoúci menu.
SpÛjrzmy dla przyk³adu na deklaracjÍ
menu pochodz¹c¹ z†prezentowanego
programu:
//deklaracja tablicy-wykazu
//opcji menu
code menuitem menus[maxoptions] =
{{“opcja 1 . ”, 0, 0},
{“opcja 2 . ”, 0, 1},
{“opcja 3 . ”, 0, 2},
{“opcja 4 . ”, 0, 3},
{“opcja 5 . ”, 1, 3},
{“opcja 6 . ”, 2, 3},
{“opcja 7 . ”, 3, 3},
{“opcja 8 . ”, 4, 3}}
spowoduje przesuniÍcie wskazaÒ na po-
zycjÍ 4†w†tablicy (pozycje numerowane
s¹ od 0), a†nie na literÍ ìcî w†napisie
ìopcja 1†.î, co odpowiada³oby dodaniu
do wartoúci wskaünika 3†bajtÛw. Tyle
s³owem przypomnienia o†arytmetyce
wskaünikÛw. WrÛÊmy do sposobu defi-
niowania menu.
Po uruchomieniu funkcji wyúwietla-
j¹cej, wskaünik do wykazu ustawiany
jest na jego pocz¹tek (pozycja 0). Na-
stÍpnie pobierane s¹ wartoúci
menus[0].y0 oraz menus[0].ptr . WartoúÊ
ptr dodawana jest do adresu pocz¹tku
tablicy (w tym przypadku ptr=0 ) i†od
wyliczonego w†ten sposÛb adresu wy-
úwietlane s¹ na ekranie LCD 4†etykiety
menu.
Parametr pobrany z†tablicy y0 to ar-
gument funkcji wyúwietlaj¹cej znaczni-
ki wyboru. W†tym przypadku, poniewaø
y0=0 , znaczniki bÍd¹ wyúwietlone na
wspÛ³rzÍdnych (0,0) oraz (19,0). Podob-
nie bÍdzie, gdy wskaünik pokaøe pozy-
cjÍ 2, 3†i†dalsze. Za kaødym razem
wartoúci y0 i† ptr okreúlaj¹ pozycjÍ zna-
ku wyboru oraz tÍ etykietÍ menu, ktÛ-
ra znajdzie siÍ w†pierwszej linii wy-
úwietlacza.
Do wyliczenia wartoúci wskaünika
do aktualnej pozycji w†tabeli-wykazie
Menu dwupoziomowe
Rozbudowuj¹c menu o†dodatkowy
poziom, zawsze naleøy liczyÊ siÍ
z†tym, øe zajmie ono duøo miejsca
List. 1. Sposób budowania definicji menu
code menuitem mainmenus [6] =
{{name = “opcja menu głównego 1”, |--> code submenu submenu1 [3] =
ptr = 0,
|
{{“podmenu 1.1”,0,0,11},
//deklaracja wskaźnika do pozycji
//w tablicy-wykazie menu
code menuitem *ptrmenus = &menus;
y0 = 0,
|
{“podmenu 1.2”,0,1,12},
nextmenu = &submenu1 , ----------------|
{0,0,0,0}}
retval = 0},
{name = “opcja menu głównego 2”,
--> code submenu submenu2 [7] = {
Wskaünik ptrmenus jest tego same-
go typu, co element tablicy - wykazu.
W†zwi¹zku z†tym operacje arytmetyczne
wykonywane na wskaüniku dodaj¹ (lub
odejmuj¹) do (od) jego wartoúci liczbÍ
bajtÛw identyczn¹ z†rozmiarem pojedyn-
czego elementu tablicy. Na przyk³ad
wykonanie poleceÒ:
ptrmenus = &menus
ptrmenus = ptrmenus+3 //równoważne
//polecenie to ptrmenus += 3
ptr = 0,
|
{{“podmenu 2.1”,0,0,21},
y0 = 1,
|
{“podmenu 2.2”,0,1,22},
nextmenu = &submenu2 , ----------------|
{“podmenu 2.3”,0,2,23},
retval = 0},
{“podmenu 2.4”,0,3,24},
{“podmenu 2.5”,1,3,25},
{“podmenu 2.6”,2,3,26},
{0,0,0,0}}
{name = “opcja menu głównego 3”,
ptr = 0,
y0 = 2,
nextmenu = 0,
retval = 3},
............
78
Elektronika Praktyczna 9/2003
39646619.009.png 39646619.010.png 39646619.011.png 39646619.001.png 39646619.002.png 39646619.003.png 39646619.004.png 39646619.005.png
K U  R S
w†pamiÍci mikrokontrolera. Sytuacja
wygl¹da zupe³nie inaczej, gdy tworzo-
na jest aplikacja dla komputera PC
niø†gdy dla mikrokontrolera. Ten pier-
wszy w†porÛwnaniu z†drugim posiada
niewyobraøalne wrÍcz zasoby do wyko-
rzystania, istne ìmorze pamiÍciî, przy
dodatkowo bardzo duøej szybkoúci dzia-
³ania. Pewnych nawykÛw†i†przyzwycza-
jeÒ (o ile takie s¹) nie da siÍ po pros-
tu w†tym momencie wykorzystaÊ, cho-
ciaø nowe, pojawiaj¹ce siÍ na rynku
mikrokontrolery imponuj¹ wrÍcz swoi-
mi zasobami sprzÍtowymi. Zostawmy
jednak rozwaøania i†wrÛÊmy do opisu
sposobu wykonania menu.
Przy jego budowie pos³uøy³em siÍ
rozwi¹zaniami z†pierwszego przyk³adu
programowania, jednak wyraünie zosta-
³y rozgraniczone menu g³Ûwne od me-
nu podrzÍdnego. Rozgraniczaj¹ je za-
rÛwno funkcje realizuj¹ce wyúwietlanie
etykiet i†wybÛr spomiÍdzy nich, jak
i†typy rekordÛw uøytych do deklaracji.
Rozpocznijmy analizÍ od menu g³Ûwne-
go. Dla potrzeb budowy tablicy-wykazu
opcji menu g³Ûwnego zadeklarowa³em
typ o†nazwie menuitem . Zawiera on
pola poznane juø wczeúniej ( name , ptr
i† y0 ) i†oprÛcz nich nowe, o†nazwach
nextmenu oraz retval.
Pole nextmenu to wskaünik do ob-
szaru wykazu opcji odpowiadaj¹cego
mu podmenu. W†przypadku, gdy na-
stÍpny poziom nie jest dostÍpny,
wskaünikowi nadawana jest wartoúÊ 0.
Z†tym polem úciúle zwi¹zana jest za-
wartoúÊ pola retval . Zawiera ono licz-
bÍ zwracan¹ przez funkcjÍ w†przypad-
ku wyboru opcji. Jak ³atwo siÍ domyú-
liÊ, wartoúÊ wpisana do retval nie ma
øadnego znaczenia w†przypadku, gdy
wywo³ywane jest podmenu. WÛwczas
to, funkcja obs³ugi menu zwrÛci war-
toúÊ zapisan¹ w†polu retval w³aúciw¹
dla danej opcji (etykiety) podmenu.
Wskaünik nextmenu jest typu sub-
menuitem . Ten typ zmiennych zosta³
utworzony dla potrzeb tablic-wyka-
zÛw†opcji menu drugiego poziomu. Jest
on prawie taki sam, jak uøywany do
potrzeb menu g³Ûwnego. ale oprÛcz pod-
stawowych pÛl (etykieta name , po³oøe-
nie znaku wyboru y0 , offset wskaünika
ptr oraz wartoúci zwracanej przez menu
retval ) nie zawiera øadnych wskaünikÛw
do nastÍpnych wykazÛw opcji.
£atwo jest rozbudowaÊ podmenu
o†nastÍpne poziomy. Wystarczy uøyÊ po-
dobnych mechanizmÛw jak dla budowy
poziomu 2. Jest w†tym jednak drobna
trudnoúÊ: naleøy w†jakiú sposÛb podaÊ
uøytkownikowi informacjÍ, z†ktÛrego me-
nu wybierana jest opcja, ot chociaøby
przez wyúwietlenie úcieøki - opisu miej-
sca, w†ktÛrym siÍ znajduje. Trudno jest
znaleüÊ to miejsce na ekranie LCD
o†niewielkich rozmiarach. W†praktyce
ograniczam wiÍc menu budowanych
przez siebie urz¹dzeÒ co najwyøej do
2...3 poziomÛw i†zazwyczaj nie ma po-
trzeby tworzenia dalszej hierarchii. Za-
miast tego warto jest przemyúleÊ uk³ad
menu i†jego opcje. WrÛÊmy do sposobu
tworzenia definicji menu g³Ûwnego. Na
list. 1 przedstawiono schemat budowy
definicji menu g³Ûwnego oraz odpowia-
daj¹cych mu opcji podmenu.
Tablica mainmenu zawiera wykaz
definicji etykiet i†parametrÛw menu
g³Ûwnego. Polu wskaünikowemu o†na-
zwie nextmenu nadawana jest wartoúÊ
adresu - wskazania do wykazu opcji
podmenu, jeúli takie istnieje. Kolorami
wyrÛøniono te przypisania. W†takim
przypadku pole retval ma wartoúÊ 0.
Gdy podmenu nie istnieje (moøe to byÊ
na przyk³ad opcja ìUruchomî, ìObliczî
itp.), polu retval nadawana jest war-
toúÊ, ktÛr¹ ma zwrÛciÊ funkcja, a†polu
nextmenu naleøy†przypisaÊ wartoúÊ 0.
Wymagane jest, aby kaøda tablica-
wykaz etykiet podmenu by³a zakoÒczo-
ny rekordem, w†ktÛrym co najmniej po-
le name ma wartoúÊ 0. Rekord ten jest
niezbÍdny, poniewaø na podstawie jego
po³oøenia obliczana jest przez funkcjÍ
wyúwietlaj¹c¹ podmenu d³ugoúÊ wyka-
zu opcji, a†tym samym liczba etykiet
do wyúwietlenia.
Menu g³Ûwne wyúwietlane jest
w†identyczny sposÛb jak to by³o robio-
ne w†przypadku menu jednopoziomowe-
go. Jego obs³ug¹ zajmuje siÍ funkcja
Main_Menu i†jej funkcje us³ugowe . Jako
rezultat zwraca ona liczbÍ jednobajto-
w¹ bÍd¹c¹ kodem wybranej opcji.
Po naciúniÍciu klawisza o†kodzie
0x0C umownie funkcjonuj¹cego jako EN-
TER, funkcja sprawdza, czy pole next-
menu przyporz¹dkowane bieø¹cej pozy-
cji zawiera jak¹ú wartoúÊ. Jeúli tak, fun-
kcja wywo³uje obs³ugÍ podmenu jako
parametr, podaj¹c zawartoúÊ odpowied-
niego pola nextmenu. W†zwi¹zku z†tym,
øe chcia³em napisaÊ funkcjÍ uniwersal-
n¹, zdoln¹ do wyúwietlenia podmenu
o†rÛønych iloúciach etykiet, przy wywo-
³aniu funkcja musi obliczyÊ, jaka jest
liczba pozycji wykazu przekazanego ja-
ko argument wywo³ania. Minimalna
wartoúÊ to 1, maksymalna 127. Koniec
wykazu rozpoznawany jest po tym, øe
pole name (etykieta menu) ma wartoúÊ
znaku o†kodzie 0. Wynik obliczeÒ zapa-
miÍtywany jest w†zmiennej maxsubopt.
Ogranicza ona od gÛry wartoúÊ zmien-
nej globalnej POS_IN_SUBMENU , ktÛra
nie moøe byÊ wiÍksza niø maxsubopt-1
i†jest sprawdzana po kaødym naciúniÍciu
klawisza w†gÛrÍ czy w†dÛ³.
Po wejúciu do podmenu zaczyna
rÛwnieø dzia³aÊ klawisz o†kodzie 0x0B
pe³ni¹cy rolÍ podobn¹ do ESCAPE
w†komputerze PC. Jego naciúniÍcie powo-
duje, øe nastÍpuje powrÛt do menu
g³Ûwnego bez podejmowania jakiejkolwiek
akcji i†moøna wÛwczas dokonaÊ innego
wyboru. WybÛr zawsze potwierdzany jest
przez naciúniÍcie klawisza ENTER.
Podobnie jak w†poprzednim przyk³a-
dzie, program g³Ûwny zawiera inicjaliza-
cjÍ wyúwietlacza, wywo³anie funkcji ob-
s³ugi menu oraz konstrukcjÍ switch -
case w†celu rozpoznania wybranej opcji.
Uwagi na temat programu
Funkcje w†moich przyk³adach czÍsto
pos³uguj¹ siÍ wskaünikami do struktur.
Ich konstrukcja oraz sposÛb zapisu jest
specyficzny i†wymaga kilku s³Ûw omÛ-
wienia zw³aszcza dla tych osÛb, ktÛre
spotykaj¹ siÍ z†nimi po raz pierwszy.
Definicja tabeli zawieraj¹cej rekordy
jest doskona³ym mechanizmem zw³asz-
cza przy tworzeniu baz danych i†pli-
kÛw dyskowych. I†chociaø w†tych przy-
k³adach programÛw nie s¹ uøywane
øadne zbiory znajduj¹ce siÍ na dysku,
to jednak tablica rekordÛw do z³udze-
nia przypomina strukturÍ bazy danych,
a†leø¹cy gdzieú w†obszarze code pamiÍ-
ci mikrokontrolera wykaz - plik dysko-
wy. Istniej¹ dwie podstawowe metody
odwo³ywania siÍ do pozycji w†takiej
strukturze:
- z†zastosowaniem indeksÛw (np. me-
nus[1] , menus[5] itd.),
- z†zastosowaniem wskaünika (wskaüni-
kÛw).
Ta pierwsza metoda jest bardzo
prosta. Ilustruje j¹ przyk³ad umieszczo-
ny na list. 2 . Indeks to po prostu nu-
mer pozycji w†tabeli, do ktÛrego ø¹da
dostÍpu aplikacja. Jeúli mamy do czy-
nienia z†tabel¹ zawieraj¹c¹ 10 elemen-
tÛw, to indeks moøe przyj¹Ê wartoúci
od 0†do 9. Gdy mamy do czynienia
z†tablic¹ struktur, dostÍp do pola moø-
List. 2. Odwołanie do tablicy rekordów poprzez indeksy
typedef struct
//definicja typu - struktury (rekordu) danych
{
char x;
//struktura zawiera 3 pola typu char: x, y, colour
char y;
char colour;
} attr;
data attr points[10]; //deklaracja tablicy zawierającej rekordy danych
void main()
{
char temp;
attr pt;
points[0].x = 1; //nadanie wartości polu x tablicy wskazywanemu
//przez indeks 0
temp = points[8].y; //pobranie wartości pola y wskazywanemu przez indeks 8
//do zmiennej temp
pt = point[2];
//przepisanie rekordu danych z tablicy (indeks=2)
//do zmiennej pt będącej
}
//tego samego typu, co element tablicy
Elektronika Praktyczna 9/2003
79
39646619.006.png
K U  R S
List. 3. Odwołanie do tablicy rekordów poprzez wskaźnik
typedef struct
//definicja typu - struktury (rekordu) danych
Odwo³anie do pola struktury umoø-
liwia operator wygl¹daj¹cy jak strza³ka
skierowana w†prawo, utworzony ze
znaku wiÍkszoúci oraz odejmowania (-
>) nastÍpuj¹cego bezpoúrednio po nim.
Stosuj¹c go, naleøy†pamiÍtaÊ, øe ma
bardzo wysoki priorytet. Operacje
(pointer+temp)->x oraz temp+pointer->x
nie s¹ rÛwnowaøne. Jednak bardziej
jaskrawy przyk³ad stanowi porÛwnanie
sposobu funkcjonowania wyraøeÒ
++pointer->x oraz (++pointer)->x .
W†tym pierwszym przypadku wyraøe-
nie zwiÍksza zmienn¹ x o†1, a†nie
wskaünik do struktury. W†drugim
wskaünik jest zwiÍkszany przed odwo-
³aniem do struktury i†na skutek tego
nastÍpuje przejúcie do nastÍpnego
w†kolejnoúci elementu tablicy.
Na tej samej zasadzie wyraøenie:
- *pointer->x udostÍpnia coú, na co
wskazuje x ,
- *pointer->x++ zwiÍksza x†po udostÍp-
nieniu obiektu wskazywanego przez
x ,
- (*pointer->x)++ zwiÍksza coú, na co
wskazuje x ,
- *pointer++->x zwiÍksza zmienn¹
pointer po udostÍpnieniu obiektu
wskazywanego przez x .
Jak wspomnia³em wczeúniej, wyko-
rzystuj¹c mechanizmy uøyte do budowy
drugiego poziomu menu ³atwo jest do-
daÊ nastÍpne poziomy. Wystarczy, øe
typ submenuitem bÍdzie zawiera³†wskaü-
nik do nastÍpnego wykazu menu, a†fun-
kcja Sub_Menu zapamiÍta i†przechowa
stan zmiennej POS_IN_SUBMENU . Praw-
dopodobnie bÍdzie rÛwnieø wymagaÊ
s³owa kluczowego reentrant (kompilator
RC-51) powoduj¹cego, øe funkcja moøe
byÊ wywo³ywana rekurencyjnie. Rozbu-
dowÍ pozostawiam jednak inwencji
w³asnej Czytelnika.
Jacek Bogusz, AVT
jacek.bogusz@ep.com.pl
{
char x;
//struktura zawiera 3 pola typu char: x, y, colour
char y;
char colour;
} attr;
data attr points[10]; //deklaracja tablicy zawierającej rekordy danych
data attr *pointer = &points; //deklaracja wskaźnika oraz nadanie mu wartości
//początkowej: wskazania na początek tablicy points
void main()
{
char temp;
attr pt;
pointer->x = 1;
//nadanie wartości polu x tablicy wskazywanemu
//przez indeks 0
temp = (pointer+8)->y;
//pobranie wartości pola y wskazywanemu przez
//indeks 8 do zmiennej temp
pt = pointer+2;
//przepisanie rekordu danych z tablicy (indeks=2)
//do zmiennej pt będącej
}
//tego samego typu, co element tablicy
na uzyskaÊ podaj¹c po kropce jego na-
zwÍ: zmienna = menu[1].ptr .
Inaczej ma siÍ sytuacja, gdy odwo-
³anie do struktury odbywa siÍ przez
wskaünik. Pos³uømy siÍ tym samym
przyk³adem - na list. 3 umieszczono
program zmodyfikowany w†taki sposÛb,
aby odwo³ania do pÛl nastÍpowa³y
przez wskaünik a†nie przez indeks.
Wskaünik powinien byÊ tego same-
go typu, co wskazywany obszar da-
nych. W†konsekwencji wszelkie opera-
cje arytmetyczne na nim wykonywane
powoduj¹ jego zmianÍ o†tak¹ liczbÍ baj-
tÛw, jaki jest rozmiar wskazywanego
elementu. Ilustracj¹ tej zasady jest po-
niøszy przyk³ad:
pointer_1++; //spowoduje przesunię-
//cie wskazania zmiennej
//points[0].x na points[0].y
//(o 1 bajt)
pointer_2++; //spowoduje przesunię-
//cie wskaźnika z rekordu
//points[0] na points[1] i jest
// równoważne wyrażeniu
//pointer_1 =
//pointer_1 + sizezeof(attr)
pointer_1 += 8; //spowoduje przesu-
//nięcie wskaźnika o 8 bajtów, to
//jest na zmienną points[2].y
pointer_2 += 8; //spowoduje przesu-
//nięcie wskaźnika o 8 rekordów,
//to jest na pozycję 9 w tabeli
pointer_1 += temp; //spowoduje
//przesunięcie wskazania o 2 baj-
//ty, to jest na zmienną
//points[0].colour
pointer_2 += temp; //spowoduje
//przesunięcie wskaźnika o 2 re-
//kordy, to jest na pozycję
//3 w tabeli
data char *pointer_1 = &points;
data attr *pointer_2 = &points;
data char temp = 2;
...
...
...
80
Elektronika Praktyczna 9/2003
39646619.007.png
Zgłoś jeśli naruszono regulamin