|
|
|
|
Обработка прерываний последовательного порта
Наш обработчик, s_inthndlr, будет вызван при генерации последовательным портом прерывания. Мы должны немедленно разрешить
прием системой последующих прерываний таким образом, чтобы другие
приоритетные задачи (такие как таймер) могли обрабатываться микропроцессором.
Следующий шаг - идентификация точной причины, вызвавшей генерацию прерывания последовательного порта. Для получения информации Вы должны считать
содержание регистра идентификации прерывания (IIR). Как только определится причина прерывания, можно
выполнять его обработку, как описывалось в разделе, посвященном
универсальному асинхронному приемопередатчику.
Так как последовательный порт способен генерировать прерывание в то время, пока Вы обрабатываете другое, необходимо проверять бит 0
(последний значащий бит) IIR на это условие. Если этот
бит равен нулю, то имеется другое прерывание и его следует обработать. С другой стороны, если значение бита равно единице, очередные прерывания
отсутствуют. В этом случае Вы должны направить
контроллеру 8259A сигнал "конец прерывания" и выйти из обработчика. Таким образом, обработчик представляет собой бесконечный
цикл, который продолжает обрабатывать последовательные прерывания
до тех пор, пока не прекратится их поступление. В Microsoft C 5.0
обработчик может быть реализован как
void interrupt far s_inthndlr(void)
{
int c;
register int int_id, intmask;
/* прерывания разрешаются немедленно */
_enable();
while (TRUE)
{
/* чтение регистра идентификации прерываний, IIR */
int_id = inp(IIR);
if (bit0(int_id) == 1)
{
/* если бит 0 равен 1, тогда прерывания не поступают. послать
* сигнал конец прерывания программируемому контроллеру
* прерываний 8259A и затем вернуться.
*/
outp(P8259_0, END_OF_INT);
return;
}
/* если есть прерывание получения данных, разрешить прерывания
* для "свободен регистр хранения передачи"
*/
if (int_id) >= RXDATAREADY)
turnon_int(THEREINT,intmask);
/* обработать прерывание в соответствии с идентификатором.
* Следующий список составлен согласно возрастанию приоритета.
*/
switch (int_id)
{
case MDMSTATUS: /* состояние готовности модема */
.
.
.
break;
case TXREGEMPTY: /* послать символ */
.
.
.
break;
case RXDATAREADY: /* читать символ */
.
.
.
break;
case RLINESTATUS: /* читать состояние линии */
.
.
.
break;
/* пропустить, если идентификатор не является одним из
* перечисленных */
}
}
}
|
Обратите внимание, что мы воспользовались ключевым словом
interrupt,имеющемся в Microsoft C 5.0 и позволяющем писать обработчик на языке Си. Это ключевое слово используется как спецификатор функции,
которую Вы желаете установить в качестве обработчика прерываний определенного номера прерывания. При трансляции
функции с атрибутом interrupt компилятор генерирует код для первоначального помещения в стек регистров AX, CX, DX, BX, SP, BP,
SP, SI, DI, DS и ES. Затем он устанавливает регистр DS в режим
ссылки на сегмент данных указанной функции. После этой начальной
последовательности следует код функции. В заключении компилятор
использует команду IRET вместо обычной команды RET для выхода из
функции. Данный пример является типичным для использования атрибута interrupt. В компиляторе Turbo C также имеется это ключевое
слово, но помещение регистров в стек происходит в другом порядке.
Когда Вы пишете обработчик прерываний на языке Си, то необходимо соблюдать такие же предосторожности, как и при написании обработчиков на языке
ассемблера. Например, Вы не должны использовать какую-либо библиотечную подпрограмму, вызывающую функцию DOS
(доступ к ним осуществляется посредством команды прерывания 21h).
Такими функциями в языке Си являются подпрограммы ввода/вывода
файлов. С другой стороны, подпрограммы, находящиеся в категории
подпрограмм манипулирования строками, хранятся в функции
interrupt.
|
|