Optmalizacja pod względem czasu

background image

http://www.easy-soft.tsnet.pl/

Programowanie zoptymalizowane pod względem

wykorzystania czasu procesora

1. Wstęp.

W artykule chcę przedstawić moje sposoby na programowanie mikrokontrolerów

jednoukladowych (8051, PIC i podobne) w języku asemblera - ze szczególnym

zwróceniem uwagi na jak najmniejsze obciążenie procesora przez dużą liczbę

podprogramów (współdzielenie czasu procesora). Takie podejście sprawia, że układ

mikroprocesorowy staje się jakby układem wielozadaniowym, a przy okazji zostaje

zminimalizowane niebezpieczeństwo zawieszania się programów i utknięcia całości w

martwym punkcie. Z pewnością wiele z przedstawionych poniżej sposobów i sposobików

będzie Wam znanych, część być może bedzie nowych - generalnie chodzi jednak o

całościowe uświadomienie sobie takiej koncepcji programowania tak, aby później można

ją było świadomie stosować w praktyce (programowanie: od koncepcji do realizacji).

Opisane tu sposoby będą przydatne zwłaszcza przy pisaniu większych programów, gdzie

się "wiecej dzieje jednocześnie", ale mogą być również stosowane przy prostszych

programach. Tyle tytułem wstępu - chciałbym jednocześnie zachęcić wszystkich

programujących do opisywania własnych sposobów na programowanie - zwłaszcza o

opisy koncepcji, podejścia do problemu i jego rozwiązania, bo dostępne jest mnóstwo

przykładów, fragmentów procedur, etc ,etc, ale brak jest bardziej ogólnych zasad

programowania, a wydaje mi się że zapotrzebowanie na tego rodzaju literaturę jest

bardzo duże.

2. Uświadomienie sobie problemu to już połowa sukcesu.

Przeważnie piszący programy skupiają się na sposobie rozwiązania problemu - jak

najprościej (jeśli nie "jak w ogóle") napisać programik, który będzie realizował

przewidziane przez nich zadanie. Jest to podejście słuszne, aczkolwiek "mikroskopowe".

Trochę na zasadzie: " bierze się procedurę obsługi I2C, do tego dodaje obsługę

klawiatury, wyświetlacza LCD, łączy sie razem i mamy programik". Potrzebne jest

również myślenie "makroskopowe", które będzie nadrzędne, będzie obejmowało całość

koncepcji programu. Jednym słowem - planowanie. Oczywiście ma to szczególnie sens

przy większych programach, gdzie łatwo się jest pogubić w gąszczu procedurek, etykiet,

skoków, itp...

Częstokroć skupiając się na problemie bieżącym zapominamy o całości programu i o tym

jaki wpływ na pozostałe procedury i programy bedzie miala opracowywana przez nas

procedura. W skrajnym przypadku może to prowadzić do powstania sytuacji, kiedy

napisane przez nas programy - każdy oddzielnie, działają prawidłowo, ale kiedy

połączymy je wszystkie razem, to okazuje się, ze wzajemnie zakłócaja sobie pracę. W

rezultacie program nie działa albo działa "skokowo", gubiąc po drodze dane. Jak temu

przeciwdziałać - poniżej.

- strona 1/11 -

background image

http://www.easy-soft.tsnet.pl/

3. Wizualizacja koncepcji działania procesora. Martwe pętle.

Dla ułatwienia zrozumienia działania procesora przygotowałem przykład opisowy - tzw.

"przedstawienie łopatologiczne".

Jednym z głównych zadań jakie wykonuje procesor jest tzw. pętla główna. Wyobraźmy ją

sobie jako dośc duży, kwadratowy pokój. Pośrodku pokoju stoi człowieczek, który jest

odpowiednikiem bieżącego procesu wykonywanego przez procesor.

Na początku naszych rozważań nasza pętla głowna jest pusta:

petla_glowna:

nop

goto petla_glowna

Wlączamy zasilanie procesora - teraz nasz czlowieczek zaczyna chodzic sobie wokól

pokoju zupelnie nic nie wykonując - po prostu chodzi w kólko.

Aby dać mu jakieś zajęcie wprowadzamy do akcji podprogramy. Wyobraźmy je sobie

jako pokoje umieszczone wokól naszego głownego pomieszczenia. Nasz czlowieczek

idąc wokół scian, gdy napotyka pokój, wchodzi do niego i wykonuje znalezione tam przez

niego zadanie. Po czym wraca do pokoju głownego, idzie dalej wzdłóż sciany, do

nastepnego pokoju i wykonuje następne zadanie....I tak dalej w kółko...

petla_glowna:

podprogram_1

podprogram_2

podprogram_3

podprogram_4

...

podprogram_n

goto petla_glowna

Na razie sytuacja jest prosta, ale jak to w życiu bywa, zaczynaja sie utrudnienia.:-))

Okazuje się bowiem, że nie zawsze jest możliwa natychmiastowa realizacja zadania

przez procesor (czyli naszego czlowieczka). Nie dowieźli danych i nasz człowieczek musi

czekać na nie ;-). Siada więc sobie gdzieś na krzeselku albo chodzi w kólko po pokoiku

podprogamu.

Wyglada to tak:

petla_glowna:

podprogram_1

podprogram_2

podprogram_3

podprogram_4

...

podprogram_n

goto petla_glowna

podprogram_1:

sprawdz_czy_sa_dane

jesli_nie - goto podprogram_1

jesli_tak - wykonaj podprogram

- strona 2/11 -

background image

http://www.easy-soft.tsnet.pl/

i powroc z podprogramu

Jak widzimy nasz czlowieczek uzależniony jest od przeplywu danych, musi siedzieć w

pokoiku i czekać na nie.

A przecież ma do wykonania prace takze w innych pokojach. Może akurat w ktorymś z

nich są juz wszystkie potrzebne dane, a on siedząc tutaj marnuje tylko czas, podczas gdy

moglby wykonać inne zadania.

I tu dochodzimy do własciwego problemu. Sa to wlaśnie tzw. martwe petle podczas

ktorych procesor testuje jakis warunek i czekajac na niego nie wykonuje nic wiecej.

Wprowadzmy wiec usprawnienie. Nasz czlowieczek po wejsciu do kazdego pokoju

bedzie sprawdzal czy sa dla niego dane - jesli beda - wykona zadanie, jesli zas nie -

opusci on pokoj i pojdzie sprawdzac nastepne pokoje. Jesli w ktorymś z nich bedą dane,

bedzie wykonywał swoje tam zadanie.

Tak to wyglada w praktyce:

petla_glowna:

podprogram_1

podprogram_2

podprogram_3

podprogram_4

...

podprogram_n

goto petla_glowna

podprogram_1:

sprawdz_czy_sa_dane

jesli_nie - wyskocz z podprogramu

jesli_tak - wykonaj podprogram

i powroc z podprogramu

W ten sposób nie mamy blokady podprogamów w oczekiwaniu na dane... Nawet gdyby

z jakiś powodów dana ta nie nadeszła nigdy, to program nie zawiesi się w martwej pętli -

pozostałe podprogramy będą się dalej wykonywać bez zakłoceń.

Oczywiście - bywają pewne krytyczne czasowo operacje, które muszą zangażowac całą

moc obliczeniowa procesora, gdyż obsługa w tym czasie innych zadań spowodowałaby

utratę części danych. W tej sytuacji rozsądnym rozwiązaniem tego problemu jest

wykorzystanie przerwań - zwłaszcza gdy dane przychodzą zupelnie asynchroniczne.

- strona 3/11 -

background image

http://www.easy-soft.tsnet.pl/

4.

Przekazywanie informacji przez

flagi.

Najprostszym sposobem na sygnalizacje czy wazne dane nadeszly sa flagi. Flaga jest

bitem, ktorego ustawienie lub wyzerowanie informuje procesor o stanie danych. W

postaci programu wyglada to nastepująco:

podprogram_1:

sprawdz_czy_flaga_ustawiona

jesli_nie - wyskocz z podprogramu

jesli_tak - wykonaj podprogram

i powroc z podprogramu

Flaga moze byc ustawiana przez inny podprogram (ten ktory zbiera dla nas dane), jak i

przez nasz wykonawczy podprogram (gdy np. chcemy zasygnalizowac innym

podprogramom, ze wykorzystalismy juz dane i moga one ladowac następną porcję)

podprogram_1:

sprawdz_czy_flaga_ustawiona

jesli_nie - wyskocz z podprogramu

jesli_tak - wykonaj podprogram

zeruj_flage

i powroc z podprogramu

podprogram_2:

sprawdz_czy_flaga_wyzerowana

jesli_nie - wyskocz z podprogramu

jesli_tak - pobierz_dane_i_umiesc_je_w_zmiennych

ustaw_flage

i powroc z podprogramu

W ten sposob jak widzimy następuje dwustronna wymiana informacji pomiedzy

podprogramami - jednocześnie są one na tyle niezależne, że nawet w przypadku blędu

(brak w doplywie nowych danych do programu 2) nie następuje zawieszenie pracy

programu głównego (tak czy tak podprogram zawsze wyskakuje). To pozwala na np.

stworzenie dodatkowego podprogramu monitorujacego, ktory w przypadku wystąpienia

błedu - przywraca normalną pracę systemu (reset programowy - czyszczenie zmiennych,

ponowna inicjalizacja otoczenia, itp)

Flagi mogą być sprawdzane, ustawiane, bądź zerowane przez kilka programów jeśli

korzystają one z tych samych danych.

Czasami zdarza się, że chcielibyśmy mieć kontrolę nad wykonywaniem sie pewnych

podprogramów w odniesieniu do innych

podprogramów. Np. taka sytuacja: jeśli wykonuje sie poprogram nr 1, to w tym czasie

nie powinien sie wykonywać podprogram nr 2, bo oba korzystaja ze wspolnych

zmiennych i moga wystąpic błedy. Taka sytuacja zdarza sie w momencie kiedy jeden z

podprogramów wykonuje się w pętli głównej, a drugi w przerwaniu. Podczas obsługi

przerwania, program z pętli głownej zostaje przerwany "w trakcie" i jest wykonywany

program z przerwania. Jesli istnieje niebezpieczenstwo zamazania danych przez

program z przerwania, nalezy również uzyć flag dla zasygnalizowania tego faktu.

- strona 4/11 -

background image

http://www.easy-soft.tsnet.pl/

podprogram_2: ; wykonywany w pętli głównej

ustaw_flage_wykonywania_programu

wykonaj_podprogram

wyzeruj_flage_wykonywania_programu

i powroc z podprogramu

podprogram_3: ; wykonywany w przerwaniu

sprawdz_czy_flaga_wykonywania_podprogramu_2_ustawiona

jesli_tak - wyskocz z podprogramu

jesli_nie - wykonaj podprogram

i powroc z podprogramu

W ten sposób jeden podprogram jest zsynchronizowany z drugim - sa wzajemnie

powiazane i nie nastapi nigdy "zderzenie danych".

Za pomoca flag mozna też przekazywac programom informacje o upływie czasu - są to

tzw. znaczniki czasowe.

Zasada jest prosta - jeden z programów (najczęściej jest to program obsługi przerwania,

wywoływany cyklicznie co określony odcinek czasu) po obliczeniu zadanego odcinka czasu

ustawia flage informującą pozostałe programy, ze "czas upłynął".

Podprogram z pętli głównej, testuje cały czas tą flagę i gdy wykryje jej ustawienie -

wykonuje określoną sekwencję działan.

Oto przykład:

podprogram_1: ; wykonywany w przerwaniu

sprawdz_czy_uplynal_zadany_czas

jesli_nie - wyskocz z podprogramu

