首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 組合語言

組合語言聲音編程經典:SOUND.ASM 八度音階播放實現

     編輯:組合語言

程序功能

SOUND.ASM 是一個極精簡的 DOS 組合語言程序,利用 PC 機 8253 定時器通道 2 和 8255 PPI 控制蜂鳴器,播放中音 C 起始的 12 半音 (一個八度)。代碼僅包含數據段 (頻率表) 和代碼段,無堆棧段,長度不足 100 行,是學習 PC 硬件定時器與聲音生成的絕佳入門樣本。

硬件原理回顧

  • 8253 定時器通道 2:輸入時鐘 1.19318 MHz,工作模式 3 (方波發生器)。計數值 = 1193180 / 目標頻率。
  • 8255 PPI Port B (61h):
    • Bit 0: 定時器 2 輸出使能 (接喇叭)
    • Bit 1: 喇叭控制位 (1=接通)
  • 喇叭聲音 = 定時器 2 方波與 Bit 1 邏輯 AND 後驅動揚聲器。

關鍵代碼段落解析

1. 數據段:音符頻率表

dseg segment
notes dw 262,277,294,311,330,349,370,392,415,440,466,494 ; C4~B4
dseg ends

2. 初始化 8253 命令字

mov al, 0b6h      ; 10110110b: Channel 2, Mode 3, Binary, LSB/MSB
out 43h, al       ; 寫命令寄存器

3. 主循環:逐音符播放

nloop:
 mov ax, 34dch        ; 1193180 (十進制) = 0x1234DC → 高位 0x12, 低位 0x34DC? 實際代碼用 34dch/12h 組合
 mov dx, 12h          ; DX:AX = 0x001234DC = 1193180
 div [notes + si]     ; AX = 1193180 / 頻率 = 計數值
 out 42h, al          ; 寫計數器低位
 mov al, ah
 out 42h, al          ; 寫計數器高位 (AH 為商高位)
; 開啟喇叭
 in al, 61h
 or al, 3             ; 置 Bit0, Bit1
 out 61h, al
; 延遲 ~1/10 秒
 mov cx, 6d60h
rpta: loop rpta
; 關閉喇叭
 xor al, 3            ; 清 Bit0, Bit1
 out 61h, al
; 音符間隙 ~1/100 秒
 mov cx, 0af0h
rptb: loop rptb
 inc si; inc si       ; SI += 2 (WORD)
 dec bx
 jnz nloop

4. 退出

mov ax, 4c00h
int 21h

技術細節補充

  • 除法運算:DIV 使用 DX:AX 作為被除數,此處 DX=0x12, AX=0x34DC 組成 32 位值 1193180。商在 AX,餘數在 DX。OUT 42h 連續兩次寫入低/高位。
  • 延遲迴圈:6D60h = 28000 次循環約 0.1 秒 (視 CPU 速度);0AF0h = 2800 約 0.01 秒。現代 CPU 需用 INT 15h/86h 或 RDTSC 校準。
  • 無堆棧段:COM 文件 CS=DS=SS=ES=PSP,SP=FFFEh,調用深度極淺可直接使用默認堆棧。
  • 頻率精度:表中頻率為等溫律近似值,實際計數值為整數會有微小誤差,音樂感知可接受。

完整源碼 (SOUND.ASM)

; sound.asm
; This is a small sound example for the IBM PC
; It will play 12 notes of the octave starting at middle C.
;-----------------------------------------------------------------------------
; How to generate sound on the IBM PC :
; The 8255 (port 61H) bit 0 controls the 8253 timer
; bit 1 controls the speaker
; The output channel 2 from the 8253 timer will be ANDed with the
; speaker control bit in order to turn on/off the speaker.
; Timer channel 2 internal count register (port 42h) is loaded in
; two successive OUT operations with the lower byte being loaded first.
; For this to work properly, timer command register has to be loaded first
; with B6H.
; Since the input clock to the timer chip is 1.19318 MHz, the counter value
; to generate the frequency X can be calculated by 1193180 / X.
;-----------------------------------------------------------------------------
; CX is used as a note counter with the frequency effectively being
; incremented by a half tone and the corresponding count being loaded
; into the count register on each iteration.
; No stack segment is needed for this small program, so don't panic
; when you receive the 'No stack segment' warning.
; Arne Asplem 880731 (MASM 4.0)
dseg segment
notes dw 262,277,294,311,330,349,370,392,415,440,466,494
dseg ends
cseg segment
sound proc far
 assume cs:cseg, ds:dseg, ss:nothing
start:
 mov ax, dseg
 mov ds, ax
 xor si, si
 mov bx, 12
 mov al, 0b6h
 out 43h, al
nloop:
 mov ax, 34dch
 mov dx, 12h
 div [notes + si]
 out 42h, al
 mov al, ah
 out 42h, al
 in al, 61h
 or al, 3
 out 61h, al
 mov cx, 6d60h
rpta:
 loop rpta
 xor al, 3
 out 61h, al
 mov cx, 0af0h
rptb:
 loop rptb
 inc si
 inc si
 dec bx
 jnz nloop
 mov ax, 4c00h
 int 21h
sound endp
cseg ends
end start

擴展思路

  1. 音樂播放器:解析文本樂譜 (如 ABC 記譜法),支持時值、休止符、多聲部。
  2. 精確定時:掛鉤 INT 1Ch (Timer Tick, 18.2Hz) 或使用 INT 15h/86h (微秒延遲) 替代軟件循環。
  3. 音量控制:通過 8253 模式 0 (單次脈衝) 調整占空比,或使用 PWM 技術 (需更高頻率中斷)。
  4. 現代移植:在裸機/嵌入式開發中,同樣適用於可編程定時器 + 蜂鳴器/無源蜂鳴器電路。

總結

SOUND.ASM 用最少代碼展示了 PC 機最基礎的聲音生成鏈路:定時器分頻 → 方波輸出 → PPI 閘控 → 揚聲器。它是理解 x86 實模式硬件編程、定時器編程、I/O 端口操作的經典教具。建議讀者在 DOSBox 或真實 DOS 環境中編譯運行,聽聽那熟悉的「蜂鳴器音樂」。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved