[Назад] [Далее]

5.10.11. Джойстик

И напоследок — о программировании джойстика. Джойстик подключается к еще одному, помимо последовательного и параллельного, внешнему порту компьютера — к игровому. Для игрового порта зарезервировано пространство портов ввода-вывода от 200h до 20Fh, но для общения с джойстиком используется всего один порт 201h, чтение из которого возвращает состояние джойстика:

С состоянием кнопок все просто — достаточно прочитать байт из порта 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

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


п»ї
"target=_blank><\/a>") //-->