jesli_tak - ustaw flage TimeOn

i powroc z podprogramu

podprogram_2: ; wykonywany w pętli głównej

sprawdz_flage_TimeOn

jesli nie ustawiona - wyskocz z podprogramu

jesli ustawiona - wykonaj_podprogram i wyzeruj_flage

i powroc z podprogramu

W ten sposob nasz podprogram z pętli głownej wykonuje się np. co 1s, zamiast

wielokrotnie szybciej - nie obciąża to nadmiernie procesora i pozwala na wykonywanie

innych podprogramów w tym czasie. Tego typu zwolnione wykonywanie się programów

ma sens w przypadku np.odczytu pomiarow, gdy nie zalezy nam na duzej ilosci próbek/s

- zwlaszcza gdy do tego dochodzą opóźnienia związane z czasem konwersji wyników

przez urządzenia zewnętrzne.

- strona 5/11 -

background image

http://www.easy-soft.tsnet.pl/

5.

Przekazywanie informacji przez zmienne.

Podział podprogramów na stany.

Flagi ze wzgledu na swoja jednobitowość nadaja się do sygnalizacji sytuacji

dwustanowych - na zasadzie "jest albo nie ma".

Czasami potrzebujemy zasygnalizowac więcej stanów - wowczas z pomocą przyjdą nam

zmienne.

W jednym bajcie mozemy przekazać do 256 stanów, a więc w wiekszości przypadków to

wystarcza ;-))

Tu trzeba zrobić rozróżnienie tzw. zmiennych sterujacych procesami, od zmienych

przekazujacych bezposrednie dane - np. o temperaturze otoczenia.

Odpowiednia budowa podprogramów pozwala na zbudowanie pewnych zespołów

decyzyjnych - sterujących wykonaniem podprogramu w zależności od wartości zmiennej

sterujacej. Innymi słowy podprogram składa się z kilku-kilkunastu ścieżek wykonania a

wybór konkretnej z nich zalezy od wartości naszej zmiennej sterujacej.

Taki podzial podprogramów na kilka-kilkanascie sekcji ułatwia programowanie ze wzgledu

na pewną modularność programu, przyporzadkowanie sciezek programu róznym

sytuacjom w systemie i wreszczie - co najwazniejsze - pozwala na dokonywanie

wstrzyman dzialania podprogramu wewnatrz niego bez stosowania martwych petli.

Nasz podprogram zostaje jakby "zamrozony" w jednym ze stanów (wskazywanym przez

nasza zmienna sterującą) na dowolnie dlugi czas - w tym czasie moze on czekać na

pojawienie sie danych, skonczenie wykonywania innego programu, czy inna sytuacje ...

Jednoczesnie nie jest wstrzymywana praca procesora - caly czas przeskakuje on od

jednego podprogramu do drugiego - wykonujac powierzone mu zadania.

Ale oto przyklad programu:

podprogram_1:

sprawdz_wartosc_zmiennej_sterujacej

jesli_wartosc =0 skocz do etykiety 'sciezka_0'

jesli_wartosc =1 skocz do etykiety 'sciezka_1'

jesli_wartosc =2 skocz do etykiety 'sciezka_2'

jesli_wartosc =n skocz do etykiety 'sciezka_n'

sciezka_0:

sprawdz_czy sa_dane

jesli nie - wyskocz z podprogramu (ew. skok do etykiety wspolne)

jesli tak - pobierz dane

ustaw zmienna_sterujaca_na_1

wyskocz_z_podprogramu

sciezka_1:

wykonaj_dzialanie_zwiazane_z_obrobka_danych

ustaw zmienna_sterujaca_na_2

wyskocz_z_podprogramu (ew. skok do etykiety wspolne)

sciezka_2:

sprawdz_czy_mozna_dokonywać_opracji_zapisu

jesli nie - wyskocz z podprogramu (ew. skok do etykiety wspolne)

jesli tak - zapisz dane

ustaw zmienna_sterujaca_na_n

