组装扬声器并等待中断无休止的睡眠

Posted

技术标签:

【中文标题】组装扬声器并等待中断无休止的睡眠【英文标题】:Assembly speaker and wait interrupt endless sleep 【发布时间】:2015-01-10 15:21:17 【问题描述】:

我正在开发一个在 PC 扬声器上播放音乐的汇编程序 (8086)。

一切正常,但我遇到了一个问题。程序在第 78 个音符时进入无休止的睡眠(扬声器打开),无论它是什么音符。

我正在使用86h function of 15 interrupt

那么为什么会出现这种无休止的睡眠,以及如何解决呢?

这是代码(带有真人快打主题):

;constants
TB equ 38636; 1.19MHz/30Hz
TC equ 34546; 1.19MHz/33Hz
TD equ 30811; 1.19MHz/37Hz
TE equ 27805; 1.19MHz/41Hz
TF equ 25909; 1.19MHz/44Hz
TG equ 23265; 1.19MHz/49Hz
TA equ 20727; 1.19MHz/55Hz
TH equ 18387; 1.19MHz/62Hz
TP equ 1;pause
;K end of melody
strophe1n equ 'ACADAEDCCECGCECGGHGCGDCFFAFCFCH'
strophe1o equ '3434344444444443333434433334343'
strophe1t equ '2222222222222222222222222222222'
strophe2n equ 'APAPAPAPGCAPAPAPAPGEAPAPAPAPGCAPAPAPAPAPAPA'
strophe2o equ '4040404045404040404440404040454040404040404'
strophe2t equ '2424242422242424242224242424222424284844484'
strophe3n equ 'AEACABACABGAEACABACABGAEACABACABGAEACGPGGPGAAPAA'
strophe3o equ '454545454544545454545445454545454454540440444044'
strophe3t equ '424242424424242424244242424242442424248488448848'

Progr           segment
                assume  cs:Progr, ds:data, ss:stacky
interval:; waits DX:CX microseconds
        mov ah,86h;
        int 15h
        ret
        ;here come notes every note set up its time and sleep
note:;0,5 sec
        mov cx,7;
        mov dx,41248;
        call interval
        ret

halfnote:;0,25sec
        mov cx,3;
        mov dx,53280;
        call interval
        ret

quarternote:;0,125sec
        mov cx,1;
        mov dx,58982;
        call interval
        ret

eighthnote:
        mov cx,0;
        mov dx,62455;
        call interval
        ret

turnon:;sets tone and turn on speaker
        ;setting up tone
        mov ax,tone
        mov dx,42h
        out dx,al
        mov al,ah
        out dx,al

        ;turning speaker on
        mov dx,61h
        in al,dx;
        or al,00000011B;
        out dx,al;
        ret

turnoff:;turning speaker off
        mov dx,61h
        in al,dx;
        and al,11111100B;
        out dx,al;
        ret

play:
;simple switch for times
        call turnon
        cmp time,1
        je whole
        cmp time,2
        je half
        cmp time,4
        je quarter
        cmp time,8
        je eighth

        whole: call note;sleep for note time (while speaker is on) and then shuts up the speaker
        jmp endplay
        half: call halfnote
        jmp endplay
        quarter: call quarternote
        jmp endplay
        eighth: call eighthnote
        jmp endplay
        endplay:
        call turnoff; turning speaker off
        ret

exit:
        mov ah,4ch
        mov al,00h
        int 21h;
;START--------------------------------------------------------------------
start: mov ax,data ;some start up
mov ds,ax
mov ax,stacky
mov ss,ax
mov sp,offset peak

mov si,0
melody:
        lea bx,notes
        mov dl,ds:[bx+si];dl = next note
        cmp dl,'K'; if K then melody ends
        je exit
        ;simple switch for notes
        cmp dl,'A'
        je A
        cmp dl,'B'
        je B
        cmp dl,'C'
        je C
        cmp dl,'D'
        je D
        cmp dl,'E'
        je E
        cmp dl,'F'
        je F
        cmp dl,'G'
        je G
        cmp dl,'H'
        je H
        mov tone,TP

        readoctave:
        lea bx,octaves;reads next octave from array
        mov cl,ds:[bx+si]
        sub cl,'0'

        shr tone,cl; double the tone octave times (tone = tone *2^octave)

        lea bx,times;read next time from array
        mov cl,ds:[bx+si]
        sub cl,'0'
        mov time,cl

        call play;
        inc si;;next index
