Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых
[Назад] [Содеожание] [Дальше]

Аппаратное обеспечение персонального компьютера

© Александр Фролов, Григорий Фролов
Том 33, М.: Диалог-МИФИ, 1997, 304 стр.

6 Асинхронный последовательный адаптер

  • Основные понятия и термины
  • Аппаратная реализация
  • Порты асинхронного адаптера
  • Функции BIOS для работы с последовательным асинхронным адаптером
  • Программирование асинхронного адаптера
  • Эта глава посвящена асинхронному последовательному адаптеру. Его называют еще портом RS232-C, или асинхронным адаптером RS232-C. Компьютер IBM PC поддерживает интерфейс RS232-C не в полной мере, скорее разъем, обозначенный на корпусе компьютера как асинхронный последовательный адаптер, содержит некоторые из сигналов, входящих в интерфейс RS232-C и имеющих соответствующие этому стандарту уровни напряжения.

    В настоящее время порт последовательной передачи данных используется очень широко. Вот далеко не полный список применений:

    ·          подключение мыши;

    ·          подключение графопостроителей (плотеров), сканеров, принтеров;

    ·          связь двух компьютеров через асинхронные последовательные адаптеры с использованием специального кабеля и таких программ, как FastLinx или Norton Commander;

    ·          подключение модемов для передачи данных по телефонным линиям;

    ·          подключение к сети персональных компьютеров

    Практически любой современный компьютер оборудован хотя бы одним асинхронным последовательным адаптером.

    Основные понятия и термины

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

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

    Исходное состояние линии последовательной передачи данных - уровень логической 1. Стартовый бит START сигнализирует о начале передачи данных. Далее передаются биты данных, вначале младшие, затем старшие. Если используется бит четности P, то передается и он. Бит четности имеет такое значение, чтобы в пакете битов общее количество единиц (или нулей) было четно или нечетно.

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

    Использование четности, стартовых и стоповых битов определяют протокол передачи данных. Очевидно, что передатчик и приемник данных должны использовать один и тот же протокол, иначе связь будет невозможной.

    Другая важная характеристика - скорость передачи данных. Она также должна быть одинаковой для передатчика и приемника.

    Скорость передачи данных обычно измеряется в бодах. Боды - это количество передаваемых бит в секунду. При этом учитываются и старт/стопные биты, а также бит четности.

    В технической литературе и в различной документации документации вы можете встретить и другой термин - биты в секунду (bps). Здесь имеется в виду эффективная скорость передачи данных без учета временных затрат на передачу служебных битов.

    Аппаратная реализация

    Компьютер может быть оснащен одним или двумя асинхронными последовательными адаптерами. Эти адаптеры расположены либо на системной плате, либо (в старых компьютерах) на отдельной плате, вставляемой в разъемы расширения системной платы.

    Бывают также платы расширения, содержащие 4, 8 или большее количество асинхронных последовательных адаптеров. Их часто используют для подключения нескольких модемов к одному компьютеру.

    Микросхема UART

    В основе последовательного порта передачи данных лежит микросхема Intel 8250 или более современные микросхемы, такие как 16450, 16550, 16550A. Это универсальный асинхронный приемо-передатчик (UART - Universal Asynchronous Receiver Transmitter). Микросхема содержит несколько внутренних регистров, доступных через команды ввода/вывода.

    В микросхеме 8250 есть регистры передатчика и приемника данных. При передаче выходной байт записывается в буферный регистр передатчика, откуда затем переписывается в сдвиговый регистр передатчика. После этого байт выдвигается из сдвигового регистра по битам.

    Аналогично работают сдвиговый и буферный регистры приемника.

    Программа имеет доступ только к буферным регистрам, копирование информации в сдвиговые регистры и процесс сдвига выполняется микросхемой UART автоматически.

    Разъемы адаптера

    Внешние устройства подключаются к порту ввода/вывода через разъем DB25P (имеющий 25 выводов) или DB9P (имеющий 9 выводов). Приведем разводку разъема последовательной передачи данных DB25P:

    Номер контакта

    Назначение контакта

    Вход или выход

    1

    Защитное заземление

    -

    2

    Передаваемые данные (Transmitted Data)

    Выход

    3

    Принимаемые данные (Received Data)

    Вход

    4

    Запрос для передачи (Request to send, RTS)

    Выход

    5

    Сброс для передачи (Clear to Send, CTS)

    Вход

    6

    Готовность данных (Data Set Ready, DSR)

    Вход

    7

    Сигнальное заземление (Signal Ground)

    -

    8

    Детектор принимаемого с линии сигнала (Data Carrier Detect, DCD)

    Вход

    9-19

    Не используются

    20

    Готовность выходных данных (Data Terminal Ready, DTR)

    Выход

    21

    Не используется

    22

    Индикатор вызова (Ring Indicator, RI)

    Вход

    23-25

    Не используется

    Наряду с 25-контактным разъемом часто используется 9-контактный разъем:

    Номер контакта

    Назначение контакта

    Вход или выход

    1

    Детектор принимаемого с линии сигнала (Data Carrier Detect, DCD)

    Вход

    2

    Принимаемые данные (Received Data)

    Вход

    3

    Передаваемые данные (Transmitted Data)

    Выход

    4

    Готовность выходных данных (Data Terminal Ready, DTR)

    Выход

    5

    Сигнальное заземление (Signal Ground)

    -

    6

    Готовность данных (Data Set Ready, DSR)

    Вход

    7

    Запрос для передачи (Request to send, RTS)

    Выход

    8

    Сброс для передачи (Clear to Send, CTS)

    Вход

    9

    Индикатор вызова (Ring Indicator, RI)

    Вход

    Уровни напряжения на линиях разъема составляют для логического нуля ‑15 вольт, для логической единицы +15 вольт.

    Доступ к отдельным линиям возможен через порты ввода/вывода асинхронного последовательного адаптера, которые мы рассмотрим в следующем разделе. Там же будет описано назначение отдельных линий разъема.

    Порты асинхронного адаптера

    На этапе инициализации системы BIOS тестирует имеющиеся асинхронные последовательные адаптеры и инициализирует первые два. Их базовые адреса располагаются в области данных BIOS начиная с адреса 0000:0400h.

    Первый адаптер COM1 имеет базовый адрес 3F8h и занимает диапазон адресов от 3F8h до 3FFh, второй адаптер COM2 имеет базовый адрес 2F8h и занимает адреса 2F8h...2FFh.

    Асинхронные адаптеры могут вырабатывать прерывания:

    ·          COM1 - IRQ4 (соответствует INT 0Ch);

    ·          COM2 - IRQ3 (соответствует INT 0Bh)

    Заметим, что в некоторых компьютерах вы можете изменить базовые адреса адаптеров и номера прерываний с помощью программы BIOS Setup.

    Порт 3F8h

    Порт 3F8h соответствует регистру данных. Для передачи необходимо записать в этот порт передаваемый байт данных. После приема данных от внешнего устройства они могут быть прочитаны порта 3F8h.

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

    Изменяя содержимое делителя, можно изменять скорость передачи данных. Старший байт делителя записывается в порт 3F9h.

    Зависимость скорости передачи данных от значения делителя частоты представлена ниже:

    Делитель

    Скорость передачи в бодах

    1040

    110

    768

    150

    384

    300

    192

    600

    96

    1200

    48

    2400

    24

    4800

    12

    9600

    6

    19200

    3

    38400

    2

    57600

    1

    115200

    Порт 3F9h

    Порт 3F9h используется либо как регистр управления прерываниями от асинхронного адаптера либо (после вывода в порт 3F9h байта с установленным старшим битом) для вывода значения старшего байта делителя частоты тактового генератора.

    В режиме регистра управления прерываниями порт имеет следующий формат:

    Поле

    Описание

    0

    Разрешение прерывания при готовности принимаемых данных

    1

    Разрешение прерывания после передачи байта, когда выходной буфер передачи пуст

    2

    Разрешение прерывания по обнаружению состояния BREAK или при возникновении ошибке

    3

    Разрешение прерывания по изменению состояния входных линий на разъеме RS232-C (CTS, DSR, RI, DCD)

    4-7

    Не используются, должны быть равны 0

    Порт 3FAh

    Порт 3FAh представляет собой регистр идентификации прерывания. Считывая его содержимое, программа может определить причину прерывания.

    Формат регистра:

    Поле

    Описание

    0

    1 - Нет прерываний, ожидающих обслуживания

    1-2

    00 - Прерывание по линии состояния приемника, возникает при переполнении приемника, ошибках четности или формата данных или при состоянии "BREAK". Сбрасывается после чтения состояния линии из порта 3FDh;

    01 - Данные приняты и доступны для чтения. Сбрасывается после чтения данных из порта 3F8h;

    10 - Буфер передатчика пуст. Сбрасывается при записи новых данных в регистр данных передатчика, порт 3F8h;

    11 - Состояние модема. Устанавливается при изменении состояния входных линий CTS, RI, DCD, DSR. Сбрасывается после чтения состояния модема из порта 3FEh

    3-7

    Должно быть равно 0

    Порт 3FBh

    Порт 3FBh – это управляющий регистр, доступен по записи и чтению.

    Формат регистра:

    Поле

    Описание

    0-1

    Длина слова в битах:

    00 - 5 бит;

    01 - 6 бит;

    10 - 7 бит;

    11 - 8 бит

    2

    Количество стоповых бит:

    0 - 1 бит;

    1 - 2 бита

    3-4

    Четность:

    X0 - контроль на четность не используется;

    01 - контроль на нечетность;

    11 - контроль на четность

    5

    Фиксация четности. При установке этого бита бит четности всегда принимает значение 0 (если биты 3-4 равны 11) или 1 (если биты 3-4 равны 01)

    6

    Установка перерыва. Вызывает вывод строки нулей в качестве сигнала BREAK для подключенного устройства

    7

    1 - порты 3F8h и 3F9h используются для для загрузки делителя частоты тактового генератора;

    0 - порты используются как обычно

    Порт 3FCh

    Порт 3FCh – это регистр управления модемом. Управляет состоянием выходных линий DTR, RTS, линий, специфических для модемов OUT1 и OUT2, для запуска диагностики.

    Формат порта:

    Поле

    Описание

    0

    Линия DTR

    1

    Линия RTS

    2

    Линия OUT1 (запасная)

    3

    Линия OUT2 (запасная)

    4

    Запуск диагностики при входе асинхронного адаптера, замкнутом на его выход

    5-7

    Должно быть равно 0

    Порт 3FDh

    Порт 3FDh представляет собой регистр состояния линии.

    Формат порта:

    Поле

    Описание

    0

    Данные получены и готовы для чтения. Сбрасывается при чтении данных

    1

    Ошибка переполнения. Был принят новый байт данных, а предыдущий еще не был считан программой. Предыдущий байт потерян

    2

    Ошибка четности. Сбрасывается после чтения состояния линии

    3

    Ошибка синхронизации

    4

    Обнаружен запрос на прерывание передачи BREAK: длинная строка нулей

    5

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

    6

    Регистр сдвига передатчика пуст. Этот регистр получает данные из регистра хранения и преобразует их в последовательный вид для передачи

    7

    Истекло время ожидания

    Порт 3FEh

    Порт 3FEh представляет собой регистр состояния модема.

    Поле

    Описание

    0

    Линия CTS изменила состояние

    1

    Линия DSR изменила состояние

    2

    Линия RI изменила состояние

    3

    Линия DCD изменила состояние

    4

    Состояние линии CTS

    5

    Состояние линии DSR

    6

    Состояние линии RI

    7

    Состояние линии DCD

    Функции BIOS для работы с последовательным асинхронным адаптером

    В этом разделе мы расскажем о функцях BIOS, облегчающих обслуживание двух асинхронных адаптеров, COM1 и COM2. Эти функции доступны через прерывание INT 14h.

    Инииализация портов асинхронного адаптера

    Первая функция с кодом 00h предназначена для инициализации портов асинхронного адаптера:

    Регистры на входе:

    AH = 00h;

    DX = номер порта адаптера: 0 - COM1, 1 - COM2;

    AL = параметры инициализации

    Регистры на выходе:

    AH = состояние порта асинхронного адаптера;

    AL = состояние модема

    Параметры инициализации, предаваемые в регистре AL, перечислены ниже:

    Поле

    Описание

    0-1

    Длина слова:

    00 - 5 бит;

    01 - 6 бит;

    10 - 7 бит;

    11 - 8 бит

    2

    Количество стоповых бит:

    0 - 1 бит;

    1 - 2 бита

    3-4

    Контроль четности:

    X0 - контроль на четность не используется;

    01 - контроль на нечетность;

    11 - контроль на четность

    5-7

    Скорость передачи данных в бодах:

    000 – 110;

    001 – 150;

    010 – 300;

    011 – 600;

    100 – 1200;

    101 – 2400;

    110 – 4800;

    111 – 9600

    После вызова функции 00h в регистр AH записывается состояние порта асинхронного адаптера.

    Формат регистра:

    Поле

    Описание

    0

    Истекло время ожидания. Если установлен этот бит, другие биты не имеют значения

    1

    Регистр сдвига передатчика пуст

    2

    Буферный регистр передатчика пуст

    3

    Обнаружено состояние BREAK

    4

    Ошибка синхронизации

    5

    Ошибка четности

    6

    Ошибка переполнения входного регистра

    7

    Данные готовы

    Регистр AL содержит байт состояния модема.

    Формат регистра:

    Поле

    Описание

    0

    Линия CTS изменила состояние

    1

    Линия DSR изменила состояние

    2

    Линия RI изменила состояние

    3

    Линия DCD изменила состояние

    4

    Состояние линии CTS

    5

    Состояние линии DSR

    6

    Состояние линии RI

    7

    Состояние линии DCD

    Передача байта

    Для передачи байта используется функция 01h:

    Регистры на входе:

    AH = 01h;

    DX = номер порта адаптера: 0 - COM1, 1 - COM2;

    AL = передаваемый байт

    Регистры на выходе:

    AL сохраняется;

    AH = состояние порта асинхронного адаптера. Если бит 7 регистра AH установлен, произошла ошибка

    Прием байта

    Функция 02h предназначена для приема байта:

    Регистры на входе:

    AH = 02h;

    DX = номер порта адаптера: 0 - COM1, 1 - COM2;

    Регистры на выходе:

    AL = принятый байт;

    AH = состояние порта асинхронного адаптера. Если бит 7 регистра AH установлен, произошла ошибка

    Определение состояния асинхронного адаптера

    Состояние порта асинхронного адаптера можно узнать с помощью функции 03h:

    Регистры на входе:

    AH = 03h;

    DX = номер порта адаптера: 0 - COM1, 1 - COM2;

    Регистры на выходе:

    AL = состояние модема;

    AH = состояние порта асинхронного адаптера. Если бит 7 регистра AH установлен, произошла ошибка

    Программирование асинхронного адаптера

    К сожалению, среди функций программного интерфейса MS-DOS нет ни одной, обеспечивающей сколько-нибудь серьезную работу с последовательным асинхронным адаптером. Две функции прерывания INT 21h с номерами 3 и 4 предназначены для чтения и записи байтов через асинхронный адаптер. Обе эти функции имеют дело с адаптером COM1 или AUX. Функция 3 получает в регистре AL символ, принятый из адаптера, функция 4 посылает в адаптер символ, записанный в регистр DL.

    Основной недостаток функций MS-DOS, предназначенных для работы с асинхронным адаптером, заключается в отсуствии их функциональной полноты. Используя только функции MS-DOS, вы не сможете проанализировать ошибочные ситуации и изменить режим работы асинхронного адаптера - нет соответствующих средств.

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

    Учитывая все это, для программирования асинхронного адаптера мы рекомендуем использовать порты ввода/вывода микросхемы UART.

    Инициализация асинхронного адаптера

    Первое, что должна сделать программа, работающая с асинхронным адаптером - установить протокол обмена и скорость передачи данных. После загрузки операционной системы для асинхронных адаптеров устанавливается скорость 2400 бод, не выполняется проверка на четность, используются один стоповый бит и восьмибитовая длина передаваемого символа. Вы можете изменить этот режим командой MS-DOS MODE.

    Выполнив ввод из порта 3FBh, программа может получить текущий режим адаптера. Для установки нового режима измените нужные вам поля и запишите новый байт режима по адресу 3FBh.

    Если вам надо задать новое значение скорости обмена данными, перед записью байта режима установите старший бит этого байта. Затем последовательно двумя командами вывода загрузите делитель частоты тактового генератора. Младший байт запишите в порт 3F8h, старший - в порт 3F9h.

    Перед началом работы необходимо также проинициализировать регистр управления прерываниями (порт 3F9h), даже если в вашей программе не используются прерывания от асинхронного адаптера. Если прерывания вам не нужны, запишите в этот порт значение 0.

    На этом инициализацию можно считать законченной.

    Передача данных

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

    Признаком того, что регистр передатчика свободен, является установленный бит 5 регистра состояния линии с адресом 3FDh.

    Прием данных

    Аналогично тому как это делается при передаче данных, перед вводом символа из порта приемника 3F8h необходимо убедиться в том, что бит 0 порта 3FDh установлен. Это означает, что символ принят из линии и находится в буферном регистре приемника.

    Программа COMTEST

    В листинге 6.1 приведен исходный текст программы COMTEST, использующей описанные выше способы работы с асинхроннымо адаптером.

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

    Листинг 6.1. Файл comtest\comtest.с

    
    	// =====================================================
    	// Работа с асинхронным адаптером COM1.
    	// Перед запуском программы необходимо замкнуть
    	// контакты 2 и 3 разъема COM1
    	//
    	// (C) Фролов А.В, 1997
    	//
    	// E-mail: frolov@glas.apc.org
    	// WWW:    http://www.glasnet.ru/~frolov
    	//            или
    	//         http://www.dials.ccas.ru/frolov
    	// =====================================================
    	
    	#include <stdio.h>
    	#include <conio.h>
    	
    	typedef struct _AUX_MODE_ 
    	{
    	  union 
    	  {
    	    struct 
    	    {
    	      unsigned char len : 2, // длина символа
    	           stop         : 1, // число стоп-битов
    	           parity       : 2, // контроль четности
    	           stuck_parity : 1, // фиксация четности
    	           en_break_ctl : 1, // установка перерыва
    	           dlab         : 1; // загрузка регистра делителя
    	    } ctl_word;
    	    char ctl;
    	  } ctl_aux;
    	  unsigned long baud; // скорость передачи данных
    	} AUX_MODE;
    	
    	void aux_stat(AUX_MODE *mode, int port);
    	int aux_init(AUX_MODE *mode, int port, int imask);
    	void aux_outp(char chr, int port);
    	char aux_inp(int port);
    	
    	int main(void) 
    	{
    	  AUX_MODE amd;
    	
    	  aux_stat(&amd, 0);
    	  printf("\nСостояние порта COM1:"
    	    "\nКод длины символа:    %d"
    	    "\nКод числа стоп-битов: %d"
    	    "\nКонтроль четности:    %d"
    	    "\nСкорость передачи:    %lu",
    	    amd.ctl_aux.ctl_word.len,
    	    amd.ctl_aux.ctl_word.stop,
    	    amd.ctl_aux.ctl_word.parity,
    	    (unsigned long)amd.baud);
    	
    	  amd.baud = 115200;
    	  aux_init(&amd, 0, 0);
    	
    	  aux_stat(&amd, 0);
    	  printf("\nСостояние порта COM1:"
    	    "\nКод длины символа:    %d"
    	    "\nКод числа стоп-битов: %d"
    	    "\nКонтроль четности:    %d"
    	    "\nСкорость передачи:    %lu",
    	    amd.ctl_aux.ctl_word.len,
    	    amd.ctl_aux.ctl_word.stop,
    	    amd.ctl_aux.ctl_word.parity,
    	    (unsigned long)amd.baud);
    	
    	  printf("\n\nТестирование асинхронного адаптера."
    	    "\nНажимайте клавиши!"
    	    "\nДля завершения работы нажмите <Contril+C>\n");
    	
    	  for(;;) 
    	  {
    	    // Вводим символ с клавиатуры и передаем его
    	    // в асинхронный адаптер
    	    aux_outp((char)getch(), 0);
    	
    	    // Вводим символ из асинхронного адаптера и
    	    // отображаем его на экране
    	    putchar(aux_inp(0));
    	  }
    	  return 0;
    	}
    	
    	/**
    	*.Name         aux_stat
    	*.Title        Определение режима асинхронного адаптера
    	*
    	*.Descr        Эта функция считывает текущий режим
    	*              асинхронного порта и записывает его
    	*              в структуру с типом AUX_MODE
    	*
    	*.Proto        void aux_stat(AUX_MODE *mode, int port);
    	*
    	*.Params       AUX_MODE mode - структура, описывающая
    	*              протокол и режим работы порта:
    	*
    	*              int port - номер асинхронного адаптера:
    	*                 0 - COM1, 1 - COM2
    	**/
    	void aux_stat(AUX_MODE *mode, int port) 
    	{
    	  unsigned long b;
    	
    	  // Запоминаем режим адаптера
    	  mode->ctl_aux.ctl = (char)inp(0x3fb - 0x100 * port);
    	
    	  // Устанавливаем старший бит режима
    	  // для считывания текушей скорости передачи
    	  outp(0x3fb - 0x100 * port, mode->ctl_aux.ctl | 0x80);
    	
    	  // Считываем значение регистра делителя
    	  b = inp(0x3f9 - 0x100 * port); b = b << 8;
    	  b += inp(0x3f8 - 0x100 * port);
    	
    	  // Преобразуем его в боды
    	  switch (b) 
    	  {
    	    case 1040: b = 110; break;
    	    case 768: b = 150; break;
    	    case 384: b = 300; break;
    	    case 192: b = 600; break;
    	    case 96: b = 1200; break;
    	    case 48: b = 2400; break;
    	    case 24: b = 4800; break;
    	    case 12: b = 9600; break;
    	    case 6: b = 19200; break;
    	    case 3: b = 38400; break;
    	    case 2: b = 57600; break;
    	    case 1: b = 115200; break;
    	    default: b=0; break;
    	  }
    	
    	  mode->baud = b;
    	
    	  // Восстанавливаем состояние адаптера
    	  outp(0x3fb - 0x100 * port, mode->ctl_aux.ctl & 0x7f);
    	}
    	
    	/**
    	*.Name         aux_init
    	*.Title        Инициализация асинхронного адаптера
    	*
    	*.Descr        Эта функция инициализирует асинхронные
    	*              адаптеры, задавая протокол обмена данными
    	*              и скорость обмена данными
    	*
    	*.Proto        int aux_init(AUX_MODE *mode, int port,
    	*                                        int imask);
    	*
    	*.Params       AUX_MODE *mode - указатель на структуру,
    	*                        описывающую протокол и режим работы 
    	*                        порта;
    	*
    	*              int port - номер асинхронного адаптера:
    	*                 0 - COM1, 1 - COM2
    	*
    	*              int imask - значение для регистра маски
    	*                          прерываний
    	*
    	*.Return       0 - инициализация выполнена успешно;
    	*              1 - ошибки в параметрах инициализации.
    	**/
    	int aux_init(AUX_MODE *mode, int port, int imask) 
    	{
    	  unsigned div;
    	  char ctl;
    	
    	  // Вычисляем значение для делителя
    	  switch (mode->baud) 
    	  {
    	    case 110: div = 1040; break;
    	    case 150: div = 768; break;
    	    case 300: div = 384; break;
    	    case 600: div = 192; break;
    	    case 1200: div = 96; break;
    	    case 2400: div = 48; break;
    	    case 4800: div = 24; break;
    	    case 9600: div = 12; break;
    	    case 19200: div = 6; break;
    	    case 38400: div = 3; break;
    	    case 57600: div = 2; break;
    	    case 115200: div =1; break;
    	    default: 
    	      return(-1); break;
    	  }
    	
    	  // Записываем значение делителя частоты
    	  ctl = inp(0x3fb - 0x100 * port);
    	  outp(0x3fb - 0x100 * port, ctl | 0x80);
    	
    	  outp(0x3f9 - 0x100 * port, (div >> 8) & 0x00ff);
    	  outp(0x3f8 - 0x100 * port, div & 0x00ff);
    	
    	  // Записываем новое управляющее слово
    	  outp(0x3fb - 0x100 * port, mode->ctl_aux.ctl & 0x7f);
    	
    	  // Устанавливаем регистр управления прерыванием
    	  outp(0x3f9 - 0x100 * port, imask);
    	  
    	  return 0;
    	}
    	
    	/**
    	*.Name         aux_outp
    	*.Title        Вывод символа в асинхронный адаптер
    	*
    	*.Descr        Эта функция дожидается готовности
    	*              передатчика и посылает символ
    	*
    	*.Proto        void aux_outp(char chr, int port);
    	*
    	*.Params       char chr - посылаемый символ;
    	*
    	*              int port - номер асинхронного адаптера:
    	*                 0 - COM1, 1 - COM2
    	**/
    	void aux_outp(char chr, int port) 
    	{
    	  unsigned status_reg, out_reg;
    	
    	  status_reg = 0x3fd - 0x100 * port;
    	  out_reg = status_reg - 5;
    	
    	  while( (inp(status_reg) & 0x20) == 0 );
    	  outp(out_reg, chr);
    	}
    	
    	/**
    	*.Name         aux_inp
    	*.Title        Ввод символа из асинхронного адаптера
    	*
    	*.Descr        Эта функция дожидается готовности
    	*              приемника и вводит символ из асинхронного
    	*              адаптера
    	*
    	*.Proto        char aux_inp(int port);
    	*
    	*.Params       int port - номер асинхронного адаптера:
    	*                 0 - COM1, 1 - COM2
    	*
    	*.Return       Принятый символ
    	**/
    	char aux_inp(int port) 
    	{
    	  unsigned status_reg, inp_reg;
    	
    	  status_reg = 0x3fd - 0x100 * port;
    	  inp_reg = status_reg - 5;
    	
    	  while( (inp(status_reg) & 1) == 0 );
    	  return(inp(inp_reg));
    	}
    

    Использование прерываний

    Так как процесс последовательной передачи данных протекает достаточно медленно, имеет смысл выполнять его в фоновом режиме, используя прерывания по окончанию передачи или приема символа. Напомним, что порту COM1 соответствует аппаратное прерывание INT 0Ch, а COM2 - INT 0Bh.

    Для разрешения прерываний необходимо установить биты порта управления прерываниями 3F9h, соответствующие тем прерываниям, которые нужно обрабатывать.

    Когда происходит прерывание, программа-обработчик прерывания должна проанализировать причину прерывания, прочитав содержимое порта идентификации прерывания с адресом 3FAh.

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

    
    	mov al, 20h
    	out 20h, al
    	iret
    

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

    Более подробное описание способов работы с последовательным асинхронным адаптером с применением прерываний и соответствующие примеры программ вы найдете в 16 томе «Библиотеки системного программиста», который называется «Модемы и факс-модемы».

    [Назад] [Содеожание] [Дальше]