В этой главе мы расскажем об использовании матричных принтеров и способах их подключения к компьютеру.
Матричные принтеры распространены наиболее широко, в основном из-за их низкой стоимости. Если у вас нет потребности в печати большого объема документации (тысячи листов), или вам не нужно типографское качество получаемых документов, используйте матричные принтеры.
Существуют две группы матричных принтеров, различающихся по системе используемых команд - это принтеры, совместимые с принтерами Epson и принтеры, совместимые с IBM Proprinter. Принтеры некоторых третьих фирм-производителей компьютерного оборудования (не Epson и не IBM) обычно выполняют эмуляцию команд обоих или одной из этих групп в зависимости от установки переключателей конфигурации.
Кроме того, различные модели принтеров, например, производства фирмы Epson, также отличаются набором команд. Как правило, обеспечивается совместимость по командам снизу вверх, то есть более новые модели поддерживают команды предыдущих моделей принтеров.
Очень распространены принтеры серии Epson FX: FX-80, FX-850, FX-1050. Печатающие головки этих принтеров имеют девять иголок, поэтому качество печати принтеров серии FX оставляет желать лучшего. Принтеры серии Epson LQ используют для печати 24 иголки, кроме того, некоторые модели способны печатать цветные изображения (например, Epson LQ-2550). Качество печати принтеров LQ сравнимо с типографским.
Принтер подключается к компьютеру двумя способами: либо через асинхронный адаптер, рассмотренный ранее, либо через порт параллельной передачи данных. Возможно подключение к одному компьютеру сразу нескольких принтеров, причем принтеры могут быть подключены одновременно и к параллельному порту, и к асинхронному последовательному адаптеру.
Для подключения принтера к последовательному порту компьютера принтер должен быть оборудован специальным последовательным интерфейсом. Кроме того, необходимо использовать специальный кабель. Если вы подсоедините принтер к последовательному порту при помощи кабеля, предназначенного для работы с параллельным портом, то это может привести к повреждениям в оборудовании компьютера или принтера. Внимательно читайте раздел документации на принтер, посвященный подключению его к компьютеру.
В этой главе мы сделаем упор на использование порта параллельной передачи данных, так как именно этот вариант подключения принтера наиболее распространен.
BIOS может работать с тремя параллельными принтерными портами. В процессе тестирования и инициализации системы BIOS находит работоспособные принтерные порты и записывает их базовые адреса в таблицу. Таблица адресов располагается в области данных BIOS по адресу 0000:0408h. Возможны следующие значения базовых адресов:
Принтерные порты могут вырабатывать запросы на прерывание:
Каждый принтерный порт (принтерный адаптер) обслуживают несколько портов ввода/вывода. Рассмотрим их назначение.
Этот порт предназначен для записи выводимого на принтер байта данных. Возможно также чтение только что записанного байта.
Порт управления принтером, доступен для чтения
и записи:
7 6 5 4 3 2 1 0 T-T-T-T-T-T-T-T-¬ | | | | | | | LT+-+T+T+T+T+T+T- L=T=- | | | | L= строб данных, принимает значение 1 при | | | | | выводе байта, подключен к 1 контакту | | | | | разъема, STROBE; | | | | | | | | | L=== автоматический перевод строки после | | | | символа "возврат каретки" CR, контакт 14, | | | | AUTO LineFeed; | | | | | | | L===== сброс принтера, активный уровень - 0, | | | контакт 16, INIT; | | | | | L======= выбор принтера для работы, контакт 17, | | SLCT IN; | | | L========= разрешение прерывания от принтера, | IRQ Enable; | L============= равно 0.
Если прерывания от принтера разрешены, они вырабатываются, когда сигнал готовности принтера ACK (контакт разъема 10) принимает уровень логического 0.
Порт состояния принтера, доступен только для чтения:
7 6 5 4 3 2 1 0 T-T-T-T-T-T-T---¬ | | | | | | | LT+T+T+T+T+T+-+T- | | | | | L===|= установлены в 0; | | | | | | | | | L======= сигнал ошибки, активный уровень - 0, | | | | контакт разъема - 15, ERROR; | | | | | | | L========= принтер выбран, контакт 13, SLCT; | | | | | L=========== конец бумаги, контакт 12, PE; | | | L============= готовность принтера, активный уровень - 0, | контакт разъема - 10, ACK; | L=============== 0 - принтер занят, находится в состоянии offline или произошла ошибка, контакт 11, BUSY.
Обычно редко приходится работать с принтером на уровне портов ввода/вывода, так как достаточно использовать функции BIOS или MS-DOS, предназначенные для этого. Приведенная выше информация может пригодиться вам для разработки собственного драйвера принтера или для подключения к принтерному порту какого-либо другого устройства ввода/вывода, например, аналого-цифрового преобразователя.
Для тех, кто будет использовать принтерный порт для подключения аппаратуры, приведем таблицу назначения контактов разъемов принтерного порта (контакт PC) на компьютере и контактов разъема непосредственно на принтере (контакт принтера):
Контакт Контакт Назначение Вход/выход PC принтера 1 1 Строб (STROBE) Выход, инверсия 2 2 Данные, бит 0 Выход 3 3 Данные, бит 1 Выход 4 4 Данные, бит 2 Выход 5 5 Данные, бит 3 Выход 6 6 Данные, бит 4 Выход 7 7 Данные, бит 5 Выход 8 8 Данные, бит 6 Выход 9 9 Данные, бит 7 Выход 10 10 Подтверждение, ACK Вход, инверсия 11 11 Занятость, BUSY Вход 12 12 Конец бумаги, PE Вход 13 13 Выбор, SLCT Вход 14 14 Авт. перевод Выход, инверсия строки, Auto Line Feed 15 32 Ошибка, ERROR Вход, инверсия 16 31 Сброс принтера, Выход, инверсия INIT 17 36 Принтер выбран, Выход, инверсия SLCT IN 18-25 16,17, Земля - 19-30,33
Для сигналов, отмеченных в таблице словом "инверсия", используется уровень логического нуля в активном состоянии сигнала.
Используя принтерный порт для управления внешними устройствами, будьте осторожны и выполняйте все правила заземления устройств. Если ваш устройство не заземлено или заземлено неправильно, принтерный порт может выйти из строя.
Следует также учитывать, что нагрузка на выходную линию принтерного порта не должна превышать одного входа TTL.
Если по каким-либо причинам вы пожелаете работать с принтером через порты ввода/вывода, вам необходимо изучить временную диаграмму принтерного порта. Она представлена на следующем рисунке:
----------------------------------¬ | | BUSY --------- L-------- ------ ACK ---------------------------------------¬ ---- | | L--------- --------------¬ | | DATA ----- L-------------------------------- ------ STROBE ------¬ ------------------------------------ | | L---------
Для того, чтобы вывести символ на принтер, программа вначале должна убедится, что уровень сигнала на линии BUSY (бит 7 порта 379h) равен 0, а уровень сигнала на линии ACK (бит 6 порта 379h) - единице. После этого следует установить код выводимого символа на линиях DATA (порт 378h).
Затем не ранее, чем через 0,5 мкс линию STROBE (бит 0 порта 37Ah) необходимо перевести в состояние логического 0. При этом выводимый символ запишется во внутренний буфер принтера. Уровень логического нуля необходимо удерживать в течение как минимум 0,5 мкс. Это время нужно для того, чтобы символ записался в буфер принтера. После истечения интервала времени линию STROBE нужно опять перевести в состояние логической единицы.
После того, как программа установит линию STROBE в состояние логического нуля, выходная линия принтера BUSY устаналвивается в единицу, сигнализируя о том, что принтер занять обработкой полученного символа и временно не может принимать другие символы.
Когда принтер полность обработает выведенный символ, линия ACK перейдет в состояние 0. Приблизительно через 5 мкс после этого линия BUSY также перейдет в состояние 0.
Еще через 5 мкс линия ACK примет состояние 1. Теперь принтер готов принят следующий символ распечатываемых данных.
BIOS использует для работы с принтером функции 0, 1, 2 прерывания INT 17h.
Функция 00h предназначена для печати одного символа:
На входе: AH = 00h; AL = ASCII-код символа для печати; DX = номер принтера: 0, 1 или 2. На выходе: AH = слово состояния принтера (см. ниже).
Эта функция выводит на принтер один символ, заданный в регистре AL. В регистр DX необходимо записать номер используемого принтера, для LPT1 это 0, для LPT2 - 1 и т.д.
После выполнения прерывания регистр AH будет содержать слово состояния, имеющее следующий формат:
7 6 5 4 3 2 1 0 T-T-T-T-T-T-T-T-¬ | | | | | | | | LT+T+T+T+T+T+T+T- | | | | | L=| L= таймаут, слишком большая задержка при | | | | | | выполнении операции печати, возможно, | | | | | | что принтер неисправен; | | | | | | | | | | | L=== не используются; | | | | | | | | | L======= ошибка ввода/вывода; | | | | | | | L========= 1 - принтер выбран для работы; | | | 0 - принтер в состоянии offline; | | | | | L=========== конец бумаги; | | | L============= подтверждение; | L=============== 1 - принтер готов, 0 - принтер занят.
Вызвав функцию 0 прерывания INT 17h, программа должна проверить отдельные биты слова состояния и убедиться в том, что вывод байта произошел без ошибок. Наиболее часто оператор забывает перевести принтер в состояние ONLINE, либо вставить бумагу, либо вообще включить принтер. В этом случае целесообразно напомнить оператору о необходимости выполнения этих действий и затем повторить печать символа.
Если принтер неисправен, программа должна предоставить оператору возможность отменить печать текста. Ниже мы приведем пример программы, выполняющей печать текста и анализирующей ошибки, которые могут возникнуть в процессе печати.
Обратите внимание на бит 1 байта состояния - таймаут. Если принтер находится в состоянии OFFLINE, функция 0 прерывания INT 17h ожидает некоторое время готовности принтера, после чего если принтер так и не перешел в состояние готовности, устанавливает бит 1 в байте состояния. Область данных BIOS по адресу 0000h:0478h содержит четыре байта, которые используются в качестве счетчиков времени при ожидании готовности принтера.
Прерывание INT 17h имеет еще две функции, выпоняющие инициализацию принтера и получающую текущее состояние принтера.
Функция 01h инициализирует принтер:
На входе: AH = 01h; DX = номер принтера: 0, 1 или 2. На выходе: AH = слово состояния принтера.
Эта функция выполняет аппаратный сброс принтера. Если вы загрузили в принтер какой-либо шрифт (например, кириллицу), после сброса загрузку шрифта придется выполнять заново. Поэтому не следует выполнять сброс принтера, если это действительно не требуется. Обычно принтер приходится сбрасывать либо перед настройкой его на заданный режим работы, которая выполняется один раз, либо при изменении этого режима.
Слово состояния принтера может быть получено с помощью функции 02h:
На входе: AH = 02h; DX = номер принтера: 0, 1 или 2. На выходе: AH = слово состояния принтера.
Эту функцию удобно использовать перед началом печати для определения готовности принтера к работе.
Приведем программу, которая распечатывает содержимое файла с использованием функции 0 прерывания INT 17h.
Программа считывает содержимое файла, открытого в двоичном режиме по байтам. Считанные файлы передаются в качестве параметра функции printchar(), которая и выводит их на принтер. После вызова прерывания INT 17h проверяется состояние принтера, и в случае, когда произошла ошибка ввода/вывода, вызывается обработчик ошибки - функция error(). Эта функция выводит на экран состояние принтера (в развернутом виде, с объяснением каждого бита байта состояния) и запрашивает оператора о дальнейших действиях.
Если оператор может устранить причину ошибки (перевести принтер в состояние ONLINE, вставить бумагу, если она кончилась и т.д.), он нажимает любую клавишу кроме ESC и тогда функция error() возвращает 0. В противном случае возвращается значение 1.
Если оператор решил повторить печать, и, соответственно, если функция error() возвратила значение 0, функция printchar() повторяет печать символа. В противном случае выдается сообщение об ошибке и работа программы завершается.
Итак, приведем исходный текст программы печати содержимого текстовых файлов:
#include <dos.h> #include <stdio.h> union REGS rg; int main(int argc, char *argv[]) { FILE *srcfile; // Открываем файл, заданный первым параметром // в командной строке. // Если при запуске программы оператор забыл // указать имя файла, выводим напоминающее сообщение. if( (srcfile = fopen( argv[1], "rb" )) == NULL ) { printf("\nЗадайте имя файла в качестве параметра"); exit(-1); } // Читаем файл по одному символу, полученный из файла // символ выводим на принтер при помощи функции printchar(). for(;;) { printchar(fgetc(srcfile)); if(feof(srcfile)) break; } // Закрываем файл. fclose(srcfile); } // ------------------------------------ // Эта функция выводит один символ // на первый принтер (LPT1) // ------------------------------------ int printchar(int chr) { int status; // Повторяем в цикле выдачу символа на принтер // до тех пор, пока он не будет выведен без // ошибок, либо пока оператор не отменит // распечатку файла. for(;;) { // Дублируем распечатываемый символ на экране putch(chr); // Вызываем функцию 0 прерывания INT 17h - // распечатка символа на принтере. // В регистре DX задаем номер принтера LPT1 - это 0. rg.h.ah = 0; rg.h.al = chr; rg.x.dx = 0; int86(0x17, &rg, &rg); // Запоминаем байт состояния принтера // после вывода символа. status = rg.h.ah; // Проверяем наличие ошибок. Нас интересуют биты: // // 0 - таймаут (задержка при печати слишком велика) // 3 - ошибка ввода/вывода // 4 - принтер в состоянии ONLINE (1) или OFFLINE (0) // 5 - конец бумаги if((status & 0x39) != 0x10) { // Вызываем функцию обработки ошибки error(). Эта // функция возвращает 0, если оператор желает // повторить печать символа, или 1 - если // оператор отменяет печать. if(error(chr, status)) { printf("\nПечать завершилась аварийно"); exit(-2); } } else break; } } // ------------------------------------ // Функция выводит на экран состояние // принтера и запрашивает у оператора // требуемые действия - повторить // печать символа или отменить печать. // ------------------------------------ int error(char chr, int status) { // Выводим состояние принтера после ошибки printf("\nОшибка принтера %02.2X" "\n\nСостояние принтера:" "\n-------------------", status); if(status & 1) printf("\nТаймаут при печати"); if(status & 8) printf("\nОшибка ввода/вывода"); if(!(status & 0x10)) printf("\nПринтер находится в состоянии OFFLINE"); if(status & 0x20) printf("\nКонец бумаги"); printf("\n\nДля отмены печати нажмите клавишу ESC," "\nдля повтора - любую другую клавишу\n"); if(getch() == 27) return(1); else return(0); }
Для печати символа на стандартном печатающем устройстве LPT1 (он же PRN) вы можете использовать функцию 05h прерывания MS-DOS INT 21h:
На входе: AH = 05h; DL = ASCII-код символа для печати. На выходе: AH = слово состояния принтера (см. ниже).
Команда MS-DOS MODE может переназначить стандартное устройство печати LPT1 на асинхронный последовательный порт:
MODE LPT1:=COM1
Мы подготовили еще одну программу распечатки содержимого файла, но уже при помощи прерывания MS-DOS:
#include <dos.h> #include <stdio.h> union REGS rg; int main(int argc, char *argv[]) { FILE *srcfile; // Открываем файл, заданный первым параметром // в командной строке. // Если при запуске программы оператор забыл // указать имя файла, выводим напоминающее сообщение. if( (srcfile = fopen( argv[1], "rb" )) == NULL ) { printf("\nЗадайте имя файла в качестве параметра"); exit(-1); } // Читаем файл по одному символу, полученный из файла // символ выводим на принтер при помощи функции printchar(). for(;;) { printchar(fgetc(srcfile)); if(feof(srcfile)) break; } // Закрываем файл. fclose(srcfile); } // ------------------------------------ // Эта функция выводит один символ // на стандартный принтер (LPT1) // ------------------------------------ int printchar(int chr) { // Дублируем распечатываемый символ на экране putch(chr); // Вызываем функцию 5 прерывания INT 21h - // распечатка символа на принтере. rg.h.ah = 5; rg.h.dl = chr; int86(0x21, &rg, &rg); }
Заметьте, что функция 05h прерывания INT 21h не возвращает состояния принтера при ошибке ввода/вывода. Вместо этого вызывается стандартный обработчик критических ошибок MS-DOS, который выводит на экран хорошо знакомое вам сообщение:
Write fault error writing device PRN Abort, Retry, Ignore, Fail?
Вы можете ответить Retry, нажав клавишу "R", тогда MS-DOS выполнит попытку повторить печать символа. Если ответить Abort (нажав клавишу "A"), MS-DOS завершит работу вашей программы.
Поэтому приведенная выше программа не содержит обработчика ошибочных ситуаций error(). Если вас не устраивают действия, выполняемые стандартным обработчиком критических ошибок MS-DOS, вы можете составить собственный. В третьей книге первого тома "Библиотеки системного программиста" мы рассказывали вам о создании и подключении собственного обработчика критических ошибок.
Более интересные возможности по управлению процессом печати предоставляет программа резидентного спулера печати PRINT.COM. Вы знаете, что команда PRINT предназначена для выполнения печати в фоновом режиме.
Оказывается, что если запущена программа PRINT, другие программы могут взаимодействовать с ней, управляя процессом печати.
Для связи со спулером печати можно использовать несколько функций прерывания INT 2Fh:
На входе: AH = 01h; AL = номер выполняемой операции. На выходе: AH = 00 - спулер печати не установлен, но его можно установить, запустив программу PRINT; 01 - спулер печати не установлен и его установка невозможна (система не содержит ни одного принтера); FFh - спулер установлен.
Приведем форматы регистров для выполнения различных операций со спулером печати.
На входе: AH = 01h; AL = 0 - проверить установку спулера печати. На выходе: AH = 00 - спулер печати не установлен, но его можно установить, запустив программу PRINT; 01 - спулер печати не установлен и его установка невозможна; FFh - спулер установлен. На входе: AH = 01h; AL = 1 - передача файла спулеру для печати; DS:DX = адрес управляющего блока: Смещение Длина (+0) 1 уровень запроса, равен 0; (+1) 4 FAR-адрес строки в формате ASCIIZ, содержащей путь файла. На выходе: AH = 00 - спулер печати не установлен, но его можно установить, запустив программу PRINT; 01 - спулер печати не установлен и его установка невозможна; FFh - спулер установлен. На входе: AH = 01h; AL = 2 - отменить печать файла; DS:DX = адрес строки в формате ASCIIZ, содержащей имя файла, удаляемого из очереди для печати. На выходе: AH = 00 - спулер печати не установлен, но его можно установить, запустив программу PRINT; 01 - спулер печати не установлен и его установка невозможна; FFh - спулер установлен. На входе: AH = 01h; AL = 3 - отменить печать всех файлов. На выходе: AH = 00 - спулер печати не установлен, но его можно установить, запустив программу PRINT; 01 - спулер печати не установлен и его установка невозможна; FFh - спулер установлен. На входе: AH = 01h; AL = 4 - определить состояние спулера и заблокировать спулер. На выходе: DS:SI = адрес очереди печати (массив строк в формате ASCIIZ, конец массива отмечен строкой, состоящей из 0; DX = количество ошибок при попытке напечатать последний символ; AH = 00 - спулер печати не установлен, но его можно установить, запустив программу PRINT; 01 - спулер печати не установлен и его установка невозможна; FFh - спулер установлен. На входе: AH = 01h; AL = 5 - разблокировать спулер для продолжения печати. На выходе: AH = 00 - спулер печати не установлен, но его можно установить, запустив программу PRINT; 01 - спулер печати не установлен и его установка невозможна; FFh - спулер установлен.
Если после вызова перечисленных выше функций флаг переноса CF установлен в 1, регистр AX содержит код ошибки:
1
|
Неправильный код функции
|
2
|
Файл не найден
|
3
|
Путь не найден
|
4
|
Слишком много открытых файлов
|
5
|
Доступ запрещен
|
6
|
Неправильный индекс (handle)
|
8
|
Переполнение очереди
|
9
|
Занято
|
0Ch
|
Слишком длинный путь и имя файла (больше 64
байтов)
|
0Fh
|
Неправильное определение диска
|
Как правило, матричные принтеры позволяют устанавливать режим своей работы с помощью переключателей режима. Для доступа к этим переключателям вам не надо разбирать принтер или снимать крышку корпуса - эти переключатели располагаются в легкодоступном месте.
Обычно используются две группы переключателей - DIP Switch 1 и DIP Switch 2. Приведем назначение первой группы переключателей для принтера Epson FX-850/1050:
Переключатель Назначение SW 1-1 Используемый набор символов: ON используются внутренние шрифты принтера; OFF набор символов может быть задан из программы. SW 1-2 Форма символа "ноль": ON ноль перечеркнут; OFF ноль не перечеркнут. SW 1-3 Выбор таблицы символов: ON используются символы псевдографики; OFF используются символы курсива; SW 1-4 Тип протокола: ON эмуляция IBM Proprinter; OFF протокол ESC/P (для принтеров Epson). SW 1-5 Пропуск перформации на бумаге: ON не используется; OFF используетя. SW 1-6,1-7,1-8 Эти переключатели задают национальный набор символов.
Переключатель SW 1-1 необходимо установить в положение OFF в том случае, когда вам необходимо загружать собственный набор символов. Например, в вашем принтере может не быть набора русских символов. В этом случае вам надо использовать специальные программы - русификаторы принтеров. Они будут работать только при правильной установке этого переключателя.
Если вы установите переключатель SW 1-2 в положение ON, все нули в распечатке будут перечеркнуты. Это удобно для распечатки программ, но не всегда приемлемо для документов.
Если вы используете псевдографику, переключатель SW 1-3 должен быть установлен в ON, в противном случае вместо символов псевдографики в распечатке появятся латинские наклонные буквы.
Тип протокола определяется используемым для печати программным обеспечением. Принтер Epson FX-1050/850 может эмулировать систему команд принтера IBM Proprinter. В приложении приведены команды как для протокола Epson6 так и для протокола IBM.
Пропуск перфорации нужен при использовании непрерывной бумажной ленты с перфорацией для отрыва отдельных листов.
Если ваш принтер содержит набор русских символов, переключатели SW 1-6...1-8 должны быть установлены соответствующим образом. Если ваш принтер не печатает русские буквы, проверьте правильность установки этих переключателей.
Назначение второй группы переключателей
приведено в таблице:
Переключатель Назначение SW 2-1 Длина страницы: ON 12 дюймов; OFF 11 дюймов. SW 2-2 Использование автоматического податчика бумаги: ON используется; OFF не используется. SW 2-3 Использование пропуска для перфорации в 1 дюйм: ON используется; OFF не используется. SW 2-4 Автоматический перевод строки при получении символа возврата каретки: ON используется; OFF не используется.
Для других принтеров назначение и нумерация переключателей может отличаться от описанного выше, но их назначение, как правило, аналогично.
Некоторые принтеры, например, Epson LQ-2550, не имеют переключателей режимов. Для задания режимов используется клавиатура и небольшой дисплей на корпусе принтера. Режим такого принтера хранится в КМОП-памяти, установленной в принтере и питающейся от аккумулятора. Поэтому установленный режим не сбрасывается при выключении питания принтера.
Для изменения режимов работы принтера и выполнения загрузки шрифтов используются специальные командные последовательности символов. Командные последовательности посылаются в принтер как обычные символы. Вы можете использовать описанные ранее функции MS-DOS или BIOS для вывода этих последовательностей.
Признак начала командной последовательности символов - байт ESC с кодом 1Bh. Вслед за этим байтом программа посылает в принтер саму командную последовательность. Длина последовательности зависит от выполняемой команды.
Первый байт командной последовательности - код выполняемой команды. Далее следует один или несколько байтов параметра команды. Некоторым командам не предшествует байт ESC (это, например, команды перевода строки, страницы или команды табуляции).
Подробное описание всех команд не входит в задачу данной книги. В приложении, однако, приведены полные таблицы команд для принтеров Epson LQ-2550 и Epson FX-1050/850 с краткими пояснениями для каждой команды. Мы опишем подробно лишь несколько команд принтера Epson FX-850/1050 с целью иллюстрации способов программирования с использованием протокола ESC/P.
Для сброса принтера в исходное состояние программа должна послать на принтер два байта - байт ESC (1Bh) и байт, соответствующий ASCII-символу "@" (40h).
Если послать этот байт, принтер издаст звуковой сигнал. Сигнал удобно использовать для привлечения внимания оператора, например, когда кончилась бумага.
Распечатываются все символы из буфера принтера, затем каретка (печатающая головка) возвращается к началу строки. В зависимости от переключателя конфигурации SW 2-4 может дополнительно выполняться прогон бумаги на одну строку.
Когда этот символ посылается на принтер, все символы, находящиеся во внутреннем буфере принтера, распечатываются, затем каретка возвращается к началу строки и происходит подача листа вперед на одну строку.
Принтер распечатывает все символы, находившиеся в буфере, затем выполняет прогон одного листа бумаги.
0 - низкое качество; 1 - качественный шрифт NLQ.
Для задания типа шрифта надо вывести на принтер три байта: символ ESC (1Bh), символ "x" (78h), затем код шрифта (30h...31h).
Существуют различные команды, позволяющие определить размер межстрочного интервала, расположение левой и правой границ листа, используемый для печати шрифт. Можно выполнять печать графических изображений, о чем мы раскажем немного позже.
Если вас не устраивает шрифт, который записан в ПЗУ принтера (например, в нем нет русских букв), вы можете использовать команды для загрузки собственного шрифта.
Приведем пример программы, которая посылает в принтер командные последовательности и обычные символы, пользуясь функцией 05h прерывания INT 21h:
#include <dos.h> #include <stdio.h> main() { char buffer[] = { 0x1b, '@', // Сбрасываем принтер в исходное // состояние. 7,7,7, // Выдаем 3 раза звуковой сигнал. 0x1b, 'x','0', // Устанавливаем низкое // качество печати. 'S','t','r','i','n','g',' ','1', // Печатаем // строку. 0x1b, 'x','1', // Устанавливаем высокое // качество печати. 'S','t','r','i','n','g',' ','2', // Печатаем // строку. 0x0a, // Переводим строку. 7,7,7, // Выдаем 3 раза звуковой сигнал. 0 }; char *p; // Выводим строку символов на принтер for(p = buffer; *p != 0; p++) bdos(0x05, *p, 0); }
Для вывода символа на принтер через функцию MS-DOS здесь использована функция bdos(), входящая в состав стандартных библиотек трансляторов Microsoft QC 2.5 и C 6.0. Первый параметр функции bdos() - номер выполняемой функции прерывания MS-DOS INT 21h, второй - содержимое регистра DX перед вызовом этой функции, и третий - содержимое регистра AL.
В комментариях к программе объясняется назначение управляющих последовательностей, посылаемых на принтер. Перед запуском программы необходимо убедиться в том, что принтер включен и находится в состоянии ON LINE, иначе программа перейдет в состояние ожидания.
Если среди национальных наборов символов, имеющихся в постоянном запоминающем устройстве, имеются русские буквы, то вам достаточно правильно установить переключатели SW 1-6...1-8 и SW 1-1.
Если же набора русских символов нет, или в ПЗУ принтера использована не та кодировка русских символов, вам потребуются специальные программы загрузки шрифтов, такие как SETPR, комплекс SOLO, LOADFONT или аналогичные. Все эти программы используют специальные командные последовательности для переопределения тех символов, коды которых соответствуют русским буквам.
Для разработки собственных символов используется сетка. В 9-игольчатых принтерах эта сетка имеет 11 столбцов и девять строк:
Из девяти строк может использоваться только 8 верхних или 8 нижних (это показано на левом и правом рисунках соответственно).
Обычно символ располагается выше утолщенной линии, то есть в строках с номерами от 1 до 7. Исключение составляют такие буквы, как "у", "ц" и т.п. Нижние "хвостики" этих букв должны находиться на строке с номером 0.
Есть ограничение на расположение отдельных точек определяемого символа в строке - эти точки не должны находиться рядом, то есть между точками в строке должна находиться одна свободная ячейка.
Для переопределения символов 9-игольчатый принтер Epson использует команду ESC "&":
ESC "&" "0" n1 n2 a1 d1 d2 ... dn Определить символы
Параметры n1 и n2 задают диапазон кодов ASCII символов, начертание которых необходимо переопределить. Если вы переопределяете только один символ, эти два параметра должны быть одинаковыми.
Параметр a1 определяет ширину символа в точках и его положение в сетке (использует ли символ верхние восемь линий, либо нижние восемь линий). Ширина определяемого символа требуется для печати в пропорциональном режиме, когда место, занимаемое каждой буквой в строке распечатки, зависит от ее ширины. Например, буква "Ш" шире, чем буква "И".
Старший бит параметра a1 задает расположение символа в сетке. Если этот бит равен 1, используются восемь верхних линий сетки, если 0 - восемь нижних.
Младшие семь битов задают ширину символа и представляют собой число, определяемое по следующей схеме:
Пусть определяемый символ располагается в верхней части сетки (использует восемь верхних строк). Пусть этот символ начинается в третьем столбце и заканчивается в 7 столбце. Тогда десятичное значение параметра a1 вычисляется следующим образом:
a1 = 8(начальное значение) - - 2(два пустых столбца справа) + + 32(два пустых столбца слева) + + 128(старший бит равен 1) = 166
Если ваш символ использует верхние восемь строк сетки, начинается в первом столбце и заканчивается в девятом, в качестве параметра a1 подходит значение 136. При этом символы будут печататься верхними восемью иголками печатающей головки. Для использования нижних восьми иголок и такой же ширины символа задайте значение a1 равное 8.
Параметры d1...dn - образцы столбцов точек для определяемого символа. Их должно быть всегда 11, даже если символ содержит пустые столбцы. Для пустых столбцов в качестве образца надо задать 0.
Для включения определенного программой набора символов в работу необходимо выдать команду ESC "%" "0", для использования набора символов из внутреннего ПЗУ принтера выдайте команду ESC "%" "1".
Приведем пример программы, изменяющей начертание символа "@" в принтере Epson FX-850/1050. Для правильной работы программы переключатель SW 1-1 должен быть установлен в положение OFF.
#include <dos.h> #include <stdio.h> main() { char buffer[] = { 0x1b, '@', // Сбрасываем принтер в исходное // состояние. 7,7,7, // Выдаем 3 раза звуковой сигнал. // Определяем вместо "@" новый символ: 0x1b, '&', 0, '@', '@', 136, 32,80,168,84,42,84,168,80,32,0,0, // Выдаем строку символов, используем начертание, // заданное в ПЗУ принтера. '@', '@', '@', '@', '@', 0x0a, // Используем новое начертание: 0x1b, '%', 1, '@', '@', '@', '@', '@', 0x0a, // Возвращаемся опять к старому начертанию: 0x1b, '%', 0, '@', '@', '@', '@', '@', 0x0a, 7,7,7, // Выдаем 3 раза звуковой сигнал. '$' // Признак конца массива данных }; char *p; // Выводим строку символов на принтер for(p = buffer; *p != '$'; p++) bdos(0x05, *p, 0); }
Рассмотрим теперь метод переопределения начертания символов в 24-иголочном принтере Epson LQ-2550. Для определения начертания символов в этом принтере используется сетка высотой 24 точки - соответственно, по одной точке для каждой иголки в печатающей головке.
24-иголочный принтер использует несколько наборов символов:
В зависимости от используемого набора символов ширина сетки может быть либо 9 точек (для чернового набора символов, либо 29 точек (для качественного набора символов), либо 37 точек (для пропорционального набора символов). Кроме того, для последних двух наборов столбцы сетки расположены ближе друг к другу, чем для чернового набора.
На рисунке показаны сетки для чернового и качественного/пропорционального наборов символов принтера Epson LQ-2550:
Обычные символы располагаются между жирными линиями. Нижние линии сетки используются для подчеркивания и изображения "хвостиков" таких букв, как "у", "ц" и т.п.
Так же, как и для 9-игольчатых принтеров, существует ограничение на расположение точек в узлах сетки: справа и слева от каждой точки должны располагаться пустые позиции.
Приведем формат команды для переопределения символов в принтере Epson LQ-2550:
ESC "&" "0" n1 n2 d0 d1 d2 data Определить символы
Параметры n1 и n2 задают диапазон кодов ASCII символов, начертание которых необходимо переопределить. Их назначение такое же, как и для 9-игольчатых принтеров Epson. Если вы переопределяете только один символ, эти два параметра должны быть одинаковыми.
Далее следуют три байта данных, которые задают ширину символа и размер свободного пространства вокруг символа. Параметр d0 задает количество свободных столбцов слева от символа, параметр d2 определяет количество свободных столбцов справа от символа. Параметр d1 определяет ширину символа в столбцах сетки.
Изменяя ширину символа и размер свободного пространства вокруг него можно формировать пропорциональные наборы символов.
В следующей таблице приведены максимальные значения для параметров d0, d1, d2 для различных наборов символов:
Набор d1 d0+d1+d2 Черновой 9 12 Качественный, 29 36 10 символов на дюйм Качественный, 23 30 12 символов на дюйм Пропорциональный 37 42
После параметра d2 следует последовательность байтов, описывающих символ, т.е. образец для символа. Для задания одного столбца сетки требуется три байта, поэтому для определения одного символа вы должны задать (d1 * 3) байтов данных.
До сих пор мы использовали принтер только для печати символьной информации - буквы, цифры, символы псевдографики и т.д. Коды символов мы тем или иным способом выводили на принтер, принтер распечатывал их с использованием внутренних шрифтов, записанных в ПЗУ принтера, или с использованием загружаемых шрифтов.
Однако печать символов - это не все, на что способен матричный принтер. Вспомним, как происходит печать букв.
Принтерная головка содержит 9 или 24 иголки, расположенных вертикально. Печатающая головка движется в горизонтальном направлении вдоль листа бумаги, причем между головкой и листом находится красящая лента. Каждая иголка управляется отдельным электромагнитом, при включении которого она "выстреливается" в направлении красящей ленты, оставляя на бумаге маленькую точку. Цвет этой точки определяется красящей лентой. Цветные матричные принтеры (например, LQ2550) заряжаются многоцветной лентой. Эта лента напоминает черно-красную ленту для механических пишущих машинок, но на ней больше цветов. Обычно используются четырехцветные ленты, раскрашенные следующими цветами - желтый, красный, синий, черный.
В процессе печати кассета с цветной лентой может перемещаться в вертикальном направлении, поэтому перед печатающей головкой может оказаться участок ленты с одним из четырех цветов.
При наложении цветов возможно получение различных цветовых комбинаций, поэтому хотя цветов на ленте всего четыре, цветной принтер может печатать достаточно качественные и многоцветные изображения.
Когда принтер печатает алфавитно-цифровой символ, он, передвигая печатающую головку слева направо (или справа налево, что тоже возможно), "выстреливает" теми иголками, которые соответствуют заданному шрифтом изображению символа.
Очевидно, что если бы у нас была возможность самостоятельно управлять иголками и перемещением кассеты с цветной красящей лентой, мы могли бы самостоятельно формировать цветное графическое изображение, так, как это делается в полиграфии. Если вы внимательно посмотрите на фотографии, напечатанные в газетах или журналах, вы заметите, что графическое изображение состоит из отдельных точек разного цвета и очень маленького размера.
Практически любые матричные принтеры позволяют печатать графические изображения. Девяти иголочные принтеры Epson FX используют для графической печати 8 верхних иголок. При этом за один проход можно напечатать одну графическую "строку", послав в принтер битовый образ строки.
Если печатаемое графическое изображение по высоте превышает 8 точек, оно выводится в несколько приемов, построчно. После вывода очередной строки программа должна продвинуть бумагу на одну строку вперед. Для того чтобы между графическими строками не оставалось свободного места, необходимо правильно установить межстрочный интервал - не более 8/72 дюйма.
Как перевести принтер в режим графической печати?
Для этого принтер Epson FX-1050 использует следующую команду:
ESC "*" m n1 n2 data Печать в графическом режиме
В этой команде m задает режим печати:
Значение m Режим 0 Одинарная плотность, 60 точек на дюйм 1 Двойная плотность, 120 точек на дюйм 2 Двойная плотность, печать с высокой скоростью, 120 точек на дюйм 3 Учетверенная плотность, 240 точек на дюйм 4 Режим CRT I, плотность 80 точек на дюйм 5 Режим плоттера (1:1), плотность 72 точки на дюйм 6 Режим CRT II, плотность 90 точек на дюйм 7 Режим плоттера с двойной плотностью, 144 точки на дюйм
Параметры n1 и n2 определяют длину печатаемой графической строки в точках. При определении длины графической строки необходимо учитывать, что в режиме одинарной плотности на строке длиной 8 дюймов можно разместить 480 точек, в режиме учетверенной плотности - около 2000.
Так как передача данных в принтер выполняется по байтам, для представления длины строки приходится использовать два байта информации. Для вычисления параметров n1 и n2 можно использоваться следующей схемой действий:
Например, пусть нам надо распечатать строку из 1234 точек. Тогда параметр n2 будет равен 1234 / 256 = 4. Остаток от деления составит 1234 - 256 * 4 = 210. Это и есть параметр n1.
Проверяем: 4 * 256 + 210 = 1234
Команда должна всегда содержать два параметра, даже если параметр n2 получился равным нулю.
Вслед за параметрами n1 и n2 должны следовать байты графических данных, предназначенные для печати. Должно быть передано точно n2 * 256 + n1 байтов.
Если вы передатите меньше графических данных, чем это было определено в команде ESC "*", следующие вводимые в принтер команды или данные будут интерпретироваться как графические данные. Если вы передадите больше графических данных чем нужно, лишние данные будут напечатаны как обычный текст.
Для представления одного восьмиточечного
столбца графической строки используется один
байт данных, причем верхней точке в столбце
соответствует старший разряд байта, а нижней -
младший:
7 Этому столбцу соответствует o 6 байт 10011011b или 9Bh o 5 * 4 * 3 o 2 * 1 * 0
На этом рисунке "*" означает точку в столбце графической строки, "o" - отсуствие точки.
Вам необходимо подготовить таким образом байты для всех столбцов, входящих в распечатываемую графическую строку.
Цветной 24-игольчатый принтер Epson LQ-2550 может работать в описанном выше 8-битовом графическом режиме. Это сделано для обеспечения совместимости со старым программным обеспечением, рассчитанным на принтеры серий FX, RX, LX и EX. Однако все возможности этого принтера раскрываются только при использовании всех его 24 иголок. В этом случае графическое изображение печатается отдельными строчками, высота которых составляет 24 точки. При этом для представления одного столбца графической строки требуется три байта данных. Каждый байт должен готовиться отдельно, при этом можно считать, что 24-битовая графическая строка состоит из трех 8-битовых.
Формат команды графической печати для этого принтера расширен по сравнению с описанным выше:
ESC "*" m n1 n2 data Печать в графическом режиме
В этой команде m, как и раньше, задает режим печати. Однако для этого параметра определено больше значений:
Значение m Режим 0 Одинарная плотность, 60 точек на дюйм, 8-битовая графика 1 Двойная плотность, 120 точек на дюйм, 8-битовая графика 2 Двойная плотность, печать с высокой, скоростью, 120 точек на дюйм, 8-битовая графика 3 Учетверенная плотность, 240 точек на дюйм, 8-битовая графика 4 Режим CRT I, плотность 80 точек на дюйм, 8-битовая графика 6 Режим CRT II, плотность 90 точек на дюйм, 8-битовая графика 32 Одинарная плотность, 60 точек на дюйм, 24-битовая графика 33 Двойная плотность, 120 точек на дюйм, 24-битовая графика 38 Режим CRT III, плотность 90 точек на дюйм, 24-битовая графика 39 Тройная плотность, 180 точек на дюйм, 24-битовая графика 40 Шестикратное увеличение плотности, 360 точек на дюйм, 24-битовая графика
Учтите, что для команды 24-битового графического вывода требуется массив графических данных в три раза больше по размеру, чем для 8-битовой команды.
Приведем пример программы, выводящей на принтер в режиме 8-битовой графики строку, состоящую из 40 столбцов:
#include <dos.h> #include <stdio.h> union REGS rg; int main() { int i; // Переводим строку printchar(0x0d); printchar(0x0a); // Выдаем на принтер команду графической // печати (ESC "*" m n1 n2 data) printchar(27); printchar('*'); // Выбираем режим 0 - 8-битовая графика, // одинарная плотность printchar(0); // Задаем длину графической строки: // n1 = 40; n2 = 0 printchar(40); printchar(0); // Выводим в цикле 40 раз байт DBh for(i=0; i<40; i++) printchar(0xdb); // Переводим строку printchar(0x0d); printchar(0x0a); } // ------------------------------------ // Эта функция выводит один символ // на стандартный принтер (LPT1) // ------------------------------------ int printchar(int chr) { // Вызываем функцию 5 прерывания INT 21h - // распечатка символа на принтере. rg.h.ah = 5; rg.h.dl = chr; int86(0x21, &rg, &rg); }
Аналогичная программа, использующая 24-битовую графику на принтере Epson LQ-2550:
#include <dos.h> #include <stdio.h> union REGS rg; int main() { int i; // Переводим строку printchar(0x0d); printchar(0x0a); // Выдаем на принтер команду графической // печати (ESC "*" m n1 n2 data) printchar(27); printchar('*'); // Выбираем режим 32 - 24-битовая графика, // одинарная плотность printchar(32); // Задаем длину графической строки: // n1 = 40; n2 = 0 printchar(40); printchar(0); // Выводим в цикле 120 раз байт DBh. Для вывода // строки из 40 столбцов в 24-битовом режиме // требуется в три раза больше графических данных, // чем для 8-битового режима. for(i=0; i<120; i++) printchar(0xdb); // Переводим строку printchar(0x0d); printchar(0x0a); } // ------------------------------------ // Эта функция выводит один символ // на стандартный принтер (LPT1) // ------------------------------------ int printchar(int chr) { // Вызываем функцию 5 прерывания INT 21h - // распечатка символа на принтере. rg.h.ah = 5; rg.h.dl = chr; int86(0x21, &rg, &rg); }
Для вывода на принтер сложных графических изображений ваша программа должна сначала подготовить массив данных для построчной 8-битовой или 24-битовой печати. Затем готовый массив можно вывести на принтер, используя несколько команд графического вывода (по одной команде на одну графическую строку).