¦ 2400 ¦ 5
¦ 4800 ¦ 6
¦ 9600 ¦ 7
¦ ¦
Четность ¦ Нет ¦ 0 или 2
¦ Нечетность ¦ 1
¦ Четность ¦ 3
- 8-16 -
Стоповые биты ¦ 1 ¦ 0
¦ 2 ¦ 1
¦ ¦
Длина слова ¦ 7 ¦ 2
¦ 8 ¦ 3
ДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДД
Подготовить упакованную форму параметров просто. Например,
если Вы используете язык высокого уровня, такой как Си, можно
достичь результата следующим образом:
pckd_commparams = (baudrate << 5) | (parity <<3) |
(stopbits << 2) | (wordlength);
Мы использовали операторы сдвига бита и поразрядного логического
сложения языка Си. Переменные baudrate, parity, stopbits и
wordlength должны быть кодированными значениями коммуникационных
параметров из последней колонки таблицы 8-2. Как только параметры
примут такой формат, Вы можете вызывать BIOS прерыванием 14h. Ис-
пользование функции int86 компилятора Microsoft С иллюстрируется
следующим фрагментом программы:
#include
#define BIOS_RS232 0x14
/* номер прерывания для обслуживания BIOS */
static union REGS xr, yr;
.
.
.
xr.h.ah = 0; /* номер функции для вызова BIOS RS-232 */
xr.h.al = pckd_commparams; /* связные параметры */
xr.x.dx = port_number; /* 0 означает COM1, 1 означает COM2 */
int86(BIOS_RS232, &xr, &yr); /* сделать вызов */
.
.
.
Компилятор Microsoft C версии 5.0 облегчает вызов подпрограмм
BIOS: функция _bios_serialcomm служит интерфейсом между Вашей Си
программой и прерыванием BIOS 14h. Например, если Вы выберете
8-битовую длину слова, 1 стоповый бит, отсутствие проверки на
четность и скорость передачи 300 бод, то достаточно вызвать
_bios_serialcom(_COM_INIT, COM1, (_COM_CHR8 | _COM_STOP1 |
_COM_NOPARITY | _COM_300) );
Вызов функции _bios_serialcom
status = _bios_serialcomm(service_code, port_number, data);
принимает три параметра, выраженных целым без знака и возвращает
код состояния того же типа данных для демонстрации результата
требуемой операции. Параметр service_code используется для опре-
деления требуемой операции и port_number принимает значение 0
(COM1) или 1 (COM2). Значение data зависит от требуемой услуги.
Подробности использования этой функции изложены в Microsoft C 5.0
- 8-17 -
Run-time Library Reference.
Получение адреса последовательного порта
Другим полезным встроенным свойством BIOS является то, что на
этапе самотестирования при включении (POST) она проверяет наличие
последовательных адаптеров COM1/COM2 (хотя MS-DOS 3.3 поддержива-
ет порты COM3 и COM4, BIOS распознает только COM1 и COM2) и, если
находит тот или другой, адрес первого регистра каждого адаптера
заносится в область памяти, начиная со смещения нуля сегмента
14h. Так как в персональном компьютере 20-битовый физический ад-
рес равен 10h * 16-битовый сегмент + 16-битовое смещение, и если
Ваша система MS-DOS имеет один последовательный порт, назначенный
как COM1, то тогда слово в физической ячейке 400h будет содержать
3F8h (если так же присутствует COM2, следующее слово в ячейке 402
h будет содержать 2F8h). Таким образом, Вы можете получить адрес
последовательного адаптера из этой области данных BIOS на смеще-
нии 0 и сегменте 40h. Например, в Microsoft C Вы можете устано-
вить базовый адрес порта следующим образом:
#define BIOS_DATA ((short far *)(0x400000L))
static short comport, /* для базового адреса порта */
port_number; /* 0 для COM1, 1 для COM2 */
.
.
.
comport = *(BIOS_DATA + port_number);
if(comport == 0) /* последовательный адаптер не установлен */
{
printf("Последовательный адаптер не установлен!\n";
exit(1);
}
Так как инициализируется переменная comport, все другие ре-
гистры последовательного адаптера могут быть доступны прибавлени-
ем соответствующих смещений к базовому адресу. В языке Си Вы мо-
жете использовать директиву препроцессора #define для установки
адресов этих регистров. Например, если инициализируется comport,
Вы имеете возможность обратиться к регистрам последовательного
порта по их именам, определив их следующим образом:
#define IER (comport + 1) /* регистр разрешения прерывания */
#define IIR (comport + 2) /* определение прерывания */
#define LCR (comport + 3) /* регистр управления линией */
#define MCR (comport + 4) /* регистр управления модемом */
#define LSR (comport + 5) /* регистр состояния линии */
#define MSR (comport + 6) /* регистр состояния модема */
Настройка на управляемый прерываниями последовательный
ввод/вывод
После получения базового адреса порта из области данных BIOS
Вы должны настроить последовательный порт и установить обработчик
прерываний перед началом управляемого прерываниями последователь-
ного ввода/вывода. Номер прерывания и IRQ прерывания последова-
- 8-18 -
тельного порта зависит от того, какой порт используется, COM1 или
COM2. Как только Вы получили номер прерывания, Вы должны получить
адрес текущего обработчика и сохранить его. Таким образом, после
выхода из программы Вы можете восстановить первоначальное значе-
ние вектора прерываний. Функции MS-DOS 35h и 25h, соответственно,
получают и устанавливают обработчики для заданных номеров преры-
ваний. Для этой цели Microsoft C предоставляет подпрограммы
_dos_getvect и _dos_setvect. Используя язык Си Вы можете проделать
это следующим образом:
short int_number; /* номер прерывания для связного порта */
void interrupt far s_inthndlr(void);
/* установить обработчик */
static void (interrupt far *old_handler)()
/* место для прежнего */
.
.
.
/* получить вектор прежнего прерывания и сохранить его */
old_handler = _dos_getvect(int_number);
/* установить новый обработчик с именем s_inthndlr
* запретить прерывания во время замены обработчика
*/
_disaple();
_dos_setvect(int_number, s_inthndlr);
_enable();
В приведенном примере мы представили обработчик как функцию
типа interrupt, которая является новым ключевым словом, содержа-
щимся в Microsoft C 5.0. В следующем разделе продемонстрировано,
каким образом атрибут interrupt позволяет Вам писать обработчик
прерываний непосредственно в Microsoft C 5.0 (Turbo C 1.5 имеет
такую же возможность).
Следует обратить внимание на использование функций _disable и
_enable. Эти две функции соответствуют ассемблерным командам STI
и CLI. Таким образом, мы выключаем прерывания во время перехода
от одного обработчика последовательных прерываний к другому. С
другой стороны, прерывание, поступающее во время переключения,
может привести к тому, что может произойти сбой центрального про-
цессора, так как вектор прерывания не являлся адресом какого-либо
действующего обработчика.
После того, как обработчик прерываний займет свое место, Вы
можете установить коммуникационные параметры и разрешить последо-
вательному порту генерировать прерывания. Вы также должны разре-
шить распознавание этих прерываний контроллером 8259A. Еще раз Вы
должны запретить прерывания до тех пор, пока порт и 8259A не бу-
дут готовы. Вот как мы можем проделать это с использованием
Microsoft C 5.0.
/* разрешает маску, зависящую от порта */
short intmask, int_enable_mask;
.
.
.
/* включает прерывания коммуникационного порта.
* устанавливает 8259A
*/
- 8-19 -
_disable();
/* устанавливает регистр управления модемом (порт = MCR) */
outp(MCR, MCRALL);
/* разрешает все прерывания последовательной платы
* (порт = IER)
*/
outp(IER, IERALL);
/* считывает регистр маски прерывания 8259A и записывает его
* обратно после логического умножения с _int_enable_mask
*/
intmask = inp(P8259_1) & int_enable_mask;
outp(P8259_1, intmask);
_enable();
С этой точки зрения последовательный порт начнет работать в
управляемом прерываниями режиме. Происходящие события зависят от
обработчика прерываний, который мы сейчас рассмотрим.
Обработка прерываний последовательного порта
Наш обработчик, s_inthndlr, будет вызван при генерации после-
довательным портом прерывания. Мы должны немедленно разрешить
прием системой последующих прерываний таким образом, чтобы другие
приоритетные задачи (такие как таймер) могли обрабатываться мик-
ропроцессором.
Следующий шаг - идентификация точной причины, вызвавшей гене-
рацию прерывания последовательного порта. Для получения информа-
ции Вы должны считать содержание регистра идентификации прерыва-
ния (IIR). Как только определится причина прерывания, можно
выполнять его обработку, как описывалось в разделе, посвященном
универсальному асинхронному приемопередатчику.
Так как последовательный порт способен генерировать прерыва-
ние в то время, пока Вы обрабатываете другое, необходимо прове-
рять бит 0 (последний значащий бит) IIR на это условие. Если этот
бит равен нулю, то имеется другое прерывание и его следует обра-
ботать. С другой стороны, если значение бита равно единице, оче-
редные прерывания отсутствуют. В этом случае Вы должны направить
контроллеру 8259A сигнал "конец прерывания" и выйти из обработчи-
ка. Таким образом, обработчик представляет собой бесконечный
цикл, который продолжает обрабатывать последовательные прерывания
до тех пор, пока не прекратится их поступление. В Microsoft C 5.0
обработчик может быть реализован как