Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЛР4. Таймер.doc
Скачиваний:
6
Добавлен:
12.11.2019
Размер:
129.02 Кб
Скачать

Использование таймера

Для таймера есть много применений, единственное ограничение здесь: таймер — это глобальный ресурс, и перепрограммировать его в многозадачных системах можно только с ведома операционной системы, если она вообще это позволяет.

Таймер можно использовать для управления динамиком, для точных измерений отрезков времени, для создания задержек, для управления переключением процессов и даже для выбора случайного числа с целью запуска генератора случайных чисел — текущее значение счетчика канала 0 представляет собой идеальный вариант такого начального числа для большинства приложений.

Управление динамиком

В связи с повсеместным распространением звуковых плат обычный динамик PC теперь практически не используется или используется для выдачи сообщений об ошибках. Поэтому программирование канала 2 системного таймера - относительно безопасная операция. Изменения же частот канала 0 может привести к сбою системных часов, а канала 1 – и вовсе к потере содержимого ОЗУ. Поэтому be careful, студент!

Канал 2 системного таймера управляет динамиком компьютера — он генерирует прямоугольные импульсы с частотой, равной 1 193 180/начальное_значение_счетчика. При программировании динамика начальное значение счетчика таймера принято называть делителем частоты — считается, что динамик работает с частотой, равной 1 193 180/делитель Гц. Диапазон слышимости человеческого уха составляет примерно от 20 Гц до 20 кГц. Следовательно, делитель должен быть в диапазоне примерно 60…60000 (3Ch…EA60h). Например, частота ноты «до» первой октавы составляет 261,6 Гц, следовательно, делитель для нее должен быть 1 193 180 / 261,6 = 4561 (11D1h).

Чтобы включить динамик, необходимо установить 2 младших бита порта 61h. Соответственно, чтобы выключить – нужно эти 2 бита сбросить. Например, следующий код будет играть ноту «до» пока не будет нажата какая-нибудь клавиша:

in al, 61h ; прочитать байт из порта 61h

or al, 03h ; установить два младших бита: XXXXXXXX or 00000011 = XXXXXX11

out 61h, al ; записать обратно в порт 61h (speaker on)

mov al, 0B6h ; команда установки режима канала 2 системного таймера

out 43h, al ; записать команду в порт 43h

mov al, 0D1h ; младший байт делителя

out 42h, al ; записать в порт 42h значение D1h

mov al, 11h ; старший байт делителя

out 42h, al ; записать в порт 42h значение 11h (значение счетчика = 11D1h)

mov ah, 0 ; функция 0 прерывания BIOS 16h ожидает нажатия любой клавиши

int 16h ; после выполнения AH=scan-код, AL=ASCII-код (или 0 для функциональных клавиш)

in al, 61h ; прочитать байт из порта 61h

and al, 0FCh ; сбросить 2 младших бита: XXXXXXXX and 11111100 = XXXXXX00

out 61h, al ; записать обратно в порт 61h (speaker off)

Задание:

Написать программу, которая при нажатии клавиши на клавиатуре играет в динамике звук любой высоты, соответствующей нажатой клавише (обработку функциональных клавиш можно исключить), например:

  1. Включает динамик.

  2. Ожидает нажатия клавиши (например, с помощью функции 0 прерывания int 16h).

  3. Если это клавиша ESC (scan-код 01h, ASCII-код 1Bh), то динамик выключается, программа завершает работу.

  4. Значение ASCII-кода умножается на коэффициент, чтобы результат попал в диапазон слышимости (коэффициент подобрать самостоятельно).

  5. Полученный результат (2 байта) записывается в канал 2 системного таймера в качестве делителя.

  6. Программа возвращается к п. 2.

Дополнительно (для умниц на хорошую оценку)

  1. Оформить код записи делителя в виде процедуры, которой значение делителя передается в качестве параметра.

  2. Оформить коды включения и выключения динамика в виде макросов.

  3. Снабдить программу адекватными комментариями.

Например, программа может выглядеть так:

.model tiny ; Программа типа COM

... ; Тут макросы SpeakerOn и SpeakerOff

SetFreq PROTO near pascal N:word ; прототип процедуры SetFreq (для директивы INVOKE)

.code

org 100h

Start: SpeakerOn ; Вызов макро включения динамика

WaitKey:

mov ah, 0 ; Вызов функции 0 (ждать нажатия клавиши)

int 16h ; прерывания BIOS int 16h

cmp ax, 011Bh ; Сравнить AX c кодом клавиши ESC

je Exit ; Если совпало - на выход

mul Coeff ; Иначе умножаем AL на коэффициент

INVOKE SetFreq, ax ; и вызываем функцию установки делителя, равного значению в AX

jmp WaitKey ; Повторяем процедуру

Exit: SpeakerOff ; Вызов макро выключения динамика

ret ; Всем пока!

Coeff db xx ; Коэффициент для делителя

... ; А тут сама процедура SetFreq

end Start