Консультация № 171702
28.08.2009, 18:07
0.00 руб.
0 13 1
доброго времени суток!
не могу понять в чем проблема с пищалкой...звук должен генерироваться без использования счетчика-таймера...(текст программы приводится ниже)..и вопрос..как нужно рассчитать время, чтобы сделать задержку в секундах?

Приложение:
.model small
.386
.stack 256h
.data
;частоты из учета 1193180/частоту ноты
music dw 4063, 2559, 3835 ;ре = 293,7 ля-диез = 466,2 ре-диез = 311,1
;длительность воспроизведения
duration dw 27, 36, 18 ;ре = 1,5 ля-диез = 2 ре-диез = 1 = > 18.2*время в секундах
dlina dw 3

.code

start:
mov ax, @data
mov ds, ax
mov si, 0
cli ;зaпpeт пpepывaний
play:
mov dx, duration[si] ;длитeльнocть тoнa в dx
in al, port_b ;пoлучaeм знaчeниe из пopтa b
and al, 11111110b ;oтключaeм динaмик oт тaймepa
next_cycle:
or al, 00000010b ;включaeм динaмик
out port_b, al ;пocылaeм кoмaнду в пopт b
mov cx, music[si] ;зaдepжкa нa пoл-циклa в cx
first_half:
loop first_half ;дeлaeм зaдepжку
and al, 11111101b ;выключaeм динaмик
out port_b, al ;пocылaeм кoмaнду в пopт b
mov cx, music[si] ;зaдepжкa нa пoл-циклa в cx
second_half:
loop second_half ;дeлaeм зaдepжку
dec dx ;вычитaeм eдиницу из cчeтчикa
jnz next_cycle ;ecли 0, тo нaдo кoнчaть

dec dlina
mov cx, dlina
inc cx
inc si
inc si
loop play
sti ;paзpeшaeм пpepывaния

mov ax, 4c00h
int 21h
end start

Обсуждение

давно
Старший Модератор
31795
6196
28.08.2009, 21:15
общий
Lyuboff:
Вот посмотрите реально работающий код с книги С.Зубкова.
Код:
; Процедура beep
; издает звук с частотой 261 Hz (нота "ми" средней октавы)
; длительностью 1/2 секунды на динамике
beep proc near
mov al,10110110b ; канал 2, режим 3
out 43h,al
mov al,0Dh ; младший байт делителя
; частоты 11D0h
out 42h,al
mov al,11h ; старший байт делителя частоты
out 42h,al
in al,61h ; текущее состояние
; порта 61h в AL
or al,00000011b ; установить биты 0 и 1 в 1
out 61h,al ; теперь динамик включен
mov cx,0007h ; старшее слово числа микросекунд паузы
mov dx,0A120h ; младшее слово числа микросекунд паузы
mov ah,86h ; функция 86h
int 15h ; пауза

in al,61h
and al,11111100b ; обнулить младшие два бита
out 61h,al ; теперь динамик выключен
ret
beep endp

Проблема в том, что Вы запускаете свою программу в режиме эмуляции MS-DOS.
Это значит, что там не всё однозначно, как должно быть в реальном режиме.
Вторая проблема динамик работает по каналам, программирования каналов нет.
Теперь явные ошибки.
Посмотрите на эти строки:
Код:
    and   al, 11111110b  ;oтключaeм динaмик oт тaймepa
next_cycle:
or al, 00000010b ;включaeм динaмик
. . .
and al, 11111101b ;выключaeм динaмиктипа правильно

Что вы тут отключили?
Циклы в режиме эммуляции работают не так как в реальном.
Вот ещё строчки:
Код:

mov cx, dlinaдлина =3
inc cxдлина =4

inc si
inc si
loop playдлина=3

