Программирование аппаратных средств
Выполняя все эти операции, необходимо учитывать временные характеристики интерфейса. Сигнал STROBE можно посылать в порт управления не ранее, чем через 0.5 мкс после установки данных, что может потребовать введению в программу небольшой программной задержки (одной или нескольких команд jmp, см. приведенный ниже текст программы). То же относится и к длительности сигнала STROBE, которая не должна быть меньше той же величины 0.5 мкс. Практически программные задержки часто оказываются не нужны.
Обратимся еще раз к рис. 3.12. Принтер, сняв с линий данных байт данных, и начав его обработку (вывод на печать или сохранение во внутренней памяти), устанавливает ответный сигнал BUSY, действующий все время, пока принтер занят обработкой байта данных. Закончив обработку байта, принтер на некоторое время устанавливает сигнал АСК и сбрасывает сигнал BUSY. Окончание сигнала АСК (при сброшенном состоянии сигнала BUSY) говорит интерфейсу об окончании данной операции обмена и о возможности посылки следующего байта данных. Ввиду краткости сигнала АСК часто оказывается, что ожидать его снятия нет необходимости; достаточно дождаться неактивного состояния сигнала BUSY (т.е. 1 в бите 7 порта состояния). Вообще следует заметить, что различные принтеры могут несколько по разному выполнять свою часть протокола обмена. Рассмотренный ниже пример отлаживался на принтере Epson LQ100.
Приведем текст программы, в которой принтер программируется, как говорят, на физическом уровне, т.е. путем обращения к его портам. Разумеется, в большинстве случаев для вывода на принтер текста из выполняемой программы проще воспользоваться функциями DOS. Однако в некоторых специальных случаях приходится прибегать и к программированию через порты, например, если принтер используется в нестандартном режиме, или параллельный интерфейс служит для связи с нестандартным устройством.
В приведенном примере предполагается, что принтер выбран и установлен в исходное рабочее состояние, что обычно выполняется автоматически при его включении. Свидетельством этого будут установленные биты 2 и 3 (SLCT IN и INIT) в порте управления, а также бит 4 (SLCT) в порте состояния. В программе не выполняется анализ байта состояния на наличие ошибки или конца бумаги, что при работе с принтером, вообще говоря, следует предусматривать.
Третий метод программирования периферийного устройства – режим прерываний – рассмотрим на примере обработки прерывания от мыши. Как известно, мышь обычно подключается к первому последовательному порту СОМ1 и работает в режиме прерываний. Нажатие или отпускание любой клавиши, так же, как даже минимальное перемещение по столу, вырабатывает сигналы прерываний, сопровождаемые определенными кодами, которые поступают в порт данных интерфейса. Написав собственный обработчик прерываний для последовательного порта, мы получим возможность выполнять заданные действия, например, при нажатии левой и правой клавиш мыши. Следует подчеркнуть, что эти действия начнут выполняться практически в тот же момент, когда мы нажали на клавишу. В приведенной ниже программе при нажатии левой клавиши в центр экрана выводится цветная надпись "Левая!", а при нажатии правой клавиши – надпись "Правая" другого цвета.
Для того, чтобы приведенная программа работала, следует загрузить драйвер мыши, который инициализирует последовательный интерфейс и саму мышь. В состав этого драйвера входит свой обработчик прерываний. Мы замещаем его адрес в векторе 0Ch адресом нашего обработчика, и поскольку в программе не предусмотрено сцепление обработчиков, на время действия программы стандартная обработка прерываний от мыши отключается. Перед завершением программы содержимое вектора 0Сh восстанавливается, и мышь опять начинает работать, как обычно.
Каждое нажатие (или отпускание) клавиши мыши, так же, как и ее перемещение, в действительности вырабатывают не по одному, а по три последовательных прерывания с различными кодами в порте данных интерфейса. Так, нажатие левой клавиши мыши дает последовательность кодов 60h, 0, 0, нажатие правой клавиши – последовательность 50h, 0, 0, отпускание любой клавиши – 40h, 0, 0, перемещение вверх – 4Ch, 0, 3Fh, перемещение вниз – 40h, 0, 1 и т.д. Таким образом, по-настоящему надо было сохранять в обработчике прерываний все три кода и затем анализировать всю последовательность. Мы для простоты ограничились анализом только первого кода. Как видно из приведенного выше перечня, анализ одного кода не дает возможность отличить, например, отпускание клавиши от перемещения вниз.
Коды, генерируемые мышью, могут зависеть от ее типа, что надо учитывать при подготовке этого примера. Для получения значений генерируемых кодов можно предусмотреть в обработчике прерываний вывод их на экран с помощью функции прерывания 10h BIOS, как это было сделано, например, в примере 3.5, или прямым выводом в видеобуфер. Следует только иметь в виду, что перехват любого прерывания от последовательного интерфейса должен обязательно сопровождаться чтением из его порта данных, так как интерфейс может принять очередной байт данных только после чтения предыдущего и освобождения своего регистра данных.