Глава 7. Клавиатура, дисплей.

Для выхода в меню нажмите кла­вишу "Reset".

Где находится клавиша "Any key "? Семеро одного дисплея не ждут.

Программисты шутят.

Данная глава является продолжением предыдущей. На примере клавиатуры, дисп­лея, принтера мы рассмотрим способы управления внешними устройствами. По тому, как программа справляется с ними, судят о мастерстве и профессионализме автора.

I.

Рассмотрим цепочку событий, которые происходят после нажатия некоторой кла­виши. Мы анализируем ситуацию какбысточки зрения микропроцессора. Более под­робно обуправлении клавиатурой см. Приложение 9.

После нажатия клавиши на микропроцессор, на вход INT, поступает сигнал пре­рывания от контролера прерываний (см. ниже). После этого микропроцессор заканчи­вает выполнение текущей команды и получает с шины номер прерывания, в данном случае 9. Затем микропроцессор выполняет команду INT 9H 16. После выполнения процедуры прерывания микропроцессор начинает выполнять следующую команду. Процедура, на которую показывает вектор 9Н, считывает из портов клавиатуры скан-код нажатой клавиши-каждой клавише присшишетсясвойскан-^^^ кодом). Данный скан-код анализируется на предмет того, какая клавиша нажата - ал­фавитно-цифровая, расширенная (с расширенным кодомASCII) или управляющая клавиша. Если клавиша алфавитно-цифровая, то ее ASCII код и скан-код помещаются в буфер клавиатуры (см. ниже). Если клавиша имеет расширенный код, то этот код также помещается в буфер клавиатуры вместе с нулевым байтом Наконец, если нажата управляющая клавиша, то 9-е прерывание меняет соответствующий флаг в словесостоянияклавиатуры,расположенномпоадресу0040Н:0017Н.Таким образом, одни клавиши изменяют содержимое буфера клавиатуры, а другие - слово состояния клавиатуры. Единственным исключением остается клавиша Ins. Она имеет расширен­ный код ASCII, и в тоже время данные о нажатии этой клавиши заносятся в слово-состояние клавиатуры. Кроме этого, 9-е прерывание выполняет ряд специальных фун­кций: распознает нажатие клавиш PrtSc, Ctrl-Break и производит соответствующие действия. На этом миссия этого прерывания заканчивается. Значение битов слова-со­стояния клавиатуры показано наРис. 7.1. На современной клавиатуре появился (и по­является) ряд новыхклавиш. Они в основном предназначеныдля операционной системы.

16 О прерываниях смотри главу 9.

17 Занимаясь программированием на любом языке, Вы, несомненно, должны знать, что расши­ренный код ASCII представляет собой двухбайтную величину, первый байт которой равен нулю.темы Windows. Операционная система MS DOS не обрабатывает эти клавиши. Одна­ко прерывание при нажатии этих клавиш происходит, и Вы {шо прочтению главы 9) сможете сами обрабатывать эти клавиши.

40Н:17Н

1 - правая Shift нажата; 1 - левая Shift нажата; 1 - Ctrl (любая) нажата; 1 - Alt (любая) нажата; 1 - режим ScrolLock; 1 - режим NumLock; 1 - режим CapsLock; 1 - режим Insert;

40Н:18Н.

1 - левая Ctrl нажата; 1 -левая Alt нажата; 1 - SysRec нажата; 1 - пауза; 1 - ScrolLock нажата; 1 - 1\1ит1_оскнажата; 1 - CapsLock нажата; 1 - Insert нажата;

Рис. 7.1, Слово-состояние клавиатуры.

Слово-состояние клавиатуры и буфер клавиатуры являются отправной точкой для работы специальной процедуры BIOS - прерывания 16Н(см. Приложение 8). Мы с ним уже встречались. Функции DOS получают сведения о нажатых клавишах только через это прерывание. Мы познакомились только с функцией 0 данного прерывания. Но есть и другие полезные функции.

Функция 1 - получить последний введенный символ из буфера клавиатуры, не ме­няя его содержимое (функция 0 удаляет символ из буфера) и не ожидая нажатия.

Функция 2 - дает первый байтслова-состояния клавиатуры, функция 5 вставляет символ в буфер клавиатуры ит.д.

Следующая программа - пример управления курсором натекстовом экране. Курсор управляется обычными клавишами управления. По нажатию клавиши ESC программа заканчивает свою работу. Границами перемещения курсора являются границы экрана.

