| [Назад] [Далее] | ![]() |
И напоследок — о программировании джойстика. Джойстик подключается к еще одному, помимо последовательного и параллельного, внешнему порту компьютера — к игровому. Для игрового порта зарезервировано пространство портов ввода-вывода от 200h до 20Fh, но для общения с джойстиком используется всего один порт 201h, чтение из которого возвращает состояние джойстика:
порт 20lh для чтения:
биты 7, 6: состояние кнопок 2, 1 джойстика В
биты 5, 4: состояние кнопок 2, 1 джойстика А
биты 3, 2: у- и х-координаты джойстика В
биты 1, 0: у- и х-координаты джойстика А
С состоянием кнопок все просто — достаточно прочитать байт из порта 201h и определить значение нужных бит. Но чтобы определить координату джойстика, придется выполнить весьма неудобную и медленную операцию: надо записать в порт 201h любое число и засечь время, постоянно считывая состояние джойстика. Сразу после записи в порт биты координат будут равны нулю, и время, за которое они обращаются в 1, пропорционально соответствующей координате (Х-координаты растут слева направо, а Y-координаты — сверху вниз).
Если джойстик отсутствует, биты координат или будут единицами с самого начала, или будут оставаться нулями неопределенно долго. Кроме того, после записи в порт 201h нельзя писать в него еще раз, пока хотя бы один из четырех координатных бит не обратился в 1.
BIOS предоставляет функцию для работы с джойстиком — функцию 84h прерывания 15h, но работа напрямую с портами оказывается гораздо быстрее и ненамного сложнее. Например, чтобы определить координаты джойстика, BIOS выполняет целых четыре цикла измерения координат, по одному на каждую.
Чтобы получить значение координаты в разумных единицах, мы будем определять, на сколько изменилось значение счетчика канала 0 системного таймера, и делить это число на 16 — это будет в точности то число, которое возвращает BIOS. Для стандартного джойстика (150 кОм) оно должно быть в пределах 0 – 416, хотя обычно максимальное значение оказывается около 150. Так как аналоговые джойстики — не точные устройства, координаты для одной и той же позиции могут изменяться на 1 – 2, и это надо учитывать, особенно при определении состояния покоя.
Покажем, как все это можно реализовать на примере чтения координат джойстика А:
; процедура read_joystick
; определяет текущие координаты джойстика А
; Вывод: ВР - Y-координата, ВХ - Х-координата (-1, если джойстик
; не отвечает), регистры не сохраняются
readjoystick proc near
pushf ; сохранить флаги
cli ; и отключить прерывания, так как
; измеряется время выполнения кода и не
; нужно измерять еще и время выполнения
; обработчиков прерываний
mov bx,-1 ; значение X, если джойстик не ответит
mov bp,bx ; значение Y, если джойстик не ответит
mov dx,201h ; порт
mov al,0
out 43h,al ; зафиксировать счетчик канала 0 таймера
in al,40h
mov ah,al
in al,40h
xchg ah,al ; AX - значение счетчика
mov di,ax ; записать его в DI
out dx,al ; запустить измерение координат джойстика
in al,dx ; прочитать начальное состояние координат
and al,011b
mov cl,al ; записать его в CL
read_joystick_loop:
mov al,0
out 43h,al ; зафиксировать счетчик канала 0 таймера
in al,40h
mov ah,al
in al,40h
xchg ah,al ; AX - значение счетчика
mov si,di ; SI - начальное значение счетчика
sub si,ax ; SI - разница во времени
cmp si,1FF0h ; если наступил тайм-аут
; (значение взято из процедуры BIOS),
ja exit_readj ; выйти из процедуры,
in al,dx ; иначе: прочитать состояние джойстика
and al,0011b
cmp al,cl ; сравнить его с предыдущим
je read_joystick_loop
xchg al,cl ; поместить новое значение в CL
xor al,cl ; и определить изменившийся бит,
test al,01b ; если это Х-координата,
jz x_same
mov bx,si ; записать Х-координату в ВХ,
x_same:
test al,10b ; если это Y-координата,
jz read_joystick_loop
mov bp,si ; записать Y-координату в ВР
exit_readj:
test bx,bx ; проверить, равен ли ВХ -1,
js bx_bad
shr bx,4 ; если нет - разделить на 16,
bx_bad:
test bp,bp ; проверить, равен ли ВР -1,
js bp_bad
shr bp,4 ; если нет - разделить на 16
bp_bad:
popf
ret
read_joystick endp
Если вы когда-нибудь играли с помощью джойстика, то наверняка встречались с процедурой калибровки, когда игра предлагает провести джойстик по двум или четырем углам. Это нужно обязательно выполнять, чтобы определить, какие координаты возвращает данный конкретный джойстик для крайних положений, так как даже у одного и того же джойстика эти величины могут со временем изменяться.