jmp melody;play next note
;notes asignment
A: mov tone,TA
jmp readoctave
B: mov tone,TB
jmp readoctave
C: mov tone,TC
jmp readoctave
D: mov tone,TD
jmp readoctave
E: mov tone,TE
jmp readoctave
F: mov tone,TF
jmp readoctave
G: mov tone,TG
jmp readoctave
H: mov tone,TH
jmp readoctave


Progr           ends

data            segment

notes db strophe1n,strophe2n,strophe3n,'K';notes k means end of melody
octaves db strophe1o,strophe2o,strophe3o,'0';octaves, tone =(tone = frequency of note *2^octave)
times db strophe1t,strophe2t,strophe3t,'0';just times to play each note
tone dw 0
time db 0

data            ends

stacky          segment
                dw    100h dup(0)
peak          Label word
stacky          ends

end start

我知道代码有点大,但我不知道问题出在哪里。

@编辑 也许数组大小太大但我不这么认为 @EDIT2 程序在第 78 个音符上失败,无论它是什么音符。

【问题讨论】:

由于代码很大,如果您提供(更多)英文cmets会很有帮助,特别是因为您的标签是波兰语(?)这样,我们可以更容易理解代码,并且为您提供更好的帮助。 这是在普通 PC 上运行吗?如果是,那为什么会出现在这个网站上? @CamilStaps 对不起,我忘了,现在已经完成了 cmp dl,'K'; if K then melody ends je exit - 也许你应该在这里打电话给turnoff @500-InternalServerError 而不是,在那种情况下程序不会结束。顺便说一句,结束旋律不是问题,问题是在程序运行的第 15 秒它只是执行无限睡眠。你可以尝试在 dosbox 上运行它。 【参考方案1】:

在 MS-DOS 中,不要尝试自己管理堆栈,除非您确切地知道自己在做什么。我唯一一次看到这样做是在一个内存非常关键的 TSR 应用程序中。

另请参阅:why must we initialize DS And ES registers in MS-DOS?

此外,256 字节非常小;请注意所有硬件中断处理程序可能会在您的程序运行时占用您的堆栈份额。

我建议你删除:

mov  ax,stacky
mov  ss,ax
mov  sp,offset peak

stacky  segment
        dw     100h dup(0)
peak    Label  word
stacky  ends

希望对您有所帮助。

【讨论】:

很好,你在写什么,我以后会注意的,但我什至没有在这个程序中使用堆栈。我也找到了问题的解决方案,我会发布现在它。谢谢 @Rotek:每个 DOS 程序都使用堆栈。 call 确实如此,Bios 和 DOS 中的每个软件和硬件中断也是如此。弄乱堆栈可能会使系统作为一个整体不稳定。我在这里谈论未定义的行为;您的程序可能会随机中断。如果不是今天,那么可能是在您对程序进行下一次(看似无关的)更改之后。或者在稍微不同的 DOS 配置上。祝你好运。【参考方案2】:

原来是这样的

interval:
        mov ah,86h;
        int 15h
        ret

工作错误,因为 int 15h 86h 函数以某种方式失败,

所以我写了自己的程序

interval:
        mov ah, 0
        int 1Ah ; actual time
        mov bx,dx
        delay:
                mov ah, 0
                int 1Ah
                sub dx,bx
                cmp di,dx
        ja delay
        ret

还有注释以其他方式定义他们的时间(现在在 di 寄存器中)例如:

note:;0,5 sec
        mov  di, 8
        call interval
        ret
halfnote:;0,25 sec
        mov  di, 4
        call interval
        ret

【讨论】:

也许int 15h 不适用于所有平台。另一方面,您说前 78 个调用工作正常。这让我很怀疑; int 15h 真的是根本原因吗?如果没有,是否有另一个错误会危及您的系统? int 15h 破坏了你的程序,还是你的程序破坏了int 15h 我的 BIOS 参考 说:“此功能旨在(在操作系统软件中)用于设置系统等待。它不适合以下用户使用应用程序。" 我不知道到底出了什么问题,但现在它工作正常,这就是我们的目标。谢谢大家的任何建议

以上是关于组装扬声器并等待中断无休止的睡眠的主要内容,如果未能解决你的问题,请参考以下文章

在 BIOS 中发出哔声

蓝牙延迟和 Android 音频提示

将中断转换为 DMA

同步异步阻塞非阻塞可中断的睡眠不可中断的睡眠

Iphone 我们可以将耳机静音并仅从底部扬声器播放吗?

在 Android 操作系统中,我可以创建一个在后台运行并检测扬声器是打开还是关闭的服务吗?