6.3.1 Вывод текстовых или графических данных на принтер.

  Процессор может заниматься  только  посылкой данных на принтер
или  он  может печатать в фоновом режиме, за  счет  использования
прерывания принтера. Возможна и  третья альтернатива, когда прог-
рамма  посылает символы на принтер через определенные  интервалы,
что можно рассматривать как "псевдопрерывание". Этот метод не так
тесно  координируется с работой принтера, как настоящее  прерыва-
ние, но во всяком случае работа принтера не критична ко времени.
   Независимо от того как выводятся данные, каждый раз на принтер
посылается только 1 байт данных. Языки высокого уровня предостав-
ляют функции, которые вроде бы выводят сразу целые строки, однако
на  самом деле эти функции разбивают строки на отдельные символы.
Обычно языки высокого  уровня  посылают  на  принтер пару возврат
каретки/перевод строки в конце каждой строки.  С другой  стороны,
программы на ассемблере  должны  сами  добавлять  эту пару кодов.
Из-за этого приходится немного больше программировать, но  взамен
Вы получаете намного большую  гибкость, особенно в отношении про-
верки ошибок.


   Высокий уровень.

   Для  посылки данных на принтер Бейсик предоставляет  операторы
LPRINT и PRINT#. LPRINT  не  требует  никакой  подготовки, но для
вывода оператором PRINT# Вы должны предварительно открыть принтер
в точности так же как и файл, с помощью  оператора OPEN "LPT1" AS
#1  или  OPEN "LPT3" AS #2.  Оператор LPRINT всегда адресуется  к
LPT1, в то время как PRINT# может адресоваться к любому принтеру.
   Пара возврат каретки/перевод строки  автоматически добавляется
в  конце  любого оператора LPRINT или PRINT#, если только  он  не
завершается точкой с запятой.   Для  избежания ненужных переводов
строки  не  забывайте завершать посылки любых  управляющих  кодов
точкой с запятой.  То же самое надо делать, если Вы хотите, чтобы
строки текста печатались подряд, прилегающие одна к другой. Одна-
ко имейте ввиду, что многие  принтеры не начинают печатать до тех
пор, пока они не получат данные для целой строки. Это определяет-
ся либо символом возврат  каретки, либо тем, что число переданных
символов достигло 80-ти (или другого числа). Не забывайте послать
завершающий  код  возврата  каретки,  чтобы  вытолкнуть последнюю
порцию символов из буфера принтера.
   Принтер  автоматически переходит на слдеующую строку по дости-
жению конца строки.  По умолчанию размер строки принтера равен 80
символам,  но у широких принтеров это значение может быть больше.
Строки, выводимые в  режимах  плотной  печати  или печати двойной
ширины, также меняют длину строки.  Для изменения номера столбца,
по достижении которого  головка  принтера  перейдет  на следующую
строку,  можно установить ширину принтера командой WIDTH "LPT1",n
- где n требуемый номер  столбца.  Когда печатается строка, длина
которой  больше или равна ширине принтера, то печатающая  головка
переходит на следующую строку,  что эквивалентно выполнению кодов
возврат каретки/перевод строки. Это означает, что в случае, когда
длина строки в точности равна  ширине  принтера, то будет сделано
два  перевода  строки, если эта строка завершается,  как  обычно,
парой возврат каретки/перевод строки.
   При графической печати принтер обычно  устанавливают на беско-
нечную  ширину.  Чтобы сделать это, надо подать команду установки
ширины, равной 255, WIDTH  "LPT1",255.  Если Вы забудете включить
эту  команду, то при выводе длинных последовательностей графичес-
ких данных Бейсик будет  вставлять  пару  возврат каретки/перевод
строки  после  каждых 80 байтов данных.  Эти  добавочные  символы
будут включаться в  общее  число  байтов  данных  для графической
печати,  поэтому  конец передаваемых данных будет просто  опущен.
   Один оператор LPRINT может содержать несколько  элементов дан-
ных в различных видах.  Информация может содержаться в самом опе-
раторе,  как  например в LPRINT "The rain in Spain", или  на  нее
можно ссылаться по имени  переменной, как в случае X$ = "The rain
in  Spain":  LPRINT X$.  Специальные символы могут включаться  за
счет использования функции  CHR$.   Управляющие коды обычно посы-
лаются  именно этим способом, например, LPRINT CHR$(10)  посылает
на принтер управляющий код перевода  строки.  Чаще всего CHR$ ис-
пользуется при посылке кодов ASCII, которые нельзя ввести с  кла-
виатуры. Любые из перечисленных типов данных могут быть объедине-
ны  в одном операторе.  Если Вы хотите, чтобы различные  элементы


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

