我参加了一个介绍性的集会课程,对于最后的项目,我们必须制作一个节日生日快乐的节目。
问题是程序播放歌曲的中途(到第13个音符),然后停止播放。我已经尝试过所有尝试修复它的东西,我不知道它为什么不能正常工作。我尝试改变代码,改变循环的工作方式,改变哪些寄存器保存不同的值,但似乎没有任何工作。我看了调试,我看不到任何与众不同的东西。这是该程序的代码:
;data segment
dseg segment para 'data'
;hex value for each note to send to port 42
NOTES DW 11CAh,11CAh,0FDAh,11CAh,0D5Ah,0E1Fh,11CAh,11CAh
DW 0FDAh,11CAh,0BE3h,0D5Ah,11CAh,11CAh,08E9h,0A97h
DW 0D5Ah,0E1Fh,0FDAh,0A00h,0A00h,0A97h,0D5Ah,0BE3h,0D5Ah,"$"
;duration for each note
DUR DB 1d,1d,2d,2d,2d,4d,1d,1d,2d,2d,2d
DB 4d,1d,1d,2d,2d,2d,2d,6d,1d,1d,2d,2d,2d,4d
dseg ends
;----------------------------------------------------------------------
;code segment
cseg segment para 'code'
main proc far ;this is the program entry point
assume cs:cseg, ds:dseg, ss:sseg
mov ax,dseg ;load the data segment value
mov ds,ax ;assign value to ds
MOV AL, 0B6h
OUT 43h, AL ;output whats in AL to port 43h
MOV SI, OFFSET NOTES ;moves the address of the first note into SI
MOV DI, OFFSET DUR ;moves the address of the first duration into DI
SUB BX, BX ;clears BX
SUB DX, DX ;clears DX
SUB CX, CX ;cleasr CX
PLAY: NOP
MOV DX, [SI] ;moves the frequency and divider for the note into DX
CMP DX, "$"
JE EXIT ;if at end of notes jump to exit
MOV BL, [DI] ;moves the number of times delay is called into BL
CALL TONE ;plays the note for the duration
INC SI ;move to next note
INC DI ;moves to next duration
JMP PLAY ;loop back to PLAY if there are still notes
EXIT: NOP
mov ah,4Ch ;set up interupt
int 21h ;Interupt to return to DOS
main endp
TONE PROC
SUB AX, AX ;clears ax
MOV AL, DL ;sets up the frequency for the tone
OUT 42h, AL ;output whats in AL to port 42h
MOV DL, 0 ;use to compare to BL
MOV AL, DH ;divider for the tone smaller value = higher pitch
OUT 42h, AL
IN AL, 61h ;input the contents of port 61h into AL
MOV AH, AL ;preserve contents of AL
OR AL, 00000011b ;uses mask to change the bits that we need
OUT 61h, AL ;outputs the changed bits back into the port to start tone
AGAIN: NOP ;loops 1/2 second delay for times needed
CALL DELAY
DEC BL
CMP BL, DL ;compares value in bl to 0
JNE AGAIN ;loops delay until bl is 0
MOV AL, AH
OUT 61h, AL ;turns off tone with preserved contents from port 61h
CALL DELAY_TWO ;adds delay between notes
RET
TONE ENDP
DELAY PROC NEAR ;half second delay
PUSH AX ;preserve value in ax in stack
MOV CX, 33156 ;delays for half second
WAITF: NOP
IN AL, 61h ;read port 61
AND AL, 10h ;gives 0001 0000 check PB4
CMP AL, AH
JE WAITF ;jump to WAITF if AL is equal to AH
MOV AH, AL ;makes both AL and AH contain same number
LOOP WAITF ;continue until CX is 0
POP AX
RET
DELAY ENDP
DELAY_TWO PROC NEAR ;small delay between notes
PUSH AX ;need value in ax for TONE so save it
MOV CX, 331
WAITO: NOP
IN AL, 61h
AND AL, 10h
CMP AL, AH
JE WAITO
MOV AH, AL
LOOP WAITO
POP AX ;get back ax value once delay is done
RET
DELAY_TWO ENDP
cseg ends
end main ;Program exit point
我们只使用16位汇编。可能还有其他定时器和制作音调的方法,但我们必须这样做,使用程序中使用的端口。另外,我使用DOSBox来运行.exe,播放时听起来有点不对。
非常感谢任何帮助。