Упс, простите, но понять не могу. Какой смысл в этих строчках? Вы нигде не изменяете переменную dlina, т.е это просто бесконечный цикл. Тогда лучше использовать элеметраный JMP.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Неизвестный
29.08.2009, 10:43
общий
Зенченко Константин Николаевич:
Звуки можно воспроизводить двумя способами:
- с использованием таймера (канал 2 режим 3);
- без использования таймера (игра с первым битом 61 порта).
сейчас я разбираюсь со вторым вариантом работы..т.е. мне не нужен второй канал...а должна как-то работать только с 61h...вот я и пытаюсь...но что-то у меня никак(((...

dec dlina ; здесь уменьшается длина
mov cx, dlina
inc cx ;здесь увеличивается сх,т.к в loop он уменьшится
inc si
inc si
loop play

да, это может и сделано по глупому, но не упускает не один элемент массива и проходит его весь)))
давно
Старший Модератор
31795
6196
30.08.2009, 09:43
общий
Lyuboff:
Как-то эту команду: dec dlina не заметил.
Биты 61-го порта только включает и выключает динамик, если в каналах ничего не записано, то и генерироваться ничего не будет. Это практически как с колоноками в РС, колонки могут быть подключены, но Вы не запустили плеер.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Неизвестный
31.08.2009, 09:17
общий
у меня начал пищать, или шипеть, точно не знаю что это, но работает...
цитата из статьи про системный таймер и музыку:"Программа может генерировать звуки и другим способом, не используя таймер. Для этого нужно сбросить младший бит порта 61h и, управляя битом 1 этого порта, формировать импульсы для громкоговорителя. Т.е. программа должна устанавливать этот бит то в 0, то в 1 с некоторым периодом. Высота генерируемого звука будет соответствовать этому периоду. "
вооооот...
странно, что этого вы не знали...ну да ладно
давно
Старший Модератор
31795
6196
31.08.2009, 20:24
общий
Lyuboff:
Цитата: 276426
цитата из статьи про системный таймер и музыку:"Программа может генерировать звуки и другим способом, не используя таймер. Для этого нужно сбросить младший бит порта 61h и, управляя битом 1 этого порта, формировать импульсы для громкоговорителя. Т.е. программа должна устанавливать этот бит то в 0, то в 1 с некоторым периодом. Высота генерируемого звука будет соответствовать этому периоду. "
вооооот...
странно, что этого вы не знали...ну да ладно

правда?
Для того, что бы динамик начал издавать звуки, должны быть, как минимум включен канал, не говоря уже о том, что он должен быть запрограммирован на определенную частоту. Бит 1, 61h-порта, ТОЛЬКО ВКЛЮЧАЕТ И ВЫКЛЮЧАЕТ ДИНАМИК. Если брать аналогию с настольной лампой, то Вы балуетесь с её выключателем, даже не проверив включена лампа в розетку или нет. Ваш подход можно использовать, если бы при выключеных каналах на динамик подавалось постоянное напряжение и Вы включая и выключая динамик создаете на нем переменное напряжение с определенной частотой и интервалами. Но все намного веселее. При выключеном канале на динамик подается НОЛЬ, и сколько бы Вы не переключали выключатель, динамик пищать не будет.
Вот Вам код(tasm), который создает загрузочную дискету, я именно с неё проверял, т.к. у меня ХР и к динамику меня не пускает ОС. Загружаясь с неё, я при отключеных каналах становлюсь глухим, а при включеных слышу меандр. Нужно только побаловатся со строчкой:or al,00000010b, один раз сделать как есть, а во второй установить младший бит в 1. В BIOS поставьте загрузку с дискеты.
Код:
model	tiny
.code
.186
org 100h
;
begin:
;программа записывающая бут-сектор
;запускаем привод дисковода
xor ax,ax
int 13h
xor ax,ax
int 13h
xor ax,ax
int 13h
;записываем один сектор
mov ax,0301h;запишем 1 сектор
mov bx,offset bootBegin;смещение на бут-сектор;
mov cx,1;
xor dx,dx;
int 13h
ret;выход в дос
;сам бут-сектор
;- - - - -
;
bootBegin:;
mov al,10110110b ; канал 2, режим 3
out 43h,al
mov al,0Dh ; младший байт делителя
; частоты 11D0h
out 42h,al
mov al,11h ; старший байт делителя частоты
out 42h,al
mov cx,9000h
isJump:
in al,61h ; текущее состояние
; порта 61h в AL
and al,11111100b
or al,00000010b ; установить биты 0 и 1 в 1
out 61h,al ; теперь динамик включен
push cx
isDelay:
mov cx,9000h
loop isDelay
; mov cx,0007h ; старшее слово числа микросекунд паузы
; mov dx,0A120h ; младшее слово числа микросекунд паузы
; mov ah,86h ; функция 86h
; int 15h ; пауза

in al,61h
and al,11111100b ; обнулить младшие два бита
out 61h,al ; теперь динамик выключен
isDelay0:
mov cx,9000h
loop isDelay0
pop cx
loop isJump
xor ax,ax
int 16h
ret
db 446 dup(?)
db 7fh,1,0,41h,0bbh,0,7,60h,66h,6ah,0,0e9h,3bh,0ffh,0,0,55h,0aah
end begin

Цитата: 276426
Звуки можно воспроизводить двумя способами:
- с использованием таймера (канал 2 режим 3);
- без использования таймера (игра с первым битом 61 порта).