100 LPRINT S$;" and ";Y$     'комбинация трех строк
110 LPRINT X, Y, Z           'вывод трех чисел
120 LPRINT "The total is "; X  'комбинация строки и числа
130 LPRINT "The ";CHR$(27);CHR$(45);CHR$(1);"real";
            CHR$(27);CHR$(45);CHR$(0);" thing."
            'подчеркивание среднего слова

   Оператор PRINT# может  использовать  те  же типы данных, что и
оператор LPRINT, и он также позволяет включать несколько  элемен-
тов данных в один оператор  и  смешивать  различные  типы данных.
Точки  с запятой и запятые действуют в нем  аналогичным  образом.
Вот примеры, эквивалентные вышеприведенным:

100 OPEN "LPT1:" AS #2
110 PRINT #2,S$;" and ";Y$
120 PRINT #2,X, Y, Z
130 PRINT #2,"The total is "; X
140 PRINT #2,"The ";CHR$(27);CHR$(45);CHR$(1);"real";
            CHR$(27);CHR$(45);CHR$(0);" thing."

   Средний уровень.

   Функция 0  прерывания  17H  посылает  один  символ на принтер.
Поместите  символ в AL, а номер принтера в DX.  При  возврате  AH
будет содержать регистр статуса, который надо постоянно проверять
для обнаружения ошибок. В [6.1.3] объясняется как это делать. Для
вывода потока данных  установите  указатель  на буфер, содержащий
данные, и напишите процедуру типа следующей:

;---вывод данных на LPT1
   MOV  CX,NUMBER_CHARS    ;CX содержит число байт для вывода
   MOV  DX,0               ;выбираем LPT1
NEXT_CHAR:  MOV  AH,0      ;функция посылки символа на принтер
   MOV  AL,[BX]            ;BX указывает на буфер данных
   INT  17H                ;посылаем символ
   TEST AH,8               ;проверяем бит ошибки

   JNZ  PRNTR_ERROR        ;на обработку ошибки
   INC  BX                 ;увеличиваем указатель
   LOOP NEXT_CHAR          ;выводим следующий символ

   Стандартное  прерывание MS DOS для вывода на принтер это функ-
ция 5 прерывания 21H.  Просто  поместите  символ в DL и выполните
прерывание.  Эта функция всегда выводит на LPT1 и у нее нет возв-
ращаемых регистров.


;---вывод данных на LPT1
   MOV  AH,5       ;номер функции
   MOV  DL,CHAR    ;готовим печатаемый символ
   INT  21H        ;посылаем его на принтер

   Другой способ вывода данных на  принтер это функция 40H преры-
вания  21H.   Это функция стандартного  вывода, с  использованием
метода дескриптора файлов  для  доступа  к  файлу  или устройству
[5.3.0].  В данном случае эта функция использует специальный пре-
допределенный номер файла для принтера.  Этот номер #4 и его надо
поместить  в BX.  Функция имеет доступ только к LPT1, поэтому для
вывода на другой  принтер  Вам   надо   поменять  базовые  адреса
[6.1.4].  DS:DX должны указывать на выводимые данные, а CX содер-
жать число посылаемых байтов. Например:

;---вывод 120 байтов данных на LPT1
   MOV  AH,40H       ;номер функции
   MOV  BX,4         ;номер файла для принтера
   MOV  CX,120       ;число посылаемых байтов
   LEA  DX,PRTR_DATA ;DS:DX указывают на данные
   INT  21H          ;посылаем данные
   JC   PRTR_ERROR   ;на обработку ошибки

При возврате установленный флаг  переноса  индицирует ошибку, при
этом AX будет содержать 5, если принтер не связан с машиной и 6 -
если указан неверный номер файла.  Отметим, что при использовании
предопределенного номера файла ненужно открывать устройство.

   Низкий уровень.

   Байт данных посылается на принтер, путем посылки его в регистр
выводимых данных, адрес порта которого  совпадает с базовым адре-
сом принтера.  Помните, что базовые адреса для LPT1-3 хранятся со
смещениями 8, 10 и  12  в  области  данных  BIOS  (начинающейся с
0040:0000).   После того как данные посланы в регистр на короткое
время включается бит строба  регистра  управления  выводом, адрес
порта  которого на 2 больше, чем для регистра данных.  Номер бита
строба равен 0 и он должен быть установлен только на очень корот-
кое  время,  чтобы инициировать передачу  данных,  находящихся  в
регистре данных. Процедура  печати  может немедленно сбросить бит
строба обратно в 0.
   После  того как байт данных послан, программа должна  ожидать,