wyskocz_z_podprogramu

...

sciezka_n:

- strona 6/11 -

background image

http://www.easy-soft.tsnet.pl/

wykonaj_dzialanie_tej_sciezki

...

ustaw zmienna_sterujaca_na_0 ; tu wracamy do stanu poczatkowego podprogramu

wyskocz_z_podprogramu

wspolne:

i powroc z podprogramu

Napisany w ten sposób podprogram wywolywany cyklicznie w pętli, bedzie kolejno

przechodzil wszystkie swoje stany w kazdym bedąc tak dlugo jak to potrzebne, a

jednocześnie nie bedzie martwego oczekiwania na dane.

Jak widzimy, podprogram w kazdym ze swoich stanow dokonuje modyfikacji zmiennej

sterujacej - moze to byc inkrementacja,

dekrementacja, wpisanie bezposredniej wartosci, skoki po kilka stanów naraz. To

pozwala na duza elastycznosc naszego podprogramu. W pewnym sensie jest to

samomodyfikacja programu, choc wykonana w sposob dozwolony (w przeciwienstwie do

modyfikacji kodu programu w pamieci).

W przerwach na oczekiwanie na dane procesor moze wykonywac obsluge innych

programow nie tracac przy tym kontroli nad bieząco wykonywanym podprogramem.

Jednoczesnie w kadej chwili mozemy stwierdzic na jakim etapie wykonywania jest nasz

podprogram - wystarczy sprawdzic zmienna sterujaca.

Ale pojdzmy jeszcze dalej - ten popdprogram bedzie sie wykonywal cyklicznie, po kolei

przechodzac swoje stany od 0 do n i tak w kółko. Czasami jednak chcemy, aby

podprogram wykonywal sie tylko raz (podobnie jak to ma miejsce w przypadku zwyklych

podprogramów). Dodajmy wiec zatem jeszcze jeden stan - stan spoczynkowy w ktorym

nasz podprogram mimo, ze wywolywany cyklicznie - nie wykonuje nic. Bedzie to

wygladac nastepująco:

podprogram_1:

sprawdz_wartosc_zmiennej_sterujacej

jesli_wartosc =0 skocz do etykiety 'sciezka_0'

jesli_wartosc =1 skocz do etykiety 'sciezka_1'

jesli_wartosc =2 skocz do etykiety 'sciezka_2'

jesli_wartosc =3 skocz do etykiety 'sciezka_3'

jesli_wartosc =n skocz do etykiety 'sciezka_n'

sciezka_0:

wyskocz z podprogramu (ew. skok do etykiety wspolne)

sciezka_1:

sprawdz_czy sa_dane

jesli nie - wyskocz z podprogramu (ew. skok do etykiety wspolne)

jesli tak - pobierz dane

ustaw zmienna_sterujaca_na_1

wyskocz_z_podprogramu

sciezka_2:

wykonaj_dzialanie_zwiazane_z_obrobka_danych

ustaw zmienna_sterujaca_na_2

wyskocz_z_podprogramu (ew. skok do etykiety wspolne)

- strona 7/11 -

background image

http://www.easy-soft.tsnet.pl/

sciezka_3:

sprawdz_czy_mozna_dokonywać_opracji_zapisu

jesli nie - wyskocz z podprogramu (ew. skok do etykiety wspolne)

jesli tak - zapisz dane

ustaw zmienna_sterujaca_na_n

wyskocz_z_podprogramu

...

sciezka_n:

wykonaj_dzialanie_tej_sciezki

...

ustaw zmienna_sterujaca_na_0 ; tu wracamy do stanu poczatkowego podprogramu

wyskocz_z_podprogramu

wspolne:

i powroc z podprogramu

W tej sytuacji - po jednorazowym przejsciu przez wszystkie stany nasz podprogram

zatrzymuje sie w stanie 0, gdzie praktycznie nic nie robi (obciazajac przy tym minimalnie

procesor). Jedynym sposobem wyrwania go z tego stanu jest ustawienie naszej

zmiennej sterujacej na wartosc 1 (albo tez i inna różną od 0, bo mozemy skakac do

dowolnego fragmentu naszego podprogramu). W ten sposob dowolny inny program moze

wyzwalac nasz podprogram ustawiajac tylko wartosc zmienej sterujacej. Po

jednorazowym wyzwoleniu naszego podprogramu zaczyna on juz jakby samodzielnie

"żyć", az do jego pelnego wykonania - mozna to porównac do lawiny kamieni poruszonej

rzutem jednego kamienia.

Jest to bardzo wygodne np. przy obsludze klawiatury i wyzwalanych przez nacisnięcie

klawiszy działaniach - we fragmencie odpowiadajacym danemu klawiszowi wpisujemy

tylko wartośc jaka ma przyjąć nasz zmienna sterująca i gotowe :-))

Dodatkową korzyscia (i czesto koniecznoscia) bedzie fakt możności sprawdzenia czy nasz

podprogram nie jest juz w stanie "wyzwolonym". Wystarczy sprawdzić znienną sterującą

- jesli jest rózna od zera, nasz podprogram jest w trakcie wykonywania się.

6. Zasady dzielenia podprogramów na stany

Każdy z fragmentów podprogramu odpowiadający jednemu ze stanów na jakie dzielimy

nasz program powinien spełniać pewne kryteria - tak żeby ten podział mial sens.

Po pierwsze - jeśli w podprogramie ma występować odwoływanie się do sprzętu, układów

zewnętrznych (np. zewnętrzne pamięci EEPROM) itp, to kolejne stany powinny być tak

zorganizowane, aby podczas każdego z nich następowało tylko jedno odwołanie do

układów zewnętrznych - tak aby okres oczekiwania na dane przypadał na czas pomiędzy

stanami (inicjalizacja transmisji w jednym stanie/.wyskok ze stanu /odczyt danych w

następnym stanie).

Po drugie - jeśli nasz program jest dość skomplikowany, zawiera wiele instrukcji, etc ,etc

- należy starać się aby zostały one podzielone na kilka fragmentów o zbliżonym czasie

wykonania, tak aby uniknąć spiętrzania się obciążenia procesora w jednym ze stanów

podczas gdy w innych obciążenie to będzie bardzo małe. Generalnie należy dążyć, aby

- strona 8/11 -

background image

http://www.easy-soft.tsnet.pl/

stany były dość krótkie czasowo - to umożliwi dostęp do procesora innym podprogramom

(ich stanom).

Przy odwoływaniu się do układów zewnętrznych, przy różnego rodzaju transmisjach

występują pewne sekcje krytyczne, które muszą sie wykonywać w pewnym, ściśle

określonym czasie - zakłócenie tego czasu spowoduje błąd transmisji.

Natomiast pomiędzy tymi sekcjami mogą występować przerwy - zazwyczaj o dowolnie

długim czasie trwania, bez obaw o zakłócenie transmisji.. W zależności od rodzaju

protokolu przerwy te mogą występować pomiedzy pojedyńczymi bitami danych,

pomiędzy bajtami lub większymi zespołami bitów. To doskonale nadaje się do

wykorzystania w naszych programach dzielonych na stany - w jednym ze stanów

wykonujemy sekcje krytyczną dostępu do danych (1bit, bajt lub wiecej bitów), pomiedzy

nimi - wyskakujemy ze stanu i mogą się wykonywać inne podprogramy, a następnie

wchodzimy w następny stan, gdzie wykonuje się następna sekcja krytyczna... itd, itd...

W ten sposób transmisja danych, mimo, że stosunkowo wolna w porównaniu z szybkością

wykonywania instrukcji procesora nie zwalnia działania procesora, nie ma zadnych

wstrzymań na czas transmisji danych (z wyjątkiem sekcji krytycznych) - dzieje się ona

jakby "w tle", "w wolnych chwilach procesora"...:-))

W ten sposób mozna w jednym układzie połączyć np. obsługę transmisji I2C, RS232, 1-

wire, obsługe przetwarzania a/c, klawiatury, wyświetlacza, beeper'a i jeszcze kilku innych

urządzeń i transmisji, a mimo to nie następuje żadne zazębianie się tych programów - z

punktu widzenia obserwatora wykonują się one jakby równocześnie.

7. Praktyczne przykłady programów

Oto przykłady praktyczne realizacji w/w sposobu programowania - w języku ASM dla

procesorów 8051 i PIC

Prosze zwrócić uwagę na jedną rzecz - jesli procedurę naszą wywolujemy poleceniem

CALL, to wówczas każda ze ścieżek musi się kończyc poleceniem RET (RETURN). Jeśli

natomiast naszą procedure wywołujemy poleceniem GOTO (SJMP), to każda ze scieżek

musi się kończyć również GOTO (SJMP).

Procedury te mozemy stosowac zarówno w pętli głownej jak i w przerwaniach - przy

przerwaniach powrotem z procedury bedzie oczywiscie rozkaz RETI :-))

a) Dla procesorów z rodziny MCS51

;----------------------------------------------------------------------------

TimeKeeper

; przykładowa nazwa naszej procedury

;----------------------------------------------------------------------------

mov dptr,#poczatek_tablicy_skokow

; ładujemy adres tablicy

mov a,zmienna_sterujaca

; pobieramy naszą zmienna sterującą do ACC

clr c

; zerowanie Carry

rlc a

; mnozymy zmienna sterujaca przez 2 bo rozkazy sjmp sa dwubajtowe

jmp @a+dptr

; skok do adresu w tablicy wskazywanego przez zmienna

sterującą

;----------------------------------------------------------------------------

poczatek_tablicy_skokow:

; tablica rozkazów koków

sjmp sciezka_1

; rozkazy skoków do różnych ścieżek działań

- strona 9/11 -

background image

http://www.easy-soft.tsnet.pl/

sjmp sciezka_2

sjmp sciezka_3

sjmp sciezka_n

;----------------------------------------------------------------------------

sciezka_1:

; sciezka dzialania nr 1

nop

; tutaj mamy ciało procedury

inc zmienna_sterujaca

; następna ścieżka w następnym przebiegu procedury

ret lub sjmp ciag_dalszy

;----------------------------------------------------------------------------

sciezka_2:

; sciezka dzialania nr 2

nop

; tutaj mamy ciało procedury

inc zmienna_sterujaca

; następna ścieżka w następnym przebiegu procedury

ret lub sjmp ciag_dalszy

;----------------------------------------------------------------------------

sciezka_3:

; sciezka dzialania nr 3

nop

; tutaj mamy ciało procedury

inc zmienna_sterujaca

; następna ścieżka w następnym przebiegu procedury

ret lub sjmp ciag_dalszy

;----------------------------------------------------------------------------

sciezka_n:

; sciezka dzialania nr n

nop

; tutaj mamy ciało procedury

mov zmienna_sterujaca,#0

; wracamy do pierwszej scieżki w następnym

przebiegu procedury

ret lub sjmp ciag_dalszy

;----------------------------------------------------------------------------

ciag_dalszy:

; częsc wspólna - jeśli scieżki mają sie znowu polączyć

ret, reti lub sjmp

b) Dla procesorów rodziny PIC (konkretnie PIC 16F877)

;----------------------------------------------------------------------------

TimeKeeper

; obsluga zegara czasu rzeczywistego - Maszyna stanow

;----------------------------------------------------------------------------

movlw HIGH(TKZwrotn)

; pobranie PCH adresu spod labelu TKZwrotn

movwf PCLATH

; zaladowanie PCLATH (=PCH) ta wartoscia

movfw TimeState

; pobranie zmiennej sterującej do W

andlw B'00000111'

; zabezp indeksu przed przekroczeniem 8

addlw D'3'

; dodanie przeskoku o 3 rozkazy (do poczatku tablicy)

addwf PCL,W

; suma PCL i rej indeksowego w W

TKZwrotn

skpnc

; spr. czy nie przekroczylismy FF

incf PCLATH,F

; jesli tak, zwieksz PCH (za pomoca PCLATCH) o 1

movwf PCL

; zaladowanie PCL suma (skok)

;---------------------------------------------------------------------

-----

goto TK_idle

; State=0

- strona 10/11 -

background image

http://www.easy-soft.tsnet.pl/

;-------inicjalizacja ukladu zegara

goto DS1307_init

; State=1

;-------odczyt czasu z zegara

goto DS1307_set_adres

; State=2

goto DS1307_read_time

; State=3

;-------zapis czasu do zegara

goto DS1307_write_time

; State=4

;---------------------------------------------------------------------------

goto TK_idle

; State=5

goto TK_idle

; State=6

goto TK_idle

; State=7

;**********************************************************************

******

TK_idle ; stan idle procedury

;---------------------------------------------------------------------------

clrf TimeState

; zerowanie zmiennej sterującej

return

itd....dalsze podprogramy :-))

8. Zakończenie.

Programy tego typu mozna dosyć rozbudowywać, chociaż w praktyce nie zdarzyło mi się

wyjść poza kilkanascie stanów zmiennej sterującej dla jednego podprogramu.

Dzieląc w ten sposob kilka, czy kilkanaście swoich podprogramów mamy pewność, że

będą się one wykonywać niemalże równolegle, wzajemnie przeplatąjac swoje stany i nie

nastąpi blokowanie jednego podprogramu przez drugi.

Oczywiście - nie wszystkie programy dadzą się zaprogramować w w/w sposób - to już

wymaga indywidualnego rozpatrzenia sytuacji.

Jacek Domański

(Jado)

- strona 11/11 -


Wyszukiwarka

Podobne podstrony:
Prace niebezpieczne pod względem pożarowym, Straż pożarna, Zagrożenia Pozarowo Wybuchowe
ZASADY UZGADNIANIA PROJEKTÓW BUDOWLANYCH POD WZGLĘDEM PPOŻ
porównanie pod względem etycznym korupcji i lobbingu ELFEJ3LXOIT5QCMEB2L5AFJDSBXOB7B26KRJTXA
raporty, Bimetal, Bimetal - trwale połączone na całej powierzchni styku elementy z dwóch różnych pod
PRZEGLĄDY I POMIARY ŚRODOWISKA PRACY POD WZGLĘDEM BHP
agro, Analiza porównawcza dwóch gmin pod względem wysokości bazy noclegowej ze szczególnym uwzględni
mikrobiologia-1kolos, Pożywką nazywamy zestaw składników pokarmowych odpowiednio dobranych pod wzglę
Kto odpowiada za zabezpieczenie obiektu pod względem PPOŻ, Studia, BUDOWNICTWO
KLASYFIKACJA POD WZGLĘDEM RYZYKA SPÓŁEK NOTOWANYCH NA GIEŁDZIE
REDUTA ORDONA ANALIZA TEKSTU POD WZGLEDEM CHARAKTERYSTYKI BOHATERÓW
10 Przygotowanie produkcji pod wzgledem BHP
Formularz oceny pod wzgledem bhp i ergonomii stanowisk pracy biurowej
NOWE Wymagania zdrowotne dla wody do spozycia pod wzgledem chemicznym - 30 04 2009, Ratownictwo medy
PODZIAŁ LEKÓW DZIAŁAJĄCYCH NA OŚRODKOWY UKŁAD NERWOWY POD WZGLĘDEM CHEMICZNYM, ZDROWIE, FARMAKOLOGIA
PODZIAŁ MATERIAŁÓW NIEBEZPIECZNYCH POD WZGLĘDEM RODZAJU ZAGROŻENIA, Pierwsza pomoc
ROZP. MZ WS WYMAGAN POD WZGLEDEM FACHOWYM I SANITARNYM, szkoła, prawo

więcej podobnych podstron