gpt4 book ai didi

组装 8086 - DOSBOX - 如何发出蜂鸣声?

转载 作者:行者123 更新时间:2023-12-03 04:11:27 27 4
gpt4 key购买 nike

我正在组装一个“simon”游戏,我需要在按钮打开时发出蜂鸣声,蜂鸣声也应该彼此不同。谢谢

最佳答案

您可以使用speaker让您的设计保持简单。
扬声器可让您播放不同频率的方波,it can actually be used to reproduce digital audio但这涉及更多。

扬声器只是一个电磁体,当电流流过它时,它会被拉回,否则它会保持在默认位置。
通过前后移动扬声器,可以产生声波。

扬声器可以手动移动或使用PIT移动的 channel 2。
端口 61h 的位 0 控制扬声器源(0 = 手动,1 = PIT),同一端口的位 1 是使用 PIT 时的“扬声器启用”位(不使用 PIT 时为扬声器“位置”)。

这是一个示意图(来自此 page )缺少手动驾驶部分:

Speaker schematic

PIT 通过端口 40h-43h 控制,每次除法器的两个字节时我们将使用模式 3(方波发生器)设置。
PIT 有一个运行频率约为 1.193180 MHz 的振荡器,分频器用于控制方波的周期。
不处理内部结构:在 PIT 振荡器的每个滴答处,加载的分频器都会递减。方波的周期等于 PIT 将分频器递减至零所需的时间。

产生声音只需使用所需的分配器对 PIT 进行编程并启用扬声器即可。
一段时间后,我们需要禁用它。
一个简单的方法是使用 int 1ch称为每秒 18.2 次。

通过在第一次播放声音时在变量中保存持续时间,在 int 1ch 的每个刻度处递减它,并在计数达到零时禁用扬声器,可以控制蜂鸣声的持续时间。

使用 int 1ch 需要一个设置函数 (beep_setup) 和一个拆卸函数 (beep_teardown)。

BITS 16

ORG 100h

__start__:

;Setup
call beep_setup

;Sample beep of ~2sec
mov ax, 2000
mov bx, 36
call beep_play

;Wait for input
xor ax, ax
int 16h

;Tear down
call beep_teardown

mov ax, 4c00h
int 21h

;-------------------------------------------------

;
;Setup the beep ISR
;

beep_setup:
push es
push ax

xor ax, ax
mov es, ax

;Save the original ISR
mov ax, WORD [es: TIMER_INT * 4]
mov WORD [cs:original_timer_isr], ax
mov ax, WORD [es: TIMER_INT * 4 + 2]
mov WORD [cs:original_timer_isr + 2], ax

;Setup the new ISR

cli
mov ax, beep_isr
mov WORD [es: TIMER_INT * 4], ax
mov ax, cs
mov WORD [es: TIMER_INT * 4 + 2], ax
sti

pop ax
pop es
ret


;
;Tear down the beep ISR
;

beep_teardown:
push es
push ax

call beep_stop

xor ax, ax
mov es, ax

;Restore the old ISR

cli
mov ax, WORD [cs:original_timer_isr]
mov WORD [es: TIMER_INT * 4], ax
mov ax, WORD [cs:original_timer_isr + 2]
mov WORD [es: TIMER_INT * 4 + 2], ax
sti

pop ax
pop es
ret

;
;Beep ISR
;
beep_isr:
cmp BYTE [cs:sound_playing], 0
je _bi_end

cmp WORD [cs:sound_counter], 0
je _bi_stop

dec WORD [cs:sound_counter]

jmp _bi_end

_bi_stop:
call beep_stop

_bi_end:
;Chain
jmp FAR [cs:original_timer_isr]

;
;Stop beep
;
beep_stop:
push ax

;Stop the sound

in al, 61h
and al, 0fch ;Clear bit 0 (PIT to speaker) and bit 1 (Speaker enable)
out 61h, al

;Disable countdown

mov BYTE [cs:sound_playing], 0

pop ax
ret

;
;Beep
;
;AX = 1193180 / frequency
;BX = duration in 18.2th of sec
beep_play:
push ax
push dx

mov dx, ax

mov al, 0b6h
out 43h, al

mov ax, dx
out 42h, al
mov al, ah
out 42h, al


;Set the countdown
mov WORD [cs:sound_counter], bx

;Start the sound

in al, 61h
or al, 3h ;Set bit 0 (PIT to speaker) and bit 1 (Speaker enable)
out 61h, al


;Start the countdown

mov BYTE [cs:sound_playing], 1

pop dx
pop ax
ret

;Keep these in the code segment
sound_playing db 0
sound_counter dw 0
original_timer_isr dd 0

TIMER_INT EQU 1ch

特别感谢Sep Roland用于修复原始代码中的缺陷!

您可以使用beep_play来播放蜂鸣声,所使用的单位是上面解释的硬件配置的“自然”单位。
如果您的频率和持续时间是固定的,这些单位可以免费简化代码。

蜂鸣声在给定的持续时间后停止,您可以使用beep_stop强制停止。

一次播放多个声音是不可能的(如果不借助 PWM 技术,甚至将它们混合起来也是不可能的)。
当另一声蜂鸣声正在播放时调用 beep_play 将具有停止当前蜂鸣声并开始新的蜂鸣声的效果。

关于组装 8086 - DOSBOX - 如何发出蜂鸣声?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43996835/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com