Модемы и факс-модемы. Программирование для MS-DOS и Windows.© Александр Фролов, Григорий ФроловТом 16, М.: Диалог-МИФИ, 1993. 6.3. Использование прерываний COM-портаЕсли ваша коммуникационная программа будет использовать прерывания, можно организовать буфер принимаемых и передаваемых данных. Обработчик прерываний должен проанализировать причину прерывания и либо передать в COM-порт очередной символ из буфера передатчика (если прерывание произошло в результате передачи очередного символа), либо считать поступивший символ из регистра данных и записать его в буфер приемника (если прерывание произошло в результате приема от модема очередного символа). В этом случае процесс обмена идет в фоновом режиме и процессор может спокойно заниматься обработкой принимаемых и передаваемых символов. Если программе понадобится передать данные модему, она может просто записать их в буфер передатчика. Для приема данных она должна считать их из буфера приемника. При работе с асинхронным последовательным адаптером (COM-портом) вы можете использовать механизм прерываний. Глава "Программирование асинхронного адаптера" содержит теоретические сведения по этому вопросу, а в главе "Коммуникационная программа, использующая прерывания" содержится исходный текст коммуникационной программы, использующей прерывания для работы с COM-портом. Если ваша программа использует прерывания от COM-порта, она должна содержать обработчик прерываний, а также программировать контроллер прерываний для разрешения прерываний. Так как передача и прием данных модемом представляют собой длительный процесс, то применение прерываний от COM-порта позволяет использовать процессорное время для других нужд. 6.3.1. Обработка прерываний асинхронного адаптераПоследовательный асинхронный адаптер можно запрограммировать таким образом, что он будет вызывать соответствующее аппаратное прерывание. Прерывания могут вырабатываться асинхронным адаптером в следующих случаях: Вы можете отдельно запрещать или разрешать эти прерывания. Для этого необходимо установить соответствующие биты в регистре управления прерываниями. Как мы указывали ранее, каждому COM-порту соответствует, кроме базового адреса его регистров, линия IRQ (см. главы "Последовательный асинхронный адаптер" и "COM-порт и номера IRQ"):
Заметим, что в данной таблице представлен только один возможный вариант соответствия номеру COM-порта линии IRQ. Некоторые платы асинхронных адаптеров и некоторые внутренние модемы имеют перемычки для выбора номера COM-порта (адреса базового регистра) и номера линии IRQ. Что представляет из себя обработчик прерываний асинхронного адаптера? На рисунке 6.1 мы привели блок схему такого обработчика прерываний.
Рис. 6.1. Блок схема обработчика прерываний Теперь опишем алгоритм обработки прерываний от асинхронного последовательного адаптера. Этот алгоритм реализован в программе CHATINT, представленной ниже. Разрешить обработку прерыванийНеобходимо выполнить команду STI, для того чтобы разрешить обработку прерываний с более высоким приоритетом, чем прерывание от асинхронного адаптера. Определить причину прерыванияДля этого следует считать содержимое регистра идентификации прерывания. Состояние битов D1 D2 определяют причину прерывания:
В зависимости от того, какое произошло прерывание, его надо соответствующим образом обработать. Произошло прерывание по линии состоянияСчитать регистр состояния линии и уточнить причину прерывания (данное прерывание сбрасывается после чтения регистра состояния линии). Если это необходимо, подать основной программе сигнал о произошедшей ошибке с целью ее устранения. Например, в случае определения на линии сигнала BREAK (удаленный модем повесил трубку), надо попытаться возобновить связь. Прерывание по принятию данныхОчередной символ принят, и его можно считать через регистр данных. Прерывание сбрасывается после чтения регистра данных. Принятый байт необходимо записать в приемный буфер программы, из которого впоследствии его прочитает основная программа. Буфер приемника удобно организовать в виде очереди. Буфер передатчика пустПрерывание происходит в случае, если буфер передатчика пуст и можно передать COM-порту очередной символ. Можно организовать буфер передатчика программы, в который программа будет записывать данные, предназначенные для передачи через COM-порт. В этом случае, когда придет прерывание, надо считать очередной символ из буфера передатчика программы и записать его в регистр данных. Прерывание сбрасывается после записи очередного символа в регистр данных UART. Если нет данных для передачи (программный буфер передатчика пуст), можно запретить это прерывание через регистр управления прерываниями. Изменилось состояние модемаПрерывание происходит при изменении состояния входных линий CTS, RI, DCD, DSR. Состояние этих линий можно определить, считав регистр состояния модема. Это прерывание используется для обнаружения звонка на телефонной линии. Прерывание автоматически сбрасывается после чтения регистра состояния модема. Считать регистр идентификации прерыванияМожет случиться, что одновременно произойдет несколько прерываний. В этом случае бит D0 регистра идентификации прерываний равен единице. Тогда перед завершением обработки прерывания необходимо обработать следующее прерывание в соответствии с состоянием битов D1, D2. Так следует поступать до тех пор, пока не будут обработаны все прерывания (бит D0 не станет равен нулю). Обработать конец прерыванияПередать контроллеру прерываний команду обработки конца прерывания. Для этого в порт с адресом 20h посылается команда конца прерывания: mov al,20h out 20h,al Теперь можно закончить обработку прерывания, выполнив команду iret. 6.3.2. Последовательность работы программыИтак, мы завершили рассмотрение обработчика прерываний. Теперь нам осталось изучить примерный порядок работы коммуникационной программы с использованием прерываний. Установить обработчик прерыванийНеобходимо установить обработчик прерываний, изменив соответствующий элемент таблицы векторов прерываний. Адрес старого обработчика сохраняется в глобальных переменных. Выполнить инициализацию COM-портаСначала надо перевести в неактивное состояние линии DTR и RTS. Затем сбросить регистр состояния линии, регистр состояния модема и регистр данных. После того как мы сбросили регистры UART, можно приступить к инициализации COM-порта. Во время инициализации задается формат данных - длина слова, количество стоповых битов, наличие контроля по четности и скорость обмена. Последним шагом в инициализации регистров UART является установка регистра управления прерываниями. Например, чтобы разрешить генерацию прерываний при приеме очередного символа, надо записать значение 01h в регистр управления прерываниями: outp(port_adr+ICR, 1); // ICR - адрес регистра // управления прерываниями На этом этап инициализации регистров UART можно считать законченным. Теперь COM-порт подготовлен для обмена данными с модемом, но модем пока еще не будет воспринимать данные от компьютера. Чтобы перевести его в рабочее состояние, надо передать ему сигналы DTR и RTS. В ответ на эти сигналы модем должен вернуть компьютеру сигналы DSR и CTS. Выполнить инициализацию контроллера прерыванийДля того чтобы прерывания от асинхронного адаптера выполнялись, необходимо разрешить прерывание по соответствующей линии IRQ через регистр маски прерываний контроллера прерываний: // Считываем состояние регистра маски прерываний mov dx,21h in dx,al // Разрешаем прерывания от порта COM1 and al,11101111b // Записываем новое значение в регистр маски прерываний out dx,al Выполнить инициализацию модема и установить связь После установки обработчика прерываний и инициализации регистров COM-порта и контроллера прерываний можно передавать модему AT-команды и принимать от него ответ на них. При этом данные можно считывать (записывать) из COM-порта через буфер обработчика прерываний. Начать обмен данными с удаленным модемом Установив связь с удаленным модемом, оба модема переходят в режим обмена данными. Теперь можно начинать передавать и принимать данные. Передача и прием данных от удаленного модема осуществляются так же, как передача модему команд и прием от него сообщений. Завершить программу Для завершения коммуникационной программы, использующей прерывания, необходимо сбросить сигналы DTR и RTS и запретить через контроллер прерываний прерывания от COM-порта: // Считываем состояние регистра маски прерываний mov dx,21h in dx,al // Запрещаем прерывания от порта COM1 or al,00010000b // Записываем новое значение в регистр маски прерываний out dx,al Затем нужно восстановить старый вектор обработчика прерываний. |