Sterowanie portami Amigi

Otrzymałem wiele listów dotyczących sterowania urządzeniami podłączonymi do portów Amigi. W większości wypadków chodzi o sterowania kilkoma urządzeniami z portu PAR. Na początek opiszę budowę portu PAR, sposób podłączenia do niego urządzeń oraz przykładowe programy w kilku językach sterujące portem. W następnej kolejności opiszę praktyczne urządzenia podłączone do portu wraz z programem je obsługującym. Jeśli temat wzbudzi zainteresowanie pojawi się opis sterowania przez port SER.

Artykuł (mam nadzieję że cykl artykułów) rozpocznę od rzeczy trochę nudnych, ale bardzo przydatnych. Omówię budowę wewnętrzną portu 8520 zastosowanego w Amidze, a właściwie sposobu sterowania pojedyńczą linią. Na


przedstawiono schemat wewnętrzny bufora portu równoległego. Jego budowa jest podobna do budowy portu pseudo-dwukierunkowego stosowanego w procesorach 8051 czy porcie PCF8574. Gdy port pracuje jako wejście, tranyzstory wyjściowe są w stanie odcięcia. Linia wejściowa portu jest podciągana do +5V rezystorem 3kohm. Gdy port pracuje jako wyjście przewodzi jeden z tranzystorów wymuszając stan niski lub wysoki. Dopuszczalne jest jednak, przy pracy jako wyjście, wymuszenie na linii stanu niskiego. Popłynie wtedy większy prąd, który jednak nie uszkodzi tranzystora wyjściowego. Odczyt portu pracującego jako wyjście da w wyniku stan jaki panuje na danej linii (zasada pracy portu pseudo-dwukierunkowego). Dlaczego o tym wspominam? Otóż kryje się tu pewne niebezpieczeństwo. Zbudujmy prosty układ

Można go zamontować w "pająku" lub na płytce uniwesalnej. Wpiszmy w Basic-u prosty program (listing 1):
Poke $BFE301,255			: Rem Ustawienie portu jako wyjście
Poke $BFE101,0			: Rem Wpisanie zera na bit 0 portu
Print "Stan portu";Peek($BFE101)	: Rem Odczyt i wyświetlenie stanu portu
Po uruchomieniu programu na ekranie ujżymy: Stan portu 0 a dioda led zgaśnie. Po wpisaniu i uruchomieniu programu (listing 2):
Poke $BFE301,255			: Rem Ustawienie portu jako wyjście
Poke $BFE101,1			: Rem Wpisanie jedynki na bit 0 portu
Print "Stan portu";Peek($BFE101)	: Rem Odczyt i wyświetlenie stanu portu
na ekranie ujżymy: Stan portu 1 a dioda led zaświeci. Wykonajmy teraz układ z

Uruchomijmy ponownie obydwa programy. Program z listingu 1 zadziałał bezbłędnie, natomiast po uruchomieniu programu 2 dioda led owszem zaświeciła, ale na ekranie ujżeliśmy: Stan portu 0 zamiast spodziewanego napisu "Stan portu 1". Dlaczego? Wyjaśnienie jest proste. Gdy na linii portu pojawił się stan logiczny 0 (napięcie bliskie 0V) tranzystor znalazł się w stanie odcięcia, dioda led zgasła. Gdy jednak na linii pojawił się stan jeden, napięcie na niej nie osiągnęło spodziewanej wartości (bliskiej 5V), a to za sprawą napięcia OE tranzystora wynoszącym około 0.7V. Odczyt takiej linii da wynik zera logicznego, chociaż na port wystawiliśmy jedynkę. Aby uniknąć tego typu problemów wystarczy szeregowo z bazą tranzystora dodać rezystor rzędu 10kohm. Wtedy wszystko wróci do normy. Dlaczego jest to takie ważne? Gdybyśmy zastosowali niezmodyfikowany układ

i chceli ustawić pojedyńczą linię portu rozkazem: "Bset" lub "Bclr" otrzymalibyśmy niespodziewany wynik. Spróbójmy. Proszę wpisać listing 3 i uruchomić.
Poke $BFE301,255			: Rem Ustawienie portu jako wyjście
Poke $BFE101,1			: Rem Wpisanie jedynki na bit 0 portu
Bset 7,$BFE101			: Rem  Wpisanie jedynki na bit 7 portu
Print "Stan portu";Peek($BFE101)	: Rem Odczyt i wyświetlenie stanu portu
na ekranie ujżymy: Stan portu 128 binarnie %10000000, zamiast %10000001. Podobnie byłoby gdybyśmy użyli rozkazu "Or". Wszystko dla tego, że asemblerowy rozkaz "Bset 7,$BFE101" wykonuje operację odczyt-modyfikacja-zapis. Możnaby to porównać do sekwencji rozkazów:
MOVE.B		$BFE101,D0
OR.B		#7,D0
MOVE.B		D0,$BFE101
Dlatego rozkazy: Bset, Bclr, Btst, Bchg tak samo jak And, Or zadziałają błędnie! Także rozkazy Add, Sub, Ror, Rol, Cmp i inne wykonane bezpośrednio na rejestrach portów będą działać błędnie! Zajmniemi się teraz budową i sposobem sterowania portem CIA-A obsługującym gównie port równoległy.

przedstawiono fragment schematu Amigi1200 ukazujący połączenie portów CIA z portem PAR i SER. W innych Amigach przyjęto takie samo rozwiązanie, inna może być tylko numeracja układów i numerów nóżek jeśli zastosowano układy w obudowie DIL40 (w A1200 PLCC44). Teraz zajmniemy się opisem najważniejszych rejestrów portu Amigi:
Adres	Nazwa	Funkcja
$bfe001	PRA		rejestr danych zewnętrznych dla portu danych A
$bfe101	PRB		rejestr danych zewnętrznych dla portu danych B
$bfe201	DDRA	rejestr kierunku danych portu A
$bfe301	DDRB	rejestr kierunku danych portu B
$bfe401	TALO	młodszy bajt zegara A
$bfe501	TAHI		starszy bajt zegara A
$bfe601	TBLO	młodszy bajt zegara B
$bfe701	TBHI		starszy bajt zegara B
$bfe801	TODLO	młodszy bajt licznika TOD
$bfe901	TODMID	środkowy bajt licznika TOD
$bfea01	TODHI	starszy bajt licznika TOD
$bfeb01	TODHR	nie używany
$bfec01	SDR		rejestr danych szeregowych
$bfed01	ICR		rejestr kontroli przerwań
$bfee01	CRA		rejestr kontrolny A
$bfef01	CRB		rejestr kontrolny B
Rejestr DDRB ustala kierunek linii portu Parallel. Wpisanie jedynki na bit 0 rejestru DDRB spowoduje, że pin 2 portu parallel będzie linią wyjściową. Wpisanie 0 spowoduje, że pin 2 portu będzie linią wejściową. Bit 1 ustala kierunek linii 3 portu, bit 2 linii 4, itd do bitu 7 odpowiedzialnego za pin 9. Wpisanie liczby 255 ($ff) ustawi linie 2...9 jako wyjściowe, liczba 0 ustawi linie jako wejściowe.

Rejestr PRB służy do odczytu danych z linii 2...9 portu parallel, gdy port pracuje jako wejście, lub zapisu stanu na liniach 2..9 portu gdy pracuje jako wyjście. Warto omówić przypadek, gdy część linii będzie ustawione jako wejścia, a część jako wyjścia. Wpiszmy i uruchomijmy program z listingu 4:

Poke $BFE301,$F0 : Rem Ustawienie bitów 0...3 portu jako wejście, bitów 4...7 jako wyjście
Poke $BFE101,%10101010 : Rem Zapisanie danych na port     
Print "Stan portu ";Bin$(Peek($BFE101)) : Rem Odczytanie i wyświetlenie stanu portu
na ekranie ujżymy (zakładam, że do portu nie jest nic podłączone, a w szczególności drukarka lub inne urządzenie z dwukierunkowym interfejsem): Stan portu %10101111 Jak można wywnioskować dane daje się zapisać tylko na te linie portu PRB, na których w rejestrze DDRB znajdują się jedynki. Zapis do linii ustawionych jako wejścia zostaje zignorowany. To jest największa różnica portu 8520 w stosunku do portów pseudo-dwukierunkowych. Działanie portu 8520 jest takie samo jak portów w procesorach serii AVR. Warto jeszcze wspomnieć, że każdy zapis lub odczyt rejestru PRB powoduje pojawienie się ujemnego impulsu, o czasie trwania około 200ns, na linii 1 portu parallel. Dzięki temu po wpisaniu danej do PRB automatycznie jest generowany strob informujący drukarkę o tym, że dane na porcie są ustalone. Gdyby port pracował jako wejściowy, strob poinformuje urządzenie nadające, że dane zostały przyjęte i można wysłać kolejną daną. Na porcie parallel jest dostępnych więcej linii. Pin 10 portu jest wejściem i jego stanu nie można oczytać bezpośrednio. Na pin 14 wyprowadzono napięcie zasilające o wartości +5V przez rezystor 47R. Z wyprowadzenia tego można czerpać prąd o wartości około 10mA. Pin 16 podłączony jest do linii reset. Pojawi się tam ujemny impuls w czasie restartu komputera. Lniami podłączonymi do pinów 11...13 można dowolnie sterować. Są one podłączone do układu CIA-B. Oto adresy rejestrów układu:
Adres	Nazwa	Funkcja
$bfd000	PRA		rejestr danych zewnętrznych dla portu danych A
$bfd100	PRB		rejestr danych zewnętrznych dla portu danych B
$bfd200	DDRA	rejestr kierunku danych portu A
$bfd300	DDRB	rejestr kierunku danych portu B
$bfd400	TALO	młodszy bajt zegara A
$bfd500	TAHI		starszy bajt zegara A
$bfd600	TBLO	młodszy bajt zegara B
$bfd700	TBHI		starszy bajt zegara B
$bfd800	TODLO	młodszy bajt licznika TOD
$bfd900	TODMID	środkowy bajt licznika TOD
$bfda00	TODHI	starszy bajt licznika TOD
$bfdb00	TODHR	nie używany
$bfdc00	SDR		rejestr danych szeregowych
$bfdd00	ICR		rejestr kontroli przerwań
$bfde00	CRA		rejestr kontrolny A
$bfdf00	CRB		rejestr kontrolny B
Rejestr DDRA ustala kierunek linii portu parallel i serial:
bit 0 	pin 11
bit1	pin 12
bit2	pin 13
bity3...7 ustalają kierunek linii podłączonych do portu serial i nie należy modyfikować ich zawartości. Jak więc ustawić kierunek? Nic prostrzego, należy posłużyć się rozkazami "And", "Or" lub "Bset", "Bclr". Naprzykład, aby ustawić linie podłączone do pinów 11...13 portu jako wyjścia należy wydać rozkaz: Poke $BFD200,Peek($BFD200) Or %00000111 lub użyć sekwencji:
Bset 1,$BFD200
Bset 2,$BFD200
Bset 3,$BFD200
Gdy linie 11...13 chcemy ustawić jako wejściowe należy wydać rozkaz: Poke $BFD200,Peek($BFD200) And %1111100 0 lub użyć sekwencji: Bclr 1,$BFD200 Bclr 2,$BFD200 Bclr 3,$BFD200 Rejestr PRA służy do odczytu danych z linii 11...13 portu parallel, gdy port pracuje jako wejście, lub zapisu stanu na liniach 11...13 portu gdy pracuje jako wyjście. Obowiązują te same zasady co dla rejestru PRB portu CIA-A, tzn zapis będzie skuteczny jeśli na odpowiednich bitach rejestru DDRA będą ustawione jedynki. Przy zapisie rejestru PRA należy pamiętać, aby nie zmieniać stanu bitów 3...7, natomiast przy odczycie ignorować stan tych bitów. Ustawianie/zerowanie linii najlepiej realizować rozkazami "Bset", "Bclr". Przy odczycie można posłużyć się rozkazem "Btst" lub zamaskować bity 3...7 rozkazem And, np:
A=Peek($BFD000) And 7
Znaczenie pozostałych rejestrów omówię w kolejnych artykułach przy okazji opisu obsługi timerów, zegara czasu rzeczywistego, portu szeregowego, klawiatury, itd.

Na koniec pierwszej części, na listingu 5, przedstawiam prosty program generujący na efekt tzw "węża świetlnego":

Poke $BFE301,255 : Rem Port jako wyjście
Restore : Rem Ustaw dane na początek
Cls: Rem Czyść ekran
Do
    Read A : Rem Czytaj daną do wyświetlenia
   If A<0 : Rem Jeśli koniec danych to:
      Restore : Rem Ustaw dane na początek
       Read A : Rem Czytaj pierwszą daną
    End If
    Poke $BFE101,A : Rem Zapisz dane do portu
    Home : Rem Kursor w lewy górny róg ekranu
    A$=Bin$(A)-"%" : Rem Wyświetl dane na ekranie
    A$="00000000"+A$   Print Right$(A$,8)
   Wait 10 : Rem Czekaj
   If Inkey$<>"" Then Exit : Rem Jeśli naciśnięto jakikolwiek klawisz to wyjdź
Loop
Data 1,2,4,8,16,32,64,128,64,32,16,8,4,2
Data -1:Rem Koniec danych
Do wyjścia portu można podłączyć układ

. Pomyślcie ile kombinacji można wyświetlić mając tylko 1Mb pamięci. UWAGA! Ze względu na małą wydajność prądową wyprowadzenia 14 portu należy zostosować superjasne diody led lub w programie zadbać o to, aby w jednej chwili nie świeciły więcej niż 3...4 diody. W AVT opracowano kilka kitów, które możemy podłączyć bezpośrednio do Amigi za pośrednictwem interfejsu AVT-2027, są to:
AVT-2047 "Programowany sterownik do zabawek i modeli"			EdW 6/96
AVT-2061 "Monitor interfejsu CENTRONICS"					Edw 9/97
AVT-2097 "Moduł wykonawczy dużej mocy na triakach"				EdW 10/97
AVT-2098 "Moduł wykonawczy dużej mocy do sterownika AVT2047"		EdW 9/96
AVT-2099 "Moduł wykonawczy do sterownika AVT2047"			EdW 8/96
AVT-2099+AVT-110 "Zestaw oświetlenia dyskotekowego-Moduł wykonawczy"	EP 2/96
po małych modyfikacjach można podłączyć:
AVT342 "Komputerowa strzelnica sportowa"					EP 6/97
W niektórych przypadkach konieczne może być zastosowanie rozkazu "Xor" przed wysłaniem danych na port. Spowodowane jest to negowaniem danych przez interfejs. W programie z Listingu 5 przed linią: Poke $BFE101,A : Rem Zapisz dane do portu należałoby wstawić:
A=Axor $FF

Często 11 linii wejścia-wyjścia okazuje się zbyt małą liczbą, aby sterować bardziej skomplikowanymi urządzeniami. W kolejnej części zajmniemy się więc sposobem zwiększenia liczby wejść/wyjść portu równoległego. Instnieją dwa zasadnicze sposoby realizacji tego zadania: - sposób szeregowy: prosta realizacja sprzętowa, bardziej skomplikowany program sterujący, mała szybkość transmisji, - sposób równoległy: bardziej somplikowana budowa sprzętowa, prostrzy program, duża prędkość transmisji.

Na początek opiszę sposób zwiększenia liczby wyjść sposobem szeregowym. Na


widzimy schemat sposobu dołączenia rejestru szeregowo-równoległego do portu Amigi. Rowiązania te mają jednak poważne wady:
Rys 6a - Podczas transmisji danych do rejestru 74HC164 stany wyjść A...H zmienią się, co może być niedopuszczalne. Gdybyśmy np. sterowali wężem świetlnym żarówki nie wygasałyby całkowicie, widać byłoby ich lekkie miganie. Gdyby żarówkami sterowały przekaźniki podczas transmisji "klekotałyby" wydając hałas i przyspieszając zużycie się styków.
Rys 6b - Rozwiązanie całkiem dobre ponieważ podczas transmisji dane zapamiętane są w zatrzasku, po transmisji impuls dodatni na linii ST przepisuje dane. Wadą tego rozwiązania jest to, że po resecie na wszystkich wyjściach portu Amigi pojawia się stan "H". Spowoduje on przepisanie danych w rejestrze 4094 podczas restartu Amigi, co często jest nieporządane. Proponuję za tym układ z

. Rozwiązaliśmy tam dwa problemy:
1 - Stan linii ST jest negowany, dzięki czemu po resecie przyjmuje poziom "L" w wyniku czego na wyjściach rejestru znajdują się ostatnio zapamiętane dane.
2 - Zakłócenia pojawiające się w często długich przewodach są minimalizowane dzięki bramkom Shmitta.
Pojawia się tu jednak problem z zanegowaniem danych. Nie powinno to być dużym kłopotem dla programisty, wystarczy dane przed wysłaniem zanegować. Jeśli dla kogoś jest to niewygodne może dodać dodatkowy inwerter na linii danych. Dalsze rozwarzania będą opierały się o ideę z

. Aby wysłać bajt (8-bitów) do rejestru należy wykonać następujące kroki:
1 - Ustawić linie portu jako wyjścia, linie wyjściowe ustawić w stan "H". Układ 8520 jest tak zbudowany, że po resecie wszystkie linie portu usttawione są jako wejścia. Po ustawieniu linii jako wyjściowa pojawi się na niej poziom "H". Jednak inny program czy system operacyjny może wprowadzić zmiany. Należy więc wykonać następującą sekwencję rozkazów:
- linie które będą wyjściami ustawić w rejestrze danych stan "H"
- w rejestrze kierunku ustawić te linie jako wyjścia
Dlaczego taka, a nie inna kolejność postępowania? Wytłumaczenie jest proste, uruchomijmy poniższy program i przyżyjmy się efektom: >>> Umieścić listing 6 <<<
Jak widać w wyniku działania programu otrzymaliśmy liczbę 4. Dlaczego tak się stało? Otóż port 8520 zawsze przyjmuje dane, które wpisujemy do rejestru wyjściowego tyle, że jeśli jakieś linie są ustawione jako wyjścia to zawsze są lekko podciągane do +5V. Stan rejestru jest przepisywany tylko na linie, które w rejestrze kierunku ustawiliśmy jako wyjścia. Gdybyśmy do ustawienia linii jako wyjścia użyli sekwencji:
- w rejestrze kierunku ustawić linie jako wyjścia
- linie które będą wyjściami ustawić w rejestrze danych stan "H"
nie mielibyśmy gwarancji, że stan tych linii na chwilę nie zmieni się na "L", za sprawą wcześniej wpisanej np. liczby 0 do rejestru wyjściowego.
2 - W kolejnym kroku musimy rostrzygnąć czy wysyłany bit jest jedynką czy zerem
jeśli jedynką wyzerować (negowanie przez bramki) linię DATA
jeśli zerem ustawić (negowanie przez bramki) linię DATA
3 - Wygenerować ujemny impuls na linii CLOCK (negowanie przez bramki)
4 - Zmienić nr analizowanego bitu, jeśli nie jest to ostatni bit skoczyć do punktu 2
5- Wygenerować ujemny impuls na linii STROBE (negowanie przez bramki)
Funkcję taką realizuje program z listingu 7 >>> Umieścić listing 7 <<<
Dziwne może się wydać to, że zawsze analizujemy stan bitu 7 zmiennej BAJT. Jest to możliwe dzięki rozkazowi:
ROL.B 1,BAJT
który przesuwa daną o jeden bit w lewo. Dzięki temu po pierwszym obiegu pętli FOR...NEXT w rzeczywistości będziemy analizowali stan bitu 6, w drugim obiegu stan bitu 5, trzecim 4, itd. Program dodatkowo wyświetla binarną wartość wysłanego bajtu. Aby przerwać program należy nacisnąć CTRL+C. Program z listingu8 (dostępny tylko na stronie www) demonstruje sposób obsługi rejestru 4094, oraz kitu AVT-996 (steruje diodą LED).
Jeśli połączyliśmy więcej rejestrów szeregowo musimy procedurę wysyłania danych powrtórzyć tyle razy ile mamy rejestrów 4094. Najprościej wywołać kilka razy procedurę _SEND, a po nich wysłać impuls na linię STROBE (patrz listing 9). >>> Umieścić listing 9 <<<
Gdy budujemy urządzenie w którym nie wszystkie porty wyjściowe muszą ciągle zmieniać stan (np. programator eprom, gdzie starszy bajt adresu zmienia się co 256) warto zastosować rozwiązanie z

. Adres portu podany na linię ADR0 i ADR1. Dekoder 4555 wybiera jeden z rejestrów jako docelowy. Dane wysyłamy na linię DATA, impulsy zegara na linię CLK. Ważne aby podczas tych operacji nie zmieniać ustawienia lini ADR0 i ADR1. Dzięki czemu impulsy zegarowe trafiają do jednego wybranego rejestru. Po wysłaniu 8 bitów przepisujemy dane na wyjście impulsem na linii STB. Nie musimy się obawiać, że zmieni się stan wyjść innych rejestrów, ponieważ na ich wejściach zegarowych nie pojawiły się impulsy, rejestry te na swoje wyjścia przepiszą poprzednią wysłaną do nich daną, czy stan ich nie zmieni się.

Teraz zajmniemy się zwiększeniem liczby wejść sposobem szregowym. Przykładowy sposób realizacji widzimy na


. Wysyłając ujemny impuls na linię LOAD przepisujemy dane z wejść do wewnętrznych rejestrów układów 74165. Stan najstarszego bitu jest dostępny na wyjściu. Po impulsie zegarowym dane w rejestrach zostaną przesunięte, dzięki czemu na wyjściu Qh pierwszego rejestru pojawi się stan wejścia g natomiast na poprzednią zawartość bitu z wejścia a zostanie wpisany stan wejścia In czyli stan wyjścia Qh drugiego rejestru. Po ośmiu impulsach zegarowych na wyjściu Qh pierwszego rejestru pojawi się stan wejścia h drugiego rejestru. W ten sposób można odczytać dowolną liczbę rejestrów. Przykładowy listing odczytujący jeden rejestr 74165 przedstawiono poniżej. >>> Umieścić listing 10 <<<

Przejdźmy do kolejnego etapu, zwiększanie liczby wyjść sposobem równoległym. Przykładowe rozwiązanie można znaleźć na


. Można podłączyć max 8 portów wyjściowych 8-bit. Aby zapisać daną do wybranego portu należy ustawić jego nr na pinach 11...13 portu np. rozkazami:
Nr=nr_rejestru
Poke $BDF000,Peek($BFD000) and %11111000 : Rem Wyzerowanie pierwszych trzech bitów
Poke $BDF000,Peek($BDF000) or NR : Rem ustawienie nr rejestru na bitach 11...13 portu

Następnie wysyłamy dane na port. Impuls strobu z pinu 1 portu równoległego pojawia się na jednym z wyjść dekodera 74138. Układy 74574 reagują na narastające (tylne) zbocze sygnału strobu, dlatego nie można zamiast nich wykorzystać rejestrów 74573. Przepisują one dane na wyjście w chwili gdy na wejściu sterującym jest poziom H, natomiast aktywnym poziomem dla 74138 jest poziom "L". Jeśli komuś bardzo zależy na wykorzystaniu układów 74573 musi wymienić dekoder na 4028 lub 4514 dla którego aktywnym poziomem jest "H" . Przykładowy program obsługujący max 8 rejestrów widzimy na listingu 11. >>> Umieścić listing 11 <<<

Zwiększenie liczby wejść sposobem równoległym przedstawiono na


. Po wybraniu adresu na pinach 11...13 portu uaktywniona zostanie jedna z bram 74245. Dane można odczytać standardowym rozkazem:
Peek ($BFE101)
W tym wypadku nie łączymy lini strobe portu do dekodera. Gdybyśmy tak postąpili, brama uaktywniałaby się tuż po odczycie danych przez układ 8520 (strob pojawia się po odczycie danej komunikując układ współpracujący, że może wystawić kolejne dane).

Zwiększenie liczby wejść-wyjść sposobem równoległym.
Jeśli chcemy zwiększyć zarówno liczbę wejść jak i wyjść proponuję układ z


. Przedstawiono tam dwa porty wejściowe i dwa wyjściowe. Wykorzystując pozostałe wyjścia dekodera można układ rozbudować do max czterech portów wejściowych i czterech wyjściowych. Obsługa portów jest podobna jak w poprzednich przypadkach. Aby odczytać dane z bramy należy port ustawić jako wejście, ustawić adres portu z zakresu 4...7, i odczytać dane. Aby zapisać dane do rejestru należy ustawić adres portu z zakresu 0...3, ustawić port jako wyjście, i zapisać daną. Jak łatwo się domyśleć dekoder 74138 musi spełniać dwie funkcje: przy pracy jako dekoder portów wyjściowych wysyłać impuls strobu do zatrzasków 74574, przy pracy jako dekoder portów wejściowych jedno z jego wyjść musi być na stałe w stanie aktywnym. Te dwie sprzeczne funkcje dało się zrealizować za pomocą dodatkowej bramki NAND. Gdy wybierzemy adres portu z zakresu 0...3 (bramy wejściowe) wejście C dekodera jest w stanie niskim, a co za tym Co jednak zrobić gdy potrzebujemy więcej niż 8 portów, a dodatkowo liczba portów wejściowych ma być różna od liczy portów wyjściowych? I z tej sytuacji jest wyjście, wystarczy rozbudować dekoder adresowy. Przykładowe rozwiązanie pokazano na BR>

. Aby wpisać adres portu: ustawiamy port PARALLEL jako wyjście, ustawiamy pin 13 w stan niski, następnie wpisujemy adres portu do portu PARALLEL. Dzięki bramce A zostanie on zatrzaśnięty w rejestrze 74574. Gdy wybierzemy adres portu wejściowego, za sprawą bramek D E demultiplekser zostanie uaktywniony. Gdy wybrany zostanie adres portu wyjściowego dzięki bramkom B C impuls strobu uaktywni na chwilę demultiplekser zatrzaskując dane w rejestrze wyjściowym. O tym które porty są wejściowe, a w konsekwencji kiedy demultiplekser zostanie uaktywniony na stałe, decyduje typ bramki E (AND czy OR) oraz do jakich wejść demultipleksera (B C D) zostanie ona podłączona. Wszystkie sensowne możliwości przedstawia tabelka poniżej:
 Adres	| Typ	|    funkcja portu	|
 portu	| bramki| dla podłączonych wejśę|
	|       +-------+-------+-------+
	|	|   D	|  CD	|  BCD	|
--------+-------+-------+-------+-------+
0	| AND	|In	|In	|In	|
1	| AND	|In	|In	|In	|
2	| AND	|In	|In	|In	|
3	| AND	|In	|In	|In	|
4	| AND	|In	|In	|In	|
5	| AND	|In	|In	|In	|
6	| AND	|In	|In	|In	|
7	| AND	|In	|In	|In	|
8	| AND	|Out	|In	|In	|
9	| AND	|Out	|In	|In	|
10	| AND	|Out	|In	|In	|
11	| AND	|Out	|In	|In	|
12	| AND	|Out	|Out	|In	|
13	| AND	|Out	|Out	|In	|
14	| AND	|Out	|Out	|Out	|
15	| AND	|Out	|Out	|Out	|
0	| OR	|in	|In	|In	|
1	| OR	|In	|In	|In	|
2	| OR	|In	|In	|Out	|
3	| OR	|In	|In	|Out	|
4	| OR	|In	|Out	|Out	|
5	| OR	|In	|Out	|Out	|
6	| OR	|In	|Out	|Out	|
7	| OR	|In	|Out	|Out	|
8	| OR	|Out	|Out	|Out	|
9	| OR	|Out	|Out	|Out	|
10	| OR	|Out	|Out	|Out	|
11	| OR	|Out	|Out	|Out	|
12	| OR	|Out	|Out	|Out	|
13	| OR	|Out	|Out	|Out	|
14	| OR	|Out	|Out	|Out	|
15	| OR	|Out	|Out	|Out	|
--------+-------+-------+-------+-------+

Dodając kolejne demultipleksery można zwiększyć liczbę portów do 256.

Pliki do probrania:
Listingi i programy

Sławomir Skrzyński
slawomir.skrzynski@ep.com.pl