в) Использование команды JMP dword ptr
Assume CS: Code;, DS: Code Code SEGMENT org 100h Start: jmp start1 len equ dend-dal ; Длина пересылаемой процедуры s_dal equ 8800h ; Сегмент места пересылки процедуры addr dw 0,s_dal ; Дальний адрес места назначения start1: cld mov ax,cs mov ds,ax ; DS = CS ; Перенос процедуры DAL в область 8800h les di,dword ptr addr ; ES:DI = s_dal:0000 lea si,dal ; SI = offset DAL mov cx,len ; CX = длине пересылаемой проц. rep stosb ; DS:SI Þ ES:DI ; Стирание процедуры в тексте mov ax,cs mov es,ax ; ES = CS lea di,dal ; DI = offset DAL mov cx,len ; CX = длине пересылаемой проц. xor ax,ax ; АХ=0 для стирания процедуры rep movsb ; AX(0) Þ ES:DI ; Вычисление значения DS для дальней процедуры push ds ; DS Þ ctack lea ax,dal ; offset DAL xor dx,dx ; Мы знаем, что это смещение mov cx,16 ; нацело делится на 16 div cx ; AX = (offset DAL)/16 mov dx,ax ; DX = (offset DAL)/16 mov ax,s_dal sub ax,dx ; AX = s_dal - (offset DAL)/16 mov ds,ax ; DS = s_dal - (offset dal)/16 ;**** Переменная часть Подготовка возврата в стеке mov ax,cs push ax ; CS Þ stack lea ax,l ; CS:(offset L) - точка возврата push ax ; offset L Þ stack ; Переход на дальнюю процедуру jmp dword ptr addr ; Переход на s_dal:0000 ;*************** Конец переменной части ****************** ; Точка возврата - печать сообщения о завершении l: pop ds ; Восстановление местного DS mov ah,9 ; Функция 9 lea dx,text ; DS:DX - смещение текста сообщения int 21h ; Вызов функции DOS ; Ожидание ввода клавиши пробела loop1: mov ah,0 ; Функция 0 int 16h ; Клавиатурное прерывание cmp al,' ' ; Пробел ? jnz loop1 ; Нет ! int 20h text db 0dh,0ah,0ah,'Программа выполнена',0dh,0ah,'$' ; Выравнивание начала засылаемой процедуры на начало параграфа if ($-start)mod 16 (если не 0) ; Псевдокоманда org $+(16-($-start)mod 16) ; условного endif ; ассемблирования ; Процедура, которая пересылается в область s_dal. ; Она начинается здесь на границе параграфа. ; Когда эта процедура находится в области s_dal, ; значение DS = s_dal - (offset dal)/16 dal proc far ; Дальняя процедура (т.е. будет дальний возврат - retf) mov ah,9 ; Функция 9 lea dx,text1 ; DS:DX - смещение текста сообщения int 21h ; Вызов функции DOS ; Ожидание ввода клавиши ENTER dal1: mov ah,0 ; Функция 0 int 16h ; Клавиатурное прерывание cmp al,0dh ; ENTER ? jnz dal1 ; Нет ! ret ; Возврат дальний !!! text1 db 0dh,0ah,0ah,'Я нахожусь по адресу S_DAL',0dh,0ah,'$' dal endp dend: ; Метка для определения конца пересылаемой процедуры Code ENDS ; Конец сегмента (кодового) END Start ; Указание точки входа в программу
2.2 РАБОТА С ФАЙЛАМИ
Задача 2.2.1. Используя функции прерывания 21h DOS, написать программу, которая · создает в текущем каталоге новый файл с именем, соот ветствующим фамилии студента · записывает в созданный файл текст длиной не менее 40 символов · изменяет дату создания файла на 11 ноября 1991 года (при этом время создания должно остаться неизменным) При возникновении ошибки во время выполнения какой-либо функции должно выводиться сообщение о возникновении ошибки, и программа должна завершаться. Классифицировать возникшую ошибку не надо.
Assume CS: Code, DS: Code Code SEGMENT org 100h Start proc near mov ax,cs mov ds,ax ; DS = CS ; Создание нового файла mov ah,5bh ; Функция создания нового файла mov cx,2 ; Атрибут "скрытый" lea dx,file ; Адрес спецификации файла int 21h ; Функция DOS jnc m1 ; Переход, если ошибки нет ; Вывод сообщения при возникновении ошибки err1: mov ah,9 ; Функция вывода строки на экран lea dx,meserr ; Адрес сообщения об ошибке int 21h int 20h m1: mov handle,ax ; Сохранение дескриптора файла ; Запись текста в файл mov ah,40h ; Функция записи в файл mov bx,handle ; Дескриптор файла mov cx,40 ; Длина записываемого текста lea dx,text ; Адрес записываемого текста int 21h jc err1 ; Переход на вывод сообщения при ошибке ; Получение даты и времени создания файла mov ah,57h ; Функция работы с датой и временем mov al,0 ; Подфункция получения даты и времени mov bx,handle ; Дескриптор файла int 21h jc err1 ; Переход на вывод сообщения при ошибке ; Изменение даты создания файла mov al,1 ; Подфункция установки даты и времени mov dx,0001011101101011b ; Год, месяц и день int 21h jc err1 ; Переход на вывод сообщения при ошибке int 20h ; Выход из программы file db 'roschin.ie4',0 meserr db 'Error during program execution$' text db '*** This file was created by Roschin *** ' handle dw ? ; Место для дескриптора файла Start endp Code ENDS END Start
Задача 2.2.2. Используя функции прерывания 21h DOS, написать программу, которая · создает в текущем каталоге новый файл с именем, соответствующим фамилии студента · записывает в созданный файл строку, вводимую с клавиатуры (только ее, и ничего лишнего) в каталог ...\PROGRAM\FILES При возникновении ошибки во время выполнения какой-либо функции должно выводиться сообщение о возникновении ошибки, и программа должна завершаться. Классифицировать возникшую ошибку не надо.
Assume CS: Code, DS: Code Code SEGMENT org 100h Start proc near mov ax,cs mov ds,ax ; DS = CS Далее идет ввод текста с клавиатуры mov ah,0ah ; Функция ввода с клавиатуры lea dx,buf ; Адрес буфера int 21h ; Создание нового файла mov ah,5bh ; Функция создания нового файла mov cx,2 ; Атрибут "скрытый" lea dx,file ; Адрес спецификации файла int 21h ; Функция DOS jc err1 ; Переход, если ошибки нет mov handle,ax ; Сохранение дескриптора файла ; Запись текста в файл mov ah,40h ; Функция записи в файл mov bx,handle ; Дескриптор файла xor ch,ch mov cl,buf+1 ; Длина записываемого текста lea dx,buf+2 ; Адрес записываемого текста int 21h jc err1 ; Переход на вывод сообщения при ошибке ; Закрытие файла mov ah,3eh ; Функция закрытия файла mov bx,handle ; Дескриптор файла int 21h jc err1 int 20h ; Выход из программы ; Вывод сообщения при возникновении ошибки err1: mov ah,9 ; Функция вывода строки на экран lea dx,meserr ; Адрес сообщения об ошибке int 21h int 20h file db 'roschin.ie4',0 buf db 255,255 dup(0) meserr db 'Error during program execution$' handle dw ? ; Место для дескриптора файла Start endp Code ENDS END Start
2.3 РАБОТА С ГРАФИКОЙ
Задача 2.3.1. Написать программу, которая переключает ЭВМ в графический режим CGA (4 цвета, 320 * 200 точек) и заполняет экранную область (8000h байтов, начиная с адреса B800h) заданным значением (color), выводит на середину экрана изображение мяча (4*4) точек и обеспечивает его движение с отражением от краев экрана. Assume CS: Code, DS: Code screen_size equ 8000h ; Размер экрана в байтах color equ 0 ; Цвет: 4 точки в байте, 55р - голубой, Code SEGMENT ;0ааh - сиреневый, 0ffh - белый org 100h Start proc near mov ah,0 ; Функция установки видеорежима mov al,4 ; Графический режим 4 цвета 320 * 200 int 10h call lab1 call lab2 int 20h Start endp lab2 proc near mov dl,40 ; Координата Х (0 - 79) mov dh,50 ; Координата Y (0 - 99) mov cl,1 ; Дельта X mov ch,1 ; Дельта Y lab20: call ball1 ; Построение светлого мяча push cx mov cx,5000 ; Задержка lab21: loop lab21 pop cx call ball0 ; Стирание мяча cmp dl,79 jnz lab22 neg cl jmp lab23 lab22: cmp dl,0 jnz lab23 neg cl lab23: add dl,cl cmp dh,99 jnz lab24 neg ch jmp lab25 lab24: cmp dh,0 jnz lab25 neg ch lab25: add dh,ch jmp lab20 ret lab2 endp ball1 proc near ; Рисование мяча mov ax,0b800h mov es,ax mov ax,80 mul dh ; 80 * Y xor bh,bh mov bl,dl add bx,ax ; 80 * Y + X mov es:byte ptr [bx],3ch add bx,2000h mov es:byte ptr [bx],0ffh sub bx,2000h-80 mov es:byte ptr [bx],0ffh add bx,2000h mov es:byte ptr [bx],3ch ret ball1 endp ball0 proc near ; Стирание мяча mov ax,0b800h mov es,ax mov ax,80 mul dh ; 80 * Y xor bh,bh mov bl,dl add bx,ax ; 80 * Y + X mov es:byte ptr [bx],0 add bx,2000h mov es:byte ptr [bx],0 sub bx,2000h-80 mov es:byte ptr [bx],0 add bx,2000h mov es:byte ptr [bx],0 ret ball0 endp lab1 proc near mov ax,cs mov ds,ax ; DS = CS mov ax,0b800h mov es,ax ; ES = B800h xor si,si ; Обнуление регистра-источника xor di,di ; Обнуление регистра назначения mov cx,screen_size/2 ; Инициализация счетчика mov al,color ; Цвет rep stosb ret lab1 endp Code ENDS END Start
2.4 РАБОТА СО ЗВУКОМ
2.4.1 Извлечение звука в IBM PC
В простейшем случае в IBM PC для генерации звука используется микросхема интегрального таймера 8253 или 8254. Эта микросхема имеет три независимых канала, каждый из которых может программироваться для работы в режиме делителя частоты или генератора одиночных импульсов. Каждый канал содержит 16-разрядный счетчик, в который записывается значение делителя частоты или коэффициента пересчета (в зависимости от режима работы). Каждый канал имеет вход частоты (clk) и вход разрешения (gate). На вход частоты всех каналов подается импульсный сигнал частотой 1,19 МГц. Канал 0 микросхемы таймера используется для выработки сигнала прерывания по таймеру (частотой 18,2 Гц). Канал 1 работает в режима генерации одиночных импульсов через каждые 15 мкс. Этот сигнал используется для регенерации динамической памяти ЭВМ.
Канал 2 микросхемы исходно программируется для работы в режиме делителя частоты. Выход канала используется для генерации звука через встроенный динамик. Для управления звуком используются биты 0 и 1 системного порта В (микросхема 8255). Бит 0 используется для разрешения прохождения сигнала на выход канала 2 таймера. Сигнал с выхода канала 2 подается на схему "И", на второй вход который подается сигнал бита 1 системного порта В. Этот сигнал может разрешать или запрещать прохождения сигнала с выхода канала 2 таймера, а при закрытом канале 2 (битом 0 порта В) сигнал бита 1 порта В может использоваться для непосредственной генерации звука в динамике. Адрес системного порта В - 61h, адреса каналов таймера - 40h, 41h, 42h, 43h - для каналов 0, 1, 2 и управляющего регистра соответственно. Ниже рассмотрены примеры генерации звука с помощью сигнала бита 1 системного порта В, а также с помощью таймера. Рассмотрен случай извлечения звука с использованием прерывания.
2.4.2 Примеры генерации звука
Задача 2.4.2.1. Написать программу, издающую различные звуки при нажатии на клавиши '1' и '2'. Для генерации звука следует использовать сигнал бита 1 системного порта В. Выход из программы должен осуществляться по нажатию клавиши 'q'.
Assume CS: Code, DS: Code Code SEGMENT org 100h frequency1 equ 300 ; Задержка переключения 1 frequency2 equ 500 ; Задержка переключения 2 number_cycles1 equ 1000 ; Количество циклов (длит.) number_cycles2 equ 600 ; Количество циклов (длит.) port_b equ 61h ; Адрес системного порта В .286 Start proc near mov ax,cs mov ds,ax ; DS = CS beg1: call kbin ; Опрос клавиатуры cmp al,'1' ; = '1' ? jnz beg2 ; Нет call ton1 ; Звук высоты 1 jmp beg1 ; Переход на начало цикла beg2: cmp al,'2' ; = '2' ? jnz beg3 ; Нет call ton2 ; Звук высоты 2 jmp beg1 ; Переход на начало цикла beg3: cmp al,'q' ; = 'q' ? jnz beg1 ; Нет int 20h ; Выход из программы start endp ton2 proc near ; Процедура генерации звука 2 mov dx,number_cycles2 ; Длительность 2 mov di,frequency2 ; Задержка 2 jmp ton0 ; Переход на универсальную процедуру генерации звука ton1 proc near ; Процедура генерации звука 1 mov dx,number_cycles1 ; Длительность 1 mov di,frequency1 ; Задержка 1 ; Универсальная процедура генерации звука ; DX - количество циклов, DI - задержка ton0 proc near cli ; Запрещение прерываний in al,port_b ; Чтение сост. системн. порта В and al,11111110b ; Отк. динамика от таймера ton01: or al,00000010b ; Включение динамика out port_b,al ; Запись в системный порт В mov cx,di ; Счетчик цикла задержки loop $ ; Задержка ; Выключение звука and al,11111101b ; Выключение динамика out port_b,al ; Запись в системный порт В mov cx,di ; Счетчик цикла задержки loop $ ; Задержка dec dx ; Декремент счетчика колич. циклов jnz ton01 ; Переход на начало нового периода sti ; Разрешение прерываний ret ; Выход из процедуры ton0 endp ; Конец универсальной процедуры ton1 endp ; Конец процедуры генерации звука 1 ton2 endp ; Конец процедуры генерации звука 2 kbin proc near ; Ввод с клавиатуры с ожиданием mov ah,0 ; Функция 0 int 16h ; клавиатурного прерывания ret ; Выход из процедуры kbin endp ; Конец процедуры ввода с клавиатуры code ends ; Конец сегмента (кодового) END Start ; Указание на точку входа
Задача 2.4.2.2. Написать программу, издающую различные звуки при нажатии на клавиши '1' и '2'. Для генерации звука следует выход канала 2 таймера. Выход из программы должен осуществляться по нажатию клавиши 'q'.
Assume CS: Code, DS: Code Code SEGMENT org 100h frequency1 equ 1000 ; Коэффиц. деления 1 frequency2 equ 3000 ; Коэффиц. деления 2 duration equ 50000 ; Длительность port_b equ 61h ; Адрес системного порта В .286 Start proc near ; Основная процедура mov ax,cs mov ds,ax ; DS = CS beg1: call kbin ; Опрос клавиатуры cmp al,'1' ; = '1' ? jnz beg2 ; Нет call ton1 ; Звук высоты 1 jmp beg1 ; Переход на начало цикла beg2: cmp al,'2' ; = '2' ? jnz beg3 ; Нет call ton2 ; Звук высоты 2 jmp beg1 ; Переход на начало цикла beg3: cmp al,'q' ; = 'q' ? jnz beg1 ; Нет int 20h ; Выход из программы start endp ; Конец основной процедуры ton2 proc near ; Процедура генерации звука 2 mov dx,duration ; Длительность mov di,frequency2 ; Коэффициент деления 2 jmp ton0 ; Переход на универсальную процедуру ton1 proc near ; Процедура генерации звука 1 mov dx,duration ; Длительность mov di,frequency1 ; Коэффициент деления 2 ; Универсальная процедура генерации звука ; DX - длительность, DI - коэффиц. деления ton0 proc near cli ; Запрещение прерываний ; Включение динамика и таймера in al,61h ; Чтение состояния системного порта В or al,3 ; Разрешение звучания (биты 0 и 1) out 61h,al ; Запись в системный порт В ; Программирование делителя частоты 2 канала mov ax,di ; Делитель частоты out 42h,al ; Мл.байт частоты Þ канал 2 таймера xchg al,ah ; AH Û AL out 42h,al ; Ст.байт частоты Þ канал 2 таймера ; Формирование задержки mov cx,dx ; Счетчик цикла задержки ton01: push cx ; Команды, используемые только для pop cx ; увеличения длит. цикла задержки loop ton01 ; Задержка ; Выключение звука in al,61h ; Чтение состояния системного порта В and al,0fch ; Запрещение звучания (биты 0 и 1) out 61h,al ; Запись в системный порт В sti ; Разрешение прерываний ret ; Выход из процедуры ton0 endp ; Конец универсальной процедуры ton1 endp ; Конец процедуры генерации звука 1 ton2 endp ; Конец процедуры генерации звука 2 kbin proc near ; Ввод с клавиатуры и проверка на выбор игры ; Процедура совпадает с одноименной в задаче 2.4.2.1. kbin endp code ends ; Конец сегмента (кодового) END Start ; Указание на точку входа
Задача 2.4.2.3. Написать программу, издающую различные звуки при нажатии на клавиши '1' и '2'. Для генерации звука следует выход канала 2 таймера. Выход из программы должен осуществляться по нажатию клавиши 'q'. Использовать прерывание от таймера.
Assume CS: Code, DS: Code Code SEGMENT org 100h .286 Start proc near ; Основная процедура mov ax,cs mov ds,ax ; DS = CS jmp beg ; "Перескок" через переменные frequency equ 0500h ; Коэффициент деления iniflag db 0 ; Флаг звучания old_int1c_off dw 0 ; Смещение старого вектора old_int1c_seg dw 0 ; Сегмент старого вектора beg: ; Сохранение старого вектора прерывания 1Сh mov ax,35h ; Функция взятия вектора mov al,1ch ; Вектор 1Сh int 21h ; Вызов функции DOS mov cs:old_int1c_off,bx ; Запись смещения mov cs:old_int1c_seg,es ; Запись сегмента ; Установка в вектор прерывания адреса новой ; программы обработки прерывания lea dx,new_int1c ; Запись нового вектора 1c mov ah,25h ; Функция установки вектора прерыв. mov al,1ch ; Номер вектора прерывания int 21h ; DS:DX - адрес новой программы обр. beg1: call kbin ; Опрос клавиатуры cmp al,'1' ; = '1' ? jnz beg2 ; Нет mov byte ptr iniflag,1 ; Взведение флага звуч. jmp beg1 ; Переход на начало цикла beg2: cmp al,'2' ; = '2' ? jnz beg3 ; Нет mov byte ptr iniflag,0 ; Сброс флага звуч. jmp beg1 ; Переход на начало цикла beg3: cmp al,'q' ; = 'q' ? jnz beg1 ; Нет ; Восстановление старого вектора 1с и выход mov dx,old_int1c_off ; Смещение старого вектора mov ax,old_int1c_seg ; Сегмент старого вектора mov ds,ax ; DS:DX - адрес устанавл. вектора mov ax,251ch ; Установка старого вектора 1ch int 21h ; Вызов функции DOS int 20h ; Выход из программы start endp ; Конец основной процедуры ; Новый обработчик прерывания 1ch new_int1c proc far ; Дальняя процедура pusha ; Сохранение всех регистров (для Intel286) call muz ; Вызов процедура извлечения звука popa ; Восстановление всех регистров iret ; Возврат из программы обработки прерывания new_int1c endp ; Конец нового обработчика прерывания 1сh muz proc near ; Процедура генерации звука test byte ptr cs:iniflag,0ffh ; Проверка флага jnz muz1 ; Продолжение in al,61h ; Чтение системного порта В and al,0fch ; Запрещение звучания (биты 0 и 1) out 61h,al ; Запись в системный порт В ret ; Выход, если флаг не взведен muz1: ; Программирование делителя частоты 2 канала mov ax,frequency ; Делитель частоты out 42h,al ; Мл.байт частоты Þ канал 2 таймера xchg al,ah ; AH Û AL out 42h,al ; Ст.байт частоты Þ канал 2 таймера ; Разрешение звучания in al,61h ; Чтение системного порта В or al,3 ; Разрешение звучания (биты 0 и 1) out 61h,al ; Запись в системный порт В ret ; Нормальный выход muz endp ; Конец процедуры генерации звука kbin proc near ; Ввод с клавиатуры и проверка на выбор игры ; Процедура совпадает с одноименной в задаче 2.4.2.1. kbin endp code ends ; Конец сегмента (кодового) END Start ; Указание на точку входа
Задача 2.4.2.4. Написать программу, исполняющую три различные мелодии при нажатии на клавиши '1', '2'и '3'. Для генерации звука следует использовать выход канала 2 таймера. Выход из программы должен осуществляться по нажатию клавиши 'q'. Использовать прерывание от таймера. Для исполнения мелодии сначала формируется массив делителей частоты, соответствующих различным нотам звукоряда. Для нот используются номера от 1 до 48. Условное соответствие номеров нот и их значений показано на рисунке. Массив делителей частоты для нот называется NOTY. Значение 0 используется в качестве признака окончания мелодии. Значение 255 используется для обозначения паузы.
В программе сформированы массивы для трех мелодий - "Чижик Пыжик" (mel1), "Подмосковные вечера" и " Кан-кан" (mel3). Длительность элементарного звука берется равной одному "тику" таймера (примерно 1/18 сек.). Для получения большей длительности в массиве мелодии записываются подряд несколько одинаковых нот. Для получения четко выраженных соседних одинаковых нот используется пауза.
Assume CS: Code, DS: Code Code SEGMENT org 100h .286 Start proc near ; Основная процедура mov ax,cs mov ds,ax ; DS = CS jmp beg ; "Перескок" через переменные iniflag db 0 ; Флаг звучания old_int1c_off dw 0 ; Смещение старого вектора old_int1c_seg dw 0 ; Сегмент старого вектора tek_mel dw ? ; Адрес текущей ноты выбранной мелодии beg: mov ax,351ch ; Сохранение старого вектора 1c int 21h mov cs:old_int1c_off,bx ; Запись смещения mov cs:old_int1c_seg,es ; Запись сегмента lea dx,new_int1c ; Запись нового вектора 1c mov ah,25h ; Функция установки вектора прерыв. mov al,1ch ; Номер вектора прерывания int 21h ; DS:DX - адрес новой программы обр. beg1: call kbin ; Опрос клавиатуры cmp al,'1' ; = '1' ? jnz beg2 ; Нет mov byte ptr iniflag,1 ; Взведение флага звуч. lea ax,mel1 mov tek_mel,ax jmp beg1 ; Переход на начало цикла beg2: cmp al,'2' ; = '2' ? jnz beg3 ; Нет mov byte ptr iniflag,1 ; Сброс флага звуч. lea ax,mel2 mov tek_mel,ax jmp beg1 ; Переход на начало цикла beg3: cmp al,'3' ; = '3' ? jnz beg4 ; Нет mov byte ptr iniflag,1 ; Сброс флага звуч. lea ax,mel3 mov tek_mel,ax jmp beg1 ; Переход на начало цикла beg4: cmp al,'q' ; = 'q' ? jnz beg1 ; Нет ; Восстановление старого вектора 1с и выход mov dx,old_int1c_off ; Смещение старого вектора mov ax,old_int1c_seg ; Сегмент старого вектора mov ds,ax ; DS:DX - адрес устанавл. вектора mov ax,251ch ; Установка старого вектора 1ch int 21h int 20h start endp ; Новый обработчик прерывания 1ch new_int1c proc far ; Дальняя процедура pusha ; Сохранение всех регистров call muz ; Вызов процедура извлечения звука popa ; Восстановление всех регистров iret ; Возврат из программы обработки прерывания new_int1c endp ; Процедура извлечения очередного звука ; tek_mel - адрес текущей ноты выбранной мелодии muz proc near test byte ptr cs:iniflag,0ffh ; Проверка флага jnz muz1 ; Продолжение muze: in al,61h ; Чтение состояния системного порта В and al,0fch ; Запрещение звучания (биты 0 и 1) out 61h,al ; Запись в системный порт В ret ; Выход, если флаг не взведен muz1: mov si,cs:tek_mel ; Адрес текущей ноты mov bl,cs:[si] ; Текущая нота cmp bl,255 ; Пауза ? jnz muz2 ; Выключение звука in al,61h ; Чтение состояния системного порта В and al,0fch ; Запрещение звучания (биты 0 и 1) out 61h,al ; Запись в системный порт В inc cs:tek_mel ; Переход к адресу след. ноты ret muz2: or bl,bl ; = 0 ? jnz muz3 ; Продолжение jmp muze ; Выход, если признак конца muz3: shl bl,1 ; Умножение bl на 2 xor bh,bh ; bh = 0 mov ax,cs:noty[bx] ; В DI частота ноты ; Программирование делителя частоты 2 канала inc cs:tek_mel ; Переход к адресу след. ноты out 42h,al ; Мл.байт частоты Þ канал 2 таймера xchg al,ah ; AH Û AL out 42h,al ; Ст.байт частоты Þ канал 2 таймера ; Разрешение звучания in al,61h ; Чтение состояния системного порта В or al,3 ; Разрешение звучания (биты 0 и 1) out 61h,al ; Запись в системный порт В ret ; Нормальный выход muz endp kbin proc near ; Ввод с клавиатуры и проверка на выбор игры ; Процедура совпадает с одноименной в задаче 2.4.2.1. kbin endp ; Мелодия "Чижик Пыжик" mel1 db 17,17,255,13,13,255,17,17,255,13,13,255,18,18,255 db 17,17,255,15,15,15,15,255,255 db 8,8,255,8,8,255,8,8,255,10,255,12,255 db 13,13,255,13,13,255,13,13,13,13 db 0 ; Мелодия "Подмосковные вечера" mel2 db 1,1,1,4,4,4,8,8,8,4,4,4,6,6,6,6,6,6,4,4,4,3,3,3 db 8,8,8,8,8,8,6,6,6,6,6,6,1,1,1,1,1,1,1,1,1,1,1,1 db 0 ; Мелодия "Кан-кан" mel3 db 18,6,25,13,22,18,25,13,20,1,23,8,22,5,20,1 db 25,6,13,13,25,10,13,13,25,10,27,13,22,10,23,13,20,1 db 11,11,20,5,11,11,20,1,23,11,22,5,20,11,18,6,30,18 db 29,17,27,15,25,13,23,11,22,10,20,8,18,6,13,13,18,10 db 13,13,20,1,23,8,22,5,20,8,25,6,13,13,25,10,13,13 db 25,6,27,13,22,10,23,13,20,1,8,8,20,5,8,8,20,1,23,8 db 22,5,20,8,18,6,25,10,20,13,22,10,18,6,6,6,6,6,6,6 db 34,8,24,12,24,15,34,12,32,1,25,5,25,8,29,5,30,6,34,13 db 37,10,34,13,34,1,32,8,32,5,8,8,34,8,24,12,24,15,34,12 db 32,1,25,5,25,8,29,5,29,3,27,7,29,10,27,13,34,12,32,8 db 34,6,32,3,34,8,24,15,24,12,34,15,32,1,29,8,25,5,29,8 db 30,6,34,13,37,10,34,13,34,1,32,5,32,8,5,5,34,8,24,15 db 24,12,34,15,32,1,25,6,25,5,29,8,29,3,27,7,29,10,27,7 db 32,8,30,6,29,5,27,3,25,1,8,8,25,5,8,8,27,12,30,15 db 29,8,27,12,32,1,8,8,32,5,8,8,32,1,34,8,29,5,30,8,27,8 db 15,15,27,12,15,15,27,8,30,12,29,15,27,12,25,1,37,1 db 36,5,34,6,32,8,30,8,29,10,27,12,25,1,8,8,25,5,8,8 db 27,8,30,15,29,12,27,15,32,1,8,8,32,5,8,8,32,1,34,8 db 29,5,30,8,27,8,15,15,27,12,15,15,27,8,30,15,29,12 db 27,15,25,1,32,8,27,5,29,8,25,1,32,32,37,37,0 ; Коэффициенты деления для нот noty dw 0eeeh,0e18h,0d49h,0c8eh,0bdfh,0b2fh,0abeh dw 9f7h,968h,8e0h,861h,7e8h,777h,70ch,6a5h,647h dw 5edh,597h,547h,4fbh,4b4h,470h,430h,3f4h dw 3bbh,386h,352h,323h,2f6h,2cbh,2a3h,27dh,25ah,238h,218h,1fah dw 1ddh,1c3h,1a9h,192h,17bh,166h,152h,13fh,12dh,11ch,10ch,0fdh dw 0 code ends END Start
Задача 2.4.2.5. Модифицировать программу из предыдущей задачи так, чтобы длительность каждого звука задавалась в массиве мелодии. Для каждого звука должна записываться пара значений: номер ноты и длительность, выраженная в элементарных "тиках" таймера. Для простоты в программе будут реализованы только первые две короткие мелодии.
Assume CS: Code, DS: Code Code SEGMENT org 100h .286 Start proc near mov ax,cs mov ds,ax jmp beg pausa equ 255 frequency dw 1000h iniflag db 0 ; Флаг звучания old_int1c_off dw 0 ; Смещение старого вектора old_int1c_seg dw 0 ; Сегмент старого вектора tek_mel dw ? duration db 0 ; Длительность текущей ноты beg: mov ax,351ch ; Сохранение старого вектора 1c int 21h mov cs:old_int1c_off,bx ; Запись смещения mov cs:old_int1c_seg,es ; Запись сегмента lea dx,new_int1c ; Запись нового вектора 1c mov ah,25h ; Функция установки вектора прерыв. mov al,1ch ; Номер вектора прерывания int 21h ; DS:DX - адрес новой программы обр. beg1: call kbin ; Опрос клавиатуры mov byte ptr duration,1 cmp al,'1' ; = '1' ? jnz beg2 ; Нет mov byte ptr iniflag,1 ; Взведение флага звуч. lea ax,mel1 mov tek_mel,ax jmp beg1 ; Переход на начало цикла beg2: cmp al,'2' ; = '2' ? jnz beg3 ; Нет mov byte ptr iniflag,1 ; Сброс флага звуч. lea ax,mel2 mov tek_mel,ax jmp beg1 ; Переход на начало цикла beg3: cmp al,'q' ; = 'q' ? jnz beg1 ; Нет ; Восстановление старого вектора 1с и выход mov dx,old_int1c_off ; Смещение старого вектора mov ax,old_int1c_seg ; Сегмент старого вектора mov ds,ax ; DS:DX - адрес устанавл. вектора mov ax,251ch ; Установка старого вектора 1ch int 21h int 20h start endp ; Новый обработчик прерывания 1ch new_int1c proc far pusha dec byte ptr cs:duration jnz ex call muz ; Вызов процедуры извлечения звука ex: popa iret new_int1c endp muz proc near test byte ptr cs:iniflag,0ffh ; Проверка флага jnz muz1 ; Продолжение muze: in al,61h ; Чтение состояния системного порта В and al,0fch ; Запрещение звучания (биты 0 и 1) out 61h,al ; Запись в системный порт В ret ; Выход, если флаг не взведен muz1: mov si,cs:tek_mel ; Адрес текущей ноты mov bx,word ptr cs:[si] ; BL -текущая нота, BH - длительность mov cs:duration,bh ; Длит. в системную переменную cmp bl,255 ; Пауза ? jnz muz2 ; Выключение звука in al,61h ; Чтение состояния системного порта В and al,0fch ; Запрещение звучания (биты 0 и 1) out 61h,al ; Запись в системный порт В inc cs:tek_mel ; Переход к адресу след. ноты inc cs:tek_mel ; след. длительности ret muz2: or bl,bl ; = 0 ? jnz muz3 ; Продолжение jmp muze ; Выход, если признак конца muz3: shl bl,1 ; Умножение bl на 2 xor bh,bh ; bh = 0 mov ax,cs:noty[bx] ; В DI частота ноты ; Программирование делителя частоты 2 канала inc cs:tek_mel ; Переход к адресу след. ноты inc cs:tek_mel ; и след. длительности out 42h,al ; Мл.байт частоты Þ канал 2 таймера xchg al,ah ; AH Û AL out 42h,al ; Ст.байт частоты Þ канал 2 таймера ; Разрешение звучания in al,61h ; Чтение состояния системного порта В or al,3 ; Разрешение звучания (биты 0 и 1) out 61h,al ; Запись в системный порт В ret ; Нормальный выход muz endp kbin proc near ; Ввод с клавиатуры ; Процедура совпадает с одноименной в задаче 2.4.2.1. kbin endp mel1 db 17,2,255,1,13,2,255,1,17,2,255,1,13,2,255,1,18,2,255,1, 17,2 db 255,1,15,4,255,2, 8,2,255,1,8,2,255,1,8,2,255,1,10,1,255,1 db 12,1,255,1,13,2,255,1,13,2,255,1,13,4,0 mel2 db 1,4,4,4,8,4,4,4,6,8,4,4,3,4,8,8,6,8,1,12,0 noty dw 0eeeh,0e18h,0d49h,0c8eh,0bdfh,0b2fh,0abeh, 9f7h,968h dw 8e0h,861h,7e8h,777h,70ch,6a5h,647h, 5edh,597h,547h dw 4fbh,4b4h,470h,430h,3f4h, 3bbh,386h,352h,323h,2f6h,2cbh dw 2a3h,27dh,25ah,238h,218h,1fah, 1ddh,1c3h,1a9h,192h,17bh dw 166h,152h,13fh,12dh,11ch,10ch,0fdh,0 code ends END Start
Популярное: Как распознать напряжение: Говоря о мышечном напряжении, мы в первую очередь имеем в виду мускулы, прикрепленные к костям ... Модели организации как закрытой, открытой, частично открытой системы: Закрытая система имеет жесткие фиксированные границы, ее действия относительно независимы... Личность ребенка как объект и субъект в образовательной технологии: В настоящее время в России идет становление новой системы образования, ориентированного на вхождение... ©2015-2024 megaobuchalka.ru Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. (1153)
|
Почему 1285321 студент выбрали МегаОбучалку... Система поиска информации Мобильная версия сайта Удобная навигация Нет шокирующей рекламы |