о надо поместить его код ASCII в соответствующюю позицию второй строки. Например: Позиция символа 1 2 3 4 5 6 7 8 9 10 Код ASCII 205 32 98 111 114 105 110 103 32 205 Код 2-й строки 205 32 32 32 32 32 32 32 32 205 В памяти должна храниться отдельная таблица цепочек битов этих символов для второго прохода. Для двойной вертикальной черты содержимое таблицы для первого прохода будет 0, 255, 0, 255, 0, 0, а для второго - 0, 15, 0, 15, 0, 0. Отметим, что во втором и четвертом байте для второго прохода верхние 4 бита сброшены, чтобы не было надпечатки. Короче, когда начинается печать, то в первую очередь прове- ряется является ли данный символ пседографическим, и если нет, то он посылается на печать, как обычный код ASCII. Во временную строку, используемую для печати второго прохода вставляется про- бел. Затем обрабатывается следующий символ. Когда встречается символ псевдографики, то 6 кодирующих его байтов берутся из таб- лицы, принтер переводится в графический режим для вывода 6 байтов и посылаются данные. Затем принтер автоматически возвращается в текстовый режим. В соответствующую позицию строки для второго прохода помещается код ASCII этого символа псевдографики. Этот процесс продолжается до конца строки, после чего делается прогон бумаги на высоту четырех точек. При повторном проходе надо опять поочередно рассмотреть каждый символ. Если это пробел, то надо печатать символ пробела (т.е. не печатать ничего, а просто прод- винуть головку к следующему символу). Если же это графический символ, то надо найти соответствующий ему данные для второго прохода в отдельной таблице и напечатать его таким же образом, как и при первом проходе. Повторно используйте строку для второго прохода с каждой печатаемой строкой. На рис. 6-3 показана эта процедура. Высокий уровень. В данном примере текст разделен на две колонки, при этом неп- рерывная линия разделяет страницу посредине. Для простоты печа- тается только одна строка, однако этот пример может печатать и целую страницу, если вставить цикл FOR/NEXT в строках 325 и 505. Для демонстрации двух подходов при первом проходе печатается по одному символу, в то время как при втором проходе печатается целая строка. 100 '''таблица данных для первого прохода (только коды 178 и 179) 110 DATA 0, 0, 255, 0, 0, 0 120 DATA 4, 4, 255, 0, 0, 0 130 '''аналогичная таблица для второго прохода 140 DATA 0, 0, 15, 0, 0, 0 150 DATA 0, 0, 15, 0, 0, 0 160 '''помещаем первую таблицу в массив 170 DIM FIRSTPASS$(45) 'описываем массив 180 FOR N = 1 TO 2 'заполняем его 190 Y$ = "" 'Y$ хранит 6 байтов на символ 200 FOR M=1 TO 6: READ X: Y$ = Y$+CHR$(X): NEXT 210 FIRSTPASS$(N) = Y$: NEXT 'помещаем в массив 220 '''помещаем в массив вторую таблицу 230 DIM SECONDPASS$(45) ' 240 FOR N = 1 TO 2 ' 250 Y$ = "" ' 260 FOR M=1 TO 6: READ X: Y$ = Y$+CHR$(X): NEXT 270 SECONDPASS$(N) = Y$: NEXT ' 280 '''печатаем текст следующей строки 290 TEXT$ = "Here is one column"+CHR$(179)+"Here is the second column" 300 TEMP$ = STRING$(80,32) 'создаем строку для 2-го прохода 310 GRAPH$ = CHR$(27)+CHR$(75)+CHR$(6)+CHR$(0) 320 OPEN "LPT1:" AS #1 'открываем принтер 330 FOR N = 1 TO LEN(TEXT$) 'для каждого символа текста 340 C$ = MID$(TEXT$,N,1) 'берем символ и проверяем его 350 IF C$ < CHR$(128) THEN PRINT #1,C$;: GOTO 400 360 '''предполагаем, что все остальные символы - псевдографика 370 PRINT #1,GRAPH$; 'входим в графический режим 380 PRINT #1,FIRSTPASS$(ASC(C$) - 178);выводим 1-й проход 390 MID$(TEMP$,N) = C$ 'маркер в строке 2-го прохода 400 NEXT 410 '''смещаемся на 8 точек вниз и делаем второй проход 420 PRINT #1,CHR$(27)+CHR$(65)+CHR$(4)+CHR$(141); 430 Z$ = "" 'Z$ содержит строку для 2-го прохода 440 FOR N = 1 TO LEN(TEXT$) 'для каждого символа текста 450 C$ = MID$(TEMP$,N,1) 'берем символ и обрабатываем его 460 IF C$ = CHR$(32) THEN Z$ = Z$+" ": GOTO 480 470 Z$ = Z$+GRAPH$+SECONDPASS$(ASC(C$) - 178) 480 NEXT 490 PRINT #1,Z$ 'печатаем всю строку сразу 500 PRINT #1,CHR$(10); 'добавляем в конце перевод строки Низкий уровень. Программа на ассемблере использует тот же самый алгоритм, что и приведенная программа на Бейсике. Когда используется только несколько символов, то Вы можете сэкономить место, сжав таблицу, с тем чтобы их положение в таблице не было пропорционально их позиции в наборе ASCII. Затем подготовьте небольшую таблицу ин- дексов с помощью инструкции XLAT, с помощью которой можно быстро искать данные в этой таблице. 6.3.5 Копирование экрана на принтер (дамп экрана). Дамп текстового экрана сделать достаточно просто, если все используемые символы содержатся в ПЗУ принтера и ни один из них не выводится со специальными атрибутами, такими как подчеркивание или негативное изображение. В этом простейшем случае программе нужно лишь установить ширину принтера равной 80 символам, а затем считывать символы поочередно из видеобуфера, посылая их как неп- рерывный поток данных на принтер. Если в ПЗУ принтера отсутствуют специальные символы, такие как символы псевдографики, то програм- ма должна подготовить свою таблицу данных для этих символов и выводить их на принтер в графическом режиме. Поскольку эти симво- лы могут заходить в межстрочные интервалы, то может потребоваться специальное программирование [6.3.4]. Каждый из специальных атрибутов символов создает свои пробле- мы. Проверяйте атрибут каждого символа при считывании его из видеобуфера (в [4.1.3] обсуждается значение битов, соответствую- щее различным атрибутам). Когда символ выделен с помощью подчер- кивания или повышенной интенсивности, то надо включать подчерки- вание или печать жирным шрифтом на принтере. Однако если символ выводится в негативном изображении, то возникают те же проблемы, что и с некоторыми графическими символами: область негативного изображения должна простираться до верхнего края следующей стро- ки. В этом случае надо следуя указаниям [6.3.4] заполнить черным всю область при втором проходе. В зависимости от принтера, Вам может понадобиться создать специальную таблицу данных для вывода символов в негативе, поскольку когда они будут печататься, то окружающие точки могут находиться слишком близко одна к другой, затемняя изображаемый символ. В этом случае не может быть и речи о печати в два прохода. Простым решением проблемы с негативным изображением является использование графического режима экрана для вывода текста, а затем сделать дамп графического экрана. Графические дампы создают свои проблемы. Байт данных принтера соответствует восьми вертикальным точкам, в то время как на экра- не байт представляет 8 горизонтальных точек. Поэтому требуется процедура преобразования, показанная на рис. 6-4. Надо сразу получать по 8 байтов памяти экрана, выбирая такие, которые соот- ветствуют области точек 8*8. Затем надо использовать логические операции для перестановки битов, как показано в примерах. Имейте ввиду, что большинство матричных принтеров искажают экранное изображение. Это происходит потому, что они используют масштабный коэффициент 1:1, в то время как экран использует коэф- фициент 5:6 (масштабный коэффициент сравнивает число горизонталь- ных точек на дюйм с числом вертикальных точек на дюйм). Точнее говоря, искажение изображения на самом деле возникает из-за масш- табного коэффициента экрана, поскольку программы должны специаль- но менять данные для изображения, чтобы оно выглядело так, как нам хочется (например, изображение окружности на экране создается выводом на него эллипса). Когда данные с экрана выводятся на принтер, то эти искажение должны обращаться. Некоторые графичес- кие принтеры имеют специальные режимы, в которых можно выводить копию экрана без искажения, а цветной принтер IBM может менять масштабный коэффициент в любом из своих графических режимов. Высокий уровень. Приводимая процедура на Бейсике делает копию текстового экра- на, игнорируя специальные атрибуты: 10 OPEN "LPT1:" AS #1 'открываем принтер 20 DEF SEG = &HB000 'указываем на видеобуфер 30 PRINT #1,CHR$(13) 'сдвигаем головку влево 40 FOR G = 0 TO 3998 STEP 2 'для каждого байта буфера 50 PRINT #1,CHR$(PEEK(G)); 'читаем его и выводим на принтер 60 NEXT 'обрабатываем следующий байт Переброска цепочек битов для графического дампа требует в Бейсике слишком много времени. Поместите в массив (здесь, BYTE$) восемь байтов, отвечающих области экрана 8*8 точек. Создайте второй массив (VERTICAL$) и обнулите его элементы, а затем поочередно перебрасывайте биты элементов этих массивов следующим образом: 500 FOR M = 0 TO 7 'для каждого бита 510 FOR N = 0 TO 7 'для каждого байта 520 X = ASC(BYTES(N)) 'получаем значение байта 530 Y = 2*(7 - M) 'маска для одного включенного бита 540 Z = X AND Y 'проверка этого бита в байте 550 IF Z <> 0 THEN VERTICAL$(M) = CHR$(ASC(VERTICAL$(M) OR 2*N) 'если он включен, то устанавливаем бит 'в соответствующей позиции 2-го массива 560 NEXT N 'следующий бит 570 NEXT M 'следующий байт Низкий уровень. Язык ассемблера делает битовые преобразования намного быстрее. Вот процедура, которая делает эти преобразования ужасно быстро, поскольку она держит все в микропроцессоре (она немного великова- та, но Вы можете использовать взамен алгоритм, показанный в Бей- сике). Процедура работает, храня 8 результирующих байтов в ре- гистрах CX, DX, BP и DI. Байт экранных данных помещается в AL, а затем в AH передвигаются последовательно CL, CH, DL и DH. Каждый раз из AL в AH сдвигается один бит и когда сделаны 4 сдвига, то CX и DX обмениваются с DX и BP, после чего все это повторяется снова. Этот процесс повторяется для каждого из 8-ми экранных байтов и когда он завершен, то преобразованное изображение хра- нится в регистрах микропроцессора, причем самый левый байт данных для печати в CL. Содержимое регистров выводится на принтер и обнуляется, после чего процесс повторяется для следующих восьми байтов экрана. Сначала получите 8 байтов из видеобуфера и помес- тите их в буфер с именем BUFFER. Поместите 0 в AX, CX, DX, BP и DI. Затем: LEA BX,BUFFER ;указываем на буфер видеоданных MOV SI,0 ;смещение в этом буфере GET_BYTE: MOV AL,[BX][SI] ;берем байт DO_HALF: XCNG AH,CL ;получаем CL, CH, DL и DH SHL AX,1 ;сдвигая бит из AL XCNG AH,CL ; XCNG AH,CH ; SHL AX,1 ; XCNG AH,CH ; XCNG AH,DL ; SHL AX,1 ; XCNG AH,DL ; XCNG AH,DH ; SHL AX,1 ; XCNG AH,DH ; ;---начинаем вторую половину перемещения битов XCNG CX,BP ;обмениваем содержимое CX и DX XCNG DX,DI ; CMP SI,7 ;если все байты преобразованы, то печатаем JE PRINT_BYTES ; INC SI ;иначе переходим к следующему байту JMP SHORT GET_BYTE ; ;---печатаем байты PRINT_BYTES: PUSH DX ;сохроаняем DX MOV AH,5 ;функция вывода на принтер MOV DL,27 ;код Esc INT 21H ;посылаем его MOV DL,75 ;код графического режима INT 21H ;посылаем его MOV DL,6 ;будет послано 6 байтов INT 21H ; MOV DL,0 ; INT 21H ; CALL PRINT_2_BYTES ;посылаем содержимое CX POP CX ; CALL PRINT_2_BYTES ;посылаем содержимое DX MOV CX,BP ; CALL PRINT_2_BYTES ;посылаем содержимое BP MOV DX,DI ; CALL PRINT_2_BYTES ;посылаем содержимое DI . (идем к следующей группе из восьми байтов) . PRINT_2_BYTES: PROC NEAR MOV AH,5 ;функция печати MOV DL,CL ;сначала CL INT 21H ;печатаем MOV DL,CH ;затем CH INT 21H ;печатаем RET PRINT_2_BYTES ENDP Глава 7. Ввод/вывод. Раздел 1. Доступ к последовательному порту. При асинхронной связи машина посылает или принимает байты информации по одному биту. Временные интервалы между байтами при этом несущественны, но времена между отдельными битами байта очень важны. Сигнал на линии может быть высокого или низкого уровня, что соответствует логическим нулю и единице, и говорят, что линия отмечена (marking), когда уровень высокий, и пустая (spacing), когда уровень низкий. Линия поддерживается в отмеченном состоянии, когда по ней нет передачи данных. При начале передачи байта данных сигнал падает в 0, отмечая стартовый бит. Затем следуют восемь битов данных (иногда меньше) в виде набора высоких и низких уровней. Последний бит данных может сопровождаться битом четности, используемым для обнаружения ошибок, а затем в последовательность включаются 1 или более стоп-битов, которым соответствует высокий уровень. Эти стоп-биты начинают отмеченное состояние, которое будет сохранять- ся до тех пор, пока не начнется передача следующего байта данных; число используемых стоп-битов существенно, поскольку они устанав- ливают минимальное время, которое должно пройти перед следующим стартовым битом. На рис. 7-1 показана эта последовательность. Конечно, передающая и приемная станции должны использовать один и тот же протокол для этих цепочек битов и они должны рабо- тать с одной и той же скоростью обмена (измеряемой в битах в секунду, называемых также бодами). При обмене могут легко возни- кать ошибки, поэтому коммуникационное оборудование предоставляет разнообразную информацию о статусе как самого порта, так и при- соединенного к нему модема. Задачей модема является преобразова- ние сигнала, генерируемого портом коммуникации, в акустический сигнал, который может затем быть передан по телефонному каналу. Большинство модемов предоставляют также дополнительные коммуника- ционные возможности, такие как автоматический вызов и ответ, которые не поддерживаются самим портом коммуникации. 7.1.1 Программирование микросхемы UART 8250. Последовательная связь настолько сложна, что были разработаны специальные микросхемы, выполняющие работу по формированию и синхронизации строк битов, составляющих последовательные данные. Такие микросхемы называют универсальным асинхронным приемни- ком-передатчиком (universal asynchronous receiver transmitter или UART). IBM PC использует UART 8250 фирмы Intel. Операционная система поддерживает 2 порта коммуникации, поэто- му в машине имеются 2 микросхемы. Их базовые адреса хранятся в ячейке 0040:0000 для COM1 и 0040:0002 для COM2. (Базовый адрес это 2-хбайтовый адрес порта, который является младшим из группы адресов портов, дающих доступ к UART.) На всех машинах кроме PCjr COM1 имеет базовый адрес 3F8H, а COM2 - 2F8H; PCjr имеет свой внутренний модем по адресу 3F8H, а COM1 - по адресу 3F8H. Для удобства, мы в дальнейшем будем всегда нумеровать регистры 3FxH, но все сказанное в равной степени применимо и к регистрам 2FxH. Микросхема 8250 имеет 10 программируемых однобайтных регист- ров, с помощью которых управляется и контролируется порт коммуни- кации. Большинство из них занимаются инициализацией порта, про- цессом, который может быть очень сложным. Доступ к этим 10 ре- гистрам осуществляется через семь адресов портов с номерами 3F8H - 3FEH (или 2F8H - 2FEH). В пяти случаях регистр, к которому получаем доступ через данный порт, зависит от того, как установ- лен бит 7 в регистре контроля линии, который является единствен- ным регистром с адресом порта 3FBH. Вот эти регистры: 3F8H (OUT, бит 7 = 0 в 3FBH) Регистр хранения передатчика 3F8H (IN, бит 7 = 0 в 3FBH) Регистр данных приемника 3F8H (OUT, бит 7 = 1 в 3FBH) Делитель скорости обмена (младший) 3F9H (IN, бит 7 = 1 в 3FBH) Делитель скорости обмена (старший) 3F9H (OUT, бит 7 = 0 в 3FBH) Регистр разрешения прерывания 3FAH (IN) Регистр идентификации прерывания 3FBH (OUT) Регистр управления линии 3FCH (OUT) Регистр управления модемом 3FDH (IN) Регистр статуса линии 3FEH (IN) Регистр статуса модема Из десяти регистров только шесть необходимы для простой после- довательной связи. Регистр хранения передатчика содержит байт данных, которые будут посланы [7.1.6], а регистр данных приемника - последний полученный байт данных [7.1.7]. Регистры управления и статуса линии инициализируют и управляют линией связи, используя скорость обмена, содержащуюся в двух регистрах делителя скорости обмена [7.1.2]. Из оставшихся четырех регистров регистры управле- ния и статуса модема используются только для связи через модем [7.1.5], а два регистра, связанных с прерываниями используются только в процедурах, управляемых прерываниями [7.1.8]. Прерывания используются при связи в целях эффективности. Обыч- ная коммуникационная процедура непрерывно проверяет регистр ста- туса линии, ожидая вводимого символа или указаниия, что все гото- во для передачи следующего байта данных. Поскольку процессор намного быстрее, чем обычные скорости с которыми передаются пос- ледовательные данные, то этот метод напрасно расходует процессор- ное время, которое может использоваться для обработки поступающих или передаваемых данных. По этой причине микросхема 8250 может быть установлена в режим, вызывающий прерывание при появлении символа, возникновении ошибки и т.п. Это прерывание моментально вызовет процедуру Вашей программы, которая, скажем, будет переда- вать следующий символ из коммуникационного буфера. 7.1.2 Инициализация последовательного порта. При инициализации порта коммуникации ("открытии") устанавли- ваются все его параметры. Эти параметры длину слова, число стоп-битов, установку четности и скорость обмена. Длина слова это число битов, которое образует основную единицу данных. Если мы работаем с привычными порциями по 8 битов, то 7 битов достаточны для стандартных файлов ASCII (в которых все символы имеют коды, не превышающие ASCII 128), в то время как для передачи численных данных достаточно порций по 4 бита. Высокий уровень. Бейсик открывает коммуникационный канал как файл, и как тако- вому ему должен быть присвоен идентификационный номер: OPEN "COM1: .........." AS #1 В кавычках должна быть помещена вся информация, необходимая для инициализации порта коммуникации, при этом каждый элемент отде- ляется от предыдущего запятой. Инициализационные данные всегда вводятся в следующем порядке: Скорость обмена дается как целое число: 75, 100, 150, 300, 600, 1200, 1800, 2400, 4800 или 9600 бод. По умолча- нию берется скорость обмена 300 бод. Четность вводится как односимвольный код: O для нечетной E - для четной и N - при отсутствии контроля по четности. Могут быть также S - когда бит чет- ности всегда равен 0 и M - когда бит четности всегда равен 1. Если используются 8 бит данных, то надо указывать N; при использовании четырех бит не надо использовать N. По умолчанию - E. Биты данных дается как целое число 4, 5, 6, 7 или 8. По умолчанию берется 7. Стоп-биты дается как целое число 1 или 2, причем 2 - значение по умолчанию для 75 и 110 бод, а 1 - для остальных. Когда число битов данных равно 4 или 5, то 2 обозначает 1 1/2 стоп-бита. Такое значение возможно при коммуникации, так как в этом случае бит является единицей времени и поэтому делим. Оператор OPEN "COM1:" AS #1 открывает COM1 для связи со скоростью 300 бод с четной четностью, используя 7 битов данных и 1 стоп-бит. OPEN "COM1:1200,O,8,1" устанавливает скорость 1200 бод, нечетную четность, 8 бит на символ и 1 стоп-бит. Отметим, что Вы можете завершить оператор OPEN выражением LEN = число, где число устанавливает максимальный размер блока, с которым операторы GET и PUT могут обрабатывать данные (по умолчанию 128 байтов). Имеет- ся также ряд команд управления модемом, которые также могут быть включены в эту спецификацию. (В [7.1.5] объясняется специальная терминология, используемая при этом): RS Подавляет сигнал "Запрос на посылку" (Request to send). Если эта команда опущена, то OPEN "COM" включает RTS. CS Вызывает проверку линии "Очистка посылки" (Clear to send). За этой командой может следовать значение (от 0 до 65535), дающее число миллисекунд которые будет ожи- даться сигнал перед тем как будет выдана ошибка таймау- та, например, CS500. Значение по умолчанию 1000, если указан параметр RS, в этом случае 0. DS Вызывает проверку линии "Готовность набора данных" (Data set ready). Допускается необязательный параметр, как и для CS. Значение по умолчанию 1000. CD Вызывает проверку линии "Определение носителя" (Carrier detect). Допускается необязательный временной параметр, как и для CS. Значение по умолчанию 0. LF Вызывает автоматическую подачу кода перевода строки (ASCII 10) после каждого символа возврата каретки (AS- CII 13). Используется для последовательного вывода на принтер. PE Разрешает проверку четности, вызывая ошибку таймаута устройства при возникновении ошибки четности. Эти специальные команды могут помещаться в любом месте опера- тора OPEN "COM" и в любом порядке. Отметим, что обычно сигналы CTS и DSR должны быть установлены, чтобы оператор OPEN выполнил- ся, а иначе будет выдана ошибка таймаута устройства. В заключение приводим оператор OPEN "COM", содержащий все параметры, кроме RS и LF: OPEN "COM1:1200,O,7,1,CS2000,DS2000,CD,PE" AS #1 LEN = 256 Средний уровень. Функция 0 прерывания 14H BIOS инициализирует порт коммуника- ции. В DX должен даваться номер коммуникационного канала (COM1 = 0, COM2 = 1). В AL должен содержаться байт инициализационных данных, значение битов которого следующее: биты 1-0 длина слова. 10 = 7 битов, 11 = 8 битов. 2 число стоп-битов. 0 = 1, 1 = 2. 4-3 четность. 00 или 10 = нет, 01 = нечет., 11 = чет. 7-5 скорость обмена. 000 = 110 бод 001 = 150 бод 010 = 300 бод 011 = 600 бод 100 = 1200 бод 101 = 2400 бод 110 = 4800 бод 111 = 9600 бод В данном примере порт инициализируется со словом в 8 битов, одним стоп-битом и четной четностью. Скорость обмена 1200 бод. ;---присваиваем значения параметров переменным MOV WORDLENGTH,00000011B ;длина слова 8 битов MOV STOPBITS,00000000B ;1 стоп-бит MOV PARITY,00011000B ;четная четность MOV BAUDRATE,10000000B ;скорость 1200 бод ;---инициализируем COM1 MOV AL,0 ;чистим AL OR AL,WORDLENGTH ;устанавливаем нужные биты OR AL,STOPBITS ; OR AL,PARITY ; OR AL,BAUDRATE ; MOV AH,0 ;функция инициализации порта MOV DX,0 ;выбираем COM1 INT 14H ;инициализируем порт Низкий уровень. Независимо от того, занимаемся ли мы вводом или выводом, как минимум 4 регистра микросхемы 8250 должны быть инициализированы для операций обмена. Это регистры делителя скорости обмена, ре- гистр контроля линии и регистр разрешения прерывания. Инициализация скорости обмена. Делитель скорости обмена это число, на которое надо разделить частоту системных часов (1190000 герц), чтобы получить желаемую скорость обмена. Например, для скорости обмена 1200 бод делитель скорости обмена должен быть равен 96, поскольку 1190000/96 приб- лиженно равно 1200. Чем больше делитель, тем меньше скорость обмена. Скорости обмена 300 и меньше требуют двухбайтного числа для делителя. Старший байт посылается в 3F9H (или 2F9H), а млад- ший в 3F8H (2F8H). В обоих случаях бит 7 регистра управления линии должен быть установлен в 1 перед засылкой значений; в про- тивном случае по этим двум адресам значения будут адресованы в другие регистры (см. [7.1.0]). Вот некоторые значения, требуемые для обычных скоростей обмена: Скорость обмена 3F9H 3F8H 110 04H 17H 300 01H 80H 600 00H C0H 1200 00H 60H 1800 00H 40H 2400 00H 30H 3600 00H 20H 4800 00H 18H 9600 00H 0CH Всегда устанавливайте регистры скорости обмена первыми, так как они единственные, которые требуют, чтобы был установлен бит 7 в регистре контроля линии. После этого надо изменить содержимое регистра контроля линии, сбрасывая 7-й бит, чтобы все остальные доступы к регистрам были правильными. Поскольку регистр контроля линии является регистром только для записи, то нет способа вер- нуть бит 7 обратно в 1 без одновременной установки всех остальных битов этого регистра. Отметим, что PCjr использует другие делите- ли, описание которых Вы можете найти в техническом руководстве. Инициализация регистра контроля линии. Значение битов регистра контроля линии, адрес порта которого равен 3FBH (или 2FBH), следующее: биты 1-0 Длина символа. 00 = 5 битов, 01 = 6 битов 10 = 7 битов, 11 = 8 битов 2 Число стоп-битов. 0 = 1, 1 = 1.5, если длина пяти, иначе 2. 3 Четность. 1 = генерируется бит четности, 0 = нет. 4 Тип четности. 0 = нечетная, 1 = четная 5 Фиксация четности. Заставляет бит четности всегда быть 0 или 1. 0 = отменена 1 = всегда 1, если бит 3 = 1 & бит 4 = 0 или 1 = всегда 0, если бит 3 = 1 & бит 4 = 1 или 1 = нет четности, если бит 3 = 0 6 Установка перерыва. Вызывает вывод строки нулей в качестве сигнала отдаленной станции. 0 = запрещено, 1 = перерыв 7 Меняет адреса портов других регистров Обычно биты 5-7 сброшены в 0. Остальные описывают значения, опре- деляемые протоколом обмена. Регистр разрешения прерывания. Даже если Вы не используете прерывания, все равно Вы должны произвести запись в регистр разрешения прерывания, чтобы быть уверенным, что прерывания запрещены. Просто поместите в этот регистр 0. Регистр идентификации прерывания можно игнорировать. Инициализация остальных регистров связана с модемами. Ясно, что модемы нужны только для связи с удаленными устройствами, а не для управления близлежащими устройствами, такими как последова- тельный принтер. В [7.1.5] объяснено как инициализировать регистр контроля модема. В данном примере из области данных BIOS берется базовый адрес COM1, после чего различные регистры инициализируются для скорости обмена 1200 бод, семибитных данных, четной четности и одного стоп-бита. ;---получаем базовый адрес COM1 MOV AX,40H ;ES указывает на область данных BIOS MOV ES,AX ; MOV DX,ES:[0] ;получаем базовый адрес COM1 ;---инициализируеи регистры делителя скорости обмена на 1200 бод ADD DX,3 ;указываем на регистр контроля линии MOV AL,10000000B ;устанавливаем бит 7 OUT DX,AL ;посылаем байт DEC DX ;указываем на старший байт делителя DEC DX ;скорости обмена MOV AL,0 ;старший байт для 1200 бод OUT DX,AL ;посылаем старший байт для 1200 бод DEC DX ;указываем на младший байт делителя MOV AL,60H ;младший байт делителя для 1200 бод OUT DX,AL ;посылаем младший байт ;---инициализируем регистр контроля линии MOV AL,0 ;обнуляем AL OR AL,10B ;длина данных 7 битов OR AL,000B ;1 стоп-бит OR AL,1000B ;генерируется бит четности OR AL,10000B ;четная четность ADD DX,3 ;указывает на регистр контроля линии OUT DX,AL ;посылаем инициализационное значение ;---инициализируем регистр разрешения прерывания DEC DX ;указываем на регистр разрешения DEC DX ;прерывания MOV AL,0 ;запрещаем прерывания OUT DX,AL ;посылаем байт 7.1.3 Установка текущего коммуникационного порта. Имеются два способа, которыми программа может определить, какой из коммуникационных портов должен использоваться. Один из способов состоит в указании номера канала в операторе программы. Второй способ состоит в написании программы для обмена через порт COM1, но изменении коммуникационного адаптера, доступ к которому идет через COM1. Область данных BIOS содержит место для четырех 2-хбайтных переменных, которые содержат базовые адреса коммуникационных каналов (MS DOS поддерживает только первые два из них). Базовый адрес порта это младший из группы адресов портов, через которые можно получить доступ к данному коммуникационному каналу. Базовый адрес для COM1 хранится в ячейке 0040:0000, а для COM2 - в ячейке 0040:0002. Для смены коммуникационных портов надо просто поменять эти два значения. Повторная смена значений приведет к первона- чальному назначению портов. Высокий уровень. В Бейсике оператор OPEN "COM" может использоваться в виде OPEN C$+"1200,N,8" AS #2, где C$ может быть либо "COM1:", либо "COM2:". В качестве альтернативы можно использовать PEEK и POKE для обмена базовых адресов: 100 DEF SEG = &H40 'указываем на область данных BIOS 110 X = PEEK(0): Y = PEEK(1) 'запоминаем первые 2 байта 120 POKE 0,PEEK(2): POKE 1,PEEK(3) 'переносим 2-е два байта 130 POKE 2,X: POKE 3,Y 'засылаем запомненные значения Средний уровень. Если программа обращается к коммуникационному порту через прерывание 14H BIOS, то COM порт определяется содержимым DX, которое равно 0 или 1 (для COM1 или COM2). Вместо того, чтобы присваивать DX непосредственное значение, заполняйте его из пере- менной, которой может быть присвоено значение 0 или 1. Программы, использующие коммуникационные функции 3 и 4 прерывания 21H всегда адресуются к COM1. В этом случае надо поменять базовые адреса: ;---обмен базовых адресов для COM1 и COM2 MOV AX,40H ;ES указывает на область данных BIOS MOV ES,AX ; MOV DX,ES:[0] ;помещаем 1-й базовый адрес в DX MOV AX,ES:[2] ;помещаем 2-й базовый адрес в AX MOV ES:[0],AX ;обмениваем адреса MOV ES:[2],DX ; 7.1.4 Определение статуса коммуникационного порта. Регистр статуса линии микросхемы UART 8250 определяет протокол связи. Этот регистр имеет адрес порта на 5 больше, чем базовый адрес данного канала. Обычно он постоянно просматривается в про- цессе коммуникационного обмена. При передаче данных регистр сооб- щает, что предыдущий символ уже послан, позволяя программе запи- сать новый символ поверх его. При приеме данных регистр информи- рует программу о поступлении следующего символа, с тем чтобы программа могла прочитать его прежде чем он будет уничтожен сле- дующим прибывшим. Значение битов этого регистра следующее: бит 0 1 = байт данных получен 1 1 = полученные данные были перезаписаны (предыдущий символ не был вовремя считан) 2 1 = ошибка четности (вероятно, из-за шума в линии) 3 1 = ошибка окружения (передача не синхронизована) 4 1 = обнаружен перерыв (получена длинная строка единиц, индицирующая, что другая станция запрашивает конец передачи) 5 1 = регистр хранения передатчика пуст (в этот регистр должны помещаться передаваемые данные) 6 1 = регистр сдвига передатчика пуст (этот регистр по- лучает данные из регистра хранения и преобразует их в последовательный вид) 7 1 = таймаут (устройство не связано с машиной) Высокий уровень. В Бейсике сначала определите базовый адрес используемого ком- муникационного порта, затем добавьте к нему 5 и используйте опе- ратор INP для получения байта из этого порта. В приложении Б объясняется как в Бейсике производятся битовые операции, которые необходимо проделать программе, чтобы интерпретировать значение этого байта. В следующем примере проверяется бит наличия переры- ва: 100 DEF SEG = &H40 'указываем на область данных BIOS 110 ADDR = PEEK(4)+PEEK(5)*256 'вычисляем адрес COM2 120 X = INP(ADDR+5) 'вычисляем адрес регистра статуса 130 IF X AND 16 THEN 500 'переход на подпр-му, если бит 4 = 1 . . 500 '''начинаем процедуру обработки перерыва Средний уровень. Функция 3 прерывания 14H BIOS возвращает в AH регистр статуса линии (AL получает регистр статуса модема [7.1.5]). При входе DX должен содержать номер коммуникационного порта, к которому осу- ществляется доступ, где COM1 = 0, а COM2 = 1. Как и предыдущий пример, этот проверяет наличие перерыва: MOV AH,3 ;номер функции MOV DX,1 ;выбираем COM2 INT 14H ;получаем байт статуса TEST AH,10000B ;обнаружен перерыв? JNZ BREAK_DETECT ;если да, то на процедуру обработки Низкий уровень. Этот пример совершенно аналогичен приведенному на Бейсике. Из области данных BIOS считывается базовый адрес коммуникационного канала, к нему добавляется 5, а затем из полученного адреса порта считывается байт статуса. MOV AX,40H ;ES указывает на область данных BIOS MOV ES,AX ; MOV DX,ES:[2] ;получаем базовый адрес COM2 ADD DX,5 ;добавляем 5 для регистра статуса IN AL,DX ;получаем байт статуса TEST AL,10000B ;бит 5 установлен? JNZ BREAK_DETECT ;если да, то на обработку перерыва 7.1.5 Инициализация и управление модемом. Имеется 6 линий, по которым модемы связываются с компьютером (усовершенствованные модели могут иметь добавочные линии по ин- терфейсу RS232). Вот их названия, сокращения и функции: От компьютера к модему: Data Terminal Ready (DTR) Информирует модем, что компьютер Готовность компьютера включен и готов к связи. Request To Send (RTS) Информирует модем, что компьютер Запрос на посылку ожидает посылки данных. От модема к компьютеру: Data Set Ready (DSR) Информирует компьютер, что модем Готовность модема включен и готов. Clear To Send (CTS) Информирует компьютер, что модем Готовность к посылке готов начать передачу данных. Data Carrier Detect (DCD) Информирует компьютер, что модем Обнаружен носитель данных связан с другим модемом. Ring Indicator (RI) Информирует компьютер, что теле- Индикатор звонка фонная линия, по которой присое- динен модем имеет звонок. Сначала компьютер устанавливает сигнал DTR, а затем инстукти- рует модем связаться с удаленной станцией. После того, как модем установил связь он устанавливает сигнал DSR. Этот сигнал информи- рует компьютер, что модем готов к связи и в этот момент компьютер может установить сигнал RTS. Когда модем ответит сигналом CTS, то передача начинается. Две стандартные линии, по которым компьютер управляет модемом, доступны через регистр контроля модема микросхемы UART 8250. Этот регистр имеет адрес порта на 4 больше, чем базовый адрес исполь- зуемого коммуникационного канала. Вот значение его битов: Регистр контроля модема: биты 7-5 (всегда 0) 4 1 = выход UART замкнут на вход 3 добавочный пользователь назначен на вывод #2 2 добавочный пользователь назначен на вывод #1 1 1 = "запрос на посылку" активен 0 1 = "готовность компьютера" активна Обычно установлены биты 0 и 1 регистра контроля модема, а остальные равны 0. Бит 2 равен 0, за исключением случаев, когда производитель модема предназначил его для специального использо- вания. Бит 3 установлен только в случае, когда используются пре- рывания [7.1.8]. Наконец, бит 4 предоставляет возможность тести- рования коммуникационных программ без установления реальной свя- зи. Выходной сигнал микросхемы UART подается на вход, как будто UART принимает последовательные данные. Это свойство можно ис- пользовать для тестирования правильности работы самой микросхемы. Оно недоступно при использовании коммуникационных процедур преры- вания 14H BIOS. Четыре линии, по которым модем посылают информацию компьютеру, управляются регистром статуса модема. Этот регистр расположен по адресу порта на 6 больше, чем базовый адрес используемого комму- никационного адаптера. Вот значение его битов: Регистр статуса модема: бит 7 1 = DCD 6 1 = RI 5 1 = DSR 4 1 = CTS 3 1 = изменение в DCD 2 1 = изменение в RI 1 1 = изменение в DSR 0 1 = изменение в CTS Программа непрерывно проверяет эти биты в ходе коммуникацион- ных операций. Отметим, что 4 младших бита параллельны старшим четырем битам. Эти биты устанавливаются в 1 только тогда, когда происходит изменение в статусе соответствующего старшего бита с тех пор, когда регистр читался последний раз. Все 4 младших бита автоматически сбрасываются при чтении регистра. Программы любого уровня могут прямо читать этот регистр. Другой возможностью яв- ляется использование функции 3 прерывания 14H BIOS, которая возв- ращает регистр статуса модема в AL (при этом в AH будет содер- жаться регистр статуса линии). При входе DX должен содержать номер коммуникационного канала (0 или 1). Большинство модемов имеет намного больше возможностей, по сравнению с теми, что отражены в двух связанных с модемом регист- рах. Имеются возможности автоматической связи и автоматического ответа, которые контролируются управляющей строкой. Эта строка посылается в модем, как будто передаются обычные данные. Модем выделяет эту строку из данных по специальному символу, используе- мому только для указания начала управляющей строки. Этот символ может быть предопределенным (часто используется код Esc - ASCII 27) или выбираемым пользователем. Модем способен определить нас- колько длинной должна быть каждая строка, поэтому по окончании строки он опять рассматривает входящий поток информации как дан- ные. Каждый модем имеет свой набор команд. В качестве примера рассмотрим команды, используемые внутренним модемом PCjr: Символ Значение Применение A ответ вход в режим ответа Bn перерыв посылает сигнал перерыва n*100 мс Cn отсчет n отсчитывает n звонков до ответа Dn...n вызов посылает строку чисел n...n Fn формат устанавливает протокол связи H разрыв прекращает связь с машиной I инициализация инициализирует модем LR долгий ответ меняет используемую кодовую систему M режим модем берет символы как данные Nn новый меняет командный символ на n O originate вход в режим originate P pick-up вход в режим голоса Q запрос запрос статуса модема R повтор повторить команду связи Sn скорость выбор скорости обмена Tn...n прозрачность игнорировать управляющие строки в следующих n...n байтах V голос перевести модем в режим голоса W ожидание ничего не делать до след. команды X передать передать тона вызова Z тест проводит диагностику оборудования В ответ на команду запроса модем посылает информацию о своем состоянии, посылая ее в UART как обычные данные. Помимо прочей информации, может сообщаться, что линия занята. Чт