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

Модемы и факс-модемы. Программирование для MS-DOS и Windows.

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

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

5.5. Первая телекоммуникационная программа

Теперь мы приведем первую телекоммуникационную программу AUX_TEST, управляющую асинхронным последовательным адаптером на уровне регистров. Программа инициализирует регистры COM-порта, устанавливая новую скорость передачи информации и формат передаваемых данных. Затем программа в цикле передает коды клавиш, нажатых на клавиатуре в COM-порт и считывает из него принятые данные, отображая их на экране.

Программа работает с асинхронным адаптером COM1. Для правильной работы необходимо замкнуть вместе контакты 2 и 3 разъема COM1. В этом случае данные передаваемые в COM-порт сразу же принимаются им обратно.

Главный файл программы AUX_TEST представлен в листинге 5.2.

Листинг 5.2. Файл AUX_TEST.C

#include 
#include 
#include "sysp_com.h"

void main(void);
void 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);

	printf("\n\nТестирование асинхронного адаптера."
			 "\nНажимайте клавиши!"
			 "\nДля завершения работы нажмите CTRL-C"
			 "\n");

	for(;;) {

		// Вводим символ с клавиатуры и передаем его
		// в асинхронный адаптер
		aux_outp(getch(), 0);

		// Вводим символ из асинхронного адаптера и
		// отображаем его на экране

		putchar(aux_inp(0));
	}
}

После запуска программы AUX_TEST вызывается функция aux_stat, определенная в нашем приложении. Она заполняет структуру amd типа AUX_MODE, записывая в нее информацию о текущем режиме COM-порта.

Информация, записанная в этой структуре, отображается на экране. Изменяем поле baud структуры amd, содержащее значение скорости передачи данных, записывая в нее число 115200. Затем функция aux_init, определенная в программе, увеличивает скорость передачи информации до 115200 бит/с.

Затем начинает выполняться бесконечный цикл, в котором вводится символ с клавиатуры и передается в COM-порт:

aux_outp(getch(), 0);

Сразу после передачи кода нажатой клавиши в COM-порт, вводим символ из этого же порта и отображаем его на экране:

putchar(aux_inp(0));

Чтобы завершить работу программы, достаточно нажать комбинацию клавиш .

Включаемый файл SYSP.H, представленный в листинге 5.3, содержит описания функций aux_stat, aux_init, aux_inp, aux_outp и определение структуры AUX_MODE.

Листинг 5.3. Файл SYSP.H

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);

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;

Теперь перейдем к рассмотрению функций aux_stat, aux_init, aux_inp и aux_outp, определенных в программе AUX_TEST.

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

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

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

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

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

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

Для того чтобы узнать текущее состояние асинхронного адаптера, вы можете использовать функцию aux_stat, представленную в листинге 5.4.

Листинг 5.4. Файл AUX_STAT.C

/**
*.Name         aux_stat
*
*.Descr        Функция считывает текущий режим
*              асинхронного порта и записывает его
*              в структуру с типом AUX_MODE.
*
*.Proto        void aux_stat(AUX_MODE *mode, int port);
*
*.Params       AUX_MODE mode - структура, описывающая
*              протокол и режим работы порта
*
*              int port - номер асинхронного адаптера:
*                 0 - COM1, 1 - COM2
*
*.Return       Ничего
**/

#include 
#include 
#include "sysp_com.h"

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);
}

Прочитав состояние адаптера, вы можете изменить нужные вам поля в структуре AUX_MODE и вызвать функцию aux_init для изменения текущего режима COM-порта. Исходный текст этой функции можно найти в листинге 5.5.

Листинг 5.5. Файл AUX_INIT.C

/**
*.Name         aux_init
*
*.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 - ошибки в параметрах инициализации.
*
*.Sample       aux_test.c
**/

#include 
#include 
#include "sysp_com.h"

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);
}

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

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

Признаком того, что регистр передатчика свободен, является установленный в 1 бит 5 регистра состояния линии с адресом base_adr + 5. Функция aux_outp (см. листинг 5.6) ждет окончания передачи текущего символа, затем посылает в асинхронный адаптер следующий символ.

Листинг 5.6. Файл AUX_OUTP.C

/**
*.Name         aux_outp
*
*.Descr        Функция дожидается готовности
*              передатчика и посылает символ.
*
*.Proto        void aux_outp(char chr, int port);
*
*.Params       char chr - посылаемый символ;
*
*              int port - номер асинхронного адаптера:
*                 0 - COM1, 1 - COM2
*
*.Return       Ничего
***/

#include 
#include 
#include "sysp_com.h"

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);
}

Аналогично передаче данных перед вводом символа из регистра данных (адрес base_adr) необходимо убедиться в том, что бит 0 регистра состояния линии (адрес base_adr + 5) установлен в 1. Это означает, что символ принят из линии и находится в буферном регистре приемника.

Для приема данных мы используем функцию aux_inp (см. листинг. 5.7).

Листинг 5.7. Файл AUX_INP.C

/**
*.Name         aux_inp
*
*.Descr        Функция дожидается готовности
*              приемника и вводит символ из асинхронного
*              адаптера.
*
*.Proto        char aux_inp(int port);
*
*.Params       int port - номер асинхронного адаптера:
*                 0 - COM1, 1 - COM2
*
*.Return       Принятый символ
*
*.Sample       aux_test.c
**/

#include 
#include 
#include "sysp_com.h"

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));
}
[Назад] [Содеожание] [Дальше]