CODE SEGMENT

ASSUME CS:CODE

ORG 100H BEGIN:

/определяем  текущее   положение курсора MOV ВН, О MOVAH,03 INT ЮН

/текущее положение теперь в DH-строка, DL-столбец L0O:

; ждем нажатия клавиши

MOV АН,О

INT 16Н ;если ESC,   то выход

CMP AL,27

JZ EXIT

CMP AL,О

JNZ   LOO /если не расширенный код,   то повторяем ввод

СМР АН,50Н /курсор вниз?

JNZ

N01

 

CMP

DH,24

;граница?

JZ

LOO

 

INC

DH

 

JMP

SHORT EX

 

CMP

АН,48Н

/курсор вверх?

JNZ

N02

 

CMP

DH, 0

/граница?

JZ

LOO

 

DEC

DH

 

JMP

SHORT EX

 

CMP

АН,4ВН

/курсор влево?

JNZ

NO3

 

CMP

DL,0

;граница?

JZ

LOO

 

DEC

DL

 

JMP

SHORT EX

 

N03:

/курсор вправо?

JNZ LOO

CMP DL>79 ;граница?

, JZ LOG

INC DL

EX:

новое   положение курсора координаты в X0R BH,BH ;страница 0

MOV AH,02

INT 10H /ставим курсор

JMP LOO

EXIT:

MOV АН,4CH

INT 21H CODE ENDS

END BEGIN

Рис. 7.2. Программа управления курсором.

Обратимсятеперькбуферуклавиатуры. Буфер клавиатуры располагается в сегменте Он имеет кольцевую структуру. Смещение головы его хранится в байте с адресом 1 АН (сегмент тот же). Смещение хвоста— в байте с адресом 1СН. Для самого буфера отведено пространство с ЗОНпо 60Н. Для записи клавиш отведено два байта: младший -код ASCII (илиО, еслирасширенньгй код), старший - скан-код (или второй байтрасширен-ногокода).Такимобразом,вбуфереможетхранитьсяпятнадцатьнажатийклавиш. Буфер становится переполненным, когда разность между содержимым байта 1 АН и байта 1СН становитсяравнымдвум(содержимое1СНна2меньшесодержимогоячейки 1АН)либов частном случае в 1 АН будет ЗО, а в 1СН - 60. Алгоритм того, как вставить очередной символ в буфер клавиатуры, можно описать следующими словами:

1. Проверяем, не переполнен ли буфер. Если не переполнен, то переходим к пунк­ту 2, в противном случае даем звуковой сигнал.

2. Помещаем код клавиши в ячейку, на которую указывает 1СН. Скан-код помеща­ем в следующий байт. Если клавиша имеет расширенный код, то в первую ячейку

поместим 0, а во вторую ее расширенный код.

3. Если содержимое 1СН было равно 60, то засылаем туда 30, в противном случае увеличиваем содержимое на 2.

Вы уже достаточно сильны в ассемблере, попробуйте реализовать этот алго­ритм ".Кстати, для очистки буфера клавиатуры нужно, чтобы и ІАНи 1СН содержа­ли одинаковое значение. Ниже представлена процедура очистки буфера клавиатуры.

Данный алгоритм реализован в прерывании 9Н. Вряд ли Вам понадобится писать свое соб­ственное прерывание обработки клавиатуры. О том, как перехватить готовое прерывание и воспользоваться им, мы поговорим в главе 9.

CLRBUF PROC CLI

PUSH AX

PUSH ES

MOV АХ,40Н

MOV ES,AX

MOV AL,BYTE PTR ES:[1CH]

MOV BYTE PTR ES:[1AH],AL

POP ES

POP AX

STI

RET

CLRBUF ENDP

Рис. 7.З. Очистка буфера клавиатуры.

На Рис. 7.4 показана процедура вставки в буфер клавиатуры кода символа. Код ASCII находится в CL, скан-код—в CH. В процедуре реализован алгоритм, описан­ный выше словесно.

IN_BUF PROC

CLI

PUSH PUSH PUSH MOV MOV MOV MOV CMP JZ ADD CMP JZ MOV MOV JMP SPEC: CMP JZ MOV MOV MOV

EN:

ES

SI

DI

DI,40H

ES,DI

