5.10.11. Джойстик

И напоследок - о программировании джойстика. Он подключается к еще одно­му, помимо последовательного и параллельного, внешнему порту компьютера -к игровому. Для игрового порта зарезервировано пространство портов ввода-вы­вода от 200п до 20РЬ, но при общении с джойстиком используется всего один порт - 20 Ш, чтение из которого возвращает состояние джойстика:

порт 201Н для чтения:

биты 7, 6: состояние кнопок 2, 1 джойстика В биты 5, 4: состояние кнопок 2, 1 джойстика Абиты 3, 2: у- и джойстика В

биты 1, 0: у- и х-координаты джойстика А

С состоянием кнопок все просто - достаточно прочитать байт из lh и опре­делить значение нужных битов. Но для определения координаты джойстика при­дется выполнить весьма неудобную и медленную операцию: надо записать в порт любое число и засечь время, постоянно считывая состояние джойстика. Сра­зу после записи в порт биты координат будут равны нулю, и время, за которое они обращаются в 1, пропорционально соответствующей координате (Х-коорди-наты растут слева направо, а Y-координаты - сверху вниз).

Если джойстик отсутствует, биты координат или будут единицами с самого на­чала, или останутся нулями неопределенно долгое время. Кроме того, после запи­си в порт 20 lh нельзя производить это же действие еще раз, пока хотя бы один из четырех координатных битов не обратится в 1.

В BIOS для работы с джойстиком есть функция 84h прерывания 15h, но обще­ние напрямую с портами оказывается гораздо быстрее и ненамного сложнее. На­пример, чтобы определить координаты джойстика, BIOS выполняет целых четы­ре цикла измерения координат, по одному на каждую.

Чтобы получить значение координаты в разумных единицах, мы определим, на сколько изменилось показание счетчика канала 0 системного таймера, и разде­лим это число на 16 - результатом окажется то самое число, которое возвращает BIOS. Для стандартного джойстика (150 кОм) оно должно быть в пределах 0-416, хотя обычно максимальное значение оказывается около 150. Так как аналоговые джойстики - не точные, устройства, координаты для одной и той же позиции мо­гут изменяться на 1-2, и это надо учитывать особенно при определении состоя­ния покоя.

Покажем, как все это можно реализовать на примере чтения координат джой­стика А:

; Процедура геасі_]оузтіск.

; Определяет текущие координаты джойстика А.

; Выход:   ВР - У-координата,   ВХ - Х-координата

; не отвечает),  регистры не сохраняются.

(-1, если джойстик

read_joystick

pushf

cli

mov mov

mov

mov

out in proc

near

bx, -1 bp, bx

dx,201h

al,0 43h,al al,40h

Сохранитв флаги

и отключитв прерывания, так как

вычисляется время выполнения кода и не

нужно измерятв еще и время выполнения

обработчиков прерываний.

Значение X,   если джойстик не ответит.

Значение У,  если джойстик не ответит.

Порт.

Зафиксироватв счетчик канала 0 таймера.

' ірограммирование на уровне портов

'І!

x same:

exit_readj: test js

shr test

is

shr

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 :

Записать его в

'stick_

.loop:

 

mov

al,0

 

out

43h,al ;

Зафиксировать счетчик канала 0 таймера.

in

al,40h

 

mov

ah, al

 

in

al,40h

 

xchg

;

АХ - значение счетчика.

mov

si,.di ;

SI - начальное значение счетчика.

sub

si, ax ;

SI - разница во времени,

cmp

;

Если наступил тайм-аут

 

;

(значение взято из процедуры BIOS),

ja

exit_read] ;

выйти из процедуры.

in

al.dx ;

Иначе: прочитать состояние джойстика

and

al.OOtib

 

cmp

al.cl ;

сравнить его с предыдущим.

je

read_joystick_loc>p

 

xchg

al,cl ;

Поместить новое значение в CL

xor

al.cl ;

и определить изменившийся бит.

test

al,01b ;

Если это Х-координата,

jz

x_same

 

mov

bx.si ;

записать Х-координату в ВХ.

test

al,10b ;

Если это

jz

read_jOystick_loc>p

 

mov

bp,si ;

записать Y-координату в ВР.

bx bad:

bp_bad:

bx, bx

bx_bad

bx,4

bp, bp bp_bad

bp, 4

Проверить, равен ли ВХ -1.

Если нет -Проверить,

Если нет -

разделить на равен ли ВР

16.

■1.

разделить на 16.

popf ret

read_joystick endp

Если вы когда-нибудь играли с помощью джойстика, то наверняка вам извест­на процедура калибровки, когда игра предлагает провести джойстик по двум илESlHIIIi'^     Сложные приемы программирования

четырем углам. Это необходимо выполнять, чтобы определить, какие координаты возвращает конкретный джойстик для крайних положений, так как даже у одного и того же джойстика данные величины могут со временем изменяться.