Джойстик
И напоследок — о программировании джойстика. Джойстик подключается к еще одному, помимо последовательного и параллельного, внешнему порту компьютера — к игровому. Для игрового порта зарезервировано пространство портов ввода-вывода от 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
Если вы когда-нибудь играли с помощью джойстика, то наверняка встречались с процедурой калибровки, когда игра предлагает провести джойстик по двум или четырем углам. Это нужно обязательно выполнять, чтобы определить, какие координаты возвращает данный конкретный джойстик для крайних положений, так как даже у одного и того же джойстика эти величины могут со временем изменяться.
Содержание раздела