DI,ES; [1СН] ;хвост SI,ES: [1AH]  ;голова DI, 60

SPEC DI,2 DI, SI

FUL

ES: [DI-2],CL ES: [DI-1],CH

SHORT EN

переполнен?

SI,30

FUL

ES: [DI], CL ES: [DI+1],CH DI, 30

случай

переполнен

MOV

ES: [1CH],DI

FUL:

POP DI POP SI POP ES STI RETN IN_BUF ENDP

Рис. 7.4. Процедура, вставляющая код символа в буфер клавиатуры.

Теперь Вы знаете достаточно, чтобы программно манипулировать буфером. Одна­ко помните, что на время работы с ним желательно отключать прерывания (CLI) -нажатие клавиши может быть сделано в момент работы программыс буфером. В этом случае могут произойти непредсказуемые события. В главе 17 будет приведен пример использования буфера клавиатуры.

Рассмотрим следующий простой пример (Рис. 7.5). Выход из программы происхо-дитлишь при одновременном нажатии клавиш CTRL, ALT, Fl.

CODE SEGMENT ASSUME CS:CODE

ORG 100H BEGIN:

;ждем нажатия клавиши MOV АН, О INT 16Н CMP AL, 0

JNZ BEGIN /если код не расширенный  - повторить

CMP АН/94 ;кОД одновременного нажатия Ctrl и F1

JZ PROV

СМР АН, 104        ;код одновременного нажатия Alt и F1 JZ PROV JMP  SHORT BEGIN PROV:

; здесь проверяем биты состояний клавиш Ctrl    и Alt MOV АХ,4ОН MOV ES,AX

TEST BYTE PTR ES:[17H],00000100В /проверка слова состояния ;   клавиатуры на клавишу Ctrl JZ BEGIN

TEST BYTE PTR ES:[17H],00001000В /проверка слова состояния /клавиатуры на клавишу Alt JZ BEGIN

EXIT:

MOV АН, 4CH

INT 21H

CODE ENDS

END BEGIN

Puc. 7.5.Выход из программы происходит при одновременном нажатии CTRL, ALT, Fl.

Идея этой программы состоит в том, что сочетания Ctrl F1 и Alt F1 имеют свои расширенные коды. Когда же нажимают все три клавиши, то неизвестно, какой код реализован на самом деле. Мы проверяем и тот, и другой случай, тем самым убежда­ясь, что по крайней мере нажата клавиша F1. А затем проверяем флаги и выясняем, нажаты ли одновременно клавиши Ctrl и Alt. Если перехватывать прерывание 9Н, то ту же процедуру можно сделать проще. Действительно, в этом случае нужно прове­рить только скан-код клавиши F1, а затем статус управляющих клавиш.

А сейчас мы рассмотрим вопрос, который волнует многих и, который до конца не знают даже некоторые опытные программисты. Вопрос собственно состоит в том, что значитдля приложений MS DOS ШСичто значит Ctrl Вгеаки "каксними бороться"?

Первое, что хотелось бы сказать, это то, что ситуации, когда эти прерывания

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

пользователем.

Чувствительными к нажатию известного сочетания клавиш являются только функ­ции DOS, процедуры BIOS не обращают на это внимание. Уровень чувствительности функций DOS можно регулировать. Естьдватаких уровня:

1. Чувствительны к Ctrl Break (Ctrl С) только функции символьного ввода-вывода -экран, принтер, в параллельный порт. .

2. Чувствительна большая часть функций DOS.

Чувствительность можно установить в файле CONFIG.SYS либо прямо в команд­ной строке командами BREAK OFF (первый уровень чувствительности) и BREAK ON (второй уровень чувствительности). Узнать, какой уровень чувствительности установ-ленвсистеме, можно из командной строки командой BREAK. Из программы это мож­но сделать, используя функцию DOS за номером ЗЗН, с помощью этой функции мож­но также изменитьуровеньчувствительности. Предположим, что в Вашей программе не используются функции DOS символьного ввода-вывода. В этом случае, того чтобы обезопасить себя от ненужного прерывания, достаточно установить первый уровеньчувствительности ». Правда, при выходе из программы может появиться зна-чок«лС», ноэто уже мелочи. Изложенномуподходу присвоим номер 1.

При распознавании Ctrl Break или Ctrl С функции DOS выполняют команду INT 23Н. 23-е прерывание осуществляет при этом выход из программы в порождающий процесс (обычно таковым является просто MS DOS). Второй способ устранения не­приятного прерывания заключается в том, что Вы перехватываете прерывание 23Н (см. главу 9) и направляете свою процедуру, в которой может стоять только одна команда - IRET. Таким образом Вы заблокируете выход по Ctrl Break (Ctrl С). Однако на экране по-прежнему может появляться значок

Стоитпоговоритьподробнееотом, что происходит принажатии клавиш Ctrl Break. Распознавание этих клавиш происходит еще на уровне 9-го прерывания. При этом

'» После выполнения программы следует восстановить исходные установки - правила хороше-готона.выполняется прерывание 1ВН. В процедуре, которая при этом выполняется, стоят все­го две . команды:

MOV BYTE PTR CS:[MEM],3 I RET

где MEM - некоторая ячейка памяти. Наличие в этой ячейке числа 3 является ин­дикатором того, что было нажато сочетание клавиш Ctrl Break. При нажатии такого сочетания клавиш ко всему прочему очищается буфер клавиатуры. При обнаружении в MEM числа 3 MS DOS немедленно выполняет команду INT 23Н. В случае с Ctrl С ситуация иная. Это сочетание распознается на уровне MS DOS. Дело в том, что у этого сочетания есть свой код - это 3. Появление данного кода в буфере клавиатуры распоз­нается MS DOS, и опять выполняется команда INT 23Н. Вы можете сэмитировать на­жатие клавиш Ctrl Break, послав в ячейку MEM число 3, а нажатие клавиш Ctrl С — послав в буфер клавиатуры также число 3 (второй байт- скан-код может быть любым).

Из всего сказанного вытекает еще один способ устранения нежелательного пре­рывания. Вектор 1ВН направляется на процедуру, где стоит всего одна команда IRET. Еще остается Ctrl С. Попадание кода 3 в буфер клавиатуры можно блокировать либо на уровне 16-го,либо на уровне 9-го прерывания. Например, на уровне 9-го прерыва­ния Вы определяете, не нажата ли клавиша С, и если нажата, то проверяете статус клавиши Ctrl. Если она также нажата, то Вы сбрасываете соответствующий битв сло­ве состояния клавиатуры. Двух этих операций достаточно, чтобы не обращать никако­го внимания ни на статус Ctrl Break, ни на то, какие функции MS DOS выполняет программа (см, конец главы 9).

П.

В предыщущей главе мы довольно долго говорили о работестекстовым экраном. От­давая себе отчет, что объем материала здесь просто неограничен, я всеже изложу здесь (далеко не полно, только для возбуждения интереса) лишь один вопрос - загружаемые символы. Вы, надеюсь, знаете, что импортная техника не русифицирована, т.е. для того, чтобы писать и читать русские тексты, необходимо вначале загрузить специальный драй­вер. В специальной области памяти хранятся шаблоны символов. Эта область памяти на­зывается знакогенератором: речьидето ЕОАили VGA-адаптере. При инициализации си­стемы BIOS загружает в знакогенератор шаблоны символов. Символы с кодами до 127 - это стандарт. Часть же символов с кодами от 128 до 255 можно использовать для введения национальныхалфавитов. В частности—русского алфавита. Этими занимают­ся всевозможные русифицирующие драйверы. Стандартные шаблоны символов находят­ся в ПЗУ, наначало этихшаблоновпоказываетвектор 44Н. При выполнении инициализа­ции режима экрана символы из ПЗУ копируются в знакогенератор.

Перед таким драйвером экрана-клавиатуры 20стоятчетыре задачи. Первая заклю­чается в том, чтобы загрузить в знакогенератор шаблоны символов. Вторая, более труд­

Вообще говоря, русификация дисплея и клавиатуры - две разные задачи, решения которых совсем не обязательно объединять в один драйвер.ная, состоит в том, чтобы установить переключатели для перехода от русского шриф­та к латинскому и обратно. Обычно это различные клавиши-переключатели. Задача решается перехватом прерывания клавиатуры и расшифровки того, нажата клавиша в русском или латинском регистре. После расшифровки клавише будет присвоен тот или иной код ASCII. Третья задача состоит в поддержке русского алфавита в графи­ческих режимах. Мыне будем это рассматривать. Замечутолько, что часто символы с кодами выше 127 в графическом режиме вообще никак не представлены (в отличие от текстового режима). Наконец четвертая задача драйвера заключается в том, чтобы не дать другим программам испортить загруженные в знакогенератор шаблоны (а испор­тить можно очень просто, если вызвать функцию 0 прерывания ЮН установка режима экрана). Для этого приходится отслеживать все вызовы прерывания 1 ОН.

