х. Он может также подготав- ливать параллельный порт для операций прерывания, с тем чтобы принтер посылал прерывание к процессору, когда он готов к приему очередного символа, оставляя процессор свободным для других дел. Вот значение битов регистров статуса и управления: Регистр управления бит 0 0 = нормальная установка, 1 = вызывает вывод байта данных 1 0 = нормальная установка, 1 = автоматический перевод строки после возврата каретки 2 0 = инициализировать порт принтера, 1 = нормальная установка 3 0 = отмена выбора принтера, 1 = нормальная установка 4 0 = прерывание принтера запрещено, 1 = разрешено 5-7 не используются Регистр статуса бит 0-2 не используются 3 0 = ошибка принтера, 1 = нет ошибки 4 0 = принтер off-line, 1 = принтер on-line 5 0 = бумага вставлена, 1 = нет бумаги 6 0 = принтер подтверждает прием символа, 1 = нормаль- ная установка 7 0 = принтер занят, 1 = принтер свободен Не имеется никаких оснований, чтобы любая программа не имела процедуру восстановления при ошибках, возникающих при работе с принтером. Хорошо написанная программа должна начинать с проверки того, что принтер связан с машиной (on line). Если присоединен не один принтер, то программа должна позволять пользователю выбрать с каким из них он будет работать. Кроме того, эта процедура долж- на восстанавливать ситуацию при любых ошибках принтера, при этом хотелось бы, чтобы не было необходимости снова печатать весь документ. 6.1.1 Инициализация порта принтера/повторная инициализация принтера. Программы должны инициализировать порт каждого принтера (LPT1 - LPT3) перед первым использованием принтера. Порты принтера должны также повторно инициализироваться после устранения причин ошибки принтера. Не путайте инициализацию порта принтера с ини- циализацией самого принтера. Инициализация принтера это внутрен- нее дело принтера. Она происходит автоматически при его включе- нии и в большинстве случаев принтер не может быть повторно ини- циализирован без его выключения и повторного включения. Но прог- рамма может повторно инициализировать принтер, в том смысле, что могут быть восстановлены начальные параметры, которые принтер использует для печати, отменяя все специальные шрифты, остановы табуляции и т.д. Считается правилом хорошего тона производить такой сброс принтера, когда программа завершает работу с ним. Языки высокого уровня инициализируют порт принтера автомати- чески, но программы на языке ассемблера требуют для этой цели короткую процедуру. С другой стороны, восстановление начальных параметров печати требуется во всех программах. Некоторые принте- ры, такие как новые Эпсоновские принтеры, имеют "главный код сброса", который приводит к полному сбросу принтера. Но поскольку не все принтеры имеют такой код, то программа должна предусматри- вать в своей завершающей части восстановление всех измененных параметров. Например, она может подать коды выключения курсива, выключения плотной печати и т.д. Не забудьте включить вызов этой процедуры в процедуру выхода по Ctrl-Break. Имейте в виду, что на многих принтерах символы не печатаются до тех пор, пока не получен код возврата каретки, завершающий строку (или до тех пор пока не введена целая строка данных). Символы могут спокойно ожидать в буфере принтера, даже после того, как породившая их программа завершилась. Когда начинается новая передача данных на принтер, то эти символы будут напечата- ны. Чтобы избежать этой проблемы, не забывайте почистить буфер перед началом печати; а в качестве правил хорошего тона, чистите буфер также при завершении программы. Это делается посылкой на принтер кода ASCII 24 (при этом параметры печати не меняются). Средний уровень. Функция 1 прерывания 17H BIOS инициализирует порт принтера и возвращает байт, дающий статус порта. Поместите в DX номер порта - число от 0 до 2 для LPT1 - LPT3, после чего вызовите прерыва- ние. Байт статуса принтера (идентичный обсуждаемому в [6.1.2]) возвращается в AH. ;---инициализация LPT1 MOV AH,1 ;функция инициализации принтера MOV DX,0 ;LPT1 INT 17H ;проводим инициализацию Низкий уровень. Ренистр управления выводом каждого адаптера принтера имеет бит, который вызывает инициализацию адаптера. Этот регистр имеет адрес порта на 2 больше, чем базовый адрес адаптера. Напоминаем, что базовый адрес для LPT1 хранится в ячейке 0040:0008, для LPT2 - в 0040:000A и т.д. Имеют значение только младшие 5 битов ре- гистра управления выводом. Бит 2 - бит инициализации принтера и обычно он устанавливается в 1. Для инициализации адаптера надо сбросить этот бит в 0 на тысячу тактов пустого цикла (3000 для AT или на 1/20 секунды, используя счетчик времени суток BIOS [2.1.5]). В этот момент нужно, чтобы был установлен только бит 3 (принтер выбран). Поэтому пошлите в порт значение 12, сделайте задержку, а затем пошлите в порт обычное (без прерываний) неини- циализонное значение, которое равно 8. В данном примере инициализируется LPT1: ;---инициализируем LPT1 MOV DX,ES:[8] ;считываем базовый адрес в DX INC DX ;прибавляем 2 к базовому адресу INC DX ; MOV AL,12 ;значение для инициализации OUT DX,AL ;начинаем инициализацию DELAY: MOV AX,1000 ;начало пустого цикла DEC AX ;уменьшаем счетчик JNZ DELAY ;повторяем 1000 раз MOV AL,8 ;обычное значение для регистра OUT DX,AL ;конец инициализации 6.1.2 Проверка того, что принтер связан с машиной. Программа всегда должна проверить, что принтер связан с маши- ной, перед тем, как послать на него вывод. Легко установить, что принтер не готов, так как бит 3 регистра статуса принтера уста- навливается в 1 в этом случае. Но намного сложнее точно опреде- лить почему принтер не готов: выключен ли он, отменен выбор прин- тера или в нем нет бумаги. Это происходит из-за того, что принте- ры разных производителей посылают разные наборы битов в регистр статуса принтера, даже когда они находятся в идентичном состоя- нии. Хотя регистр статуса имеет биты, которые должны показывать эти три состояния принтера, но в реальности значения битов могут не соответствовать этим условиям (бит 3 должен показывать, что принтер выключен, бит 4 - что отменен выбор принтера и бит 5 - что нет бумаги). Нижеприведенные значения возвращаются в регистр статуса по стандарту "Эпсон", которому обычно следует IBM: Значение Цепочка битов Интерпретация 223 11011111 принтер готов 87 01010111 принтер не готов 119 01110111 нет бумаги в принтере 247 11110111 принтер выключен Регистр статуса ввода имеет адрес порта на 1 больше, чем базо- вый адрес принтера. Базовый адрес для LPT1 хранится по адресу 0040:0008, для LPT2 - по адресу 0040:000A и т.д. Имейте в виду, что если принтер был выключен, то ему требуется некоторое время на инициализацию после включения. Не начинайте печатать до тех пор, пока регистр статуса ввода не сообщит, что принтер связан с машиной и готов к приему данных. Высокий уровень. Данная процедура проверяет связан ли принтер с машиной и гово- рит пользователю что делать, если нет. Она использует значения из вышеприведенной таблицы. Как уже отмечалось, такой подход не подходит для процедуры общего назначения, которая будет обслужи- вать множество разных принтеров, но он вполне подходит, когда Вы пишете драйвер данного печатающего устройства. Отметим, что в строке 120 вычисляется двухбайтное число, путем умножения старше- го байта на 256 и добавления к младшему байту. Для получения адреса регистра статуса ввода к значению полученного базового адреса добавляется 1. 100 '''Получаем адрес LPT1 и проверяем готов ли принтер 110 DEF SEG = &H40 'указываем на область BIOS 120 PRTRBASE = PEEK(9)+256*PEEK(8)+1 'адрес регистра статуса 130 IF INP(PRTRBASE) = 223 THEN 180 'если принтер готов 140 BEEP 'иначе звонок и проверки 150 IF INP(PRTRBASE) = 87 THEN LOCATE 1,1: PRINT"Strike the SELECT key": GOTO 150 160 IF INP(PRTRBASE) = 247 THEN LOCATE 1,1: PRINT"Turn the printer on": GOTO 160 170 IF INP(PRTRBASE) <> 223 THEN 170 'ждем инициализации 180 '''Теперь принтер on-line -- можно начинать печать 190 LPRINT Z$ Средний уровень. Для получения байта статуса из порта принтера надо использо- вать функцию 2 прерывания 17H. При входе DX содержит номер LPT (0-2 для LPT1-3). Эта функция сбрасывает три неиспользуемых бита байта и делает операцию исключающего ИЛИ над двумя другими, поэ- тому значения отличаются от приведенных выше: Значение Цепочка битов Интерпретация 144 10010000 принтер готов 24 00011000 принтер не готов 184 10111000 принтер выключен И опять необходимо помнить, что эти значения меняются от принтера к принтеру. Наиболее общую информацию "выключен или не готов" дает бит 3 статуса равный 0. Низкий уровень. Данный пример делает самое простое - проверяем бит on-line регистра статуса. Для получения байта статуса используется базо- вый адрес LPT1. ;---в сегменте MESSAGE DB 'Printer not ready - strike any key when OK$' ;---проверка связан ли принтер с машиной (on-line) MOV AX,40H ;ES указывает на область данных BIOS MOV ES,AX ; MOV DX,ES:[8] ;получаем базовый адрес INC DX ;смещение для регистра статуса IN AL,DX ;получаем байт статуса в AL TEST AL,1000B ;проверяем бит 3 JNZ GO_AHEAD ;если принтер on-line, то вперед ;---печатаем сообщение об ошибке и ждем нажатия клавиши MOV AH,9 ;функция вывода строки LEA DX,MESSAGE ;DS:DX указывают на сообщение INT 21H ;печатаем сообщение MOV AH,7 ;функция ожидания ввода INT 21H ;ожидаем нажатия клавиши (без эха) GO_AHEAD: ;продолжение программы 6.1.3 Интерпретация ошибок принтера и восстановление после них. Проверка ошибок не должна прекращаться на том, что Вы убеди- лись, что принтер связан с машиной. Ошибки принтера могут проис- ходить в любой момент печати и программа должна быть готова восс- тановить ситуацию при сбоях. Хотя на принтере могут происходить самые разнообразные ошибки, только три типа ошибок возвращают информацию о себе в компьютер. Это ошибка "отсутствия бумаги", ошибка "отсутствия связи с машиной" и общее сообщение "произошла ошибка". Как уже говорилось в [6.1.2], не все принтеры сообщают об этих ошибках одинаковым образом, но теоретически регистр ста- туса ввода использует следующие биты: бит 3 = 0 когда произошла ошибка на принтере бит 4 = 0 когда принтер не связан с машиной (off-line) бит 5 = 1 когда кончилась бумага на принтере В частности, бит 4 может не использоваться указанным образом. Регистр статуса ввода имеет адрес порта, который на 1 больше, чем базовый адрес принтера. Базовый адрес для LPT1 хранится по адресу 0040:0008, для LPT2 - по адресу 0040:000A и т.д. На низком уровне, когда программа посылает данные на принтер, то она постоянно обращается к биту 7 этого регистра, чтобы прове- рить готов ли принтер принять очередной символ. Несложно при этом проверить при этом и бит 3, чтобы узнать о произошедшей ошибке. Если происходит ошибка, индицируемая битами 4 и 5, то по крайней мере бит 3 будет равен 0. Программа должна постараться проанали- зировать ошибку, а затем может попросить пользователя исправить ситуацию. Отметим, что функцию DOS, которая выводит символы на принтер (функция номер 5 прерывания 21H - см. [6.3.1]), можно заставить непрерывно проверять принтер на ошибку таймаута пос- редством команды MODE. Перед загрузкой программы, использующей функцию 5, надо ввести команду MODE LPT1: ,,P (еще лучше помес- тить эту команду в файл AUTOEXEC.BAT, с тем чтобы она всегда выполнялась при загрузке системы). Все эти ошибки приводят к тому, что печать останавливается и должны быть предприняты какие-то действия прежде чем она будет продолжена. Слишком огорчительно для пользователя программы, если большая порция документа должна будет печататься заново при воз- никновении ошибки на принтере. Тщательное продумывание процедуры восстановления по ошибке позволит программе возобновить печать с начала той страницы, на которой произошла ошибка. Необходимо всегда запоминать указатель выводимых данных при начале печати новой страницы. При начале работы процедуры восстановления она может попросить пользователя вставить новый лист бумаги, а затем продолжить печать с начала той страницы, на которой произошла ошибка. Высокий уровень. В Бейсике распознаются два ошибочных условия для принтера. Код ошибки 24 возвращается когда был отменен выбор принтера, а код 27 - когда принтер выключен или в нем отсутствует бумага. Эти коды можно получить с помощью техники обнаружения ошибок, приведенной в [7.2.5]. К сожалению эффективно отлавливается только код 27. Чтобы зарегистрировать код 24 требуется примерно полминуты, в течение которых программа заморожена. Не слишком полезно прямо читать регистр статуса перед каждой операцией печати. Этот метод сработает перед началом печати, но ничем не поможет, если во время печати произойдет отмена выбора принтера. Приводим процеду- ру обработки ошибок принтера: 100 ON ERROR GOTO 1000 'устанавливаем обработку ошибок . . 1000 '''проверяем произошла ли ошибка на принтере 1010 IF ERR = 24 OR IF ERR = 27 THEN GOSUB 2000: RESUME . . 2000 BEEP: LOCATE 1,1: PRINT"Printer not ready" 2010 PRINT "Strike any key when ready" 2020 IF INKEY$ = "" THEN 2020 'ожидаем ввода 2030 RETURN Средний уровень. Когда функция 0 прерывания 17H выводит символ на принтер, то она возвращает байт статуса принтера в AH. Проверяйте значение этого байта после посылки каждого символа. BIOS слегка модифици- рует байт статуса. Обычно бит 0 не имеет значения, но в данном случае он устанавливается, когда происходит ошибка таймаута (принтер не связан с машиной). В следующем примере проверяются два типа ошибок: общая ошибка "принтер не готов" и ошибка "от- сутствия бумаги". В примере предполагается, что в начале каждой страницы (т.е. после каждого перевода формата) программа запоми- нает указатель на начало выводимых данных, помещая его в перемен- ную STARTING_PTR. Это позволяет программе при возникновении ошиб- ки повторить печать с начала страницы, а не с начала всего доку- мента. Конечно принтер должен быть повторно инициализирован перед повторной печатью и должны быть восстановлены все его параметры. (Данный пример просто иллюстрирует проверку ошибок - он ни в коей мере не является рабочей процедурой.) ;---в сегменте данных MESSAGE1 DB 'Printer off-line - strike any key when ready$' MESSAGE2 DB 'Printer out of paper - strike any key when ready$' ;---посылаем символ и проверяем на ошибку NEXT_CHAR: MOV AH,0 ;номер функции MOV DX,0 ;выбираем LPT1 MOV AL,[BX] ;BX указывает на данные INC BX ;увеличиваем указатель INT 17H ;посылаем символ на принтер TEST AH,00001000B ;выделяем бит 3 (флаг ошибки) JZ NEXT_CHAR ;если нет ошибки, то печатаем дальше TEST AH,00100000B ;выделяем бит 5 (отсутствие бумаги) JZ OFF_LINE ;переход если с бумагой все в порядке MOV AH,9 ;готовим печать сообщения LEA DX,MESSAGE2 ;DS:DX указывает на строку INT 21H ;выводим строку JMP SHORT RECOVER ;уходим на восстановление OFF_LINE: MOV AH,9 ;готовим печать сообщения LEA DX,MESSAGE1 ;DS:DX указывают на строку INT 21H ;выводим строку RECOVER: MOV BX,STARTING_PTR ;восстанавливаем указатель MOV AH,0 ;функция ожидания ввода INT 16H ;ждем CALL PRTR_INIT ;инициализация принтера JMP NEXT_CHAR ;начинаем печать с начала страницы 6.1.4 Переключение между двумя или несколькими принтерами. Компьютеры, оснащенные несколькими параллельными портами могут иметь одновременно подсоединенными два или более принтеров. Вывод может перенаправляться с одного принтера на другой двумя способа- ми. Один способ состоит в том, чтобы использовать только такие операторы вывода на печать, которые указывают на какой принтер надо осуществлять вывод. Вы можете написать такой код, который позволит Вам изменять спецификацию. Второй способ переключения принтеров состоит в использовании вывода по умолчанию на LPT1, но указания другого принтера, кото- рый будет использоваться в качестве LPT1. Это достигается измене- нием базового адреса, относящегося к LPT1. Этот базовый адрес хранится в области данных BIOS в ячейке 0040:0008. Поменяйте его с базовым адресом для LPT2 или 3 (хранящимися в ячейках 0040:000A и 0040:000C) и в качестве LPT1 будет использоваться другой адап- тер. Высокий уровень. В Бейсике, если принтер был открыт оператором OPEN "LPT1" AS #1, то чтобы переключиться на другой принтер надо сначала напи- сать оператор CLOSE #1, а затем открыть другой принтер с помощью оператора OPEN "LPT2" AS #1. Впоследствии все операторы PRINT #1 будут направлять свой вывод на второй принтер. Это изменение труднее осуществить в программах, использующих оператор LPRINT, поскольку LPRINT по умолчанию посылает весь вывод на LPT1. В этом случае Вам необходимо поменять базовые адреса принтеров. Следую- щая программа на Бейсике делает именно это, переключая LPT1 и LPT2. Ее повторное использование переключает адреса обратно, возвращая систему к первоначальной конфигурации. 100 DEF SEG = &H40 'указываем на область данных BIOS 110 X = PEEK(8) 'получаем младший байт адреса LPT1 120 Y = PEEK(9) 'получаем старший байт адреса LPT1 130 POKE 8,PEEK(10) 'переносим младший байт адреса LPT2 140 POKE 9,PEEK(11) 'переносим старший байт адреса LPT2 150 POKE 10,X 'посылаем младший байт LPT1 в LPT2 160 POKE 11,Y 'посылаем старший байт LPT1 в LPT2 170 SYSTEM 'выходим из Бейсика Эта программа будет очень кстати, если готовое программное обеспечение не адресуется к нужному принтеру. Ее можно откомпили- ровать и хранить на диске, скажем под именем OTHERPRN, после чего надо будет только напечатать ее имя (в ответ на запрос DOS), чтобы переключиться с принтера на принтер. Если у Вас нет транс- лятора с Бейсика, то создайте командный файл OTHERPRN.BAT и по- местите в него строку BASIC OTHERPRN. Когда Вы напечатаете OT- HERPRN, то будет автоматически загружен Бейсик, который загрузит и выполнит программу OTHERPRN.BAS, после чего Вы вернетесь в операционную систему. Необходимо, правда, чтобы на диске имелся интерпретатор Бейсика BASIC.COM. Помните, что Вы должны устоять перед искушением испытать эту программу перед тем, как она будет записана на диск, поскольку если Вы ее запустите, то она сотрет себя. Низкий уровень. Один способ, которым программа на ассемблере может изменить принтер, на который она посылает данные, состоит в использовании для печати только функции 0 прерывания 17H [6.3.1]. Эта функция требует, чтобы номер принтера был помещен в DX. Заведите перемен- ную для этого номера, с тем чтобы он мог быть изменен в любой момент. Вторая возможность состоит в обмене базовых адресов LPT1 и LPT2 или LPT3. Следующая программа делает именно это. Как и все короткие утилиты, она должна писаться в COM форме, как объяснено в [1.3.6]. ;---обмен базовыми адресами LPT1 и LPT2 MOV AX,40H ;сегмент области данных BIOS MOV ES,AX ;ES указывает на данные MOV BX,8 ;смещение для базового адреса LPT1 MOV DX,ES:[BX] ;сохраняем базовый адрес LPT1 MOV AX,ES:[BX]+2 ;сохраняем базовый адрес LPT2 MOV ES:[BX],AX ;меняем базовый адрес LPT2 MOV ES:[BX]+2,DX ;меняем базовый адрес LPT1 Раздел 2. Установка спецификаций печати. Для установки различных спецификаций, относящихся к формату страницы, стилю шрифта и т.п., на принтер посылаются специальные управляющие коды. Эти коды посылаются на принтер как и любые другие данные. Некоторые из них это простые однобайтные коды из числа первых 32-х набора кодов ASCII. Эти управляющие коды (пере- численные в [7.1.9]) инициируют такие простые действия принтера, как перевод строки или перевод формата (прогон страницы). Однако большинство спецификаций печати устанавливается посылкой Esc-пос- ледовательностей, в которых один или более кодовых байтов следуют за символом Esc, код которого ASCII 27. Начальный код Esc инфор- мирует принтер, что символ(ы) который следует за ним следует интерпретировать как команду, а не как данные. Такие Esc-последо- вательности обычно не имеют символа-ограничителя, поскольку прин- тер "знает" длину каждой последовательности. Только в некоторых случаях, когда последовательность может иметь разную длину, тре- буется ограничивающий символ, в качестве которого всегда исполь- зуется код ASCII 0. Почти во всех случаях спецификации установленные этими кодами действуют до тех пор, пока они не будут явно отменены. Как только будет получен код, например, подчеркивания, то оно будет осу- ществляться до тех пор, пока не будет послан код отмены подчерки- вания. Буфер принтера может быть очищен без отмены установленных спецификаций. Но если произошла ошибка на принтере и принтер был выключен и включен, то необходимо снова устанавливать все специ- фикации. Большинство кодов устанавливающих спецификации принтера пере- мешаны с данными, на которые они действуют. Например, данные для слова, которое должно быть выделено жирным шрифтом, должны пред- варяться Esc-последовательностью, включающей жирный шрифт, и завершаться Esc-последовательностью, выключающей его. Поскольку универсальный стандарт на эти коды отсутствует, то печать с ис- пользованием мощных возможностей требует, чтобы для каждого под- держиваемого принтера были написаны драйверы. Каждый драйвер преобразует инструкции, генерируеиые процедурой печати, в прото- кол, используемый данным принтером. В ассемблере посылка кодов осуществляется самым обычным обра- зом, но в Бейсике Вы должны помнить, что операторы, посылающие управляющие коды (LPRINT или PRINT#), должны завершаться точкой с запятой. В противном случае операторы будут автоматически добав- лять к посылаемым кодам пару возврат каретки/перевод строки. Обсуждения и примеры последующих страниц в основном относятся к графическому принтеру IBM. Коды, используемые этим принтером, настолько же "стандартны", насколько и любой другой протокол. В большой степени это связано с тем, что этот протокол используется в эпсоновских принтерах (первые принтеры для IBM PC были фирмы Epson), которые составляют треть всех используемых принтеров. Управляющие коды, используемые принтерами IBM сравниваются в разделе [6.2.7]. Хотя информация, приведенная в данном разделе, может быть неприменима к тому принтеру, с которым Вы работаете, но большинство общих принципов применимо. 6.2.1 Установка текстового и графического режимов. Принтер всегда находится в текстовом режиме, до тех пор пока он специально не переведен в графический режим. Команда, устанав- ливающая графический режим, должна сообщать какое число байтов графических данных будет передано (но не больше одной строки) и после того, как это число байтов будет интерпретировано как гра- фическое изображение, принтер вернется в текстовый режим. По этой причине нет команды, которая переводит принтер в текстовый режим. Число графических режимов у разных принтеров разное. Во всех случаях, за кодом устанавливающим графический режим следуют 2 байта, указывающие какое число графических байтов будет передано (сначала младший байт). Чтобы вычислить значение этих двух бай- тов, разделите число байтов данных на 256 и поместите результат во второй байт, а остаток - в первый байт. За этими двумя байтами должны сразу следовать байты данных. Каждый байт определяет цепочку битов, соответствующих восьми вертикальным точкам одной позиции в строке. Младший бит (1) соот- ветствует низу колонки, а старший бит (128) - верху. Например, чтобы напечатать пирамиду, пошлите сначала байт, у которого уста- новлен только нижний бит, затем байт у которого установлены 2 нижних бита и т.д. После восьмого байта расположите те же байты в обратном порядке. Значение первого байта будет 1, второго - 3 (1+2), затем 7 (1+2+4), затем 15 (1+2+4+8) и т.д. На рисунке 6-1 изображена вся картина. Для печати пирамиды в Бейсике на графическом принтере IBM напишите следующий код: 100 LPRINT CHR$(27);CHR$(75);CHR$(15);CHR$(0);CHR$(1);CHR$(3); CHR$(7);CHR$(15);CHR$(31);CHR$(63);CHR$(127);CHR$(255); CHR$(127);CHR$(63);CHR$(31);CHR$(15);CHR$(3);CHR$(1); Первые два байта переводят принтер в графический режим с 480 точками, следующие два - сообщают, что будет передано 15 байтов графических данных, а затем идет последовательность байтов дан- ных. Конечно то же самое можно запрограммировать умнее, организо- вав цикл, в котором будут передаваться байты данных. Отметим, что все проблемы в этом случае возникают, если указанное число байтов не соответствует числу посылаемых байтов. Чтобы создать пробел между графическими фигурами выведите несколько байтов с нулевым значением. В Бейсике, когда в одной строке выводится больше 80 байтов графических данных, не забудьте предварительно установить "бесконечную" ширину принтера. Для этого надо ввести команду WIDTH "LPT1:",255. Графический принтер IBM имеет четырек графических режима, которые более или менее "стандартны". Они такие: 27,75 480 точек в строке. Нормальный режим. Максимум 480 байтов данных на оператор. 27,76 960 точек в строке. Удвоенное горизонтальное разрешение, но печать вдвое медленнее (двойная плотность). Максимум 960 байтов данных на оператор. 27,89 960 точек в строке, печать с нормальной скоростью (двой- ная плотность с высокой скоростью). Две точки, прилегаю- щие по горизонтали, не могут быть напечатаны, поскольку не будут успевать иголки печатающей головки. Если делается попытка их напечатать, то вторая точка будет игнорировать- ся. Максимум 960 байтов данных на оператор. 27,90 1920 точек в строке, печать вдвое медленнее (четверная плотность). Соседние точки по горизонтали должны отстоять по крайней мере на 3 точки (т.е. 1 печатаем, 2 пропуска- ем). Максимум 1920 байтов данных на оператор. В более плотных режимах две прилегающие по горизонтали точки не могут быть напечатаны. Чтобы заполнить пропуски между точками, верните каретку к левому полю, немного сдвиньте печатающую голов- ку вправо и сделайте второй проход, используя те же данные. Вот сравнение плотностей печати вызываемых одними и теми же управляю- щими кодами на разных принтерах: Коды Графический Цветной Компактный Пропринтер 27,75 480 точек 1108 560 480 27,76 960 точек 2216 - 960 27,89 960 точек 2216 - 960 27,90 1920 точек 4432 - 1920 Цветной принтер уникален из принтеров IBM тем, что он может устанавливать масштабный коэффициент (aspect ratio) для графичес- ких изображений. Этот коэффициент отражает разницу горизонтальных и вертикальных расстояний между точками. Обычно желателен коэффи- циент 1:1, поскольку в противном случае трудно проводить графи- ческие вычисления. Но при копировании графического экрана надо чтобы масштабный коэффициент был таким же, как у дисплея. В эк- ранном режиме умеренного разрешения 5 точек по вертикали занимают тот же размер, что 6 точек по горизонтали. Это соответствует масштабному коэффициенту 5:6 и именно это значение используется по умолчанию цветным принтером. Допускаются только коэффициенты 1:1 и 5:6. 6.2.2 Управление расстоянием между строками. Если не принимать во внимание принтеры, имеющие специальные возможности графопостроителя, то вся печать осуществляется стро- ками. Даже графические изображения рисуются построчно, хотя в этом случае нет пустых мест между строками. Код ASCII 10 - стан- дартный управляющий код перевода строки. Посылка его на принтер (без предшествующего кода Esc) приводит к тому, что бумага будет продвинута вперед на указанный интервал. Обычно, если перевод строки не посылается за кодом возврата каретки, то печатающая головка возвращается к левому краю бумаги и можно снова печатать на той же строке. Однако можно сделать так, чтобы перевод строки делался автоматически при каждом возврате каретки. Этим управляют переключатели на принтере. Это же можно сделать установив бит 1 регистра управления выводом (см. [6.1.0]). Многие принтеры могут включать и выключать автоматический перевод строки с помощью управляющих кодов 27,53, а некоторые могут делать обратный пере- вод строки с пмощью кодов 27,93. По умолчанию графический принтер использует интервал печати равный 1/6 дюйма (т.е. выводят 6 строк на дюйм) и к этому режиму всегда можно вернуться, посылая управляющие коды 27,50 (эти коды используются также в сочетании с коды изменения интервала между строками, обсуждаемыми ниже). Для этого принтера имеются еще два предопределенных межстрочных интервала, 1/8 дюйма и 7/72 дюйма. Соответствующие им управляющие коды 27,48 и 27,49. Возможна и более тонкая градация межстрочных интервалов. Гра- фический принтер использует три кода, позволяющие изменить интер- вал на очень малую величину. Все три управляющих кода используют 2-хбайтную Esc-последовательность, за которой следует число 72-х или 216-х долей дюйма, определяющих межстрочный интервал. Верти- кальное расстояние между центрами двух точек равно 1/72 дюйма. Интервал 8/72 дюйма не оставляет промежутка между строками (9 строк на дюйм). Стандартный интервал 6 строк на дюйм задается числом 12/72 дюйма. Наконец, 1/216 равна 1/3 от 1/72. Изменение на такую величину позволяет печатающей головке слегка сдвинуться от центра строки, с тем чтобы точки при втором проходе заполнили промежутки, обеспечивая печать более высокого качества. Вот эти Esc-последовательности: Изменение Esc-последовательность 72-е дюйма 27,65,n (где n от 1 до 85) 216-е дюйма 27,51,n (где n от 1 до 255) 216-е дюйма 27,74,n (где n от 1 до 255) Команды для изменения интервала в 72-х дюйма не станут активными до тех пор, пока не встретится второй управляющий код: 27,50. Как объяснялось выше, этот код может также использоваться отдельно для восстановления стандартного интервала в 1/6 дюйма. Если ранее была использована команда 27,65,n, то для восстановления интерва- ла в 1/6 дюйма надо послать команду 27,65,12,27,50. Два управляю- щих кода для интервалов в 1/216 дюйма не идентичны. Первый код устанавливает, что все последующие переводы строки будут выпол- няться с указанным интервалом; второй же действует только на один перевод строки, а затем возвращает интервал, который действовал до этого. Следующая таблица сравнивает межстрочные интервалы, вызываемые одними и теми же управляющими кодами на различных принтерах IBM: Коды Матричный Графический Цветной Компактный Струйный Ромашка Про- принтер принтер принтер принтер принтер принтер 27,48 1/8 1/8 1/8 1/9 1/8 1/8 1/8 27,49 7/72 7/72 6/72 1/9 9/96 7/72 27,50 1/6 1/6 1/6 1/6 1/6 1/6 1/6 27,51 n/216 n/144 n/216 27,65 n/72 n/72 n/72 n/72 n/72 27,74 n/216 n/144 n/216 Независимо от того как изменяются межстрочные интервалы, прин- тер всегда контролирует прямые и обратные движения листа, поэтому пропуски перфорации всегда делаются вовремя. 6.2.3 Управление движением бумаги. Бумага на принтере передвигается командами перевода строки, вертикальной табуляции и перевода формата. Установкой переключа- телей на принтере определяется будет ли принтер автоматически переходить на новую страницу при обнаружении перфорации между страницами. Если перфорация не будет пропускаться, то печать может завершиться прямо на вернем краю очередной страницы. Про- пуск перфорации оставляет по три пустых строки сверху и снизу каждой страницы. На самом деле принтер не распознает перфорацию, вместо этого он считает, что в начальный момент бумага выравнена на начало страницы и считает число переводов строки. Можно прог- раммно переопределить установку переключателей, посылая на прин- тер управляющие коды 27,56, чтобы принтер не делал пропуска пер- форации и 27,57, чтобы делал пропуск перфорации. Графический принтер использует код, который определяют число строк, пропускаемых между страницами. Этот код 27,78,n, где n - число строк от 1 до 127. Например, код 27,78,10 приведет к тому, что принтер будет пропускать по 10 строк. Если межстрочный интер- вал равен 1/6 дюйма, то 11-тидюймовая страница будет содержать 66 строк и после печати каждых 56-ти строк принтер будет делать пропуск 10-ти строк. Уже Ваша программа должна позаботиться, чтобы в самом начале прогнать бумагу на 5 строк, с тем чтобы 55 строк текста были центрированы на каждой странице. Если используется бумага, размер которой отличается от стан- дартного 11-тидюймового, то можно изменить длину страницы, с тем чтобы пропуски перфорации происходили в нужном месте и чтобы перевод формата устанавливал бумагу в правильную позицию. Размер страницы может устанавливаться либо числом строк на странице, либо размером в дюймах. Чтобы установить число строк на странице, пошлите код 27,67,n, где n - число строк. Та же последователь- ность используется и для установки длины страницы в дюймах, за исключением того, что длина страницы записывается в форме 0,n, где n может быть от 1 до 22 дюймов. Для стандартной страницы надо послать команду 27,67,0,11. 6.2.4 Управление положением печатающей головки. Печатаемый текст распределяется по странице частично за счет движения бумаги [6.2.3], а частично за счет движения печатающей головки. Головка может быть позиционирована в любое место, но не путем задания ее координат. Вместо этого указывается ее смещение, относительно самой левой позиции, которую она может достигать. У принтера нет датчиков, сообщающих текущее положение головки. Ваша программа должна отслеживать положение головки, если оно должно быть известным. При этом хорошей практикокй является начинать печать с подачи управляющего кода 27,60, который сдвигает головку в самую левую позицию, не делая перевода строки (то же самое делает и код возврата каретки). При печати текста имеется несколько способов передвинуть го- ловку в нужное положение. Она может сдвигаться вправо подачей одного или нескольких символво пробела или табуляции и влево подачей одного или нескольких символов "возврат на шаг" или сим- вола возврата каретки. Движения осуществляются непрерывно - не воспринимайте их как соответствующие последовательности на обыч- ной пишущей машинке. До тех пор, пока Ваша программа знает на- чальное положение печатающей головки она может комбинацией пере- водов строки, пробелов, табуляций и возвратов на шаг форматиро- вать Ваш вывод в соответствии с Вашими пожеланиями. Принтеры, которые умеют выполнять обратный пеервод строки могут использо- ваться и как графопостроители. В графических режимах возможно перемещение головки на малые доли дюйма. При печати текста Вы можете войти в графический ре- жим, чтобы добиться разных промежутков между словами. К сожале- нию, этот процесс существенно замедляет печать. Смотрите пример в пункте [6.3.2]. Имеется специальный код, который заставляет головку всегда возвращаться в крайнюю левую позицию перед печатью очередной строки, отменяя двунаправленную печать. Хотя это значительно замедляет печать, однако при этом достигается более точное пози- ционирование головки. Это особенно полезно при работе в графичес- ком режиме. Чтобы включить однонаправленную печать надо послать код 27,85,1, а чтобы вернуться к двунаправленной печати - код 27,85,0. 6.2.5 Установка позиций табуляции. В зависимости от принтера могут устанавливаться позиции гори- зонтальной и вертикальной табуляции (графический принтер IBM не имеет вертикальной табуляции). Горизонтальные табуляции опреде- ляются, как смещения от левого края, выраженные в пробелах. В некоторых случаях допускаются до 112 позиций горизонтальной табу- ляции. Аналогично, вертикальные табуляции определяются как смеще- ния относительно верха страницы, а измеряются они в межстрочных интервалах. Для большинства принтеров IBM допускается не больше 64-х позиций вертикальных табуляций. Первые два байта кода для установки горизонтальной табуляции 27,68, а для установки вертикальной табуляции - 27,66. Для обоих типов табуляций далее идет строка байтов, дающая позиции табуля- ции в возрастающем порядке. Эта строка должна завершаться байтом ASCII 0, который служит ограничителем. Для установки горизонталь- ной табуляции в позициях 15, 30 и 60 пошлите на принтер код 27, 68, 15, 30, 60, 0. Для установки вертикальной табуляции в строках 8 и 12 - пошлите код 27, 66, 8, 12, 0. Отметим, что если размер страницы отличается от стандартных 11-ти дюймов, то он должен быть установлен перед установкой позиций вертикальной табуляции. Вертикальная табуляция отменяется кодом 27,67. Отметим, что большинство принтеров не имеют установки полей как таковой. Левое поле может создаваться за счет вывода табуля- ции или ряда пробелов в начале каждой строки. Для точной установ- ки полей перейдите в графический режим и выведите ряд байтов ASCII 0. Правое поле создается просто за счет ограничения длины строки. 6.2.6 Изменение шрифта печати. Ширина страницы 8 1/2 дюйма позволяет напечатать в строке до 80-ти обычных символов, если все они имеют одинаковую ширину. Пропорциональная печать [6.3.3] позволяет поместить в строке еще несколько символов. С другой стороны, плотная печать позволяет вывести в строке 132 символа, печать с двойной шириной - 40 сим- волов, а плотная печать с двойной шириной - 64 символа. Имейте ввиду, что использование печати с разной шириной в одной строке приведет к трудностям с форматированием. Большинство матричных принтеров предоставляют набор режимов печати специальными шрифтами. Вот перечень стандартных возможнос- тей предоставляемых графическим принтером IBM: Плотная печать: Для включения режима плотной печати надо послать однобайтный управляющий код 15. Для выключения этого режима - код 18. Стан- дартная страница шириной 8 1/2 дюйма позволяет напечатать 132 символа в строке в этом режиме. Печать с двойной шириной: Для того, чтобы принтер начал печатать с двойной шириной надо послать на него управляющий код 14. Режим печати с двойной шири- ной необычен тем, что принтер автоматически выключает этот режим, когда встречает символ возврата каретки или перевода строки. Поскольку такой вид печати обычно используется для однострочных заголовков, то это свойство удобно. Чтобы выключить этот режим в середине строки пошлите код 20. Выделенная печать: При выделенной печати каждый символ печатается два раза в одной и той же позиции. Это делает точки темнее, что создает эффект выделения. Скорость печати при этом уменьшается вдвое. Для включения этого режима пошлите код 27,69. Для выключения - 27,70. Печать за два прохода: В режиме печати за два прохода бумага сдвигается на 1/216 дюйма перед вторым проходом печатающей головки. При этом полу- чаются более заполненные буквы, которые к тому же выглядят ярче. Скорость печати уменьшается вдвое. Этот