пока принтер не сообщит, что он  готов  к  приему следующего. Это
делается  двумя способами.  При готовности принтер дает импульс в
бит подтверждения регистра статуса ввода, адрес порта которого на
1 больше базового адреса принтера. Номер бита подтверждения равен
6 и обычно он установлен в 1.   Импульс  подтверждения сбрасывает
этот бит в 0 на достаточно долгое время, чтобы программа на языке
ассемблера могла увидеть это,  если  она  постоянно следит за ре-
гистром.


   Другой  способ узнать, что принтер готов к  приему  следующего
байта данных состоит в  непрерывной проверке бита 7 регистра ста-
туса,  который сбрасывается в 0, когда принтер занят и устанавли-
вается в 1, когда он готов принять  данные. Если Вы пишите проце-
дуру печати низкого уровня, которая должна работать в интерпрети-
руемом Бейсике или другом очень медленном  языке, то надо исполь-
зовать этот метод.
   Следующий пример получает базовый адрес LPT1 из области данных
BIOS и затем выводит данные из  буфера,  на который указывает ре-
гистр BX.  Программа постоянно проверяет регистр статуса на заня-
тость и одновременно  проверяет  бит  3,  чтобы проверить наличие
ошибки на принтере.

;---подготовка
   MOV  AX,40H          ;ES указывает на область данных BIOS
   MOV  ES,AX           ;
   MOV  DX,ES:[8]       ;базовый адрес LPT1 в DX
   MOV  BX,DATA_START   ;BX указывает на буфер данных
;---посылаем символ
NEXTCHAR:  MOV  AL,[BX]  ;помещаем символ в AL
   OUT  DX,AL           ;посылаем символ
   INC  DX              ;DX будет указывать на регистр
   INC  DX              ;управления выводом
   MOV  AL,13           ;цепочка битов для импульса строба
   OUT  DX,AL           ;посылаем сигнал строба
   DEC  AL              ;нормальное ссотояние регистра
   OUT  DX,AL           ;посылаем его
;---проверка на ошибку и ожидание готовности принтера
   DEC  DX              ;DX указывает на регистр статуса
NOT_YET:  IN   AL,DX    ;получаем байт статуса
   TEST AL,8            ;ошибка?
   JNZ  PRTR_ERROR      ;переход на обработку ошибки
   TEST AL,80H          ;принтер занят?
   JZ   NOT_YET         ;если занят, то назад
   INC  BX              ;увеличиваем указатель в буфере данных
   DEC  DX              ;DX указывает на регистр данных
   JMP  NEXTCHAR        ;идем на печать следующего символа

   Когда  установлен  бит  4 управляющего регистра  принтера,  то
разрешено прерывание принтера.  Когда используется прерывание, то
программа  не должна ожидать сигнала готовности от принтера, неп-
рерывно опрашивая регистр  статуса  принтера. Вместо этого, прог-
рамма  может  послать символ и заниматься другими  делами;  когда
принтер будет готов для приема  следующего  символа, то он пошлет
сигнал  подтверждения (бит 6 регистра статуса на  короткое  время
будет установлен в 1)  и  автоматически  будет вызвано прерывание
принтера.  Процедура обработки прерывания пошлет на принтер  сле-
дующий символ и  вернет  управление  в программу, чтобы она могла
продолжать  свою работу, до тех пор пока не произойдет следующего
прерывания. Когда все данные будут выведены, то прерывание должно
отключить себя. Прерывание принтера во многом аналогично коммуни-
кационному прерыванию, которое обсуждается в [7.1.8].


   К сожалению, оборудование сделано так, что Вы не всегда можете
полагаться  на  это свойство для первого адаптера  принтера.   На
некоторых адапторах оно работает, а на других нет.  Только в слу-
чае последовательной/параллельной карты AT Вы может полагаться на
него полностью.  Вместо него можно использовать прерывание тайме-
ра, как объяснено в [2.1.7].  Установите микросхему таймера  8253

так,  чтобы  прерывание  происходило  медленнее,  чем скорость, с
которой  принтер обрабатывает данные.  Затем  напишите  процедуру
обработки прерывания, которая  посылает на принтер очередной сим-
вол  каждый раз, когда происходит прерывание времени суток.   Для
того чтобы обеспечить надежную синхронизацию  заставьте процедуру
проверять бит занятости принтера регистра статуса (бит 7) и  если
принтер еще занят, то пусть процедура не посылает символ.

 

Вы находитесь в разделе: 
Также вам будет интересно:

Добавить коментарий