Глава 2. Таймеры и звук.

Раздел 1. Установка и чтение таймера.

2.1.7 Управление работой в реальном времени.

При операциях в реальном времени программа выполняет инструкции в указанный момент времени, а не при первой возможности. Такого рода операции обычно ассоциируются с роботехникой, но имеется множество других приложений. Имеется выбор подхода к операциям в реальном времени. Для программ, которые не должны ничего делать в промежутке между инструкциями, требующими временной привязки, можно просто периодически проверять счетчик времени суток, ожидая наступления нужного момента. Такой подход практически сводится к набору пустых циклов, описанных в {2.1.5}.

Второй подход более сложен. Он используется, когда программа постоянно занята какой-либо работой, но она должна в определенные моменты времени прерывать свои операции для выполнения определенной задачи. В этом случае расширяют прерывание таймера, которое выполняется 18.2 раза в секунду. Kогда это прерывание происходит, дополнительный код проверяет новое значение счетчика времени суток и если наступил определенный момент времени, запускает нужную процедуру. Этот процесс показан на рис. 2-3. Приведенные здесь простые примеры показывают, как создать в своей программе будильник, который устанавливается пользователем и подает звуковой сигнал, когда подошло время. (Более сложный пример низкого уровня в {2.2.6} исполняет музыку, в то время когда процессор занят другими делами.)

Hизкий уровень.

BIOS содержит специальное пустое прерывание (1CH), которое ничего не делает, пока Вы не напишите для него процедуру. При старте вектор этого прерывания указывает на инструкцию IRET (возврат из прерывания); при его вызове происходит моментальный возврат. Hо прерывание 1CH интересно тем, что оно вызывается прерыванием таймера BIOS после того, как это прерывание обновило значение счетчика времени суток. Можно сказать, что это аппаратное прерывание, происходящее автоматически 18.2 раза в секунду. Вы можете изменить вектор этого прерывания так, чтобы он указывал на процедуру в Вашей программе. После этого Ваша процедура будет вызываться 18.2 раза в секунду. О том как написать и установить свою процедуру обработки прерывания см. в {1.2.3}.

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

В приведенном примере процедура (не показанная здесь) запрашивает у пользователя число минут (до 60), которое должно пройти до того, как раздастся звонок будильника. Это число, запасенное в MINUTES, умножается на 1092 для перевода в эквивалентное число импульсов счетчика времени суток. Для периода в пределах одного часа достаточно 16 бит - более длинные периоды требуют более сложных 32-битовых операций. Это число импульсов добавляется к младшему слову текущего значения счетчика времени суток и запоминается в ALARMCOUNT.

Затем вектор прерывания 1CH изменяется таким образом, чтобы он указывал на процедуру ALARM. Помните, что как только вектор будет изменен, ALARM будет автоматически вызываться 18.2 раза в секунду. При вызове эта процедура читает текущее значение счетчика времени суток через прерывание 1AH и сравнивает с ALARMCOUNT. При совпадении этих величин вызывается процедура BEEP (также не показанная здесь - см. {2.2.4}), которая выдает звуковой сигнал. В противном случае происходит возврат. Обычный код возврата из аппаратных прерываний (MOV AH,20H / OUT 20H,AL) включать в процедуру не нужно, так как он будет в прерывании таймера. Будьте внимательны и не забудьте сохранить изменяемые регистры.
;---в сегменте данных
MINUTES DW 0 ;хранит число минут до звонка
ALARMCOUNT DW 0 ;хранит счетчик времени для звонка
;---установка ожидаемого значения счетчика времени суток
CALL REQUEST_MINUTES ;запрос числа минут до звонка
MOV AX,MINUTES ;пересылка в AX
MOV BX,1092 ;число импульсов счетчика в минуте
MUL BX ;умножаем - результат в AX
;получаем текущее значение счетчика
MOV AH,0 ;номер функции чтения счетчика
INT 1AH ;читаем значение, младший байт в DX
;складываем оба значения
ADD AX,DX ;
MOV ALARMCOUNT,AX ;получаем нужное значение счетчика
;---заменяем вектор пустого прерывания
PUSH DS ;сохраняем сегмент данных
MOV AX,SEG ALARM ;берем сегмент процедуры ALARM
MOV DS,AX ;помещаем его в DS
MOV DX,OFFSET ALARM ;берем смещение процедуры
MOV AL,1CH ;номер изменяемого вектора
MOV AH,25H ;функция изменения вектора
INT 21H ;меняем вектор
POP DS ;восстанавливаем сегмент данных
;
;---дальше продолжается программа
;
;---в конце программы возвращаем вектор прерывания
MOV DX,0FF53H ;оригинальные значения для
MOV AX,0F000H ;прерывания 1CH
MOV DS,AX ;помещаем сегмент в DS
MOV AL,1CH ;номер изменяемого вектора
MOV AH,25H ;номер функции
INT 21H ;восстанавливаем вектор
;---процедура выдачи звукового сигнала
ALARM PROC FAR ;создаем длинную процедуру
PUSH AX ;сохраняем изменяемые регистры
PUSH CX ;
PUSH DX ;
;---читаем счетчик времени суток
MOV AH,0 ;номер функции чтения счетчика
INT 1AH ;читаем значение счетчика
;---сравниваем с требуемым значением
MOV CX,ALARMCOUNT ;берем требуемое значение
CMP DX,CX ;сравниваем с текущим
JNE NOT_YET ;если неравны, то на выход
;---выдаем звуковой сигнал, если значения совпали
CALL BEEP ;эта процедура не показана
;---иначе возвращаемся из прерывания
NOT_YET: POP DX ;восстанавливаем регистры
POP CX ;
POP AX ;
IRET ;возврат из прерывания
ALARM ENDP ;конец процедуры


<~-2.1.6 Операции запрограммированные во времени.
Содержание
Раздел 2. Создание звука.-~>

Сайт управляется системой uCoz