Rozdział 10
OBSŁUGA MANIPULATORÓW
W każdym komputerze ważną rolę pełnią manipulatory.
Szczególnie ważne jest ich zastosowanie w komputerach domowych,
gdzie służą do gier. Zasadniczo można wyróżnić dwa rodzaje
manipulatorów stosowanych w sprzęcie komputerowym: manipulatory
analogowe i manipulatory cyfrowe.
Sygnałem z manipulatora analogowego jest napięcie. W
najprostszych rozwiązaniach uzyskuje się to przez włączenie
między bieguny zasilania komputera potencjometru. Rozwiązaniem
bardziej skomplikowanym może być przetwornik zamieniający np.
szybkość obrotową na napięcie. Do manipulatorów analogowych
zalicza się potencjometry (paddle), myszy i tabliczki
graficzne.
Całkowicie odmienne jest działanie manipulatora cyfrowego.
Zawiera on kilka styków, które mogą mieć tylko dwa stany -
zwarty i rozwarty. Najczęściej spotykanym rozwiązaniem jest
takie, w którym styk ma napięcie 5 V i jest zwierany do masy.
Ten zespół styków jest dołączony do jednego z układów
komputera, skąd położenie poszczególnych styków jest
odczytywane jako stany bitów rejestru. Manipulatorem cyfrowym
jest przede wszystkim joystick. Ponadto w manipulatorach
analogowych stosuje się jeden lub dwa przyciski, których
działanie jest oparte na zasadzie zwierania styków, a więc
cyfrowe.
Komputery Atari 400/800 miały po cztery gniazda
manipulatorów. Do każdego z tych gniazd można było dołączyć
joystick lub dwa potencjometry. W sumie daje to ogromną liczbę
czterech joysticków lub ośmiu potencjometrów. Dało tu o sobie
znać pochodzenie komputerów Atari od gier telewizyjnych.
W nowych modelach XL i XE liczba gniazd została zredukowana do
przyzwoitej liczby dwóch, lecz ze względu na zachowanie
zgodności oprogramowania pozostały rejestry w pamięci RAM.
Ponieważ manipulatory dwóch wymienionych wyżej typów mają
zupełnie odmienne działanie, to są one obsługiwane przez różne
układy komputera. Są to trzy układy, a nie dwa, jak można by
przypuszczać, gdyż przyciski joysticków są obsługiwane
oddzielnie.
10.1. Potencjometry
Do dwóch gniazd manipulatorów można dołączyć w Atari cztery
potencjometry (parami). Sygnał analogowy (napięcie) z gniazda
jest przesyłany do układu POKEY i tam poddawany konwersji na
postać cyfrową. Wykonuje tą operację specjalny przetwornik
analogowo-cyfrowy (A/DC - Analog/Digital Converter).
Przetworniki te sprawiają konstruktorom komputerów dużo
kłopotów i to nie ze względów technicznych. Osiągnięcie nawet
bardzo dużej dokładności nie stanowi żadnego problemu. Wymaga
za to czasu. Doprowadzany sygnał jest kolejno porównywany z
napięciami wzorcowymi o rosnących wartościach. Czym więcej
napięć wzorcowych, tym dokładniej określone jest napięcie
sygnału, ale także tym dłużej trwa pomiar. Największą
trudnością jest znalezienie właściwego kompromisu pomiędzy
dokładnością i szybkością przetwornika.
Rozwiązanie zastosowane w Atari jest następujące: POKEY
mierzy jednocześnie osiem sygnałów wejściowych (modele XL i XE
wykorzystują tylko cztery z nich). Ponieważ wykonuje to co 1/50
sekundy (z częstotliwością synchronizacji obrazu - 50 Hz), to w
tym czasie możliwe jest porównanie każdego sygnału z 228
napięciami wzorcowymi. Zamiana sygnału analogowego na cyfrowy
daje więc w rezultacie wartości z zakresu od 0 do 228.
Obliczone wartości mogą być odczytane z rejestrów POT0-7
(POTentiometr 0-7 - $D200-$D207). Niestety w języku maszynowym
nie jest to proste (Atari Basic i większość języków wyższego
poziomu sama wykonuje opisane niżej czynności). Rejestry te
bowiem są jednocześnie licznikami sprzętowymi układu POKEY. Ich
stan jest stopniowo zmniejszany, a po wyzerowaniu
któregokolwiek wywoływane jest przerwanie IRQ (TIMER 1, 2 i 4),
natomiast licznik jest ponownie ustawiany na 228 lub według
zawartości rejestrów-cieni. Dzięki temu mogą one być
wykorzystane do zliczania okresów czasu krótszych od
częstotliwości obrazu (50 Hz, czyli 1/50 sekundy) - jest to
opisane w poprzednim rozdziale.
Prawidłowy odczyt stanu potencjometru umożliwiają dwa
dodatkowe rejestry. Rejestr POTGO (POTentiometrs GOes - $D20B)
uruchamia odczyt i konwersję sygnału wejściowego po wpisaniu do
niego dowolnej wartości. Zakończenie zamiany sygnału
analogowego na cyfrowy jest sygnalizowane skasowaniem bitu w
rejestrze POTSTAT (POTentiometrs STATus - $D208). Każdemu
bitowi tego rejestru (0-7) odpowiada potencjometr o tym samym
numerze. Ustawienie bitu w POTSTAT oznacza więc, że wartość
odpowiadającego mu potencjometru jest jeszcze obliczana i
odczyt z POT... da nieprawidłowy wynik.
Jeżeli znacznie ważniejsza od dokładności jest szybkość
przetwarzania sygnału, to można ją zmienić poprzez rejestr
SKCTL (Serial and Keyboard ConTroL - $D20F). Gdy bit 2 tego
rejestru jest skasowany (stan normalny), to przetwarzanie
sygnału trwa 20 milisekund, co odpowiada utworzeniu na ekranie
228 linii. Po ustawieniu tego bitu czas przetwarzania skraca
się do 128 mikrosekund (dwie linie ekranu), jednak kosztem
znacznego zmniejszenia dokładności pomiaru. Przy zmianie
zawartości tego rejestru trzeba pamiętać, aby nie zmienić
innych, wcześniej ustawionych bitów (normalnie wszystkie są
skasowane).
Stosowane do gier potencjometry (tzw. paddle) są ponadto
wyposażone w przyciski - każdy paddle ma jeden przycisk.
Sygnały z tych przycisków są dołączone do układu obsługującego
joysticki (zob. rozdział następny). Odpowiadają one
przesunięciom joysticka w lewo i w prawo:
przycisk potencjometru 0 = joystick 0 w lewo
przycisk potencjometru 1 = joystick 0 w prawo
przycisk potencjometru 2 = joystick 1 w lewo
przycisk potencjometru 3 = joystick 1 w prawo
przycisk potencjometru 4 = joystick 2 w lewo
przycisk potencjometru 5 = joystick 2 w prawo
przycisk potencjometru 6 = joystick 3 w lewo
przycisk potencjometru 7 = joystick 3 w prawo
Potencjometry 4-7 oraz joysticki 2 i 3 występują tylko w
komputerach Atari 400/800.
10.2 Joysticki
Wykorzystanie joysticków jest znacznie prostsze ponieważ
uzyskiwany jest z nich sygnał cyfrowy. W Atari obsługą
joysticków zajmuje się układ scalony PIA (typowy układ 6520 lub
6820), a właściwie jego port A, gdyż PIA składa się z dwóch
identycznych, niezależnych od siebie części. W modelach 400/800
port B obsługiwał dwa dalsze gniazda joysticków.
Joystick ma cztery zasadnicze położenia (oprócz
neutralnego): w lewo, w prawo, naprzód i wstecz. Pozostałe
położenia są ich kombinacją. Do cyfrowego przedstawienia tych
położeń wystarczą cztery bity, dla dwóch joysticków potrzebny
jest więc jeden rejestr 8-bitowy. Takim rejestrem jest właśnie
PORTA (PORT A - $D300). Jego poszczególne bity są przypisane
następującym położeniom joysticka:
bit 0 - joystick 0 naprzód
bit 1 - joystick 0 wstecz
bit 2 - joystick 0 w lewo
bit 3 - joystick 0 w prawo
bit 4 - joystick 1 naprzód
bit 5 - joystick 1 wstecz
bit 6 - joystick 1 w lewo
bit 7 - joystick 1 w prawo
Jak wynika z wstępnego opisu, normalnie wszystkie bity są
ustawione. Wykonanie ruchu joystickiem powoduje skasowanie
odpowiedniego bitu (lub bitów). Języki wyższego poziomu
odczytują położenie joysticka z rejestrów-cieni - $0278
(joystick 0) lub $0279 (joystick 1). Odczyt położenia
bezpośrednio z PORTA stosowany przeważnie w języku maszynowym
wymaga natomiast wykonania kilku operacji. Przedstawia to
poniższa procedura (analogicznie przeprowadzane jest
przepisanie zawartości PORTA do rejestrów-cieni podczas
przerwania VBLK).
0100 ;Read Joystick's Movements
0110 ;
0120 PORTA = $D300
0130 ;
0140 *= $0600
0150 ;
0160 ;Joystick 0
0170 ;
0180 JOY0 LDA PORTA
0190 AND #$0F
0200 RTS
0210 ;
0220 ;Joystick 1
0230 ;
0240 JOY1 LDA PORTA
0250 LSR A
0260 LSR A
0270 LSR A
0280 LSR A
0290 RTS
Dla uproszczenia późniejszego rozpoznania położenia
joysticka zwykle po rozkazie LDA PORTA stosuje się jeszcze
rozkaz EOR #$FF, który zamienia wartości wszystkich bitów na
przeciwne. Teraz sprawdzenie konkretnego bitu jest wykonywane
przez sekwencję rozkazów AND, BNE. Na przykład ruch w lewo
wykrywany jest rozkazami AND #$04, BNE LEFT. Jeżeli bit 2 był
ustawiony (po EOR #$FF oznacza to ruch w lewo), wykonywany jest
skok do miejsca oznaczonego etykietą LEFT. Podobna metoda
została zastosowana w procedurze zamieszczonej na stronie 194.
Oczywiście można także sprawdzać po kilka bitów jednocześnie
(np. AND #$06 wykrywa ruch w lewo i wstecz).
Podobnie jak potencjometry, także każdy joystick wyposażony
jest w przycisk (najczęściej jest ich kilka, lecz połączone są
razem). Do wykrywania ich stanu służą rejestry układu GTIA (w
PIA zabrakło miejsca) - TRIG0 i TRIG1 (TRIGger 0-1). W
rejestrach tych bity 1-7 są niewykorzystywane, a stan przycisku
jest sygnalizowany jedynie przez bit 0. Normalnie bit ten jest
ustawiony, a jego skasowanie oznacza, że przycisk został
wciśnięty.
Wszystkie wymienione wyżej rejestry mają swoje kopie w
pamięci RAM. Zawartości ich są uaktualniane podczas przerwania
synchronizacji pionowej VBLK. Spojrzenie na mapę pamięci
ujawnia, że rejestrów-cieni jest dwa razy więcej! Jest to
pozostałość po modelach 400/800 utrzymana w celu zachowania
zgodności oprogramowania. Przy przepisywaniu do rejestrów-cieni
wartości dotyczące joysticka 0 są umieszczane w rejestrach
joysticków 0 i 2, a joysticka 1 w rejestrach 1 i 3. Dotyczy to
zarówno położenia joysticka, jak i stanu jego przycisku.
10.3. Wyjście z gniazd joysticków
Układ PIA, do którego dołączone są gniazda joysticków, jest
programowalnym układem wejścia/wyjścia. Można więc,
przeprogramować go tak, aby zamiast odczytywać sygnał z tego
gniazda, zapisywał go tam. Do tego celu trzeba wykorzystać
rejestr PACTL (Port A ConTroL - $D302).
Układ PIA ma wiele funkcji, które są sterowane między
innymi przez PACTL. Trzeba więc uważać, aby nie wywołać
zamieszania przy ingerowaniu w jego zawartość. Jedynym
interesującym nas bitem tego rejestru jest bowiem bit 2. Gdy
jest on ustawiony, rejestr PORTA działa jako rejestr
przesyłania danych. Oznacza to, że sygnał doprowadzony z jednej
strony rejestru jest przekazywany na drugą. Specjalnie używam
enigmatycznych określeń stron: "jedna" i "druga", gdyż kierunek
przesyłania jest zmienny. Skasowanie bitu 2 zamienia rejestr
PORTA w rejestr porządkowania danych. Teraz wpisanie jakiejś
wartości do tego rejestru ustawia kierunek przesyłania danych i
to oddzielnie dla każdego bitu! Jeżeli bit wpisanej wartości
jest skasowany, to ten bit rejestru PORTA będzie działał jako
wejście (odczyt sygnału z gniazda joysticka). Ustawiony bit
wpisanej wartości ustawia bit rejestru PORTA jako wyjście
(zapis sygnału na gniazdo joysticka). Oto przykładowe wartości:
$00 (bin 00000000) - wszystkie bity jako wejście
$FF (bin 11111111) - wszystkie bity jako wyjście
$F0 (bin 11110000) - gniazdo joysticka 0 jako wejście, a
joysticka 1 jako wyjście
$AA (bin 10101010) - bity parzyste (0, 2, 4 i 6) jako
wejście, bity nieparzyste (1, 3, 5 i 7) jako wyjście
Po odpowiednim ustawieniu portu należy odtworzyć jego
właściwą funkcję przez ustawienie bitu 2 w PACTL. Wszystkie te
operacje można przeprowadzić nawet z poziomu Basica, a w języku
maszynowym na przykład tak:
0100 DIR = $xx ;kierunek transmisji
0110 PACTL = $D302
0120 PORTA = $D300
0130 ;
0140 LDY #DIR
0150 LDA PACTL
0160 AND #$FB
0170 STA PACTL
0180 STY PORTA
0190 ORA #$04
0200 STA PACTL
0210 RTS
Sygnały wejściowe i wyjściowe w gniazdach joysticków
odpowiadają standardowi TTL. Układ PIA jest dodatkowo
separowany od gniazd rezystorami 2,2 kOhma, co zabezpiecza go
przed przeciążeniem prądowym. Bardzo łatwe jest więc
zaprojektowanie układu sterującego dowolnym urządzeniem, a
nawet kilkoma urządzeniami. Można też zastosować komputer jako
inteligentny sterownik, który będzie reagował na impulsy z
urządzenia wysyłaniem do niego odpowiednich poleceń. Stworzono
tu ogromne pole do popisu dla inwencji użytkownika. Warto
jednak pamiętać, że komputer jest urządzeniem delikatnym i
drogim. Przy stosowaniu napięć wyższych od 5 V należy stosować
galwaniczne oddzielenie obwodów za pomocą transoptorów lub
przekaźników. Niektórzy zalecają nawet oba sposoby jednocześnie
i stopniowanie napięcia: 5 V, 12 V i dopiero 220 V.
Zamiast podsumowania przedstawiam zaczerpnięty z
miesięcznika "Atari User" program, który jest przykładem
wykorzystania portu A (a jednocześnie przykładem własnej
procedury obsługi przerwania).
0100 ;Joystick Driver
0110 ;for device "J:"
0120 ;
0130 ICAX1Z = $2A
0140 ICAX2Z = $2B
0150 BOOT? = $09
0160 PACTL = $D302
0170 PORTA = $D300
0180 HATABS = $031A
0190 ;
0200 *= $0600
0210 ;
0220 ;construct HATABS entry
0230 ;
0240 PLA
0250 JINIT LDX #$00
0260 NEXTENT LDA HATABS,X
0270 BEQ TABENT
0280 INX
0290 INX
0300 INX
0310 CPX #$22
0320 BCS NOROOM
0330 JMP NEXTENT
0340 NOROOM BRK
0350 ;
0360 ;now to put the entry in
0370 ;
0380 TABENT LDA #'J
0390 STA HATABS,X
0400 INX
0410 LDA # <JDRIVER
0420 STA HATABS,X
0430 INX
0440 LDA # >JDRIVER
0450 STA HATABS,X
0460 RTS
0470 ;
0480 ;vector table
0490 ;
0500 JDRIVER .WORD OPEN-1
0510 .WORD CLOSE-1
0520 .WORD GET-1
0530 .WORD PUT-1
0540 .WORD STATUS-1
0550 .WORD SPEC-1
0560 JMP INIT
0570 ;
0580 ;open routines
0590 ;
0600 OPEN LDA ICAX1Z
0610 CMP #$0C
0620 BEQ IOOP
0630 CMP #$08
0640 BEQ OPOP
0650 CMP #$04
0660 BEQ IPOP
0670 LDY #$92
0680 RTS
0690 ;
0700 ;open for INPUT/OUTPUT
0710 ;
0720 IOOP LDX ICAX2Z
0730 PATCH LDA #$38
0740 STA PACTL
0750 STX PORTA
0760 LDA #$3C
0770 STA PACTL
0780 OK LDY #$01
0790 INIT RTS
0800 ;
0810 ;open for OUTPUT only
0820 ;
0830 OPOP LDX #$FF
0840 JMP PATCH
0850 ;
0860 ;open for INPUT only
0870 ;
0880 IPOP LDX #$00
0890 JMP PATCH
0900 ;
0910 ;normal is INPUT, so...
0920 ;
0930 CLOSE JMP IPOP
0940 ;
0950 ;put a byte to port
0960 ;
0970 PUT STA PORTA
0980 JMP OK
0990 ;
1000 ;get a byte from port
1010 ;
1020 GET LDA PORTA
1030 JMP OK
1040 ;
1050 ;function not implemented
1060 ;
1070 STATUS
1080 SPEC RTS
Program ten instaluje w tabeli HATABS urządzenie o nazwie
"J:". Może być ono otwarte do odczytu, zapisu lub odczytu i
zapisu. W tym ostatnim przypadku można dowolnie ustalić, które
styki będą wejściem, a które wyjściem. Po zainstalowaniu
urządzenie można wykorzystywać z poziomu Basica. Dostępne są
wtedy następujące instrukcje:
OPEN #n,4,0,"J:" - otwarcie do odczytu
OPEN #n,8,0,"J:" - otwarcie do zapisu
OPEN #n,12,x,"J:" - otwarcie do zapisu i odczytu (x określa
bity wejściowe i wyjściowe)
GET #n,A - odczyt bajtu
PUT #n,A - zapis bajtu
CLOSE #n - zamknięcie; ustawia PORTA do odczytu (normalny
stan portu)
|