Во втором случае Вам сказали не всё, при запуске программы Вы не можете быть увереными, что у Вас включен канал таймера, т.к. он формирует опорное напряжение на динамик(а раз канал должен быть включен, то ни о каком без использования таймера, не может быть и речи).
Вот одно из правил ассемблера: В Ассемблере за всё должен отвечать программист.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Старший Модератор
31795
6196
01.09.2009, 13:52
общий
Lyuboff:
Посмотрел сегодня схему материнской платы GIGABYTE, действительно бипер управляется двумя паралельными ключами.
Такой вариант возможен.
Сорри, что сразу не проверил.
Сейчас буду разбиратся.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Старший Модератор
31795
6196
01.09.2009, 15:57
общий
Lyuboff:
Вы считаете задержку в тактах процессора. Количество тактов в секунду приблизительно равно частоте процессора.
На выполнение этой строчки first_half:loop first_half при СХ=4063, у Вас выйдет:
4063*17(выполнение цикла)+5(не выполнение цикла)=69076 тактов на одну полуволну. На моей машине при частоте процессора 2,5Гц, получается частота генерируемого звука 18096 герц. Даные по тактам взяты для х86 процессора, для потомков эти цифры ещё меньше, т.е. частоты будут ещё больше.

Используйте стандартную 15h-86h.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Неизвестный
01.09.2009, 21:32
общий
.model small
.386
.stack 256h
.data
;частоты из учета 1193180/частоту ноты
music dw 294, 466, 311 ;ре = 293,7 ля-диез = 466,2 ре-диез = 311,1
;длительность воспроизведения
duration dw 15000, 30000, 10000 ;ре = 1,5 ля-диез = 2 ре-диез = 1
dlina dw 3
pb equ 61h ;aдpec пopтa b микpocxeмы 8255

.code

start:
mov ax, @data
mov ds, ax
mov si, 0
cli ;зaпpeт пpepывaний
;---зaпpeт микpocxeмы тaймepa
in al, pb ;пoлучaeм из нeгo бaйт
or al, 1 ;cбpacывaeм бит 0
out pb, al ;вoзвpaщaeм бaйт в пopт
;---уcтaнoвкa чacтoты и длитeльнocти звукa
play:
mov bx, music[si] ;нaчaльнoe знaчeниe cчeтчикa
mov dx, duration[si] ;длитeльнocть звукa
repeat: ;cюдa вoзвpaщaeмcя пocлe циклa
;---уcтaнoвкa битa динaмикa
or al, 00000010b ;уcтaнaвливaeм бит 1
out pb, al ;пocылaeм бaйт в пopт b
mov cx, bx ;уcтaнoвкa cчeтчикa
cycle1:
loop cycle1
;---cбpoc битa динaмикa
and al, 11111101b ;cбpacывaeм бит 1
out pb, al ;пocылaeм бaйт в пopт
mov cx, bx ;уcтaнoвкa cчeтчикa
cycle2:
loop cycle2 ;пуcтoй цикл
;---пepexoд к cлeдующeму циклу
dec bx ;увeличивaeм чacтoту, умeньшaя
dec bx ;cчeтчик
dec dx ;умeньшaeм ocтaвшуюcя длитeльнocть
jnz repeat ;ecли dx нe 0, тo нoвый цикл

dec dlina
mov cx, dlina
inc cx
inc si
inc si

loop play
sti ;paзpeшaeм пpepывaния

mov ax, 4c00h
int 21h
end start

я тут немного переделала...что-то шипит или жжужит..но правда теперь с частотами не разберусь)))
давно
Старший Модератор
31795
6196
01.09.2009, 21:41
общий
Lyuboff:
Последний мой вариант был такой:
Код:
model	tiny
.code
.186
org 100h
;
begin:
;программа записывающая бут-сектор
;запускаем привод дисковода
xor ax,ax
int 13h
xor ax,ax
int 13h
xor ax,ax
int 13h
;записываем один сектор
mov ax,0301h;запишем 1 сектор
mov bx,offset bootBegin;смещение на бут-сектор;
mov cx,1;
xor dx,dx;
int 13h
ret;выход в дос
;сам бут-сектор
;- - - - -
;
bootBegin:;
xor si,si
mov ss,si
mov sp,7C00h
mov ds,si
mov si,7B00h
;
in al, 61h ;пoлучaeм знaчeниe из пopтa b
and al, 11111100b ;oтключaeм динaмик oт тaймepa
;
cli ;зaпpeт пpepывaний
mov cx,3
play: push cx
mov cx, duration[si] ;длитeльнocть тoнa в dx
next_cycle:
push cx
mov cx, music[si] ;зaдepжкa нa пoл-циклa в cx
call beep
call beep
pop cx
loop next_Cycle
pop cx
inc si
inc si
loop play
sti;paзpeшaeм пpepывaния
xor ax,ax
int 16h
int 19h
beep: xor al,00000010b
out 61h,al
push ax
push cx
xor dx,dx
mov ah,86h
int 15h
pop cx
pop ax
ret
;частоты из учета 1193180/частоту ноты
music dw 63, 25, 35 ;ре = 293,7 ля-диез = 466,2 ре-диез = 311,1
;длительность воспроизведения
duration dw 27, 36, 18 ;ре = 1,5 ля-диез = 2 ре-диез = 1 = > 18.2*время в секундах
db 416 dup(?)
db 7fh,1,0,41h,0bbh,0,7,60h,66h,6ah,0,0e9h,3bh,0ffh,0,0,55h,0aah
;начиная с метки bootBegin всегда должно быть 512 байт
end begin

Я задавал только старшее значение задержки. При желании его можно более точно задать.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Старший Модератор
31795
6196
01.09.2009, 22:03
общий
Lyuboff:
если делать вариант с циклами, то у меня были такие вставки(вместо функции задержки):
;1
push cx
isAAA:loop isAAA
pop cx
;2
push cx
isBBB:loop isBBB
pop cx
и т.д.

где то на 4-х, 5-ти вставках я достигал более-мение не противного писка.
А с функцией задержки, там расчет простой: переводите нужную задержку в микросекунды, после этого переводите это число в 16-ю форму и записываете её в CX:DX.
Нужно учесть, что Вы задаете полупериод, т.е. задержка будет в два раза больше.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Неизвестный
01.09.2009, 22:05
общий
спасибо)))
"мы строили строили..и наконец построили"
давно
Старший Модератор
31795
6196
01.09.2009, 22:13
общий
Lyuboff:
Цитата: 276426
"мы строили строили..и наконец построили"

Получилось, что-то или нет.
В варианте с задержкой, там нужно задавать CX:DX, а это лишний код.
Цитата: Зенченко Константин Николаевич
Нужно учесть, что Вы задаете полупериод, т.е. задержка будет в два раза больше.

наоборот в два раза меньше.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Старший Модератор
31795
6196
02.09.2009, 13:11
общий
это ответ
Здравствуйте, Lyuboff.

Вам нужно использовать стандартную функцию BIOS ah=86h, прерывания 15h.
Расчитываете паузу в микросекундах и подставляете в регистры CX:DX(старшее слово числа микросекунд паузы:младшее слово).
Необходимые значения считаете по формуле:
ПАУЗА(мкс)=( 1 000 000 / ЧАСТОТА ) / 2
где ЧАСТОТА=количество периодов с секунду.
Нота РЕ=(1 000 000/293,7)/2=1 70210=6A610
Длительность воспроизведения одной ноты или количество повторов воспроизведения одного периода:
N=ЧАСТОТА * ВРЕМЯ
Нота РЕ = 293,7 * 1,5 = 44010

В приложении программа с использованием указанной функции, с учетом того, что старшее слово паузы в микросекундах(СХ) будет всегда равно 0.
Программа под tasm.

ps: Используя в качестве задержки, строки first_half: loop first_half, Вы считаете её в тактах процессора.
При современных процессорах, с высокой тактовой частотой, генерируемый звук будет на грани слышимости, около 20кГц.

Удачи!

Приложение:
model tiny
.186
.code
org 100h
start:
;
in al, 61h ;пoлучaeм знaчeниe из пopтa b
and al, 11111100b ;oтключaeм динaмик oт тaймepa
;
cli ;зaпpeт пpepывaний
;количество нот
mov cx,3
play: push cx
;загружаем данные
mov cx, duration[si];длитeльнocть тoнa в сx
mov dx, music[si];длительность полу-волны в dx
next_cycle:
push cx
;генерируем частоту
call beep;
call beep;
;цикл вопроизведения одной ноты
pop cx
loop next_Cycle
;востанавливаем счетчик
pop cx
;следующее значение
inc si
inc si
;цикл проигрывания всй мелодии
loop play
sti;paзpeшaeм пpepывaния
;ждем нажатия на любую клавишу
xor ax,ax
int 16h
;выход в DOS
ret
;инвентируем бит включения-выключения динамика
beep: xor al,00000010b
out 61h,al
;запоминаем состояние порта
push ax
;запоминаем задержку
push dx
;сбрасываем старшеё слово паузы
xor cx,cx
;функция задержки
mov ah,86h
int 15h
;востанавливаем регистры
pop dx
pop ax
ret
;длительность одной полуволны ноты
music dw 6a6h,430h,647h;ре = 293,7 ля-диез = 466,2 ре-диез = 311,1
;длительность воспроизведения
duration dw 440, 892, 311;ре = 1,5 ля-диез = 2 ре-диез = 1 в секундах
end start
5
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Форма ответа