Программирование модемов© Александр Фролов, Григорий ФроловТом 4, М.: Диалог-МИФИ, 1993, 236 стр. 2.9. Стандартные функции библиотеки Си для работы с последовательным портомК сожалению, библиотеки трансляторов Microsoft Quick C 2.5 и C 6.0, а также трансляторов Borland C++ и Turbo C содержат всего одну функцию управления последовательным портом ввода/вывода. Трансляторы Microsoft Quick C 2.5 и C 6.0 содержат функцию _bios_serialcom(), а Borland C++ и Turbo C - функцию bioscom(). Функции _bios_serialcom() и bioscom() управляют асинхронным последовательным портом компьютера через прерывание BIOS INT 0x14. Вследствие этого функции _bios_serialcom() и bioscom() могут не успевать работать со скоростями больше чем 1200 бод (baud). Если вам нужны программы, обеспечивающие более высокие скорости, вам необходимо использовать непосредственное программирование контроллера асинхронного последовательного порта. Заметим, что функции _bios_serialcom() и bioscom() работают только на компьютерах, полностью совместимых с IBM PC/XT/AT. При использовании функций _bios_serialcom() и bioscom() необходимо включить директивой #include файл bios.h. Для трансляторов фирмы Borland этот файл включает объявление функции bioscom(), а для Microsoft кроме объявления функции _bios_serialcom() - также определения констант, которые можно использовать с этой функцией. Рассмотрим функцию _bios_serialcom(): unsigned _bios_serialcom( unsigned service, unsigned serial_port, unsigned data ); Первый аргумент функции - serial_port - определяет номер порта. Для COM1 этот аргумент должен быть равен 0, для COM2 - 1 и так далее. Второй аргумент - service - определяет производимое функцией действие и может содержать одну из следующих констант:
Назначение третьего аргумента функции - data -
зависит от значения аргумента service. Если агрумент
service установлен на _COM_RECEIVE или _COM_STATUS, то значение
аргумента data безразлично. Если агрумент service
установлен на _COM_INIT, то этот аргумент может
состоять из одного или нескольких констант,
объединенных булевой опрерацией ИЛИ (|). Данные
константы приведены в следующей таблице:
По умолчанию используется один стоповый бит, не выполняется проверка на четность, обмен происходит со скоростью 110 бод. Функция возвращает 16-битное целое число. В старшем байте возвращаемого значения содержатся биты, определяющие состояние последовательного порта. Содержимое младшего байта зависит от значения параметра service, с которым вызывалась функция. Назначение старшего байта представлено в
следующей таблице:
Когда аргумент service равен _COM_SEND, бит 15 устанавливается в единицу, если данные не могут быть переданы. Если аргумент service равен _COM_RECEIVE и чтение байта произошло успешно, он находится в младшем байте возвращаемого функцией значения. Если чтение произошло с ошибками, они конкретизируются битами 9, 10, 11 или 15. Если атрибут service равен _COM_INIT или _COM_STATUS, биты
младшего байта определяются следующим образом:
Приведем небольшой пример использования функции. В этом примере функция _bios_serialcom() сначала инициализирует последовательный порт, а затем передает символы, набранные на клавиатуре в порт, а символы, считанные из порта, - на экран компьютера. Для того чтобы введенные символы отображались на экране, надо соединить выход COM-порта со входом. Или использовать два компьютера, соединенных нуль-модемом. // QC_LIB.C // программа иллюстрирует доступ к последовательному порту // через функцию _bios_serialcom() #include <bios.h> // необходимо включить при // использовании _bios_serialcom() #include <stdio.h> #define COM1 0 // первый последовательный порт #define DATA_READY 0x100 // данные приняты и готовы для чтения int main(void) { unsigned in, out, status; // инициализируем последовательный порт // устанавливаем скорость 1200 бод, 8 битов на символ, один // стоповый бит _bios_serialcom(_COM_INIT, COM1, _COM_1200 | _COM_CHR8 | _COM_STOP1); printf("\n\n Для выхода нажмите клавишу [ESC]\n"); for(;;) { // определяем состояние последовательного порта status = _bios_serialcom(_COM_STATUS, COM1, 0); // если данные готовы, считываем их из // последовательного порта и выводим на экран дисплея if(status & DATA_READY) if((out = _bios_serialcom(_COM_RECEIVE, COM1, 0) & 0x7F) != 0) putch(out); // проверяем, не нажата ли клавиша на клавиатуре? if(kbhit()) { // если нажата клавиша [ESC] выходим из программы if((in = getch()) == 0x1b) break; // в противном случае передаем код нажатой клавиши // на асинхронный последовательный порт _bios_serialcom(_COM_SEND, COM1, in); } } return(0); } Теперь рассмотрим функцию bioscom() из библиотеки трансляторов Borland C++ и Turbo C: int bioscom(int service, char data, int serial_port); Эта функция аналогична функции _bios_serialcom(), трансляторов Microsoft Quick C 2.5 и C 6.0, за исключением следующих моментов:
Рассмотрим подробнее аргументы функции bioscom(). Первый аргумент функции - serial_port - определяет номер порта. Для COM1 этот аргумент должен быть равен 0, для COM2 - 1 и так далее. Назначение второго аргумента функции - data -
зависит от значения аргумента service. Если аргумент
service равен единице (_COM_RECEIVE) или тройке (_COM_STATUS), то
значение аргумента data безразлично. Если аргумент
service равен нулю (_COM_INIT), то этот аргумент может
состоять из одного или нескольких битовых полей
(констант), объединенных булевой операцией ИЛИ (|).
Данные константы приведены в следующей таблице:
По умолчанию используется один стоповый бит, не проводится проверка на четность, обмен происходит со скоростью 110 бод. Третий аргумент - service - может принимать следующие значения:
Так как _COM_xxx константы не определены, то для совместимости с трансляторами Microsoft и для удобства мы можем определить их самостоятельно: // BC_CONST.H // определение констант для Turbo C и Borland C++ #define _COM_INIT 0 #define _COM_SEND 1 #define _COM_RECEIVE 2 #define _COM_STATUS 3 #define _COM_CHR7 0x02 #define _COM_CHR8 0x03 #define _COM_STOP1 0x00 #define _COM_STOP2 0x04 #define _COM_NOPARITY 0x00 #define _COM_EVENPARITY 0x18 #define _COM_ODDPARITY 0x08 #define _COM_110 0x00 #define _COM_150 0x20 #define _COM_300 0x40 #define _COM_600 0x60 #define _COM_1200 0x80 #define _COM_2400 0xa0 #define _COM_4800 0xc0 #define _COM_9600 0xe0 Аналогично функции _bios_serialcom() функция bioscom() возвращает 16-битовое целое число. В старшем байте возвращаемого значения содержатся биты, определяющие состояние последовательного порта. Содержимое младшего байта зависит от значения параметра service, с которым вызывалась функция. Возможные значения для старшего байта
представлены в следующей таблице:
Когда аргумент service равен _COM_SEND, бит 15 устанавливается в единицу, если данные не могут быть переданы. Если аргумент service равен _COM_RECEIVE и чтение байта произошло успешно, принятый байт находится в младшем байте возвращаемого функцией значения. Если чтение произошло с ошибками, они конкретизируются битами 9, 10, 11, или 15. Если атрибут service равен _COM_INIT или _COM_STATUS, биты
младшего байта используются следующим образом:
Приведем небольшой пример использования функции bioscom(). Данная программа проверяет состояние линий DSR и CTS для асинхронных портов COM1..COM4. Если обе линии DSR и CTS находятся в активном состоянии, значит устройство, подключенное к данному порту готово к работе (активно). // BC_LIB.C // программа иллюстрирует доступ к последовательному порту // через функцию bioscom() #include <bios.h> //необходимо включить при использовании _bios_serialcom() #include <stdio.h> #include "bc_const.h" // определяем констаны _COM_xxx void main(void) { unsigned status, port; for( port = 0; port < 4; port++ ) { status = bioscom( _COM_STATUS, 0, port, ); // Проверяем состояние каждого последовательного порта // и определяем наличие присоединенных к нему устройств // типа модема. // Считаем, что если биты data-set-ready и clear-to-send // установлены в единицу, то внешнее устройство отвечает. printf( "COM%c состояние: %.4X\tАктивный: %s\n", (char)port + '1', status, (status & 0x0030) ? "Да" : "Нет" ); } } |