Mikrokontrolery cz13.pdf

(310 KB) Pobierz
1128252 UNPDF
Też to potrafisz
Dzisiejszy odcinek klasy mikroprocesorowej
to pierwsze „po okrągłym roku” spotkanie
z Wami. Tak moi drodzy, spotykamy się już
tak długo. Jak wynika z listów które otrzymu−
ję od Was, materiał z 12−tu miesięczników,
średnio po 10 stron co daj ponad 100 stron
materiałów, większości z Was wystarczył aby
do tej pory pochwalić się pierwszymi prosty−
mi, aczkolwiek funkcjonalnymi programikami
na 8051. Mniej więcej połowa jednak ma na−
dal pewne problemy, bądź to z pisaniem lis−
tingów, bądź ich kompilacją (roczniacy) lub
nawet z poprawnym uruchomieniem kompu−
terka edukacyjnego który opisałem 9 m−cy te−
mu na łamach EdW. Podejrzewam, że gdy−
byśmy wszyscy spotykali się w jednej sali
(tak jak w szkole) na zajęciach z programowa−
nia, wszyscy z pewnością byliby zadowoleni.
Musimy zdać sobie jednak sprawę, że nauka
programowania mikrokontrolerów (nie tylko
8051) jest tematem dość złożonym, i wyma−
ga nie tylko cierpliwości, lecz także nieco wy−
siłku w samodzielnym myśleniu i sięganiu po
dodatkową literaturę związaną nie tylko z te−
matem mikroprocesorów, ale i techniką cyf−
rową w szczególności.
Namawiam więc wszystkich, was drodzy
Czytelnicy do korzystania takiego sposobu
nauki, w którym przewodnikiem może być
publikowany w EdW cykl, który opracowuję
co miesiąc specjalnie dla Was.
A tak na marginesie mam nadzieję, że 13−ty
odcinek szkoły mikroprocesorowej nie będzie
pechowy, i tym optymistycznym akcentem
zapraszam więc do lektury.
Mikrokontrolery?
To takie proste...
Część 13
Układ przerwań i układ czasowo−licznikowy
W poprzednim odcinku w praktyczny sposób omówiłem port szere−
gowy mikrokomputera 8051 oraz sposoby transmisji danych poparte
prostymi listingami.
Dzisiaj przypomnimy sobie wiadomości na temat omawianych
wcześniej układów czasowo−licznikowych oraz układu przerwań proce−
sora. Teraz kiedy zapoznaliście się z językiem procesora, będzie mi łat−
wiej pokazać w praktycznych przykładach sposób obsługi przerwań
i liczników mikrokontrolera.
Układ przerwań
W jednym z pierwszych odcinków szkoły mikroprocesorowej, przy
okazji omawiania końcówek mikroprocesora, podałem przykład – po−
równanie systemu przerwań mikroprocesora do sytuacji z życia co−
dziennego. Wspominałem że sama nazwa „przerwanie” doskonale od−
zwierciedla sposób i znaczenie tego układu dla pracy całego mikropro−
cesora. Jeżeli nie pamiętasz, z czym się „je” temat układu przerwań, ra−
dzę przypomnieć sobie ten artykuł. Przejdźmy zatem do konkretów.
W układzie mikrokontrolera 8051 istnieje kilka źródeł przerwań.
„Źródeł”, czyli dosłownie mówiąc podukładów mikroprocesora, które
mogą generować przerwania. I tak np. weźmy omawiany w poprzed−
nim odcinku port szeregowy. Opisywałem, jak w prosty sposób można
np. odebrać znak z portu szeregowego. Pamiętasz, że podałem dwa
przykłady. Pierwszy – mniej doskonały polegał na ciągłym sprawdzaniu
flagi RI – odbioru znaku, i jeżeli stwierdzaliśmy, że flaga ta została przez
procesor ustawiona, to znaczy że odebrano znak, który znajduje się
w rejestrze SBUF i jest gotowy do odczytania. Wadą tego sposobu był
fakt niekończącego oczekiwania na nadejście bajtu danych z urządzenia
zewnętrznego dołączonego do portu szeregowego. Procesor po prostu
nie robił nic innego jak tylko czekał na przyjęcie znaku z portu.
Drugi sposób wprowadzał tzw. błąd przeterminowania, kiedy to np.
przy braku nadejścia znaku z portu szeregowego, procesor po określo−
nym w programie przez nas) czasie przerywał wykonywanie procedury
czekania na znak z UART−a, i powracał do programu głównego sygnali−
zując błąd przeterminowania.
A gdyby tak w pewnych przypadkach dało się uniezależnić odbiór
znaków portu szeregowego (szczególnie wtedy gdy nadchodzą one
w nieokreślonych przedziałach czasowych) od wykonywania pętli głów−
nej programu?
Otóż tu z pomocą może przyjść system przerwań mikrokontrolera.
Ano wyobraźmy sobie sytuację, kiedy program główny wykonuje pew−
ne określone przez nas czynności, natomiast port szeregowy jest usta−
wiony w taki sposób, że w momencie kiedy zostaje odebrany znak
z UART u, procesor automatycznie przerywa wykonywanie programu
i wykonuje skok do tzw. „procedury (podprogramu) obsługi przerwania
z portu szeregowego”. Po wykonaniu tej procedury – napisanej oczy−
wiście przez programistę i kończącej się instrukcją
RETI
program powraca do kolejnej instrukcji pętli głównej która następuje po
tej przy której nastąpiło przerwanie.
A co się dzieje w podprogramie obsługi przerwania? Co nam przyj−
dzie do głowy, czyli przede wszystkim przepisanie danej z rejestru
SBUF do innego rejestru, z obszary wewnętrznej pamięci danych pro−
cesora, aby nie stracić cennego znaku, kiedy przyjdzie następny (i SBUF
zostanie ponownie zmieniony).
To tylko ilustracja wykorzystania systemu przerwań do wspomożenia
pracy programu mikroprocesora.
Przejdźmy jednak od szczegółowego omówienia źródeł wszystkich
przerwań w mikrokontrolerze 8051 i sposobów ich wykorzystania w na−
szych programach.
Układ przerwań procesora może przyjmować zgłoszenia następują−
cych przerwań:
– zewnętrzne: z wejść /INT0 i /INT1 (piny P3.2 – 12, P3.3 – 13) (2 prze−
rwania)
– z portu szeregowego (jedno przerwanie)
– z układu licznikowego: przepełnienie licznika T0, lub T1 oraz w przy−
padku procesora 80C52 – z układu licznikowego T2 (dwa przerwania
dla 8051)
Zanim przejdziemy do omówienia każdego ze źródeł przerwań powin−
niśmy sobie uzmysłowić fakt istnienia tzw. znaczników każdego z prze−
rwań. Znacznik fizycznie jest pojedynczym bitem zawartym w kilku re−
jestrach SFR procesora. W przypadku początkowym znacznik danego
przerwania jest wyzerowany – do bitu wpisane jest zero. W przypadku
ustawienia znacznika przerwania (wpisania do niego jedynki) następuje
zgłoszenie przerwania. Wyzerowania znacznika to anulowanie zgłosze−
nia. Każde z wymienionych przerwań posiada własny znacznik zgłosze−
nia przerwania. Znaczniki przerwań są ustawiane automatycznie przez
procesor w momencie wystąpienia warunku nadejścia przerwania, i tak
dla poszczególnych źródeł będą to:
– /INT0, /INT1 : opadające zbocze sygnału na tym wejściu (lub poziom
niski)
– zakończenie odbioru lub nadawania znaku przez UART
– przepełnienie licznika T0 lub T1 (zmiana zawartości z 0FFFF na
0000h)
E LEKTRONIKA DLA WSZYSTKICH 5/98
37
1128252.013.png
Też to potrafisz
Ponieważ jednocześnie w programie może pracować kilka układów
generujących przerwania, a same przerwania czasem nie są nam po−
trzebne, istnieje specjalny rejestr w obszarze SFR o nazwie IE (ang.
„Interrupt Enable” – zezwolenie na przerwanie), dzięki któremu może−
my uaktywniać lub blokować generowanie wybranych przerwań. Po−
szczególne bity tego rejestru odpowiadają za generowanie przerwania
od określonego podbloku mikrokontrolera, a dodatkowo najstarszy bit
tego rejestru pozwala na bezwarunkowe wyłączenie systemu prze−
rwań. Bity te często nazywa się maskującymi, co w praktyce oznacza,
że wpisanie do niego jedynki powoduje uaktywnienie danej funkcji bi−
tu, wyzerowanie zaś – to zablokowanie.
Oto rejestr IE (adres w SFR A8h) i znaczenie jego poszczególnych bi−
tów:
I tak ze względu na to że mamy w procesorze 8051 pięć (w 8052
sześć) źródeł przerwań, każde z nich posiada odpowiedni priorytet, i tak
w kolejności od najmniejszego priorytetu do największego jest:
ET2, ES, ET1, EX1, ET0, EX0, czyli
najmniej uprzywilejowanym jest przerwanie od licznika T2 (w 8052), da−
lej w kolejności (jak w rejestrze IE) większy priorytet ma przerwanie
z portu szeregowego UART, dalej od licznika T1, z wejścia INT1, wresz−
cie od licznika T0, a najbardziej uprzywilejowanym jest przerwanie z we−
jścia /INT0.
Ktoś zapyta, a co się stanie, jeżeli nadchodzi przerwanie np. z wejścia
INT1 i rozpoczęte zostaje wykonywanie procedury obsługi przerwania
dla tego wejścia, a w czasie jej trwania nadchodzi przerwanie o wy−
ższym priorytecie np. z wejścia INT0?. A no wtedy procedura obsługi
przerwania z INT1 zostaje natychmiast przerwana i procesor skacze do
procedury obsługi przerwania z wejścia INT0. Kiedy ją skończy, powra−
ca (skacze) do miejsca skąd nastąpił skok gdy nadeszło przerwanie
o wyższym priorytecie i program toczy się dalej, prawda że logiczne roz−
wiązanie. Jak nad tym wszystkim zapanować tak, aby program nie
„poszedł w maliny”, opowiem za chwilę.
„...No dobrze, już wiem, o co chodzi z tym priorytetem przerwań, ale
przecież może zajść przypadek, kiedy mam taki układ elektroniczny,
w którym zastosowany procesor musi wykorzystywać przerwania z nie−
co inną kolejnością priorytetów, i co wtedy? Czy jestem skazany na
ustaloną kolejność priorytetów przerwań? Odpowiedź brzmi nie. Otóż
istnieje dodatkowy specjalny rejestr tzw. priorytetów przerwań o na−
zwie IP (ang. „Interrupt Priority” – priorytet przerwania). Znajduje się on
pod adresem B8h jak się zapewne domyślasz w obszarze SFR proce−
sora.Dzięki niemu można zmieniać priorytety poszczególnych prze−
rwań wymienionych wcześniej, powodując że dane przerwanie mające
dotąd niższy priorytet może uzyskać wyższy, dzięki odpowiedniemu
ustawieniu bitów w rejestrze priorytetu IP. Oto szczegółowe znaczenie
poszczególnych bitów tego rejestru:
EA (bit IE.7, adres: AFh) – bit aktywacyjny systemu przerwań (=0
wszystkie przerwania są zablokowane, =1 odblokowane są te przerwa−
nia, których bit jest ustawiony)
bit IE.6 o adresie AEh jest nie wykorzystany
ET2 (bit IE.5, adres: ADh) – tylko w 80C52 (8052) bit maskujący prze−
rwanie z licznika T2
ES (bit IE.4, adres: ACh) – bit maskujący przerwanie z portu szeregowego
ET1 (bit IE.3, adres: ABh) – bit maskujący przerwanie z licznika T1
EX1 (bit IE.2, adres: AAh) – bit maskujący przerwanie z wejścia /INT1
ET0 (bit IE.1, adres: A9h) – bit maskujący przerwanie z licznika T0
EX0 (bit IE.0, adres: A8h) – bit maskujący przerwanie z wejścia /INT0
Czyli jeżeli np. chcemy uaktywnić przerwanie z wejścia zewnętrzne−
go INT1, należy wykonać instrukcje:
SETB EX1 ;uaktywnienie przerwania z INT1
SETB EA ;globalne odblokowanie przerwań
W przypadku chęci uaktywnienia kilku przerwań np. z licznika T0
i układu transmisji szeregowej UART, można wykonać następujące ope−
racje:
SETB ET0 ;uaktywnienie przerwania od T0
SETB ES ; uaktywnienie przerwania od UART a
SETB EA ;globalne odblokowanie przerwań
Ponieważ wszystkie bity maskujące przerwania znajdują się w jed−
nym rejestrze, można w/w instrukcje zapisać jako jedną:
MOV IE, #10010010b
prawda, że proste. W praktyce jeżeli chcemy np. na jakiś czas wyłączyć
jakieś przerwanie np. od licznika T0 wystarczy wykonać instrukcję:
CLR ET0 ;zablokowanie przerwania od T0
Jeżeli zaś zachodzi potrzeba zablokowania całego systemu przerwań
można tego dokonać wyzerowując bit EA za pomocą instrukcji :
CLR
bity IP.7 i IP.6 – nie wykorzystane
PT2 (bit IP.5, adres: BDh) – bit priorytetu przerwania z licznika T2 (tylko
w 80C52,8052
PS (bit IP.4, adres: BCh) – bit priorytetu przerwania z portu szeregowego.
PT1 (bit IP.3, adres BBh) – bit priorytetu przerwania z licznika T1
PX1 (bit IP.2, adres BAh) – bit priorytetu przerwania z wejścia /INT1
PT1 (bit IP.3, adres BBh) – bit priorytetu przerwania z licznika T1
PX1 (bit IP.2, adres BAh) – bit priorytetu przerwania z wejścia /INT1
PT0 (bit IP.1, adres B9h) – bit priorytetu przerwania z licznika T0
PX0 (bit IP.0, adres B8h) – bit priorytetu przerwania z wejścia /INT0
EA
I tak ustawienie jednego z bitów powoduje ustawienie danego prze−
rwania na wyższym poziomie i odwrotnie, wyzerowanie danego bitu
powoduje ustawienie niższego priorytetu danego przerwania. W przy−
padku kiedy ustawimy wyższy priorytet kilku przerwań na raz, o kolej−
ności wykonywania poszczególnych procedur obsługi przerwań decy−
duje ustalona wcześniej kolejność dla przypadku kiedy wszystkie bitu
rejestru IP są równe 0. Warto zatem powiedzieć sobie, że podprogram
(procedura) obsługi przerwania z umieszczonego na najwyższym pozio−
mie jest nieprzerywalna. W przypadku np. kiedy IP=0, będzie to prze−
rwanie z wejścia /INT0.
Po resecie procesora podobnie jak w przypadku rejestru IE, wszyst−
kie bity rejestru IP są wyzerowane (IP=0).
“...No dobrze ale co fizycznie zachodzi, kiedy nadchodzi przerwanie,
i o co chodzi z tą procedura obsługi przerwania? Oto wyjaśnienie.
Otóż kiedy zajdzie warunek przerwania (kiedy znacznik danego prze−
rwania zostaje ustawiony), np. kiedy nadejdzie zbocze opadające na
wejściu /INT1, przy ustawionym bicie EX1 oraz uaktywnionym syste−
mie przerwań (EA=1) procesor wykona następujące operacje
– po pierwsze: sprawdzi czy nie jest wykonywana akurat procedura
obsługi przerwania o wyższym priorytecie lub czy jednocześnie nie
nadeszło przerwanie o wyższym priorytecie z innego źródła
– po drugie (jeżeli nie zdarzy się warunek z pierwszego): wyzeruje
znacznik zgłoszenia przyjętego przerwania.I tu wyjątek, nie są bo−
wiem automatycznie zerowane znaczniki przerwań: z portu szerego−
wego TI – przy wysłaniu znaku, RI – przy nadejściu znaku, oraz z licz−
nika T2 w przypadku procesora 8052/C52.
– po trzecie: procesor zapisze na stosie zawartość 16−bitowego liczni−
ka rozkazów PC
– i po czwarte : procesor automatycznie wpisze do licznika rozka−
zów PC ustalony fabrycznie adres początku programu (procedury)
obsługi danego przerwania, oto te adresy dla poszczególnych
przerwań:
lub
ANL IE, #7Fh ;7Fh = 01111111b
Ten pierwszy sposób, kiedy operujemy na bitach jest bardziej czytel−
ny, dlatego polecam go w praktyce.
Ważną informacją jest fakt, że po resecie procesora rejestr IE jest wy−
zerowany, co oznacza że wszystkie przerwania są zablokowane (EA=0)
oraz dodatkowo maski wszystkich przerwań są także zablokowane (IE.5
– IE.0 = 0).
Ze względu na fakt że przerwania nie są przeważnie generowane roz−
myślnie poprzez instrukcje programisty (a jak?... to proste przecież po−
przez ustawienie jednego ze znaczników przerwań – o tym za chwilę)
ale przez podbloki wykonawcze procesora, zatem może się zdarzyć sy−
tuacja, kiedy to w jednej chwili nadejdą dwa lub więcej przerwania – np.
w tej samej chwili na wejściu INT1 pojawi się stan niski (generując prze−
rwanie od /INT1) oraz przepełni się licznik T0 (generując przerwanie od
T0), i co wtedy, czy nie nastąpi zatem jakiś konflikt? Otóż nie. Okazuje
się bowiem, że projektanci mikrokontrolerów 8051 i pochodnych po−
myśleli o takiej sytuacji i ustalili, że każde przerwanie procesor posiada
odpowiedni priorytet. To bardzo ważne słowo i dlatego warto je dobrze
zapamiętać.
Priorytet danego przerwania nad innym, w praktyce to znaczy, że
w przypadku kiedy zajdzie przypadek jak przedstawiony powyżej, kiedy
w jednej chwili zachodzą dwa różne przerwania, to w pierwszej kolej−
ności zostanie przyjęte przerwanie o wyższym priorytecie i wykonana
zostanie stosowna dla niego procedura obsługi przerwania (czyli nic in−
nego jak kawałek napisanego przez ciebie programu zakończony in−
strukcją RETI).Przerwanie drugie – o niższym priorytecie będzie jak
gdyby „czekać na swoją kolej”, a kiedy ta przyjdzie, zostanie ono przy−
jęte i wykonana zostanie procedura obsługi tegoż drugiego przerwania
(także zakończona instrukcją RETI).
38
E LEKTRONIKA DLA WSZYSTKICH 5/98
1128252.014.png 1128252.015.png 1128252.016.png
 
Też to potrafisz
0003h – dla przerwania z wejścia /INT0
000Bh – dla przerwania z licznika T0
0013h – dla przerwania z wejścia /INT1
001Bh – dla przerwania z licznika T1
0023h – dla przerwania z portu szeregowego
oraz dodatkowo w procesorach 8052/C52
002Bh – dla przerwania z licznika T2
z przerwań do miejsc w programie gdzie rozpoczynają się właściwe
procedury ich obsługi.
W praktyce w zależności od rozmiarów kodu programu można użyć
także instrukcji AJMP ale tylko kiedy wszystkie podprogramy znajdują
się w pierwszych 2 kilobajtach kodu programu (czyli o adresach:
0000h....07FFh). Można także umieszczać podprogramy obsługi prze−
rwań w różnych miejscach pamięci programu w stosunku do pętli głów−
nej np. przed nią (w naszym przykładzie przed etykieta START). Czasa−
mi, w przypadku kiedy rozmiar dostępnej pamięci programu jest dość
krytyczny – (brakuje nam pamięci) aby nie marnować drogocennych baj−
tów, można także zrezygnować ze skoku typu LJMP, i rozpocząć proce−
durę obsługi przerwania od adresu z tabeli wektorów przerwań. Oczy−
wiście dotyczy to przypadku, kiedy wspomniane przerwanie albo jest
jedyne w uaktywnionych w systemie, albo jest na ostatnim miejscu
w tabeli wektorów przerwań. W przypadku naszego przykładu listing
mógłby wyglądać następująco:
Jak zauważyliście, przytoczone adresy są ustalone fabrycznie a odda−
lone od siebie dokładnie o 4 bajty. Dlaczego akurat o cztery, zaraz się
okaże. W każdym razie zanim to wyjaśnię, spróbuję oswoić Was przy
tej okazji z określeniem takiej struktury adresów, które obowiązuje nie
tylko w nazewnictwie związanym z 8051, ale wszystkimi układami mik−
roprocesorowymi, a mianowicie nazwą: tablicy wektorów przerwań.
Tablicy – bo poszczególne adresy oddalone dodatkowo równo od sie−
bie (o 4 bajty) mogą kojarzyć się z tablicą
Wektorów – bo ze względu na tylko 4 bajty przeznaczone na podpro−
gram, fizycznie nie zapiszemy w tym miejscu podprogramu, a jedynie
wpiszemy wskaźnik (wektor) pokazujący gdzie w programie (pod jakim
adresem) znajduje się właściwa procedura obsługi danego przerwania.
Przerwań – bo oczywiście cały zwrot dotyczy przerwań.
„...Co oznaczają te adresy, i jak je wykorzystać?” Otóż jak zapewne
pamiętacie po resecie procesora licznik rozkazów jest wyzerowany, co
oznacza że procesor rozpoczyna wykonywanie programu od adresu
0000h.
Z drugiej strony zauważcie, że pomiędzy adresem 0000h a adresami
procedur obsługi przerwań znajdują się zawsze 4 bajty na... program,
czy to aby nie za mało? Otóż nie!
Istnieje przecież w liście rozkazów mikrokontrolera 8051 instrukcja
skoku bezwzględnego pod wskazany adres. Jest to LJMP, czasem
AJMP (SJMP)
Aby zbytnio nie namieszać Wam w głowach posłużę się przykładem.
Załóżmy że chcemy napisać program, w którym wykorzystamy dwa
źródła przerwań: pierwsze z wejścia /INT0 drugie z licznika T1.
Generalnie zatem program będzie składał się z:
– instrukcji pętli głównej programu
– oraz dwóch procedur (podprogramów) obsługi przerwań: pierwsza
dla wejścia /INT0, druga dla licznika T1. Podprogramy z reguły są cią−
giem minimum kilku instrukcji, które przecież nie zmieszczą się
w 4 bajtach! Użyjemy więc wektorów „przekierowujących” program
z tablicy wektorów przerwań do właściwego miejsca w programie
gdzie znajduje się właściwy dla danego przerwania podprogram.
;początek programu
ORG
0000h ;początek wykonywania programu
LJMP
START ;skocz do etykiety początku programu
;głównego
;tablica wektorów przerwań
ORG
0003h ;pod adresem 0003h umieszczam
LJMP
intEX0 ;wektor – czyli instrukcję skoku do
;procedury intEX0
ORG
001Bh ;a tu zaczyna się procedura obsługi
;przer. od T1
intT1:
...........
;instrukcje dotyczące
...........
;procedury w przypadku
...........
;nadejścia przerwania z T1
reti
;właściwy początek pętli głównej programu
START:
..................
;instrukcje inicjujące (początkowe)
SETB
EX0
;uaktywnienie przerwania z /INT0
SETB
ET1
;uaktywnienie przerwania z T1
SETB
EA
;globalne odblokowanie przerwań
...........
;inne instrukcje pętli głównej
...........
...........
;tu początek podprogramu obsługi przerwania z /INT0
intEX0:
...........
Przykładowy listing takiego programu mógłby wyglądać następująco:
;początek programu
ORG
;instrukcje dotyczące
...........
;procedury w przypadku
0000h ;początek wykonywania programu
...........
;nadejścia przerwania z /INT0
LJMP
START ;skocz do etykiety początku programu
;głównego
reti
END
;koniec programu
;tablica wektorów przerwań
ORG 0003h ;pod adresem 0003h umieszczam
LJMP intEX0 ;wektor – czyli instrukcję skoku do
;procedury intEX0
ORG 001Bh ;a pod adresem 001Bh umieszczam
LJMP intT1 ;wektor do procedury obsługi
;przerwania od T1
;właściwy początek pętli głównej programu
START:
..................
;instrukcje inicjujące (początkowe)
Oczywiście w zasadzie etykieta intT1 jest w tym przypadku zbędna,
informuje jedynie o tym że w tym miejscu zaczyna się procedura obsłu−
gi przerwania od licznika T1.
Można by oczywiście przerzucić procedurę intEX0 w miejsce pomię−
dzy instrukcję kończąca procedurę intT1 a etykietę START, w praktyce
najczęściej nie ma to żadnego znaczenia.
Program obsługi przerwania musi być zakończony instrukcją RETI. Do
tej instrukcji nie zostanie przyjęte zgłoszenie żadnego przerwania z po−
ziomu równego (tego samego) lub niższego. Wreszcie kiedy procesor
wykona instrukcję kończącą podprogram przerwania (RETI) odtwarzany
jest ze stosu adres powrotu sprzed wywołania i wpisany do licznika roz−
kazów PC procesora, po czym program główny toczy się dalej.
SETB
EX0
;uaktywnienie przerwania z /INT0
SETB
ET1
;uaktywnienie przerwania z T1
SETB
EA
;globalne odblokowanie przerwań
...........
;inne instrukcje pętli głównej
...........
...........
;tu początek podprogramu obsługi przerwania z /INT0
intEX0:
...........
Jeżeli chodzi o znaczniki zgłoszenia przerwań to można je „wyłowić”
z wkładki z EdW nr 11/97, gdzie znajduje się skrócony opis wszystkich
rejestrów SFR procesora. Oto one:
a) z wejścia /INT0: bit IT0 (adres: 88h) w rejestrze TCON (88h)
b) z wejścia /INT1: bit IT1 (adres: 8Ah) w rejestrze TCON (88h)
c) z licznika T0: bit TF0 (adres: 8Dh) w rejestrze TCON (88h)
d) z licznika T1: bit TF1 (adres: 8Fh) w rejestrze TCON (88h)
e) z portu szeregowego: bit TI w przypadku nadania znaku (adres: 99h)
oraz bit RI w przypadku odbioru znaku z portu (adres: 98h) z rejestru
SCON (98h)
f) z licznika T2: bit TF2 (adres: CFh) – dla przepełnienia licznika T2 oraz
bit EXF2 (adres: CEh) – przy wykryciu opadającego zbocza sygnału
na tym wejściu (P1.1 w 8052/C52), oba znaczniki z rejestru sterują−
cego praca licznika T2 – T2CON (C8h).
Ponieważ sprawą układu czasowo−licznikowego zajmę się w drugiej
części artykułu, pozostaje mi do omówienia kilka dodatkowych informa−
cji dotyczących obsługi i generowania przerwań zewnętrznych z wejść
/INT0 i /INT1.
;instrukcje dotyczące
...........
;procedury w przypadku
...........
;nadejścia przerwania z /INT0
reti
intT1:
...........
;instrukcje dotyczące
...........
;procedury w przypadku
...........
;nadejścia przerwania z T1
reti
END
;koniec programu
Tak więc jak widać z przytoczonego listingu w tablicy wektorów prze−
rwań umieszczone zostały jedynie skoki bezwzględne dla każdego
E LEKTRONIKA DLA WSZYSTKICH 5/98
39
1128252.001.png
Też to potrafisz
I tak na wstępie ważna informacja: przerwania te mogą być zgłasza−
ne opadającym zboczem sygnału na tym wejściu (zmiana z poziomu lo−
gicznego H na L) lub poziomem niskim sygnału. Wybór należy do pro−
gramisty i może być zmieniany za pomocą odpowiedniego rejestru, ale
o tym za chwilę.
W praktyce różnica pomiędzy tymi dwoma typami zgłaszania prze−
rwań polega na tym, że:
– w przypadku zgłoszenia przerwania opadającym zboczem: procedu−
ra zostanie wywołana tylko jeden raz, nawet jeżeli pierwsze jej wy−
wołanie zostanie zakończone (instrukcja RETI) a stan na wejściu
/INTx po jej zakończeniu nadal jest niski.
– w przypadku zgłoszenia przerwania poziomem niskim: poziom na
wejściu /INTx powinien zmienić się znowu na wysoki przed zakoń−
czeniem procedury obsługi przerwania (przed instrukcją RETI)
w przeciwnym przypadku procedura obsługi zostanie wywołana po−
nownie.
A oto wspomniany rejestr kontrolujący przerwania zewnętrzne:
TCON (adres: 88h). Starsze 4 bity z tego rejestru obsługują układy cza−
sowo licznikowe, toteż omówieniem ich zajmę się za chwilę.
Wyobraźmy sobie sytuację, kiedy to procesor spokojnie i „sielan−
kowo” wykonuje napisany przez ciebie program główny i np. w tej
chwili próbuje dodać dwie liczby znajdujące się w rejestrach A i B, po
czym będzie chciał wypisać je na wyświetlaczu naszego komputerka
edukacyjnego korzystając ze standardowej procedury A2HEX (dla
uproszczenia przyjmujemy wypisanie wyniku bez najstarszego bitu wy−
niku umieszczonego w C).
Aby to wykonać zapewne posłuży się instrukcjami:
MOV A, #składnik1
;załadowanie składnika
(1)
ADD A, #składnik2
;i dodanie składnika 2
(2)
MOV B, #1
;na 1−szej pozycji
(3)
LCALL A2HEX
;wypisz zawartość Acc
(4)
.........
;i rób cos dalej
(5)
W nawiasach podano numery linii.
Popatrzmy, niech no wykonane zostaną instrukcje z linii (1) i (2) oraz
(3), w tym momencie, przed wykonaniem linii (4), kiedy wypisany zosta−
je wynik, następuje zgłoszenie jakiegoś przerwania (obojętne jakiego)
o program automatycznie skacze do odpowiedniego wskaźnika z tabli−
cy wektorów przerwań, a z tamtą prawdopodobnie w inne miejscy pro−
gramu, gdzie znajduje się właściwa dla danego zdarzenia procedura ob−
sługi przerwania.
Dla przykładu powiedzmy, że procedura ta wykonuje pewne oblicze−
nia i operacje na rejestrach, w tym m.in. na akumulatorze, np.
intT2:
MOV A, LICZNIK
ADD A, #1
DA A
MOV LICZNIK, A
RETI
Bity dotyczące wejść /INT0 i /INT1 procesora:
IE1 (bit TCON.3, adres: 8Bh) – znacznik zgłoszenia przerwania na wejs−
ciu /INT1. Jest ustawiany sprzętowo po wykryciu zgłoszenia. Zerowany
automatycznie przy przyjęciu przerwania (przy wejściu do procedury ob−
sługi)
IT1 (bit TCON.2, adres: 8Ah) – bit sterujący sposobem zgłoszenia prze−
rwania na wejściu /INT1: opadającym zboczem (IT1=1) lub poziomem
niskim (IT1=0) sygnału zewnętrznego
IE0 (bit TCON.1, adres: 89h) – znacznik zgłoszenia przerwania na wejs−
ciu /INT0. Jest ustawiany sprzętowo po wykryciu zgłoszenia. Zerowany
automatycznie przy przyjęciu przerwania (przy wejściu do procedury ob−
sługi)
IT0 (bit TCON.0, adres: 88h) – bit sterujący sposobem zgłoszenia prze−
rwania na wejściu /INT0: opadającym zboczem (IT0=1) lub poziomem
niskim (IT0=0) sygnału zewnętrznego
No dobrze, po zgłoszeniu przerwania i wykonaniu instrukcji zawar−
tych w procedurze procesor po wykonaniu instrukcji RETI powróci do
linii (4) programu głównego i.... no właśnie, wypisana zostanie nie war−
tość sumy dwóch składników, ale zawartość jakiegoś rejestru LICZNIK
(zdefiniowanego gdzieś wcześniej w programie przez programistę).
W efekcie wyświetlacz pokaże bzdury, a my nie będziemy wiedzieli co
się stało.
Takich sytuacji może być bardzo wiele. Jak zatem w prosty sposób
można się zabezpieczyć przed skutkami modyfikacji rejestrów podczas
wykonywania pojawiających się często „nie stąd ni z owąd” procedur
obsługujących przerwania? Metoda jest bardzo prosta i polega na zapa−
miętywaniu wartości używanych w danej procedurze rejestrów na po−
czątku tej procedury, po czym przed końcem procedury obsługi prze−
rwania – odtworzenie ich pierwotnej zawartości i wykonaniu standardo−
wej już instrukcji powrotu z przerwania RETI.
Najprostszym i zdecydowanie polecanym, a praktycznie jedynym
sensownym sposobem zapamiętywania i odtwarzania rejestrów jest
korzystanie ze stosu.
Oto poprzedni przykład zmodyfikowany w sposób zabezpieczający
zawartość akumulatora przed przypadkową utrata bieżącej „wartości”,
intT2:
PUSH Acc
Analizując sposób zgłaszania przerwań zewnętrznych nie sposób nie
powiedzieć w jaki sposób fizycznie procesor rejestruje zajście zgłosze−
nia przerwania. Czy np. wejścia /INTx mają na wejściu jakieś przerzut−
niki? Otóż nie. Procesor w pewnych okresach każdego cyklu maszyno−
wego próbkuje stan wejść /INTx, i jeżeli w dwóch kolejnych cyklach
stwierdzi zmianę stanu z 1 na 0 oznaczało to będzie że nastąpił waru−
nek zgłoszenia przerwania. Dokładne zależności czasowe pomiędzy fi−
zyczną zmianą poziomu na wejściu przerywającym /INTx a zgłoszeniem
przerwania można znaleźć w katalogach procesorów 8051 różnych pro−
ducentów (Philips, Atmel, itp.)
Ponieważ w praktyce rzadko zachodzi potrzeba takiej analizy, nadmie−
nię, żeby wobec braku sprzętowych „przerzutników rejestrujących”
opadające zbocza na wejściach /INTx, każdy z sygnałów przerywających
(generowanych na końcówkach /INTx) trwał co najmniej przez 12 tak−
tów zegarowych procesora.
W praktyce oznacza to, że np. w przypadku procesora pracującego
z kwarcem 12MHz najkrótsza jedynka i zero generowana na tym we−
jściu (przez układ zewnętrzny) wystarczająca jednakże do wywołania
przerwania w programie procesora, powinna trwać nie mniej niż 1 us
(mikrosekundę – każdy poziom)
W sumie wyszło nam, że można już łapać ujemne impulsy o czasie
trwania 1 us (poziom niski).
Z pewnością niektórzy z czytelników odwrócą sytuację i stwierdzą, że
przerwanie /INTx można teoretycznie generować przy takim kwarcu
prawie 500 000 razy na sekundę (500kHz), tylko po co?
Zresztą gdyby ktoś np. uaktywnił przerwanie np. /INT0 i do tego we−
jścia /INT0 dołączyć generator przebiegu TTL o takiej częstotliwości, to
program procesora w praktyce „zwariowałby”, bowiem co chwilę wy−
woływana był procedura obsługi przerwania z INT0, i nic innego w pro−
gramie nie byłoby wykonywane. Dlatego pamiętając o tym należy roz−
sądnie wybierać zastosowania układu przerwań zewnętrznych pamięta−
jąc także o występujących tu ograniczeniach.
Na koniec omawiania układu przerwań nie można zapomnieć o prak−
tycznej wskazówce dotyczącej pisania procedur obsługi przerwań. I tak
przypomnijmy sobie stwierdzenie, mówiące że procedura obsługi prze−
rwania rozpoczyna się w chwili nadejścia przerwania. Ponieważ gene−
rowanie przerwania zazwyczaj zależy od mniej lub bardziej złożonych
czynników zewnętrznych, i nie jest z reguły przewidywalne w progra−
mie, może nastąpić sytuacja tzw. gubienia zawartości rejestrów robo−
czych (np. akumulatora) po wykonaniu procedury obsługi przerwania.
;zapamiętanie akumulatora
MOV A, LICZNIK
ADD A, #1
DA A
MOV LICZNIK, A
POP Acc
;odtworzenie akumulatora
RETI
Jak widać stos w tym przypadku oddał nam niesamowitą przysługę,
bowiem za pomocą jednej instrukcji odłożenia na stos a następnie zdję−
cia nie zakłóciliśmy toku wykonywania części głównej programu – aku−
mulator pozostał ten sam, a wynik na wyświetlaczu będzie z pewnoś−
cią poprawny.
Ktoś może w tym miejscu powiedzieć, że przecież można by podzie−
lić używane rejestry (w końcu w procesorze jest ich dużo...) na dwie
grupy w tym przypadku, jedna byłaby modyfikowana w programie
głównym, a druga wykorzystywana by była tylko w procedurze obsługi
przerwania. Gdyby dało się tak zrobić w praktyce, byłoby wspaniale,
rzeczywistość jest jednak nieco mniej różowa. Co zrobić bowiem z re−
jestrami uniwersalnymi np. jednostki arytmetyczno – logicznej ALU?
Przecież jest tylko jeden rejestr Acc oraz np. rejestr B (nie mówiąc
o wskaźniku danych DPTR).
Odpowiedź jest jedna: używać stosu.
W przypadku gdy w procedurze obsługi przerwania modyfikowanych
jest więcej niż jeden rejestr, należy „odkładać je” i „zdejmować” ze
stosu w sposób zgodny z zasadą działania samego stosu, a mianowicie,
„to co pierwsze odłożyliśmy to ostatnie zdejmujemy”, czyli np. jeżeli
w naszym przykładzie procedury intT2 zaprzęgniemy dodatkowy re−
jestr, prawidłowa kolejność instrukcji będzie następująca.
40
E LEKTRONIKA DLA WSZYSTKICH 5/98
1128252.002.png 1128252.003.png
Też to potrafisz
Też to potrafisz
intT2:
PUSH Acc
;zapamiętanie akumulatora
w systemie. W przypadku używania np. wszystkich czterech banków
oraz dodatkowo korzystania ze stosu (choć w ograniczonym zakresie)
w procedurach obsługi przerwań, na początku programu należy wyko−
nać instrukcję:
MOV SP, #1Fh ;przesunięcie wskaźnika stosu
co spowoduje że żaden z 32 rejestrów roboczych (4 banki po
8 – R0...R7) nie zostanie zamazany w przypadku odłożenia jakiejś
zmiennej w procedurze obsługi przerwania.
Oczywiście używanie pojęcia banków oraz takiej architektury rejest−
rów roboczych nie jest wymagane, można przecież adresować każdy
z nich (32) bezpośrednio za pomocą odpowiednich instrukcji MOV, np.
MOV adres, #dana
gdzie adres jest z zakresu <0...31>.
Korzystanie z systemu banków rejestrów roboczych powoduje jed−
nak, że listing programu, jest bardziej czytelny, a jego późniejsza anali−
za przez programiste szybsza.
PUSH B
;zapamiętanie rejestru B
MOV A, LICZNIK1
ADD A, #1
DA A
MOV B, #3
MUL AB
MOV LICZNIK1, A
MOV LICZNIK2, B
POP B
;odtworzenie rejestru B
POP Acc
;odtworzenie akumulatora
RETI
Przy okazji omawiania systemu przerwań nie sposób nie wspomnieć
o dwóch głównych, często popełnianych błędach początkujący progra−
mistów podczas pisania pierwszych programów wyposażonych w pro−
cedur obsługi jednego lub kilku przerwań.
Pierwszy błąd polega na wykorzystywaniu zbyt dużej liczby rejestrów
w procedurze obsługi przerwania, a co za tym idzie konieczności odkła−
dania na stos zbyt dużej liczby danych. W efekcie często (szczególnie
w przypadkach kiedy pracują więcej niż jeden źródła przerwań) stos zo−
staje przepełniony – tzn. że wskaźnik stosu zostaje zwiększony do war−
tości pod którą w pamięci wewnętrznej RAM programista zaplanował
mniej lub bardziej ważne (ale ważne i przewidziane w programie!)
zmienne programowe. W takim przypadku zmienne te zostaną z pew−
nością zamazane, i nasz program będzie do niczego. O tym jakie są spo−
soby omijania takich przypadków, opowiem za chwilę.
Drugi błąd polega na tym że programista tworzy „zbyt długi” kod pro−
cedury obsługi przerwania. Przecież każda instrukcja zajmuje proceso−
rowi określoną ilość czasu! W efekcie np. w sytuacji kiedy przerwanie
zewnętrzne (lub z przepełnienia licznika) nadchodzi odpowiednio często
– czyli w określonych przedziałach czasu, może dojść do sytuacji, kiedy
to w trakcie trwania nie zakończonej jeszcze procedury obsługi prze−
rwania zajdzie ponowny warunek zgłoszenia przerwania. W większości
takich przypadków procesor po prostu „zwariuje” a cały program albo
się zawiesi, albo pójdzie w przysłowiowe „maliny”.
Unikajmy więc takich przypadków, i piszmy procedury obsługi prze−
rwań w taki sposób aby nie powodować krytycznych błędów czaso−
wych, a przynajmniej zabezpieczajmy się przed nimi.
Oczywiście nie w każdym przypadku obowiązuje zasada pisania krót−
kich procedur obsługi przerwań. Bywają przypadki (z doświadczenia po−
wiem Wam że należy do nich kompleksowa procedura obsługi sygnału
DCF77 i dekodowanie aktualnych danych o dacie i czasie), kiedy proce−
dura jest na pierwszy rzut oka dość długa. Lecz sposób jej działania oraz
maksymalny czas niezależnie od cyklu, jest przemyślany w taki sposób,
aby pozostawić bezpieczny margines czasowy i co najważniejsze dać
czas procesorowi także na wykonywanie procedur obsługi innych prze−
rwań, a co najważniejsze, na wykonanie instrukcji części głównej pro−
gramu. Wszystko to w warunkach kiedy mamy do czynienia z małymi
wartościami częstotliwości pracy procesora przy dość często zachodzą−
cy przerwaniach tak zewnętrznych jak i wewnętrznych.
Na koniec omawiania systemu przerwań warto wspomnieć o przewi−
dzianym w zasadzie do obsługi podprogramów przerwań systemie blo−
ków rejestrów roboczych : R0, R1, R2...R7. I tak w przestrzeni adreso−
wej wewnętrznej RAM procesora (adresy 0...127) w pierwszych 32 re−
jestrach (adresy: 0...31) przewidziano cztery „banki” rejestrów R0...R7.
Dostęp do nich za pomocą operowania instrukcjami wykorzystującymi
nazwy rejestrów roboczych R0...R7, jest możliwy za pomocą odpo−
wiedniego ustawienia dwóch bitów w omawianym już w naszym cyklu
słowie PSW (ang. „Program Status Word”, SFR adres: D0h). Są to bity
RS0 (adres: D3h) i RS1 (adres: D4h). I tak w zależności od kombinacji
tych bitów uzyskujemy dostęp poprzez nazwy robocze R0...R7 do na−
stępujących rejestrów w wewn. RAM procesora:
Układy czasowo−licznikowe
W procesorze 8051/C51 mamy do dyspozycji 2 takie układy (T0 i T1),
a w kości 8052/C52 dodatkowo trzeci (T2). To, czym dokładnie są ukła−
dy czasowo−licznikowe, dowiedzieliście się drodzy Czytelnicy z jednego
z wcześniejszych odcinków klasy mikroprocesorowej. Zamieszczone
tam informacje były jednak (przy braku znajomości języka asemblera
8051) dość teoretyczne. Warto jest jednak je sobie odświeżyć przed
lekturą niniejszego paragrafu.
Teraz kiedy opanowaliśmy (choć może nie wszyscy w takim samym
stopniu) sztukę bodaj prostego programowania procesora, będzie mi
łatwiej zilustrować podane wcześniej wiadomości i sprowadzić je do
czystej praktyki, wspartej jednak krótkimi, lecz niezbędnymi informacja−
mi na temat układów czasowo licznikowych.
Z układami czasowo licznikowymi procesora 8051 związane są nie−
rozłącznie dwa rejestry specjalne: TCON i TMOD
Rejestr TMOD określa tryby pracy układu czasowo licznikowego – za−
równo dla T0 jak i T1. Rejestr ten nie jest adresowany bitowo. Wszyst−
kie bity rejestru TMOD moga być zmieniane wyłącznie programowo
czyli przez użytkownika.
Połowa rejestru (młodsze 4 bity) określa parametry układu licznika T0,
natomiast 4 starsze bity określają to samo lecz dla układu licznikowego
T1. Z tego względu przy opisie będę kierował się tylko jednym z liczni−
ków.
GATE – bit uaktywnienia zewnętrznego bramkowania licznika Tx
(x=0,1). Kiedy GATE=0 to licznik pracuje wtedy kiedy bit TRx w słowie
TCON jest ustawiony. Kiedy GATE=1 to licznik pracuje gdy TRx = 1 oraz
wejście INTx (x:1 to INT1, x:0, to INT0) jest w stanie wysokim (INTx=1).
C/T – bit określający funkcję jaka pełni podczas pracy dany układ liczni−
kowy, i tak gdy bit =0 to układ pracuje jako czasomierz taktowany we−
wnętrznym sygnałem zegarowym o częstotliwości Fxtal / 12. Gdy zaś
bit = 1, to układ pracuje jako licznika impulsów zewnętrznych z wejścia
Tx (T1 lub T0). Temat maksymalnej częstotliwości zliczanych impulsów
zewnętrznych poruszany był w części 5 szkoły mikroprocesorowej.
M1, M0 – bity określające wybór trybu pracy układu czasowo−liczniko−
wego, i tak:
Zajmiemy się teraz rejestrem TCON, w którym 4 najstarsze bity są
bezpośrednio powiązane z układami czasowo licznikowymi procesora.
Oto on.
W przypadku korzystania z tej cechy adresowania rejestrów robo−
czych procesora, należy pamiętać o odpowiednim przesunięciu wskaź−
nika stosu (który na początku po resecie procesora zawsze wskazuje na
adres 07h) w zależności od ilości wykorzystywanych banków rejestrów
R0...R7, która to ilość często wiąże się z ilością używanych przerwań
TF1 (bit TCON.7, adres: 8Fh) – znacznik przepełnienia licznika T1, jest
sygnałem zgłoszenia przerwania. Ustawiany jest automatycznie –
sprzętowo, zerowany także automatycznie przy przyjęciu przerwania.
E LEKTRONIKA DLA WSZYSTKICH 5/98
41
1128252.004.png 1128252.005.png 1128252.006.png 1128252.007.png 1128252.008.png 1128252.009.png 1128252.010.png 1128252.011.png 1128252.012.png
 
Zgłoś jeśli naruszono regulamin