Не вдаваясь в подробности, рассмотрим только, как можно загрузить в знакогене­ратор свои шаблоны символов. Вы можете использовать это в своей программе, если захотите работать с нестандартными символами. При выходе из нее легко восстано­вить прежнее состояние, выполнив команды:

MOV АХ,0003Н INT     ЮН       . - •

При этом знакогенератор загружается символами из ПЗУ. Чтобы не портить содер­жимое экрана, добавьте к содержимому AL 80H.

В качестве иллюстрации к сказанному Рис. 7.5 представлена простая програм­ма, после выполнения которой символ буквы А (код 65) будет заменен на прямоуголь­ник. ПрограммаиллюстрируетработуподфункцииОфункции 1 Шпрерывания ЮН. Функция 11 Нпрерывания ЮН-довольно сложная штука, и Вам не миновать ее, если требуется манипулировать экранными шрифтами.

CODE SEGMENT

ASSUME CS:CODE ORG 100H

BEGIN:

JMP BEG

для буквы А,  точнее символа с кодом 65

FONT:

DB 11111111В DB 10000001В

DB 10000001B DB 10000001B DB 10000001B

DB 10000001B DB 10000001B DB 10000001B

DB 40000001B

DB 10000001B

DB 10000001В DB 10000001В DB 10000001B DB 11111111В

BEG:

;следующие две ;Почему?

PUSH CS POP ES

MOV BP,OFFSET CS:FONT

;ES:BP теперь указывает на

MOV CX, 1

MOV DX,65

MOV BL, 0

MOV BH,14

MOV AL,0

MOV AH,11H

INT 10H

MOV AH,4CH

INT 21H CODE ENDS

END BEGIN

команды для  СОМ-программы не обязательны.

шаблон ;один символ ;буква А латинская

/блок 0,   отображаемый по умолчанию /в шаблоне   14  строк (байт) /подфункция О /функция 11Н /вызов прерывания

Рис. 7.б. Загрузка в знакогенератор шаблона символа А (65).

Ш. О различных видеоадаптерах.

Материал данного раздела носит несколько исторический оттенок.

В нашей книге мы касаемся в основном УвА-адаптеров. Между тем вопрос о ви­деоадаптерах- больной вопрос для многих программистов21. В текстовом режиме для УОА-адаптеров имеется 32 килобайта памяти. Есть соблазн использовать эту память в своих программах. Но у СОА-адаптеров памяти в текстовом режиме ІбК.ауНегсиІев'а всего4К.Крометого,видеобуферупоследнего адаптера начинается с адреса ОВОООН. Поэтому если нужно, чтобы Ваша программа работала на всех адаптерах, откажитесь от использования страниц видеопамяти. Мой совет: выделите в ОЗУ некоторую об­ласть памяти и эмулируйтеработу с ней, какс видеопамятью. Таким образом, по край­ней мере, часть проблемы по совместимости программы Вы решите.

Другая проблема - это адрес видеобуфера. Здесь проще всего поступить следую­щим образом. Причем можно обойтись без тестирования видеосистемы компьютера Проверьте режим экрана, если режим окажется равным 7, то попытайтесь переустано­вить его в 3-й. Если это удалось, то буфер начинается с ОВ800Н, а если нет — то с

а| Конечно сейчас CGA-уже экзотика. Материал, представленныйздесь,носитисторико-про-светительский характер.

ОВОООН. Как видим, алгоритм весьма прост. Необходимость переустановки связана с тем, что VGA-адаптеры при запуске компьютера устанавливают режим 7 на моно­хромном дисплее и 3 на цветном.

Если Ваша программа, однако, использует некоторые другие возможности видеосисте­мы, например, загружает в знакогенератор свои символы, то не обойтись без более тщатель­ного тестирования адаптера. Ниже приводится процедура, которая определяетвид адаптера. В АЬюзвращаетсяОдля VGA, 1 для EGA, 2для CGA, 3 - MDA, 4 - HerculesfHGC).

