
- •Программирование прерываний Механизм прерываний
- •Void (* interrupt_table[256])();
- •Вызов прерываний из программ
- •Int intdos (union regs *inregs,
- •Int intdosx (union regs *inregs,
- •Архітектура центрального процесора
- •Intel8086/88
- •01.12Регістри загального призначення
- •Регістр ознак стану процесора (регістр флагів)
- •Int SetSvgaMode (int iVMode)
- •Int86 (0x10, &inregs, &outregs);
- •Int 10h ; прерывание для работы с ; видеосистемой.
- •Изменение таблицы векторов прерываний
- •Void interrupt far int_funct(void)
- •Void (_interrupt _far *oldvect)(void);
- •Void _interrupt _far timer(void)
Void interrupt far int_funct(void)
{
// Обработчик прерывания
}
Функция обработки прерывания должна быть FAR-функцией, т.к. таблица векторов прерываний содержит полные адреса в виде сегмент:смещение.
Ключевое слово _interrupt используется также для описания переменных, предназначенных для хранения векторов прерываний:
Void (_interrupt _far *oldvect)(void);
Модификаторы _interrupt и _far для Quick C 2.5 и C 6.0 являются синонимами соответственно interrupt и far.
Какие требования предъявляются к программе обработки прерывания?
Если прерывания происходят часто, то их обработка может сильно замедлить работу прикладной программы. Поэтому обработчик прерывания должен быть короткой, быстро работающей программой, которая выполняет только самые необходимые действия. Например, считать очередной символ из порта принтера и поместить его в буфер, увеличить значение какого-либо глобального счетчика прерываний и т.п.
Для установки своего обработчика прерываний используется функция _dos_setvect. Эта функция имеет два параметра - номер прерывания и указатель на новую функцию обработки прерывания. Например:
_dos_setvect(0x16, my_key_intr);
В этом примере для клавиатурного прерывания с номером 16h устанавливается новый обработчик прерывания my_key_intr.
Если надо узнать адрес старого обработчика прерывания по его номеру, следует воспользоваться функцией _dos_getvect, которая принимает в качесте параметра номер прерывания и возвращает указатель на соответствующий этому номеру в таблице векторов прерываний обработчик. Например:
old_vector = _dos_getvect(0x16);
Для организации цепочки прерываний используйте функцию _chain_intr. В качестве параметра эта функция принимает адрес старого обработчика прерываний.
Следующий пример иллюстрирует применение всех трех функций, предназначенных для работы с прерываниями. Эта программа встраивает собственный обработчик прерывания таймера, который будет вызываться примерно 18,2 раза в секунду. Встраиваемый обработчик прерывания считает тики таймера, и если значение счетчика кратно 20, на динамик компьютера выдается звуковой сигнал. В конце работы новая программа обработки прерывания таймера вызывает старый обработчик с помощью функции _chain_intr.
После установки нового обработчика прерывания таймера основная программа ждет нажатия на клавиатуре любой клавиши, затем она восстанавливает старое содержимое вектора прерывания.
#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
// Выключаем проверку стека и
// указателей
#pragma check_stack( off )
#pragma check_pointer( off )
// Этот макрос используется для
// выдачи сигнала на внутренний
// динамик компьютера.
// Используется вывод
// в формате TTY символа BELL (7)
// через прерывание BIOS 10h
#define BEEP() _asm { \
mov bx,0 \
mov ax, 0E07h \
int 10h \
}
void main(void);
// Объявление программы обработки
// прерывания:
void _interrupt _far timer(void);
// Переменная предназначена для
//хранения старого значения
// вектора прерывания таймера;
//она должна быть глобальной:
void(_interrupt_far *oldvect)(void);
// Переменная для подсчета тиков
// таймера:
volatile long ticks;
void main(void)
{
ticks=0L;//Сбрасываем счетчик тиков
// таймера.
// Запоминаем адрес старого
//обработчика прерывания:
oldvect = _dos_getvect(0x1c);
// Устанавливаем свой обработчик:
_dos_setvect(0x1c, timer);
printf("\nТаймер установлен."
"Нажмите любую клавишу...\n");
getch(); //(Ожидание нажатия на
//любую клавишу).
// Восстанавливаем старый обработчик
// прерывания таймера:
_dos_setvect(0x1c,oldvect);
exit(0);
}
// Функция обрабатывает прерывания
// таймера: