Главная · Поиск книг · Поступления книг · Top 40 · Форумы · Ссылки · Читатели

Настройка текста
Перенос строк


    Прохождения игр    
Demon's Souls |#13| Storm King
Demon's Souls |#11| Мaneater part 2
Demon's Souls |#10| Мaneater (part 1)
Demon's Souls |#9| Heart of surprises

Другие игры...


liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня
Rambler's Top100
Образование - Роберт Журден Весь текст 1069.56 Kb

Справочник программиста на IBM PC

Предыдущая страница Следующая страница
1 ... 7 8 9 10 11 12 13  14 15 16 17 18 19 20 ... 92
момента, когда счетчик времени суток был последний раз установлен
в 0. Обычно это число  секунд,  прошедших  со  времени последнего
включения  компьютера.   Если при старте системы  правильно  было
установлено системное время,  то  TIMER  возвращает число секунд,
прошедших с полуночи. Просто напишите N = TIMER.

   Средний уровень.

   Прерывание  1AH  имеет  две функции для установки (AH =  1)  и
получения (AH = 0) счетчика  времени  суток.  Для чтения счетчика
надо просто выполнить прерывание с AH = 0.  При возврате значение
счетчика содержится в CX:DX, причем младшее слово в CX. AL содер-
жит 0, если счетчик не переходил через границу 24 часов с момента
последней установки. Для установки счетчика поместите два слова в
те  же  регистры, а в AH - 1.  В приведенном  примере  измеряются
промежутки времени в  пределах  часа.  При  этом нужны только два
младших  байта счетчика.  Hо в этом случае необходимо  проверять,
что не было перехода через границу, когда начальное значение было
больше, чем следующее.
;---в сегменте данных
OLDCOUNT  DW   0     ;храним начальное значение счетчика
;---получаем начальное значение счетчика
          MOV  AH,0        ;номер функции
          INT  1AH         ;получаем значение счетчика
          MOV  OLDCOUNT,DX ;сохраняем начальное значение
           .
   (здесь идет процесс, длительность которого измеряется)
           .
;---позднее вычисляем длительность процесса
          MOV  AH,0        ;номер функции
          INT  1AH         ;получаем значение счетчика
          MOV  BX,OLDCOUNT ;считываем старое значение
          CMP  BX,DX       ;проверяем на переполнение
          JG   ADJUST      ;обработка переполнения
          SUB  DX,BX       ;иначе берем разность
          JMP  SHORT FIGURE_TIME  ;и переводим ее в обычный вид
;---обработка переполнения
ADJUST:   MOV  CX,0FFFFH   ;помещаем в CX максимальное число
          SUB  CX,BX       ;вычитаем первое значение
          ADD  CX,DX       ;добавляем второе значение
          MOV  DX,CX       ;результат храним в DX
;---процедура перевода времени в обычный формат
FIGURE_TIME:               ;делим на 18.2 секунды и т.д.
   2.1.7 Управление работой в реальном времени.

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

   Высокий уровень.

   Бейсик  обеспечивает  примитивный контроль  над  операциями  в
реальном времени посредством оператора  ON TIMER(n) GOSUB.  Kогда
программа встречает этот оператор, то она начинает отсчитывать  n
секунд.  Тем временем выполнение программы продолжается.  Kогда n
секунд  прошло, то программа переходит на подпрограмму,  начинаю-
щуюся с указанного номера  строки,  выполняет ее и возвращает уп-
равление  на  то место, откуда была вызвана подпрограмма.   После
этого отсчет снова начинается с нуля и подпрограмма будет вызвана
снова еще через n секунд.
   ON  TIMER не будет функционировать, до тех пор пока он не раз-
решен оператором TIMER ON. Оператор TIMER OFF запрещает его рабо-
ту.   В тех случаях, когда отсчет времени должен продолжаться, но
переход на подпрограмму должен  быть  задержан, надо использовать
оператор TIMER STOP. В этом случае отмечается, что n секунд прош-
ло, но переход на подпрограмму будет выполенен только после того,
как встретится оператор TIMER ON.
   Поскольку  он повторяется, оператор ON TIMER особенно  полезен
для вывода на экран текущего времени:

100 ON TIMER(60) GOSUB 500   'меняем показания часов каждые 60
110 TIMER ON                 'секунд и разрешаем работу таймера
 .
 .
500 LOCATE 1,35:PRINT "TIME: ";LEFT$(TIME$,5)  'позиционируем
510 RETURN                   'курсор и печатаем время
   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.8 Генерация случайных чисел с помощью микросхемы таймера.

   Для  генерации  последовательности случайных  чисел  требуются
сложные математические манипуляции. Hо иногда программе в опреде-
ленный момент требуется только одно случайное число.  В этом слу-
чае случайное число может быть получено  просто чтением из канала
микросхемы таймера.  Бейсик использует это число в качестве ядра,
по которому генерируется случайная  последовательность.  Kонечно,
Вы не можете использовать ряд последовательно  считанных значений
в  качестве  случайной последовательности, так как сами  по  себе
интервалы времени между считываниями будут неслучайными.

100 RANDOMIZE TIMER      'сброс генератора случайных чисел
110 PRINT RND,RND,RND    'печать трех случайных чисел

в результате получаем:  .7122483  .4695052  .9132487

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

   Поскольку регистр  счетчика   канала  таймера  перезагружается
снова  и  снова данным числом (а в промежутках идет счет вниз  до
0), выберите в качестве  загружаемого  в  счетчик значения число,
равное требуемому диапазону случайных чисел.  Hапример, для полу-
чения случайного значения часа дня загружайте в счетчик 23.
   Лучше всего использовать режим 3 канала 2 (порт 42H) микросхе-
мы  таймера  [2.1.1].  Сначала установите для  счетчика  желаемый
диапазон случайных чисел (в примере  используется 10000, что при-
водит к выдаче случайного числа в диапазоне от 0 до 9999). Затем,
чтобы получить из  канала  случайное  число,  надо подать команду
командному  регистру микросхемы таймера через порт 43H  перенести
текущее значение счетчика  в  регистр  "задвижки",  для чего надо
сбросить  биты 4 и 5.  Этот перенос в регистр задвижки не  мешает
продолжающемуся счету. Затем установите оба бита 4 и 5 командного
регистра, чтобы процессор мог читать из регистра задвижки.  После
этого две инструкции IN дадут  сначала  младший,  а затем старший
Предыдущая страница Следующая страница
1 ... 7 8 9 10 11 12 13  14 15 16 17 18 19 20 ... 92
Ваша оценка:
Комментарий:
  Подпись:
(Чтобы комментарии всегда подписывались Вашим именем, можете зарегистрироваться в Клубе читателей)
  Сайт:
 
Комментарии (1)

Реклама