# Лабораторная работа № 15.

Тема: Работа со звуковой картой и внешними устройствами через аудиоинтерфейсы.

Цель работы: Научить студентов работать со звуком на программном уровне.

Генерация звука с помощью адаптера интерфейса с периферией 8255 состоит во включении и выключении с желаемой частотой бита порта B, который связан с динамиком (бит 1). Порт B имеет адрес 61H (хотя AT не имеет микросхемы интерфейса с периферией 8255 как таковой, он использует для этой цели тот же адрес порта и тот же бит). Если программа переключает значение бита с максимально возможной частотой, то частота слишком высокая, чтобы быть полез- ной. Поэтому между двумя переключениями надо вставлять пустой цикл. Помните, что бит 0 порта B управляет воротами канала 2 микросхемы таймера, который в свою очередь связан с динамиком. Поэтому этот бит должен быть сброшен, отсоединяясь от канала таймера.

В следующем примере введены две переменные. Одна, обозначенная "FREQUENCY", используется в качестве счетчика в пустом цикле между действиями включения и выключения. Чем меньше ее значение, тем быстрее происходит изменение бита и тем больше частота. Переменная же "NUMBER_CYCLES" устанавливает продолжительность тона. Она говорит сколько раз должен быть повторен процесс включения и выключения. Чем больше это число, тем дольше звучит данный звук.

Отметим, что для этой процедуры аппаратные прерывания должны быть запрещены. Причина этого в том, что прерывание таймера происходит с такой частотой и регулярностью (18.2 раза в секунду), что оно будет существенно влиять на частоту. Имейте ввиду, что пока прерывания запрещены, счетчик времени суток BIOS не будет работать. Если затем прочитать его значение, то оно будет отличаться на некоторую величину от реального, до тех пор, пока не будет сделано соответствующее изменение.

Пример.

NUMBER_CYCLES EQU 1000

FREQUENCY EQU 300

PORT_B EQU 61H

CLI ;запрет прерываний

MOV DX,NUMBER_CYCLES ;длительность тона в DX

IN AL,PORT_B ;получаем значение из порта B

AND AL,11111110B ;отключаем динамик от таймера

NEXT_CYCLE: OR AL,00000010B ; включаем динамик

OUT PORT_B,AL ;посылаем команду в порт B

MOV CX,FREQUENCY ;задержка на пол-цикла в CX

FIRST_HALF: LOOP FIRST_HALF ; делаем задержку

AND AL,11111101B ;выключаем динамик

OUT PORT_B,AL ;посылаем команду в порт B

MOV CX,FREQUENCY ;задержка на пол-цикла в CX SECOND_HALF: LOOP SECOND_HALF ;делаем задержку

DEC DX ;вычитаем единицу из счетчика

JNZ NEXT_CYCLE ;если 0, то надо кончать

STI ;разрешаем прерывания

Генерация звука одновременно с другими действиями.

Просто пошлите счетчик в канал 2, как объяснено в. Микросхема должна быть предварительно разрешена через порт B микросхемы интерфейса с периферией 8255 (адрес 61H). Вычислите требуемое значение счетчика для задвижки, разделив 1.19 миллионов на требуемую частоту в герцах. Звук будет продолжаться до тех пор, пока не будут закрыты ворота канала 2. Поэтому Вы должны сбросить бит 1 порта B в 0, иначе звук будет продолжаться беско- нечно и может быть прекращен только перезагрузкой компьютера. Для точного регулирования длительности звука можно использовать счет- чик времени суток BIOS. В данном примере генерируется частота 440 герц. Звук прекращается после нажатия любой клавиши на клавиатуре.

;---рарешение канала 2 установкой порта B микросхемы 8255

PORT_B EQU 61H ;установка адреса порта B

IN AL,PORT_B ;чтение его значения

OR AL,3 ;установка двух младших битов

OUT PORT_B,AL ;посылаем байт в порт B ;---установка регистров ввода/вывода

COMMAND_REG EQU 43H ;адрес командного регистра

CHANNEL_2 EQU 42H ;адрес канала 2

MOV AL,10110110B ;цепочка битов для канала 2

OUT COMMAND_REG,AL ;засылка в командный регистр ;---засылка счетчика в задвижку

MOV AX,2705 ;счетчик = 1190000/440

OUT CHANNEL_2,AL ;посылаем младший байт

MOV AL,AH ;сдвигаем младший байт в AL

OUT CHANNEL_2,AL ;посылаем старший байт ;---ждем нажатия клавиши

MOV AH,1 ;номер функции прерывания 21H

INT 21H ;вызываем прерывание ;---выключение звука

IN AL,PORT_B ;получаем байт из порта B

AND AL,11111100B ;сбрасываем два младших бита

OUT PORT_B,AL ;посылаем байт обратно

Гудок динамика

