Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C.doc
Скачиваний:
29
Добавлен:
08.05.2015
Размер:
1.17 Mб
Скачать

Использование стека

При вызове функции адрес возврата из функции и параметры заносятся в стек. При входе в программу обработки прерываний содержимое регистров общего назначения и адрес возврата также заносится в стек. Поэтому бывают случаи, например, при использовании рекурсии, что стандартного размера стека (4 Кбт) не хватает для выполнения данной программы. Для задания нового размера стека программы можно использовать глобальную переменную стека _stklen типа unsigned int. Например, для задания стека в 20000 Бт можно использовать конструкцию:

unsigned _stklen=20000;

main()

{

. . .

}

Организация прерываний в программе. Модификатор volatile

Прерывание программы происходит в случае, когда какое-либо событие требует немедленного вмешательства процессора.

Прерывания бывают программные и аппаратные. Программные прерывания вызываются в самой программе и служат, как правило, для вызова какой-либо функции операционной системы. Из С они задаются путем вызова соответствующих функций, поэтому здесь не рассматриваются. Аппаратные прерывания вызываются устройствами ПЭВМ. Например, при нажатии клавиши на клавиатуре текущая выполняемая программа прерывается и процессор переходит к выполнению программы обработки данного прерывания. При этом адрес программы находится в фиксированном месте, определяемом номером вектора прерывания (для клавиатуры фиксированный - 9 (линия IRQ1)). В стеке при этом запоминаются состояния ключевых регистров общего назначения процессора и адрес возврата (адрес команды, на которой прервалось выполнение текущей программы). После выполнения программы обработки прерывания по команде возврата из прерывания происходит восстановление значения ключевых регистров общего назначения процессора и переход на продолжение выполнения прерванной программы. Например, при обработке прерываний с клавиатуры принимается код клавиши и заносится в буфер клавиатуры по установленному адресу.

Функция обработки прерываний должна быть описана с модификатором interrupt. Ее тип - void, в качестве параметров можно тоже указать void. Обмен данными с остальными программами программа обработки прерываний может вести через глобальные объекты.

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

1. Запретить процессору обрабатывать аппаратные прерывания. Это нужно для того, чтобы не произошло прерывание в момент смены адреса программы его обработки. Сделать это можно, вызвав, например, функцию disable. Ее прототип

void disable(void);

2. Если надо, сохранить старое значение вектора прерывания для последующего восстановления с помощью функции getvect. Ее прототип

void interrupt (*getvect(номер вектора прерывания))(void);

3. Задать новое значение вектора прерывания с помощью функции setvect. Ее прототип

void setvect(номер вектора прерывания,void interrupt (*vect)(void));

где vect - имя программы обработки прерывания.

4. Разрешить аппаратные прерывания, вызвав функцию enable. Ее прототип

void enable(void);

Как только вызвано аппаратное прерывание, происходит выход в программу его обработки. При этом на IBM-совместимых компьютерах происходит блокировка всех остальных аппаратных прерываний. Это связано с аппаратной их реализацией. Для того, чтобы разрешить дальше обрабатывать аппаратные прерывания, необходимо сбросить контроллер прерываний, выдав код 20 по адресу регистра контроллера прерываний (устройств, подключенных к линиям IRQ0-7, например, клавиатуры и таймера, 20) (код и адрес шестнадцатиричные). Это можно сделать, вызвав функцию outp с параметрами 0x20, 0x20.

Прерывания от конкретных устройств можно как запретить, так и разрешить, задавая значения битов регистров маски контроллера прерываний. Например, для таймера (его вектор прерывания 8) путем задания значения младшего бита регистра по адресу 21 (шестнадцатиричный) можно разрешить или запретить (соответственно 0 или 1) прерывания от него. Эти регистры также можно читать, например, с помощью вызова функции inp.

Для устройств, подключенных к линиям прерываний IRQ8-15 шестнадцатиричные адреса контроллера прерываний и маски соответственно a0 и a1. При этом номера адресов векторов прерываний для этих линий начинаются с шестнадцатиричного адреса 70.

При компиляции программы С производит анализ, задается ли начальное значение переменной до момента ее использования и, если не задается, то выдает предупреждающее сообщение. Если же программа использует прерывания, то значение переменных может задаваться в программе обработки прерываний. В этом случае переменную можно описать с модификатором volatile. Тогда компилятор не будет проверять переменную на изменение и генерировать сообщение о возможном использовании до задания значения.

Пример: перехват прерываний клавиатуры (ее вектор 9), принимаем сканкоды, при нажатии Escape (сканкод 1) выдаем звуковой сигнал, при нажатии 1 (сканкод 2) - выход из программы.

#include <dos.h>

#include <stdio.h>

/* программа обработки прерываний */

void interrupt prcl(void)

{

extern int zero;

extern char ch;

/* считывание кода */

/* код - из порта с 16-тиричным адресом 60 */

ch=inp(0x60);

/* для сброса контроллера клавиатуры выдаем восьмеричные

коды 300 и 100 по 16-тиричному адресу 61 */

outp(0x61,0300);

outp(0x61,0100);

/* признак нажатой клавиши */

zero=1;

/* разрешение следующего прерывания */

outp(0x20,0x20);

return;

}

int zero;

char ch;

main()

{

void interrupt (*cl)(void);

void interrupt prcl(void);

zero=0;

/* считывание адреса вектора прерываний от клавиатуры */

cl=getvect(9);

/* присвоение нового значения вектора прерываний */

/* запрещение прерываний */

disable();

/* новое значение вектора ... */

setvect(9,prcl);

/* разрешение прерываний */

enable();

/* общий цикл ... */

for(;;)

{

/* ждем нажатия клавиши */

while (!zero) ;

zero=0; /* сбрасываем признак нажатия клавиши */

/* анализ знака ... */

/* если клавиша ESC */

if (ch==1)

{

/* звук частотой 1000 Гц в течение 500 мс */

sound(1000);

delay(500);

nosound();

}

/* если клавиша 1 */

if (ch==2) break;

}

/* запрещение прерываний */

disable();

/* восстановление старого вектора ... */

setvect(9,cl);

/* разрешение прерываний */

enable();

}

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]