【汇编&硬件】声音输出中断的具体实现
前言
在8086汇编中,外接声音设备(如扬声器)的中断控制通常涉及对硬件端口的操作,结合中断处理实现声音的触发、频率控制等功能。8255芯片是8086机上的常见声音设备。以下是一个模拟外接声音设备中断的实现,支持设置频率、播放/停止声音,并通过中断响应外部触发信号。
代码实现
; 常量定义
SPEAKER_PORT equ 61h ; 扬声器控制端口(8255芯片A口)
TIMER_PORT equ 43h ; 定时器控制端口(8253芯片)
TIMER_CH2 equ 42h ; 定时器通道2端口(控制扬声器频率)
SOUND_ON equ 03h ; 扬声器开启掩码(bit0=1:定时器输出,bit1=1:扬声器开关)
SOUND_OFF equ 00h ; 扬声器关闭掩码
code segment
assume cs:code, ds:data
; 声音设备中断服务程序(入口:AH=功能号)
; 功能:
; AH=00h:设置声音频率(BX=频率值)
; AH=01h:开启声音(使用当前设置的频率)
; AH=02h:关闭声音
; AH=03h:响应外部触发(如按键触发声音,简化为播放固定频率)
sound_int proc far
push ax
push bx
push cx
push dx
push si
push di
push es
push ds ; 保存所有寄存器
push bp
mov bp, sp
; 根据功能号跳转处理
cmp ah, 00h
je set_freq ; 设置频率
cmp ah, 01h
je start_sound ; 开启声音
cmp ah, 02h
je stop_sound ; 关闭声音
cmp ah, 03h
je trigger_sound ; 外部触发声音
jmp int_end ; 不支持的功能
; 功能00h:设置声音频率
; 入口:BX=目标频率(Hz)
; 原理:通过8253定时器通道2设置频率,计算公式:计数初值=1193180/频率
set_freq:
cmp bx, 0
je int_end ; 频率为0则无效
; 计算定时器计数初值(1193180是8253定时器基准频率)
mov dx, 0
mov ax, 1193180
div bx ; AX=计数初值(1193180 / 频率)
; 向定时器写入控制字(通道2,模式3,二进制计数)
mov al, 10110110b ; 控制字:通道2,读写高8位+低8位,模式3,二进制
out TIMER_PORT, al
; 写入计数初值(先低8位,后高8位)
mov al, al ; AL=计数初值低8位
out TIMER_CH2, al
mov al, ah ; AL=计数初值高8位
out TIMER_CH2, al
; 保存当前频率
mov [current_freq], bx
jmp int_end
; 功能01h:开启声音
; 操作:通过扬声器端口开启输出(结合定时器信号)
start_sound:
in al, SPEAKER_PORT ; 读取当前扬声器状态
or al, SOUND_ON ; 开启扬声器(设置bit0和bit1)
out SPEAKER_PORT, al
mov [sound_state], 1 ; 标记声音为开启状态
jmp int_end
; 功能02h:关闭声音
; 操作:关闭扬声器端口输出
stop_sound:
in al, SPEAKER_PORT ; 读取当前扬声器状态
and al, not SOUND_ON ; 关闭扬声器(清除bit0和bit1)
out SPEAKER_PORT, al
mov [sound_state], 0 ; 标记声音为关闭状态
jmp int_end
; 功能03h:外部触发声音(如按键触发)
; 简化:播放固定频率(440Hz,A调)100ms后自动停止
trigger_sound:
; 设置固定频率440Hz
mov bx, 440
mov ah, 00h
call set_freq ; 调用内部功能设置频率
; 开启声音
mov ah, 01h
call start_sound ; 开启声音
; 延时约100ms(通过循环实现,8086约1MHz主频)
mov cx, 0Fh
mov dx, 4240h
delay:
dec dx
jnz delay
dec cx
jnz delay
; 关闭声音
mov ah, 02h
call stop_sound ; 关闭声音
jmp int_end
; 中断结束:恢复寄存器并返回
int_end:
pop bp
pop ds
pop es
pop di
pop si
pop dx
pop cx
pop bx
pop ax
iret ; 中断返回
sound_int endp
; 安装自定义声音设备中断向量(假设使用int 60h,用户自定义中断)
install proc
cli ; 关中断,防止安装过程被打断
mov ax, 0
mov es, ax ; ES指向中断向量表(0段)
mov di, 60h*4 ; int 60h向量地址:60h×4=0000:0180
mov ax, offset sound_int ; 中断服务程序偏移地址
stosw ; 写入偏移量到向量表
mov ax, cs ; 中断服务程序段地址(当前代码段)
stosw ; 写入段地址到向量表
sti ; 开中断
ret
install endp
; 主程序:安装中断并测试声音功能
main:
mov ax, data
mov ds, ax ; 初始化数据段
call install ; 安装自定义声音中断
; 测试1:设置频率并播放(500Hz,持续1秒)
mov ah, 00h
mov bx, 500
int 60h ; 调用中断设置频率
mov ah, 01h
int 60h ; 开启声音
; 延时约1秒
mov cx, 0FFh
mov dx, 0FFFFh
delay1:
dec dx
jnz delay1
dec cx
jnz delay1
mov ah, 02h
int 60h ; 关闭声音
; 测试2:等待外部触发(此处简化为循环等待,实际可结合键盘中断)
loop_wait:
; 检测按键(如按下任意键触发声音)
mov ah, 01h
int 16h ; 检查键盘缓冲区
jz loop_wait ; 无按键则继续等待
mov ah, 00h
int 16h ; 读取按键(清空缓冲区)
mov ah, 03h
int 60h ; 触发声音
jmp loop_wait ; 循环等待下一次触发
; 程序退出(实际中可通过特定按键退出)
exit:
mov ah, 4Ch
int 21h
code ends
; 数据段:保存声音状态和当前频率
data segment
current_freq dw 0 ; 当前设置的频率
sound_state db 0 ; 声音状态(0=关闭,1=开启)
data ends
end main代码说明
- 硬件交互基础:代码通过8253定时器(控制频率)和8255芯片(控制扬声器开关)实现声音输出。定时器通道2产生特定频率的方波,通过扬声器端口(61h)控制是否输出声音。
- 中断功能设计:a.支持设置频率(通过定时器计数初值计算)、开启/关闭声音(控制扬声器端口掩码)、外部触发(如按键触发固定频率声音)。b.频率计算公式为 计数初值 = 1193180 / 目标频率 (1193180是8086系统定时器的基准频率)。
- 中断安装:使用用户自定义中断号(int 60h),通过修改中断向量表(0段)将中断入口指向自定义服务程序,安装时关中断( cli )确保操作安全。
- 测试逻辑:主程序先测试固定频率播放,再通过键盘触发检测,按下任意键时播放预设频率的声音,演示中断的响应能力。