Для простого гудка лучше всего подходит метод, основанный на использовании микросхемы интерфейса с периферией 8255. Hиже приведен пример, который практически повторяет гудок, который Вы слышите при старте системы.

;---гудок динамика

MOV DX,800 ;счетчик числа циклов

IN AL,61H ;читаем порт B 8255

AND AL,0FEH ;выключаем бит таймера 8253

NEXTCYCLE: OR AL,2 ;включаем бит динамика

OUT 61H,AL ;посылаем байт в порт B

MOV CX,150 ;длительность первой половины

CYCLEUP: LOOP CYCLEUP ;задержка пока сигнал высокий

AND AL,0FDH ;выключаем бит динамика

OUT 61H,AL ;посылаем байт в порт B

CYCLEDOWN: LOOP CYCLEDOWN ;задержка пока сигнал низкий

DEC DX ;уменьшаем счетчик циклов

JNZ NEXTCYCLE ;повторяем цикл пока DX не 0

Генерация набора тонов.

В примере для генерации звука используется микросхема таймера 8253. Здесь просто исполняются 8 нот, но небольшая модификация может сильно расширить возможности этой процедуры. Имеется три строки данных. Первая устанавливает длительность каждой ноты, как кратное произвольного периода задержки (изменяя этот период задержки, можно изменять темп). Вторая строка содержит частоты каждой из 8 нот; эти значения должны быть помещены в регистр задвижки канала 2 микросхемы 8253 для исполнения желаемых тонов. Третья строка содержит мелодию в виде кодовых номеров от 1 до 8, которые соответствуют восьми частотам. Эта строка завершается кодом 0FFH, который служит признаком конца мелодии. Процедура просто читает очередную ноту мелодии, находит соответствующую частоту и помещает ее в канал 2. Затем длительность для этой ноты помещается в счетчик цикла задержки, который использует счетчик времени суток, а когда задержка кончается, то переходим к обработке следующей ноты.

Пример

;---в сегменте данных

BEAT DB 10,9,8,7,6,5,4,3,2 ;длительность нот

FREQUENCY DW 2280,2031,1809,1709 ;таблица частот

DW 1521,1353,1207,1139 ;

MELODY DB 1,2,3,4,5,6,7,8,0FFH ;номер частоты ноты

;---инициализация

PORT_B EQU 61H

COMMAND_REG EQU 43H

LATCH2 EQU 42H

IN AL,PORT_B ; получаем текущий статус

OR AL,00000011B ; разрешаем динамик и таймер

OUT PORT_B,AL ; заменяем байт

MOV SI,0 ;инициализируем указатель

MOV AL,0B6H ;установка для канала 2

OUT COMMAND_REG,AL ;посылаем в командный регистр ;---смотрим ноту, получаем ее частоту и помещаем в канал 2

NEXT_NOTE: LEA BX,MELODY ;берем смещение для мелодии

MOV AL,[BX][SI] ;берем код n-ной ноты строки

CMP AL,0FFH ;проверка на конец строки

JE NO_MORE ;если конец, то на выход

CBW ;переводим в слово

;получение частоты

MOV BX,OFFSET FREQUENCY ;смещение таблицы частот

DEC AX ;начинаем отсчет с 0

SHL AX,1 ;умножаем на 2, т.к. слова

MOV DI,AX ;адресуем через DI

MOV DX,[BX][DI] ;получаем частоту из таблицы

;начинаем исполнение ноты

MOV AL,DL ;готовим младший байт частоты

OUT LATCH2,AL ;посылаем его

MOV AL,DH ;готовим старший байт частоты

OUT LATCH2,AL ;посылаем его ;---создание цикла задержки

MOV AH,0 ;номер функции чтения счетчика

INT 1AH ;получаем значение счетчика

MOV BX,OFFSET BEAT ;смещение таблицы длин

MOV CL,[BX][SI] ;берем длину очередной ноты

MOV CH,0 ;

MOV BX,DX ;берем младшее слово счетчика

ADD BX,CX ;определяем момент окончания

STILL_SOUND: INT 1AH ;берем значение счетчика

CMP DX,BX ;сравниваем с окончанием

JNE STILL_SOUND ;неравны - продолжаем звук

INC SI ;переходим к следующей ноте

JMP NEXT_NOTE ; ;---завершение

NO_MORE: IN AL,PORT_B ; получаем статус порта B

AND AL,0FCH ; выключаем динамик

OUT 61H,AL ; заменяем байт

Задания:

1. Напишите программу, которая создает звук с помощью динамика длительностью 2 секунды.

2. Напишите программу, которая создает гудок динамика.

3. Напишите программу, которая имитирует звук сирены.

4. Напишите программу, которая создает мелодию типа «Бумер»

Литература: 10, стр.54-62; 23, стр.85-92; 8, стр.23-32.

Контрольные вопросы

1. Как происходит генерация звука одновременно с другими действиями?

2. Как выполнить гудок динамика?

3. Какая микросхема отвечает за динамик?