对照音符和发音频率(Hz)的对应关系,将曲谱翻译作程序中需要的数据,演奏出音乐来
低音符 频率 | 中音符 频率 | 高音符 频率 |
1 138 | 1 262 | 1 524 |
2 147 | 2 294 | 2 587 |
3 165 | 3 330 | 3 659 |
4 175 | 4 349 | 4 698 |
5 196 | 5 392 | 5 784 |
6 220 | 6 440 | 6 880 |
7 247 | 7 494 | 7 988 |
根据乐谱翻译得到的数据如下:
mus_freq dw 262,294,330,262
dw 262,294,330,262
dw 330,349,392
dw 330,349,392
dw 392,440,392,349,330,262
dw 392,440,392,349,330,262
dw 262,392,262
dw 262,392,262,-1
mus_time dw 2dup(25,25,25,25)
dw 2 dup (25,25,50)
dw 2 dup(18,6,18,6,25,25)
dw 2 dup(25,25,50)
把这段数据放到程序的数据段。
assume cs:codeseg, ds:dataseg, ss:stackseg
dataseg segment
mus_freq dw 262,294,330,262
dw 262,294,330,262
dw 330,349,392
dw 330,349,392
dw 392,440,392,349,330,262
dw 392,440,392,349,330,262
dw 262,392,262
dw 262,392,262,-1
mus_time dw 2dup(25,25,25,25)
dw 2 dup (25,25,50)
dw 2 dup(18,6,18,6,25,25)
dw 2 dup(25,25,50)
dataseg ends
stackseg segment
db 100h dup (0)
stackseg ends
codeseg segment
start:
mov ax, stackseg
mov ss, ax
mov sp, 100h
mov ax, dataseg
mov ds, ax
lea si, mus_freq
lea di, mus_time
play:
mov dx, [si]
cmp dx, -1
je end_play
call sound
add si, 2
add di, 2
jmp play
end_play:
mov ax, 4c00h
int 21h
;演奏一个音符
;入口参数:si - 要演奏的音符的频率的地址
; di - 要演奏的音符的音长的地址
sound:
push ax
push dx
push cx
;8253 芯片(定时/计数器)的设置
mov al,0b6h ;8253初始化
out 43h,al ;43H是8253芯片控制口的端口地址
mov dx,12h
mov ax,34dch
div word ptr [si] ;计算分频值,赋给ax。[si]中存放声音的频率值。
out 42h, al ;先送低8位到计数器,42h是8253芯片通道2的端口地址
mov al, ah
out 42h, al ;后送高8位计数器
;设置8255芯片, 控制扬声器的开/关
in al,61h ;读取8255 B端口原值
mov ah,al ;保存原值
or al,3 ;使低两位置1,以便打开开关
out 61h,al ;开扬声器, 发声
mov dx, [di] ;保持[di]时长
wait1:
mov cx, 28000
delay:
nop
loop delay
dec dx
jnz wait1
mov al, ah ;恢复扬声器端口原值
out 61h, al
pop cx
pop dx
pop ax
ret
codeseg ends
end start
不要悲伤,不要心急,忧郁的日子总会过去,把时间用在丰富自己的知识上,才是正事,加油!
——致悲伤的自己