26_11.pdf

(239 KB) Pobierz
1128249 UNPDF
Też to potrafisz
W niniejszym odcinku szkoły mikro−
procesorowej kończymy omawianie
listy instrukcji procesora 8051. Po−
zostało kilka prostych instrukcji uży−
wanych głównie w pętlach progra−
mowych oraz instrukcja pusta.
W dalszej części artykułu zajmiemy
się dokładnym opisem wszystkich
podprogramów usługowych monitora
– czyli programu komputerka eduka−
cyjnego, który każdy z Was ma zapi−
sany w EPROM−ie swego zestawu.
Poznamy tez proste sposoby na wy−
korzystanie podstawowych zaso−
bów tego programu, dzięki którym
możliwa będzie kontrolowana inge−
rencja we wszystkie mechanizmy
dostępne w Twoim systemie eduka−
cyjnym.
Mikrokontrolery?
To takie proste...
Część 10
Asembler – język maszynowy procesora
Kontynuujemy opis instrukcji z grupy skoków. Pozostała nam do
omówienia dość rzadko wykorzystywana przez początkujących progra−
mistów, instrukcja skoku względem wskaźnika danych DPTR, dwie in−
strukcje skoków warunkowych testujących zawartość akumulatora
oraz dwa typy instrukcji, które dzięki swojej konstrukcji znajdują najszer−
sze zastosowanie przy porównywaniu zawartości niektórych rejestrów
z wartościami stałymi (wykorzystywane np. przy odczycie kodów naciś−
niętego klawisza) lub w pętlach programowych. Oto one:
etyk02:
;właściwe miejsce skoku według pozycji = 1
.....
etyk03:
;właściwe miejsce skoku według pozycji = 2
.....
etyk04:
;właściwe miejsce skoku według pozycji = 3
.....
Poniżej zapoznamy się z instrukcjami skoków warunkowych, któ−
re badają warunek zgodności zadanego bajtu w wew. RAM proceso−
ra (rejestru) z innym rejestrem lub argumentem bezpośrednim (licz−
bą). Dwie z nich JZ i JNZ sprawdzają czy w akumulatorze znajduje
się liczba zero czy nie i na tej podstawie podejmowana jest decyzja
o skoku. Pozostałe instrukcje porównujące wybrane rejestry z innym
lub konkretną liczbą znajdują zastosowanie szczególnie w pętlach
programowych, gdzie konieczne jest wykonanie n–razy określonej
opracji.
JMP A+DPTR
– ang. “Jump Indirect relative to DPTR” – skocz pośrednio względem
rejestru DPTR
– w wyniku tej instrukcji następuje skok pod adres będący sumą aktu−
alnej wartości rejestru DPTR (liczba 16–bitowa) i wartości akumulato−
ra (liczba 8–bitowa). Można powiedzieć że skok następuje pod adres
w pamięci programu umieszczony w DPTR z przesunięciem poda−
nym w akumulatorze. Przesuniecie to traktowane jest jako liczba bez
znaku, czyli z zakresu <0...255>
PC <– A + DPTR
– kod: 01110011
73h
JZ rel
– ang. “Jump if Accumulator is Zero”, skocz jeżeli w akumulatorze jest
liczba 0 (zero)
– sprawdzana jest zawartość akumulatora (A), jeżeli jest równa zero, to
do licznika rozkazów PC dodawane jest przesunięcie “rel” – na zasa−
dach takich jak opisano wczesniej przy okazji omawiania poprzednich
instrukcji skoków z argumentem “rel” (liczba 8–bitowa ze znakiem
w kodzie U2).
PC <– PC + 2, jeśli A = 0, to PC <– PC + rel
– kod: 0 1 1 0 0 0 0 0
– cykle: 2 bajty: 1
– przykład: realizacja skoków w miejsca w programie określone po−
przez numer w zmiennej “pozycja” (umieszczonej – zadeklarowanej
z wewn. RAM procesora)
MOV A, pozycja ;załadowanie numeru pozycji
MOV B, #2 ;2 bo instrukcje w tabeli skoków sa
2–bajtowe (AJMP)
MUL A, B ;obliczenie faktycznego ofsetu
do tabeli skoków
MOV DPTR, #tablica_skokow ;załadowanie adresu
tabeli skoków do DPTR
60h
– cykle: 2
bajty: 2 (kod instrukcji 60h + przesunięcie “rel”)
– przykład:
MOV A, B
;załadowanie rej. B do Acc celem
;sprawdzenia czy = 0
JMP A+DPTR
;wykonanie skoku
tablica_skoków:
;tu zaczyna sie tabela skoków
JZ
jest_zero
;jeżeli tak to skok do etykiety “
jest_zero”
AJMP etyk01
;tu nastapi skok gdy “pozycja” = 0
AJMP etyk02
;tu nastąpi skok gdy “pozycja” = 1
AJMP etyk03
;tu nastąpi skok gdy “pozycja” = 2
nie_zero:
;jeżeli nie to wykonuj pozostałe instrukcje
AJMP etyk04
;tu nastąpi skok gdy “pozycja” = 3
.....
.....
jest_zero:
.....
;pozostałe instrukcje programu
.....
etyk01:
;tu nastąpi skok jeżeli rej.B był równy zero
;właściwe miejsce skoku według pozycji = 0
.....
;i zostaną wykonane te instrukcje
.....
;tu mozna umieścić instrukcje
.....
E LEKTRONIKA DLA WSZYSTKICH 2/98
35
1128249.002.png
Też to potrafisz
JNZ rel
– ang. “Jump if Accumulator is Not Zero”, skocz jeżeli akumulator nie
jest = 0 (zero)
– sprawdzana jest zawartość akumulatora (A), jeżeli jest różna od zera,
to do licznika rozkazów PC dodawane jest przesunięcie “rel” – na za−
sadach takich jak opisano wczesniej przy okazji omawiania poprzed−
nich instrukcji skoków z argumentem “rel” (liczba 8–bitowa ze zna−
kiem w kodzie U2).
PC <– PC + 2, jeśli A <> 0, to PC <– PC + rel
– kod: 01110000
choćby w naszym komputerku). Jeżeli chcemy podjąć określone
działanie w zależności od rodzaju klawisza, należy przechowywany
kod klawisza porównać z konkretna liczbą.
czekaj:
MOV A, klawisz
;pobranie kodu wciśniętego klawisza
CJNE A, #65, sprB
;czy wcisnięto klawisz “A” (65 – kod “A”)
........
;tak to wykonuj te instrukcje
sprB:
CJNE A, #66, sprC
70h
;nie to czy wciśnięto klawisz “B”
– cykle: 2
bajty: 2 (kod instrukcji 70h + przesuenięcie “rel”)
........
;tak to wykonuj te instrukcje
– przykład:
MOV A, B
sprC:
CJNE A,#67, sprD
;załadowanie rej. B do Acc celem
sprawdzenia czy = 0
;nie to czy wciśnięto klawisz “C”
.........
;tak to wykonuj te instrukcje
JNZ
nie_zero
;jeżeli nie to skok do etykiety “nie_zero”
sprD:
CJNE A, #68,czekaj
jest_zero:
;jeżeli tak to wykonuj pozostałe instrukcje
;nie to czekaj na kolejne naciśnięcie
klawisza
.....
.....
nie_zero:
.........
;tak to wykonuj te instrukcje
;tu nastapi skok jeżeli rej.B był różny od
zera
CJNE Rn, #dana, rel
– rejestr Rn (R0...R7) zostaje porównany z argumentem bezpośred−
nim, jeżeli nie sa zgodne zostaje wykonany skok
PC <– PC + 3, jeśli Rn <> dana, to PC <– PC + rel
.....
;i zostaną wykonane te instrukcje
.....
gdzie
A oto wspomniana wczesniej grupa instrukcji używana głównie
w pętlach programowych lub przy zwielokrotnionym sprawdzaniu wa−
runków zgodnosci określonych rejestrów z innym lub z argumentami
stałymi. Ogólna postać instrukcji jest następująca:
n = 0...7
dodatkowo: C <– 0 gdy Rn>= dana, lub C<–1 gdy Rn< dana
– kod: 1 0 1 1 0 n2 n1 n0 gdzie n2 n1 n0 określają jeden z rejest−
rów R0...R7 stąd kody: B8h....BFh
– cykle: 2
bajty: 3 (kod instrukcji + dana + przesuniecie “rel”)
CJNE <arg1>, <arg2>, rel
– ang. “Compare and Jump if Not Equal”, porównaj i skocz jeżeli argu−
menty porównania nie są sobie równe
– przykład:
MOV R4, P1 ;odczytanie stanów z portu P1
CJNE R4, #100, nie_100 ;porównanie ich z liczbą 100
SETB P3.0
;równe to ustaw pin 0 portu P3
W instrukcji tej porównywane sa dwa argumenty: arg1 i arg2. Jeżeli
nie są one równe (ich wartości nie sa równe), to do zawartości licznika
rozkazów jest dodawane przesunięcie “rel” na zasadach zgodnych
z omówionymi wcześniej. W efekcie zostaje wykonany skok w progra−
mie. Tu uwaga, skok nastepuje względem instrukcji występującej po in−
strukcji CJNE. Dodatkowo jest zmieniany znacznik przeniesienia C.
I tak, jeżeli w wyniku porównania okaże sie zę argumrent arg1 jest
mniejszy od argumentu arg2 to do znacznika C wpisywana jest jedynka
(znacznik jest ustawiany), w przeciwnym przypadku znacznik jest zero−
wany (C=0). W zalezności od typu argumentów instrukcji możliwe są
cztery przypadki, oto one.
......
nie_100:
CLR
P3.0
;nie równe to zeruj pin 0 portu P3
......
......
W przykładzie porównywana jest zawartość rejestru R4 z liczbą 100,
jeżeli występuje zgodność, to w porcie P3 zostaje ustawiony najmłod−
szy bit (pin) P3.0,w przeciwnym przypadku jest zerowany. Jest to pros−
ty przykład komparatora liczby 8–bitowej podawanej na port P1 z ze−
wnątrz ze stałą liczbą (w tym przypadku jest to liczba 100).
CJNE A, adres, rel
– porównywany jest akumulator oraz komórka wew. RAM o adresie
podanym bezposrednio jako argument “adres”
PC <– PC + 3, jesli A <> (adres), to PC <– PC + rel
dodatkowo: C <– 0 gdy A>= (adres), lub C<–1 gdy A< (adres)
– kod: 10110101
CJNE @Ri, #dana, rel
– porównywana jest zawartośc komórki w wew. RAM której adres
znajduje sie w rejestrze Ri (R0 gdy i=0, lub R1 gdy i=1) z argumen−
tem bezpośrednim. Jeżeli się różnią to następuje skok.
PC <– PC + 3, jeśli (Ri) <> dana, to PC <– PC + rel
gdzie
B5h
i = 0, 1
dodatkowo: C <– 0 gdy (Ri) >= dana, lub C<–1 gdy (Ri) < dana
– kod: 1 0 1 1 0 1 1 i gdzie i=0, 1 stąd kody: B6h, B7h
– cykle: 2 bajty: 3 (kod instrukcji + dana + przesuniecie “rel”)
– przykład: sekwencja instrukcji porównania w postaci:
MOV R1, #30h
CJNE @R1, #255, skocz
.......
skocz:
.......
jest równoważna sekwencji
MOV A, #255
CJNE A, 30h, skocz
.......
skocz:
.......
– cykle: 2
bajty: 3 (kod instrukcji + adres + przesunięcie “rel”)
– przykład:
MOV B,#56
check:
CJNE A, B, zwieksz
SJMP koniec
zwieksz:
INC A
SJMP check
koniec:
CLR
B
......
W przykładzie tym do rejestru B wpisywana jest liczba 56. Nastepnie
sprawdzany jest warunek zgodności akumulatora z rejestrem B, jeżeli
nie są sobie równe, to akumulator jest inkrementowany (dodawana jest
do niego jedynka) – patrz etykieta “zwieksz”. Następnie operacja jest
powtarzana od początku – instrukcja “SJMP check”. Jeżeli w końcu na−
stąpi zgodność obu rejestrów, wykonywany jest skok do etykiety “ko−
niec”, gdzie rejestr B zostaje wyzerowany.
przeanalizuj i zastanów sie dlaczego. Podpowiem tylko, że w przykła−
dzie porównywana jest zawartość komórki pamięci wew. RAM z okreś−
loną liczbą, przy różnicy wystepuje skok.
Ostatnią instrukcją skoków warunkowych jest polecnie DJNZ. Ogól−
na postać instrukcji jest następująca:
CJNE A, #dana, rel
– akumulator zostaje porównany z argumentem bezpośrednim (8–bito−
wą liczbą), jeżeli nie są zgodne nastepuje skok.
PC <– PC + 3, jeśli A <> dana, to PC <– PC + rel
dodatkowo: C <– 0 gdy A>= dana, lub C<–1 gdy A< dana
– kod: 10110100 B4h
– cykle: 2 bajty: 3 (kod instrukcji + dana + przesunięcie “rel”)
– przykład: niech w zmiennej (rejestrze) “klawisz” będzie przechowy−
wany kod wciśnętego klawisza w systemie mikroprocesorowym (ot
DJNZ <arg>, rel
– ang. “Decrement and Jump if Not Zero”, zmniejsz o jeden i skocz je−
żeli nie równe zero
W wyniku tej operacji od wskazanego argumentu “arg” jest odejmo−
wana jedynka (jest on dekrementowany). Jeżeli w wyniku odjęcia war−
tość argumentu nie jest równa zero, to zostaje wykonany skok zgodnie
z zasadami opisanymi wcześniej w przypadku argumentu “rel”. Stan
36
E LEKTRONIKA DLA WSZYSTKICH 2/98
1128249.003.png
Też to potrafisz
znaczników nie zmienia się. W zalezności od typu argumentu rozróżnia
się dwa typy instrukcji, oto one.
”ręczniacy” powinny tłumaczyć (rozumieć) te 3 litery “DL1” jako liczbę
120. I tak jeżeli w dalszej części programu, juz w samym kodzie pojawi
sie np. instrukcja:
MOV DL1, A
oznaczać to bedzie to samo co instrukcja
MOV
DJNZ Rn, rel
– zmniejszona zostaje zawartość podanego rejestru Rn (R0...R7) o je−
den, a nastepnie jeżeli nie jest równa zero, to następuje skok.
PC <– PC + 2, Rn <– Rn – 1, gdzie n = 0...7
jeżeli Rn <> 0, to PC <– PC + rel
– kod: 1 1 0 1 1 n2 n1 n0 gdzie n2 n1 n0 określają jeden z rejest−
rów R0...R7 stąd kody: D8h...DFh
– cykle: 2 bajty: 2 (kod instrukcji + przesunięcie “rel”)
– przykład: sekwencja instrukcji
CLR A
MOV R7, CLR A #26
dodaj:
ADD A, #1
DJNZ R7, dodaj
......
jest równoważna poleceniu
ADD A,#26
co w obu przypadkach powoduje dodanie do akumulatora liczby 26.
78h, A
Podobnie np. jeżeli zechcemy np. załadować liczbę (nie zawartość ko−
mórki spod podanego adresu) 78h np. do rejestru B wykonamy operację:
MOV B, #DL1
co będzie tożsame jako
MOV
Znaczek “#” oznacza że mamy do czynienia z argumentem bezpo−
średnim, czyli liczbą, a nie jak w przykładzie poprzednim z adresem ko−
mórki w wewnętrznej pamięci RAM procesora. Warto to zapamiętać.
Dla zapamiętania jeszcze jeden przykład: niech pod adresem F005h
w obszarze zewnętrznej przestrzeni adresowej procesora (w jakimś
układzie skonstruowanym przez nieznanego elektronika a wykorzystu−
jącym procesor 8051) znajduje się 8–bitowy rejestr pracujacy jako wy−
jście informacji, np. sterujący ośmioma przekaźnikami załączającymi ża−
rówki węża świetlnego – chociażby znany wam już układ 74573. Aby
zapalić co drugą żarówkę należy wykonać proste instrukcje zapisu do
zewnętrznej pamięci danych, zakładając że rejestr jest zatrzaskiwany
pod wpływem (nie bezpośrednio !!!) sygnału /WR – zapisu do ext. RAM
procesora. Zadeklarujmy zatem ten specjalny adres jako nazwę pocho−
dzaca od angielskiego słowa “wąż”:
SNAKE EQU 0F005h
Wykonanie w dalszej części programu sekwencji:
MOV DPTR, #SNAKE ;załaduj adres do wskaźnika
danych
MOV A, #55h ;w liczbie 55h sąsiednie bity
sa różne: 01010101
MOVX @DPTR, A ;i zapisz do rejestru pod
wskazany adres
spowoduje zamierzony efekt. Pierwszą linię można zapisać oczywiście
jako:
MOV
DJNZ adres, rel
– zmniejszona zostaje zawartość komórki pamięcie wew. RAM o poda−
nym bezpośrednio adresie o jeden, a nastepnie jeżeli nie jest równa
zero, to następuje skok.
PC <– PC + 2, (adres) <– (adres) – 1, jeżeli (adres) <> 0, to PC
<– PC + rel
– kod: 11010101 D5h
– cykle: 2 bajty: 3 (kod instrukcji + adres + przesunięcie “rel”)
– przykład: sekwencja instrukcji przedstawiona poniżej daje taki sam
efekt jak w porzednim przykładzie.
CLR A
MOV B, #26
dodaj:
ADD A, #1
DJNZ B, dodaj
.......
DPTR, #F005h
......
......
ale jak sami widzicie pierwszy sposób jest bardziej czytelny, bowiem od
razu wiemy czytając program, że w tym miejscu nastapi zapis do rejes−
tru węża świetlnego.
A teraz pora na naprawdę ostatnią instrukcję z listy poleceń proceso−
ra 8051.
NOP
– ang. “No Operation”, nie rób nic
– jest to instrukcja, w wyniku której nie zmienia się stan procesora,
z wyjątkiem licznika rozkazów którym po pobraniu tej instrukcji jest
zwiększany o jeden.
– kod: 00000000
00h
Drugą deklaracją ważną szczególnie a może przede wszysktim dla
komputerowców jest dyrektywa “INCLUDE” – ang. włącz w sensie do−
łącz, dopnij, weź pod uwagę kompilując program”. Służy ona do włącza−
nia podczas kompilacji zbiorów dodatkowych ), oprócz tego, którym jest
celem kompilacji, przy wywołaniu programi kompilatora PASM51.EXE,
w których znajdują się dodatkowe kawałki “kodu” źródłowego użyt−
kownika. W sensie dosłownym mogą to być zbiory tekstowe zawiera−
jące biblioteki (w postaci źródłowej) dodatkowych procedur np. mate−
matycznych.
W praktyce np. kiedy zachodzi potrzeba użycia podprogramu doda−
wania dwóch liczb 32–bitowych w pięciu aplikacjach (programach), nie
warto umieszczać kodu tej procedury w każdym z pięciu zbiorów źród−
łowych. Lepiej i wygodniej jest raz zapisać kod źródłowy takiej procedu−
ry w odzielnym zbiorze np. pod nazwą: “ ADD32.INC ”, po czym w każ−
dym z pieciu aplikacji zapisać 1–liniową deklarację dołączenia tego zbio−
ru podczas kompilacji w postaci:
INCLUDE ADD32.INC
co spowoduje dołączenie treści zbioru ADD32.INC do pliku głównego
w miejscu jej wywołania. Oczywiście jeżeli w zbiorze z podprogramem
wystąpi błąd w zapisie jakiejś instrukcji kompilator automatycznie prze−
rwie tłumaczenie sygnalizując komunikatem odpowiedni błąd z poda−
niem nazwy zbioru włączonego dyrektywą “INCLUDE”.
– cykle: 1 bajty: 1
– przykład: sekwencja instrukcji
MOV A, B
NOP
MUL A, B
zajmie procesorowi o 1 cykl maszynowy więcej niz sekwencja
MOV A, B
MUL A, B
ale efekt działania będzie taki sam w obu przypadkach.
I na tym kończy się lista instrukcji procesora 8051. Teraz pozostaje juz
tylko praktyczne ich wykorzystanie w celu tworzenia programów. Na
początku będą to aplikacje na komputerek edukacyjny, który każdy
z Was powinien już mieć uruchomiony, potem na dowolne układu elek−
troniczne, które już sami będziecie konstruować bazując na proceso−
rach serii 8051 I pochodnych.
Pozostaje jeszcze do wyjaśnienia grupa poleceń nie bedących in−
strukcjami asemblera procesora 8051, lecz będąca deklaracjami przypi−
sania i definiowania ciagów bajtów, akceptowanymi przez wiekszość
kompilatorów (w tym zamieszczony na dyskietce AVT–2250/D program
PASM51.EXE). Dzięki nim czytanie kodu programu przez programistę
jest łatwiejsze, toteż powinni szczególnie pamiętać o tym “kompu−
terowcy”. Ze względu jednak na używanie takich poleceń w naszych
przykładach, szczególną uwagę powinni zwrócić na te część artykułu
także “ręczniacy”.
Pierwszą uzyteczną deklaracją jest polecenie “EQU” (ang. “equal“ –
równy, taki sam, tożsamy) – przypisania nazwie występujacej po lewej
stronie polecenia wartości z prawej strony, np.
DL1 EQU 78h
oznacza że w dalszej części programu przez skrót “DL1” należy rozu−
mieć liczbę szesnastkową 78h (120 dziesiętnie). I tak kompilator oraz
Jak wiecie, kod programu (już po przetłumaczeniu) na procesor skła−
da się z ciągu bajtów instrukcji i danych. Czasami zachodzi potrzeba de−
finiowania w kodzie programu (podczas pisania) tablic wartości stałych,
np. opisujących przebieg sinusa dla kąta pełnego, lub numer ostatniego
dnia każdego miesiąca. Program w czasie pracy za pomoca instrukcji
MOVC A, @A+DPTR ” (patrz opis instrukcji) może pobrać takie dane
i wykorzystać je do dalszych obliczeń. Jak zatem zdefiniowac takie cią−
gi bajtów w naszym programie, ano za pomoca dyrektyw: DB – definiu−
jacej bajty, DW – definiujacej 16–bitowe słowa (podwójne bajty) oraz
DD – definiującej 32–bitowe słowa (poczwórne bajty).
Przy tworzeniu takiego strumienia danych (stałych) wszystkie skład−
niki, liczby musza być oddzielone przecinkami. Liczby mozna zapisywać
E LEKTRONIKA DLA WSZYSTKICH 2/98
37
B, #78h
1128249.004.png
Też to potrafisz
z ogólnie przyjetą zasadą (jak w całym asemblerze) w czterech różnych
postaciach:
– dziesietnej, np. 23, 199, 45, 255, 54675
– szesnastkowej (na końcu litera “h”): 12h, 7Fh, 0ABh, 1234h, itp
– binarnej (na końcu litera “b”): 10101010b, 010b, 010010010010b
– za pomocą kodu znaku (znak w apostrofach): ‘4 – oznacza kod zna−
ku ASCII “4” czyli fizycznie liczbę: 52. Sposób ten w przypadku kom−
pilatora PASM51.EXE daje sie wykorzystać z dyrektywą “DB”. Argu−
mentami “DW” i “DD” mogą być tylko liczby zapisane w trzech po−
przednich formatach.
i wyszukiwanie błędów, a o modyfikacjach nie wspomnę. Przykład ko−
mentarza:
MOV A, B ;załadowanie zawartości rejestru B do akumulatora
Tekstem pochyłym zaznaczono komentarz.
Pozostała jeszcze do omówienia dyrektywa “ORG”, której zadaniem
jest deklarowanie adresu w pamieci programu procesora, od którego
będą umieszczane kolejne, wystepujace po tej dyrektywie, bajty pro−
gramu. I tak np. kiedy piszemy aplikacje na nasz komputerek edukacyj−
ny, liczymy się z tym, że fizyczna pamieć (SRAM) do której ładowany
jest program zaczyna się od adresu 8000h. Dlatego każdy z przykładów
do wklepania zaczyna sie od dyrektywy:
ORG 8000h
co mówi kompilatorowi PASM51.EXE, że występujące instrukcje po tej
dyrektywie ma umieszczać od adresu 8000h począwszy, czyli od po−
czątku fizycznej pamięci SRAM komputerka.
Dyrektywa ORG, tak jak omówione wcześniej, może być używana
wielokrotnie w tym samym kodzie źródłowym programu. Ważne jest
aby “panować”na nią, ale o tego nauczymy sie przy innej okazji, kiedy
zajdzie taka potrzeba.
Korzystając z ostatniego sposobu mozna zapisywać całe teksty (np.
do wyświetlenia potem na dołączonym do komputerka – wyświetlaczu
tekstowym LCD), lub po prostu informacje autorskie o danym progra−
mie, jego wersji, czy dacie powstania.
I tak np. jeżeli chcemy zdefiniowac tablicę cyfr wykorzystywanych
w kodzie szesnastkowym, należy użyć dyrektywy DB w postaci np.
hextab DB ‘0123456789ABCDEF’
co po przetłumaczeniu na kod maszynowy procesor zrozumie jako ciąg
bajtów:
48 49 50 51 52 53 54 55 56 57 65 66 67 68 69 70
zapisanych dziesiętnie.
Czyli można zapisac ten ciąg w inny sposób np.:
hextab DB 48,49,50,51,52,53,54,55,56,57,65,66,67,68,69,70
W przypadku dyrektywy DW mozna w roli składników umieszczać
liczby 16–bitowe czyli z zakresu: 0...65535, a w przypadku dyrektywy
DD, liczby z zakresu 0... 4294967295, przykłady deklaracji mieszanych:
bigtab DW 1234h, 65535, 1010101001010101b, 1, 0
longtab DD 12345678h, 10000234,0101010b, 1000000000000000000001b
No i ostatnia sprawa dotycząca stosowania etykiet przy skokach wa−
runkowych ale i bezwarunkowych,czy deklaracjach podprogramów. Dla
porządku należy powiedzieć że wszysktie etykiety powinny zaczynać
się od pierwszej kolumny w danej linii tekstu, czyli od pierwszego zna−
ku, dodatkowo należy je zakończyć znakiem dwukropka, np.
etyk01:
etyk02:
dodaj:
przyklad:
Wielkość liter z kodzie źródłowym programu w przypadku kompilato−
ra PASM51.EXE nie ma znaczenia, wyjątek stanowią teksty będace ar−
gumentami instrukcji czy dane w tablicach tworzonych z wykorzysta−
niem dyrektywy “DB” i umieszczone pomiedzy znakami apostrofa, np.
‘tekst’.
Zauważcie, że przed każdą deklaracją umieściłem jakiś wyraz, który jest
po prostu etykietą opisujacą deklarowane stałe. W programie jest to bar−
dzo często niezbędne a nader wygodne. No bo jaki adres zapiszecie do
wskaźnika DPTR przy uzyciu instrukcji “ MOVC A, @A+DPTR ”, ręczniacy
beda musieli po prostu policzyć wszysktie bajty znajdujące sie przed da−
na deklaracją tablicy i wpisać je po kodzie instrukcji MOV DPTR,# ja−
kaś_liczba_16_bitowa, komputerowcy zastosuja polecenie, np.
MOV DPTR, #bigtab
a kompilator PASM51 sam obliczy adres tablicy, gdziekolwiek ona by się
znalazła, a następnie wstawi go za kodem instrukcji MOV DPTR, #nn .
W przypadku dyrektywy “DB” możliwe jest łączenie w jednej lini−
i kilku rodzajów zapisów liczb, np. mieszając teksty z zapisem dziesięt−
nym, np.
tekst1 DB 16, ‘WITAJ CZYTELNIKU’
A propos ten przykład może posłużyć jako ilustracja argumentu wy−
wołania jakiejś procedury (podprogramu) w wyniku którego zostaje wy−
pisany wskazany tekst. Pierwszy bajt w deklaracji tablicy określa fizycz−
ną liczbę znaków w tablicy tekstowej – czyli długość napisu, dalej od ra−
zu wystepuje dany tekst, prawda że logiczne podejście. W ten prosty
sposób procedura wie kiedy dany tekst się kończy. Istnieją także inne
sposobu realizacji tego pomysłu, ale to nie jest w tej chwili tematem na−
szego artykułu.
Każdy program pisany i kompilowany przez komputerowców za po−
mocą programu PASM51.EXE musi się kończyć deklaracją “END”, któ−
ra mówi programowi, że w tym miejscu kończy się tekst źródłowy
i resztę linii jeżeli one istnieją, należy zignorować.
Dodatkowo przy użyciu tego kompilatora w każdym programie źródło−
wym (głównym a nie w zbiorach z podprogramami typu INC) w pierw−
szej linii powinna znaleźć się dyrektywa deklarujaca procesor na który pi−
sany jest dany program. Dyrektywa ta to : “CPU”, za którą powinien zna−
leźć sie argument w postaci nazwy zbioru zawierającego deklaracje typu
EQU – opisujące nazwy wszystkich rejestrów specjalnych oraz bitów
i w ogóle całego nazewnictwa zwiazanego z wybraną kostką.
Na dyskietce AVT–2250/D znajduje sie taki zbiór definicyjny o nazwie
8052.DEF warto go sobie obejrzeć, aby stwierdzić zgodność informacji
przedstawionych przeze mnie w niniejszym artykule. Zbiór taki mozna
oczywiście modyfikować, lecz na wstepnym etapie nauki programowa−
nia radze tego nie robić, a przynajmniej zrobić jego wierną kopię przed
takimi eksperymentami.
Jak każdy program – tekst źródłowy powinien zawierać komentarze
programisty, dzięki czemu późniejsza analiza programu jest łatwiejsza
czy w ogóle możliwa do zrealizowania. Wiekszość asemblerów na
procesory 8051 (ale nie tylko) rozpoznaje znak średnika “;” jako znak
zaczynający w danej linii tekst komentarza. Toteż kompilator analizu−
jąc linię po linii kod źródłowy programu i tłumaczac go, napotkawszy
średnik ignoruje cały tekst od tego znaku aż do końca linii. Jak zdąży−
liście sie zorientować, komentarze mogą być umieszczane na począt−
ku linii wtedy cała linia jest komentarzem, lub po każdej linii z instruk−
cją dla procesora, co znacznie ułatwia późniejszą analize programu
Program monitora (“BIOS”)
Ze względu na ograniczoną objętość a jednoczesnie dość szeroką te−
matykę związaną z programem monitora zawartym w EPROM’ie, a znaj−
dującym się w każdym zestawie edukacyjnym AVT–2250, nie byłem
w stanie opisać szczegółowo tego problemu przy okazji opisu kontruk−
cji i sposobów uruchomienia tego urządzenia w poprzednich numerach
EdW.
Drugim powodem pewnego “ominięcia” tego tematu był fakt bezce−
lowości wyjasniania tego problemu na etapie kiedy nie znaliście jeszcze
listy instrukcji procesora 8051, no przynajmniej większej jej części.
Skoro tak już sie stało i w ostatnich trzech numerach “wałkowa−
liśmy” teoretycznie ten temat, przyszła odpowiednia pora na wyjaśnie−
nie sobie podstawowego pytania: “Co tak naprawdę siedzi w tym
“monitorze” prócz funkcji usługowych które już znacie – czyli operacji
umożliwiających np. ładowanie (LOAD), podglądanie (EDIT) i urucha−
mianie programów (JUMP)”.
Jak wspomaniałem w lekcji nr 4 zamieszczonej w poprzednim stycz−
niowym numerze EdW, w programie “monitora” znajdują się dodatko−
we procedury – podprogramy (użyte określenia są tożsame), dzięki któ−
rym w prosty sposób możliwe jest wywołanie określonego działania na−
szego komputerka z zależności od Twoich potrzeb, czyli np. wyczysz−
czenie pola odczytowego wyświetlacza, odczyt nacisniętego klawisza,
czy wyświetlenie liczby lub pseudo–tekstu w celu poinformowania
uzytkownika o zaistniałym zdarzeniu lub wykonaniu pewnej operacji
przez nasze urządzenie. W tym miejscu szczególnie “komputerowcy”
stwierdzą że sprawa wygląda podobnie jak w przypadku zwykłego PC−ta
czy każdego innego komputera, który posiada przecież dwa podstawo−
we urządzenia wejścia–wyjścia czyli klawiaturę i monitor (u nas jest to
ośmiopozycyjny wyświetlacz 7–segmentowy).
Tym osobom chcę wyjaśnić, że aby zrozumieć znaczenie dodatko−
wych procedur o których mówię, wystarczy porównać “monitor”– pro−
gram komputerka do coraz rzadziej (”niestety” z punktu widzenia elek−
tronika–“hardware’owca” a zarazem programisty) dziś spotykanego
systemu operacyjnego MS–DOS w waszym komputerze. Taki system
oprócz tego że posiada pewne standardowe polecenia, chociażby do
pokazania na ekranie drzewa katalogów na danym napędzie dyskietek
lub dysku twardym (“dir” w PC−tach). Te polecenia można właśnie po−
równać do poleceń dostępnych bezpośrednio (bez pisania programu)
z klawiatury komputerka edukacyjnego. W komputerze (np. PC) trzeba
wpisać polecenie w postaci wyrazu i potwierdzić, u nas w naszym urzą−
dzeniu wystarczy nacisnąć jeden klawisz aby wywołać określoną funk−
cję – porównanie to dotyczy samej zasady posługiwana się programem
monitora jako takim właśnie prościutkim systemem operacyjnym, któ−
ry nagminnie nazywam “monitorem” lub “biosem”.
38
E LEKTRONIKA DLA WSZYSTKICH 2/98
1128249.005.png
Też to potrafisz
Jak jednak wiecie (zwracam się nie tylko do komputerowców ale i do
ciekawskich “ręczniaków”), może nie wszyscy, w każdym systemie
operacyjnym istnieją dodatkowe funkcje usługowe, które wykorzysty−
wane są poprzez różne programy, które użytkownik uruchamia z pozio−
mu systemu np. gry, arkusze kalkulacyjne, edytory tekstów, lub inne
specjalistyczne oprogramowanie, praktycznie wszystko. Takie funkcje
np. w sysytemie MS–DOS dostepne są poprzez funkcję systemową
INT21h. Programiści piszący aplikacje np,. w asemblerze x86 lub popu−
larnym Turbo Pascalu z pewnością wiedzą o co chodzi.
Takie też funkcje posiada nasz komputerek,oczywiscie ze względu na
ograniczone możliwości i potrzeby naszego systemiku oraz zupełnie od−
mienną architekturę procesora, są one mocno ograniczone, lecz dla na−
szych zastosowań w zupełności wystarczą.
– przykład:
MOV A, #60h ;liczba 60h do zamiany
LCALL HEXASCII ;wywołanie podprogramu
....... ;po wykonaniu w B będzie
znak ‘6 (liczba 54)
....... ;a w Acc kod znaku ‘0` (liczba 48)
Procedurę można też wywołać w postaci :
LCALL 0235h
co przyniesie taki sam skutek. “Ręczniacy” mogą sobie od ręki
przetłumaczyć na język maszynowy te polecenie jako ciąg bajtów: “ 02,
02, 35h ” – pierwszy bajt to kod instrukcji LCALL, dwa następne to
adres procedury HEXASCII. Tak samo można postępować z każdym
innym wywołaniem, jednak w przypadku “komputerowców” ze wzglę−
du na czytelność programu, należy używać nazw słownych.
Przejdźmy zatem do ich omówienia. Przestawiając wspomniane pod−
programy będę kierował sie pewnym schematem, co z pewnoscia ułat−
wi zrozumienie poszczególnych procedur i pozwoli na ich bezproblemo−
we użycie w programie przykładowym, który przeanalizujemy krok po
kroku w kolejnej lekcji nr 5. Oto schemat:
– umowna nazwa podprogramu oraz jego adres fizyczny (adres wywo−
łania instrukcją LCALL)
– krótki opis działania danego podprogramu, “czyli co w efekcie się
stanie”
– parametry wejściowe (“we:”) wywołania, czyli “co i do jakiego rejes−
tru trzeba załadować przed wywołaniem podprogramu
– parametry wyjściowe (“wy:”), czyli wynik (efekt) działania danej pro−
cedury po jej zakończeniu
– dodatkowo podam w niektórych przypadkach, “co taki podprogram
zmienia (jakie rejestry) w procesorze”. Ta informacja jest bardzo waż−
na, bowiem przecież pisząc jakiś program operujemy na rejestrach
procesora, do których zapisujemy określone wartości, i w których
przechowuujemy wyniki operacji. Niektóre z tych rejestrów (np. aku−
mulator lub rejestr B, czy rejestry R0...R7) są także wykorzystywane
dodatkowo w celu zrealizowania określonej operacji (wewnątrz pod−
programu) a więc ich zawartość jest w wyniku działania danej proce−
dury zmieniana. Konieczne zatem się staje zapamiętanie przechowa−
nie na czas wykonywania podprogramu zawartości tych rejestrów,
aby po zakończeniu procedury, mozna było odtworzyć ich zawartość
pierwotną. Ktoś w tym miejscy moze zadac pytanie: “a dlaczego każ−
dy podprogram po rozpoczęciu swego działania (po wywołaniu) sam
nie zadba i nie przechowa tych rejestrów, po czym je odtworzy po za−
kończeniu działania – przeciez jest to możliwe...”. Tak ale z punktu
widzenia użytkowego, taka sytuacja jest w praktyce po prostu niepo−
trzebna, wydłuża to tylko niepotrzebnie działanie podprogramu, a co
za tym idzie spowalnia działanie programu głównego.
A2HEX (024Eh)
– powoduje wyświetlenie zawartości akumulatora na wyświetlaczu w
postaci dwóch znaków ze zbioru 0...9, A...F, na pozycji (wyświet−
laczu) podanej w rejestrze B
– adres wywołania: 024Eh
– we: Acc – 8–bitowa liczba do wyświetlenia, B – numer wyświetlacza
(1...8) od którego ma sie zaczynać wyświetlana liczba
– wy: wyświetlenie liczby na określonej pozycji
– traci: R0, A i B
– przykład: patrz lekcja nr 4 z poprzedniego numeru EdW, inny
przykład:
;niech w rejestrze pod nazwą “sek” bedą przechowywane sekundy pro−
gramu zegara, który akurat uruchomilismy w naszym komputerku za
pomoca innego podprogramu, w rej. “min” minuty a w rejestrze “godz”
– godziny aktualnego czasu, aby pokazać aktualny czas w postaci np.
GG_ MM_ SS ,gdzie GG – pozycja godzin,
;MM – pozycja minut
;SS – pozycja sekund
(podkreślenie oznacza wygaszoną pozycję wyświetlacza)
np. “12 45 00” (godz 12:45 i 00 sekund) nalezy wykonac sekwencję:
LCALL CLS
;najpierw wyczyścimy całe pole odczytowe
MOV B, #1
;godziny wyświetlimy od 1 wyświetlacza
MOV A, godz
;załadowanie godzin
LCALL A2HEX
;i wywołanie podprogramu
;...... po wykonaniu na DL1 i DL2 będzie
godzina
MOV B, #4
;minuty wyświetlimy od 4 wyświetlacza
MOV A, min
;załadowanie minut
LCALL A2HEX
;i wywołanie podprogramu
;...... po wykonaniu na DL4 i DL5 będą
minuty
HEXASCII (0235h)
Przejdźmy zatem do opisu poszczególnych procedur – podprogramów.
– zamienia liczbę znajdującą się w akumulatorze (Acc) na dwa znaki
ASCII których kody umieszcza w rejestrach B (starszy półbajt) i A
(młodszy półbajt), np. jeżeli w Acc przed wywołanie podprogramu
bedzie liczba 4Fh (wszystkie liczby w kodzie heksadecymalnym), to
po zakończeniu wykonywania procedury będzie: B = ‘4` (52) a aku−
mulator Acc= F (70)
– adres wywołania: 0235h
– we: Acc – 8–bitowa liczba do zamiany
– wy: B – kod starszego półbajtu liczby wejściowej, Acc – to samo ale
młodszy
MOV B, #7
;sekundy wyświetlimy od 7 wyświetlacza
MOV A, sek
;załadowanie sekund
LCALL A2HEX
;i wywołanie podprogramu
;...... po wykonaniu na DL7 i DL8 będą
sekundy
DPTR4HEX (025Fh)
– wyświetla 16–bitową liczbę zawartą w parze rejestrów DPH i DPL
(DPTR) jako 4 znaki 0...9, A...F na pozycji podanej w rejestrze B
(1...5).
– adres wywołania: 025Fh
– we: DPTR – liczba do wyświetlenia, B – numer pozycji na wyświet−
laczu (1...5)
– wy: wyświetla na 4 pozycjach 16–bitowa liczbę z DPTR
– traci: R0, A i B
– przykład:
MOV DPTR,#1998h
;wyświetl aktualny rok
MOV B, #3
;od 3–ciego wyświetlacza
LCALL DPTR4HEX
;wywołanie podprogramu
;po wykonaiu na DL3–4–5–6 będzie
wyświetlony;rok z DPTR
CLS (0274h)
– czyści całe pole wyswietlacza (wstawia spacje na pozycje DL1...8)
– adres wywołania: 0274h
– we: bez parametrów
– wy: czyści wyswietlacz
– traci: R0 i R7 z aktualnie ustawionego zbioru
– przykład:
LCALL CLS
;wyczyszczenie wyświetlacza
Sławomir Surowiński
E LEKTRONIKA DLA WSZYSTKICH 2/98
39
1128249.001.png
Zgłoś jeśli naruszono regulamin