WHAT_AD PROC PUSH DX

PUSH BX ' .

PUSH CX; проверка наличия у прерывания ЮН функции 1АН - есть у VGA XOR AL,AL .     <    Л ,<

MOV АН, 1АН INT ЮН CMP AL, 1АН JNZ NO_VGA XOR AL, AL JMP SHORT EXIT NO_VGA:

; проверка наличия у прерывания ЮН функции 12Н - есть у EGA

MOV АН, 12Н

MOVBL, ЮН

INT ЮН

CMPBL, ЮН

JZ NOEGA

MOVAL,l

JMP SHORT EXIT NO_EGA:

/проверка наличия CGA ■ -

MOV DX,3D4H CALL SEARCH_6845

JC NO_CGA MOV AL,2

JMP     SHORT EXIT NO_CGA:

;проверка наличия MDA

MOV    DX, 3B4H ■ • • • ■■

CALL   SEARCH_ 6845

JC       NO_MDA ■ ■ ■

MOV AL,3 JMP     SHORT EXIT NO_MDA: .

MOV    AL,4 ■    : . .

EXIT:

POP CX POP BX POP DX RET

WHAT_AD ENDP

наличия контролера 6845

осуществляется путем записи в регистр,   а потом из него если значения совпали,  то контролер присутствует регистра OFH, адрес же порта у CGA и MDA различные SEARCHJ584 5 PROC MOV AL, OFH OUT DX, AL

INC DX

IN    AL, DX MOV AH, AL MOV AL, 66H OUT DX,AL MOVCX,100H DELAY:

LOOP DELAY

IN AL, DX XCHG AH, AL OUT DX,AL CMP АН,66H

JZ QUIT STC

QUIT:

RET

SEARCH_6845 ENDP

PMC.   Процедура определения видеоадаптера. уже отмечалось, материал, изложенный выше, носит исторический характер.

Однако сам метод определения, точнее, алгоритм, который можно назвать "последова­тельным прошу взять на заметку.

VI.

Данный раздел посвящен работе принтера. Материал поистине необъятный, но он будет сужен, если условимся говорить только о средствах работы с принтером и опус­тим подробности работы самого принтера. Приведя довольно полный пример по вы­воду на печать текста, я отсылаю за подробностями управления принтером к велико­лепному справочнику [5].

Выше был уже рассмотрен пример, как с помощью описателей можно направить вывод на принтер. У MS DOS есть специализированная функция для вывода на печа­тающее устройство - номер этой функции 5. Ксожалению, эта функция недаетдиагностики ошибок устройства.

В BIOS есть специализированная процедура вывода на печатающее устрой­ство. На нее направлен вектор Существенно то, что позволяет работать с тремя принтерами (порты LPT1, LPT2, LPT3), тогда как функции DOS работа­ют только с первым принтером - Кроме того, данное прерывание позволя­ет инициализировать принтер и дает полную диагностику ошибок на этом уст-ройстве(см. [5,13]).

Даннымпрерываниемпользуютсямногиедрайверы.Ивнекоторыхслучаяхжела-тельно обойти его, т.е. обратиться непосредственно к портам адаптера. Например, вы­вод можно сделать через INT ПН, а проверку готовности принтера осуществить, об­ратившись непосредственно к портам принтера.

На Рис. 7.7 приведена программа печати текстового файла, имя которого наби­рается в командной строке вместе с именем программы. Программа достаточно сложная. К ней Вам еще придется вернуться после изучения работы с файлами. Поэтому я не буду объяснять строки, относящиеся к чтению файла. Разберем дру­гие моменты.

По адресу DS:[81Н] располагаются параметры, которые набирались в команд­ной строке. В DS:[80H] лежит длина командной строки, но мы не используем этот байт. Если в командной строке ничего не набиралось, то по адресу DS:[81H] будет лежать 0DH. Если же в командной строке что-то было набрано, то необходимо учесть наличие в строке пробелов, как перед параметром, так и после него (если в строке он не один). Мы делаем это путем проверки каждого символа на пробел и фиксацией (с помощью регистра DL) того, что первая цепочка пробелов уже за­кончилась.

Перед каждым выводом на печать символа с помощью порта статуса определяем

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

готовности принтера. Если принтер готов, то символ из буфера посылается на печать с помощью функции 0 прерывания 17Н. После посылки символа проверяется байтв АН на случай ошибки вывода.

