Программа 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));
}