Программирование игр для Windows. Советы профессионала

Вектор Номер Адресная функция


0х0В           0x002C-0x002F   RS-232 порт 1

0х0С           0х0030-0х0033    RS-232 порт 2

Все что нам нужно сделать для установки нового ISR, это использовать функцию Си _dos_getvect(), чтобы запомнить прежнее значение вектора, и _dos_setvect(), чтобы инсталлировать наш собственный ISR на место старого. Далее, с приходом прерывания (то есть когда получен символ), будет вызываться наша процедура. Звучит это великолепно, но что она будет делать?

Наш ISR должен выполнять только одну задачу — получить символ из регистра приемного буфера (RBR) и поместить его в программный буфер. Чтобы основная программа могла брать поступающие символы по мере надобности, мы должны буферизировать ввод. С этой мыслью создадим буфер с перезаписью и установим его размер равным 128 байтам, хотя, вообще-то, его длина может быть любой.                   

Алгоритм буферизации работает так. Полученный из RBR следующие символ помещается в буфер в текущую позицию. Далее текущий индекс буфера инкрементируется. Когда позиция записи в буфере доходит до конца, она перемещается к началу. Как вы понимаете, при этом данные, которые были записаны ранее, окажутся перекрыты. Надеюсь, что до того, как это произойдет основная программа успеет прочитать символы из буфера и обработать полученные данные. Рисунок 14.3 поясняет принцип работы буфера с перезаписью.

Мы должны обсудить еще одну тонкость, прежде чем закончим разговор об ISR. Непосредственно перед выходом из процедуры обработки прерывания необходимо сообщить PIC'y о ее завершении. Для этого в конец процедуры нужно вставить команду записи в порт 20h значения 20h. Если этого не сделать, произойдет сбой системы. Но это — между прочим, ибо пока вы используете функции Си, об этом не стоит беспокоиться. Вот если бы вы решили писать программы исключительно на ассемблере, то вопрос правильного завершения прерываний оказался бы весьма актуален и мы обсудили бы его более подробно. Но давайте пока остановимся на Си.

Листинг 14.1 показывает операции с ISR.






Листинг 14.1. Операция ISR.

void _interrupt _far Serial_Isr(void)

{



// Это процедура обработки прерывания СОМ-порта. Она очень проста.

// При вызове она читает полученный символ из регистра 0 порта

//и помещает его в буфер программы. Примечание: язык Си сам

// заботится о сохранении регистров и восстановлении состояния

// запрещаем работу всех других функций

//во избежание изменения буфера

serial_lock = 1;

// записываем символ в следующую позицию буфера

ser_ch = _inp(open_port + SER_RBF);

// устанавливаем новую текущую позицию буфера

if (++ser_end > SERIAL_BUFF_SIZE-1) ser_end = 0;

// помещаем символ в буфер

ser_buffer[ser_end] = ser_ch;

++char_ready;

/ / восстанавливаем состояние контроллера прерываний

_outp(PIC_ICR,0x20);

// разрешаем работу с буфером

serial_lock = 0;

} // конец функции

Программа из Листинга 14.1 выполняет все то, о чем мы говорили. Однако стоит обратить внимание на одну маленькую деталь. В программу включена переменная serial_lock, которая оберегает основную программу от конфликт тов связанных с обращением к буферу, пока ISR обновляет его. Такой прием называется «блокировкой» или «семафором». В DOS'e подобной проблемы никогда не возникает по ряду причин, о которых говорить слишком долго. Необходимость регулирования доступа к общим данным возникает только для полностью многозадачных систем. Тем не менее, введение «семафоров» - хорошая практика, даже если на данном этапе такая техника и не нужна. Все, мы почти у цели!


Содержание раздела