Адрес порта для первого принтера (обычно только он и есть) получаем в ячей­ке 40Н:08Н. Это так называемый базисный адрес. В нем содержится адрес порта принтера, в который посылают данные. Увеличив его на 1, мы получим порт стату­са принтера. Порт управления принтером можно получить, увеличив базисное зна­чение 2.

CODE SEGMENT

ASSUME CS-.CODE ORG 100Н

BEGIN:

JMP BEG

ТЕХТ1 DB 'Нет параметров.',13,10,'$'

4 - 4072

ТЕХТ2 ТЕХТЗ

PATH BUF PORT

PRIZ

COUNT DW BEG:

DB   'Файл не найден.1,13,10,'$'

DB не

DB 80 DUP(O) DB 160 DUP{?) DW ? DB 0 ?

/путь к файлу ;буфер для чтения файла ;адрес порта статуса принтера ;признак последнего считанного блока /количество считанных символов

XOR

XOR DI,DI MOV DL, 1

LOO:

CMP BYTE PTR JZ NO_PAR MOVAL, [81H+SI] CMP AL, ' '

JZ SPACE XOR DL, DL

MOV [PATH+DI],AL INC DI

JMP.   SHORT L001

/служит для определения конца первого параметра [81H+SIL0DH

SPACE:

OR JZ

DL, DL

NO_PAR

;пропустим пробел

/начался первый параметр /символ  в PATH

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

LOOl:

/был ли параметр

INC SI

JMP   SHORT LOO NO_PAR:

OR    SI,SI JNZ CONT ;сообщение,   затем выходим MOV DX,OFFSET TEXTl MOV AH,9 INT 21H JMP EXIT

CONT:

'/открываем файл LEA DX,PATH MOV AX,3D00H

INT 21H

JNC CONT1

/файла с таким именем, по-видимому, MOV DX, OFFSET TEXT2 MOV" AH, 9

нет

INT 21H

JMP SHORT EXIT CONT1:

MOV BX,AX

порт статуса ,-проверяем только LPT1

описатель будет в BX

MOV

базового порта по адрес

MOV

ES,AX

 

MOV

DX,ES:[8H]

 

INC

DX

статуса на 1 больше

MOV

PORT,DX

 

в буфер

 

PR_CONT:

 

 

MOV

DX,OFFSET BUF

;читаем в BUF

MOV

CX,160

;160 байт

MOV

AH,3FH

 

INT

21H

 

CMP

AX,0

 

JZ

CLOSE

/буфер пуст,   заканчиваем ■

MOV

COUNT, AX

считали - в COUNT

CMP

AX,CX

;не последний ли блок

JZ

NORM

 

MOV

PRIZ,1

/если 1,   то блок был последним

NORM:

 

 

LEA

SI,BUF

 

N1:

 

 

XOR

CX,CX

 

MOV

DX,PORT

 

NORM2:

 

 

IN

AL, DX

/читаем порт

40Н-.08Н

проверяем готовность TEST AL,00010000В

JZ N2

TEST AL,00001000B

JZ N2

TEST AL,10000000В

JNZ NORM1

N2:

CMP JZ

INC JMP

CX,400

PAUSE

CX

SHORT NORM2

/будем читать 400

/принтер не готов

раз,   и только

- сообщаем

тогда сообщение

NORM1:

XOR

О

4*

XOR DX,DX MOV AL, [SI] INT 17H CMP AH,1 JZ N1 INC SI DEC COUNT

JNZ N1

CMP PRIZ,1

JNZ PR_CONT ; закрываем файл CLOSE:

MOV

INT 21H

EXIT:

MOV

INT 21H

/Здесь сообщение о неготовности принтера /и ожидание указаний /если нажимаем Y,   то выходим в DOS PAUSE :

MOV АН,9

LEA DX,TEXT3

INT 21H

MOV AH,0

INT 16H

CMP AL,'Yr

JZ CLOSE

CMP AL, 'y'

JZ CLOSE JMP SHORT N1 CODE ENDS

END BEGIN

/принтер LPT1

в

/печатаем

/проверка на time-out /если ошибка,   то на проверку статуса /на следующий символ /уменьшаем счетчик / если не равен 0,   то продолжить печатать /не кончился ли файл /если не кончился,   то читать следующий блок

Рис. 7.8. Вывод на печать текстового файла.

В некоторых ситуациях желательно вообще обойтись без прерывания 17Н и рабо­тать только с портами. Рассмотрим в этой связи более подробно порты принтера. Выше было показано, как правильно получить адреса этих портов. Ниже подробно описьта-ются эти порты.

Порт данных - сюда засылается байт, посылаемый на печать. При этом порт может работать и на чтение. В нем хранится последний посланный на принтер байт.

Порт состояния принтера. Работает только на чтение. Первые три бита не исполь­зуются:

и

7       6      5      4       3      2       1 О

Биты:

'- 3:0=при печати возникла ошибка

1 .„-------_., _. -   4; 0=принтер в автономном режиме

I- 5:1=сигнал "конец бумаги"

I- 6: 0=принтер готов к печати

следующего символа

'- 7: 0=принтер занят, находится в

автономном режиме или произошла ошибка

Порт управления принтером. Работает на запись. Последние три бита не исполь­зуются:

7      6     5      4      3      2      1 О

Биты:

0:    запуска печати (см. ниже)

возврата каретки выводить перевод строки (в MS DOS должен

быть сброшен)

2: принтер вывод на печать

(Должен быть всегда установлен)

прерывания

Приведу алгоритм посылки данных на принтер. Я думаю, что читатель без труда сможет реализовать этот алгоритм самостоятельно. Замечу, что речь здесь идет о па­раллельном интерфейсе в стандарте Центроникс. При работе на отечественной техни­ке (вряд ли Вы ее сейчас встретите) можно встретить и другой стандарт ИРПС, кото­рый отличается от предыдущего в значительной степени механизмом посылки строба.

1. Посылаем байтв порт данных.

2. Послать сигнал строба - установить бит 0 в порте управления, а затем сразу сбросить его. Это может быть вначале байт 11, а затем 10.

3. Проверяем, биты 3-5 для обнаружения ошибки. Если ошибка, то переход на процедуру обработки ошибки.

4. Проверяем бит 7. Если принтер готов, то переходим к шагу 1.

В заключение сделаю еще одно, на мой взгляд, важное замечание. Статус принте­ра можно получить и с помощью функции 2 прерывания 17Н. Однако прерывание 17Н можетперехватывать какой-нибудь драйвер, не совсем кб^^

мацию. Информацию лучше получать из первых рук. При работе с портом статуса помните, что самыми информативными битами являются 7-й и 4-й. Может статься, что бит 7 всегда будет показывать готовность, тогда вся надежда только на бит 4. Воз­можна и обратная ситуация, когда о неготовности принтера можно будет судить толь­ко по биту 7.

V.

Проблема управления внешними устройствами усложняется тем, что как сами устройства, так и их адаптеры могут несколько отличаться друг от друга. В связи с этим возникает необходимость программного распознавания того, с какими устрой­ствами работает данный компьютер. Мы выходим на совершенно новую тему, кото­рую можно назвать "Ревизией системныхресурсов". Данный вопрос наиболее полно излагаетсявкниге [5] (см.также [9)13]).Мырассматриваемэтотвопросвглаве23. В данной главе ограничимся лишь перечислением и краткой характеристикой тех средств, с помощью которых можно осуществить такую ревизию.

Функции MS DOS. Среди функций, с помощью которых можно получитьразлич-ную системную информацию, особо следует выделить функции 1ВН, 1СН, 32Н, 52Н. Из вопросов, которые приходится решать программе с помощью функций DOS, отме­чу особенно важные: количество итип носителей, размер доступной памяти и начало цепочки блоков МСВ.

Функции BIOS. Следует особо выделить прерывание возвращающее слово -список оборудования. Отмечу также прерывания 13Н, ЮН, через которые можно по­лучить много интересной информации.

Информация на диске. Вместо того чтобы использовать функции DOS, можно по­средством прерываний 1 ЗН, 25Н получить информацию непосредственно с диска (см. главу

Область данных BIOS. Расположение области данных BIOS вы найдете в главе 2, подробную же структуру этой области можно узнать в [13]. Отмечу такие поля, как EGA область, списокоборудования (тоже, что прерывание 11Н),флаги клавиатуры идр.

Порты ввода-вывода. В некоторых случаях без обращения к ним вообще нельзя обойтись. Использование их для диагностики см. в [5]. Описание портов ввода-выво­да дано в Приложении 9.