2026年3月

前言

在8086汇编环境中,直接实现关机功能通常依赖硬件支持(如ATX电源的控制端口),且不同系统的实现方式存在差异。以下是一个基于ATX电源控制逻辑的关机中断模拟实现,通过操作特定端口发送关机命令,实际使用需结合硬件环境。

代码实现

; 常量定义(ATX电源相关端口和命令)
POWER_CTRL_PORT equ 0604h ; 假设的电源控制端口(不同硬件可能不同)
SHUTDOWN_CMD equ 0FEh ; 关机命令(ATX电源通常使用特定命令码)
WAIT_LOOP_COUNT equ 10000 ; 等待硬件响应的循环次数
 
code segment
    assume cs:code, ds:data
 
; 关机中断服务程序(入口:AH=00h表示执行关机)
; 功能:向电源控制端口发送关机命令,等待硬件响应
shutdown_int proc far
    push ax
    push bx
    push cx
    push dx
    push si
    push di
    push es
    push ds ; 保存所有寄存器
 
    ; 仅处理AH=00h的关机命令
    cmp ah, 00h
    jne int_end
 
    ; 步骤1:发送关机命令到电源控制端口
    mov dx, POWER_CTRL_PORT
    mov al, SHUTDOWN_CMD
    out dx, al ; 向硬件发送关机指令
 
    ; 步骤2:等待硬件响应(循环延迟,确保命令被接收)
    mov cx, WAIT_LOOP_COUNT
wait_shutdown:
    loop wait_shutdown ; 空循环等待
 
    ; 步骤3:若支持,可检测电源状态(此处简化,不处理反馈)
 
int_end:
    pop ds
    pop es
    pop di
    pop si
    pop dx
    pop cx
    pop bx
    pop ax
    iret ; 中断返回
shutdown_int endp
 
; 安装关机中断到int 63h(用户自定义中断号)
install proc
    cli ; 关中断,防止安装过程被打断
    mov ax, 0
    mov es, ax ; ES指向中断向量表(0段)
    mov di, 63h * 4 ; int 63h的向量地址:63h×4=0000:018C
    ; 保存原中断向量(用于恢复)
    mov ax, es:[di]
    mov [orig_63h_off], ax
    mov ax, es:[di + 2]
    mov [orig_63h_seg], ax
    ; 写入自定义关机中断的地址
    mov ax, offset shutdown_int
    stosw ; 写入偏移量
    mov ax, cs
    stosw ; 写入段地址
    sti ; 开中断
    ret
install endp
 
; 恢复原始中断向量(程序退出时调用)
restore proc
    cli
    mov ax, 0
    mov es, ax
    mov di, 63h * 4
    ; 恢复原中断向量
    mov ax, [orig_63h_off]
    stosw
    mov ax, [orig_63h_seg]
    stosw
    sti
    ret
restore proc
 
; 主程序:测试关机中断
main:
    mov ax, data
    mov ds, ax ; 初始化数据段
 
    call install ; 安装关机中断
 
    ; 测试:调用关机中断(实际使用时需谨慎!)
    mov ah, 00h ; 功能:执行关机
    int 63h ; 触发关机中断
 
    ; 若关机失败,恢复中断并退出(仅作演示)
    call restore
    mov ah, 4Ch
    int 21h
 
code ends
 
; 数据段:保存原始中断向量
data segment
    orig_63h_off dw 0 ; int 63h原始偏移量
    orig_63h_seg dw 0 ; int 63h原始段地址
data ends
 
    end main

代码说明

  1. 硬件交互逻辑:代码假设系统使用ATX电源,通过特定控制端口(0604h,实际需根据硬件手册修改)发送关机命令(0FEh)。ATX电源通常支持通过端口命令触发关机,具体端口和命令码需参考硬件文档。
  2. 中断功能设计:a.自定义int 63h作为关机中断,仅响应AH=00h的功能调用,执行以下操作:- 向电源控制端口发送关机命令;b.循环延迟等待硬件处理命令(避免命令未被接收)。
  3. 中断安装与恢复:b.安装时将自定义中断服务程序地址写入int 63h的向量表,并保存原始向量;b.程序退出前恢复原始向量,避免影响系统默认中断处理。
  4. 注意事项:a.实际关机端口和命令因硬件而异(如某些系统使用0x60/0x64端口或ACPI协议),需根据具体环境调整;b.现代操作系统(如Windows/Linux)在保护模式下禁止直接端口操作,此代码仅适用于实模式环境(如DOS)。

前言

在8086汇编环境中,网络连接功能通常依赖硬件(如网卡)和底层协议(如TCP/IP简化版),且8086本身无原生网络支持,需通过外接网卡及端口操作实现。以下是一个模拟网络连接中断的简化实现,包含基本的连接建立、数据发送/接收功能,基于假设的网卡端口和简化协议,供学习参考。

代码实现

; 常量定义(假设的网卡端口和状态码)
NET_CTRL_PORT equ 0300h ; 网卡控制端口
NET_DATA_PORT equ 0301h ; 网卡数据端口
NET_STATUS_PORT equ 0302h ; 网卡状态端口
NET_CONNECTED equ 01h ; 连接成功状态
NET_DISCONNECTED equ 00h ; 断开状态
NET_DATA_READY equ 02h ; 数据就绪状态
 
code segment
    assume cs:code, ds:data
 
; 网络连接中断服务程序(入口:AH=功能号)
; 功能:
; AH=00h:建立网络连接(DX=目标IP地址低16位,CX=目标端口)
; AH=01h:断开网络连接
; AH=02h:发送数据(SI=数据缓冲区地址,CX=数据长度)
; AH=03h:接收数据(DI=接收缓冲区地址,CX=最大接收长度,返回CX=实际长度)
; AH=04h:获取连接状态(返回AL=状态:0=断开,1=连接)
net_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 net_connect ; 建立连接
    cmp ah, 01h
    je net_disconnect ; 断开连接
    cmp ah, 02h
    je net_send ; 发送数据
    cmp ah, 03h
    je net_recv ; 接收数据
    cmp ah, 04h
    je net_get_status ; 获取状态
    jmp int_end ; 不支持的功能
 
; 功能00h:建立网络连接
; 入口:DX=目标IP(低16位),CX=目标端口
; 原理:向网卡发送连接请求,等待响应
net_connect:
    ; 保存目标IP和端口
    mov [dest_ip], dx
    mov [dest_port], cx
 
    ; 向网卡控制端口发送连接命令(假设命令01h)
    mov al, 01h
    out NET_CTRL_PORT, al
 
    ; 等待网卡响应(轮询状态端口)
    mov cx, 0FFFFh ; 超时计数
wait_connect:
    in al, NET_STATUS_PORT
    test al, NET_CONNECTED
    jnz connect_ok ; 连接成功
    loop wait_connect
    jmp int_end ; 超时失败
 
connect_ok:
    mov [net_state], NET_CONNECTED ; 更新状态为连接
    jmp int_end
 
; 功能01h:断开网络连接
; 操作:发送断开命令,重置连接状态
net_disconnect:
    mov al, 02h ; 断开命令(假设02h)
    out NET_CTRL_PORT, al
    mov [net_state], NET_DISCONNECTED ; 更新状态为断开
    jmp int_end
  
; 功能02h:发送数据
; 入口:SI=数据缓冲区,CX=数据长度(<=255)
; 操作:逐个字节写入数据端口
net_send:
    cmp [net_state], NET_CONNECTED
    jne int_end ; 未连接则退出
 
    mov bl, cl ; BL保存长度
    mov bh, 0
    mov si, si ; SI指向数据
 
send_loop:
    mov al, [si] ; 读取数据字节
    out NET_DATA_PORT, al ; 写入网卡
    inc si
    dec bl
    jnz send_loop
    jmp int_end
 
; 功能03h:接收数据
; 入口:DI=接收缓冲区,CX=最大长度;返回:CX=实际接收长度
; 操作:从数据端口读取可用数据
net_recv:
    cmp [net_state], NET_CONNECTED
    jne int_end ; 未连接则退出
 
    in al, NET_STATUS_PORT
    test al, NET_DATA_READY
    jz recv_end ; 无数据则退出
 
    mov bl, 0 ; BL计数实际长度
recv_loop:
    in al, NET_DATA_PORT ; 从网卡读取数据
    mov [di], al
    inc di
    inc bl
    dec cx
    jz recv_end ; 达到最大长度
    ; 检查是否还有数据(简化:假设一次读完)
    in al, NET_STATUS_PORT
    test al, NET_DATA_READY
    jnz recv_loop
 
recv_end:
    mov cx, bx ; 返回实际接收长度
    jmp int_end
 
; 功能04h:获取连接状态
; 返回:AL=当前状态(0=断开,1=连接)
net_get_status:
    mov al, [net_state]
    jmp int_end
 
; 中断结束:恢复寄存器并返回
int_end:
    pop bp
    pop ds
    pop es
    pop di
    pop si
    pop dx
    pop cx
    pop bx
    pop ax
    iret ; 中断返回
net_int endp
 
; 安装自定义网络中断向量(使用int 61h,用户自定义中断)
install proc
    cli ; 关中断,防止安装冲突
    mov ax, 0
    mov es, ax ; ES指向中断向量表(0段)
    mov di, 61h*4 ; int 61h向量地址:61h×4=0000:0184
    mov ax, offset net_int ; 中断服务程序偏移地址
    stosw ; 写入偏移量
    mov ax, cs ; 中断服务程序段地址
    stosw ; 写入段地址
    sti ; 开中断
    ret
install endp
 
; 主程序:测试网络连接功能
main:
    mov ax, data
    mov ds, ax ; 初始化数据段
 
    call install ; 安装网络中断
 
    ; 测试1:建立连接(目标IP=0A0A0A0A(模拟10.10.10.10),端口=80)
    mov ah, 00h
    mov dx, 0A0A0h ; IP低16位(0A0A)
    mov cx, 80 ; 端口80
    int 61h
 
    ; 测试2:发送数据("Hello")
    mov ah, 02h
    mov si, offset send_buf
    mov cx, 5 ; 长度5
    int 61h
 
    ; 测试3:接收数据(最多10字节)
    mov ah, 03h
    mov di, offset recv_buf
    mov cx, 10
    int 61h ; 返回CX=实际长度
 
    ; 测试4:获取状态并显示(简化:通过字符表示)
    mov ah, 04h
    int 61h
    cmp al, NET_CONNECTED
    jne show_disconnected
    ; 连接成功,显示'C'
    mov ah, 09h
    mov al, 'C'
    mov bl, 07h
    mov cx, 1
    int 10h
    jmp end_test
show_disconnected:
    ; 断开,显示'D'
    mov ah, 09h
    mov al, 'D'
    mov bl, 07h
    mov cx, 1
    int 10h
 
end_test:
    ; 断开连接
    mov ah, 01h
    int 61h
 
    jmp $ ; 暂停
 
code ends
 
; 数据段:保存网络状态和缓冲区
data segment
    net_state db NET_DISCONNECTED ; 网络状态(0=断开,1=连接)
    dest_ip dw 0 ; 目标IP地址(低16位)
    dest_port dw 0 ; 目标端口
    send_buf db 'Hello' ; 发送缓冲区
    recv_buf db 10 dup(0) ; 接收缓冲区(最大10字节)
data ends
 
    end main

代码说明

  1. 硬件抽象:假设网卡通过3个端口(控制、数据、状态)与CPU通信,定义了连接、断开等命令及状态码,模拟真实网卡的交互逻辑。
  2. 中断功能:实现了网络连接的核心操作:a.建立/断开连接:通过控制端口发送命令,轮询状态判断结果。b.发送/接收数据:通过数据端口读写字节,限制长度以简化处理。c.状态查询:返回当前连接状态(连接/断开)。
  3. 中断安装:使用用户自定义中断号(int 61h),修改中断向量表指向自定义服务程序,安装时关中断保证原子性。
  4. 测试逻辑:主程序依次测试连接建立、数据发送、接收及状态查询,并通过屏幕显示状态('C'表示连接,'D'表示断开)。

前言

在8086汇编中,鼠标中断通常通过int 33h(鼠标BIOS中断)实现,其功能包括初始化鼠标、获取鼠标位置、处理按键等。下面我们学习一个模拟int 33h核心功能的自定义鼠标中断程序,支持鼠标初始化、位置获取、按键检测。

代码实现

; 常量定义
MOUSE_DATA_PORT equ 03f8h ; 鼠标数据端口(COM1)
MOUSE_CTRL_PORT equ 03f9h ; 鼠标控制端口
MOUSE_PACKET_LEN equ 3 ; 鼠标数据包长度(3字节)
 
code segment
    assume cs:code, ds:data
 
; 自定义鼠标中断服务程序(入口:AX=功能号)
; 功能:
; AX=0000h:初始化鼠标(返回BX=0表示成功)
; AX=0003h:获取鼠标状态(BX=按键状态,CX=X偏移,DX=Y偏移)
; AX=000Bh:设置鼠标显示(CX=X坐标,DX=Y坐标,显示鼠标指针)
mouse_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 ax, 0000h
    je mouse_init ; 初始化鼠标
    cmp ax, 0003h
    je get_status ; 获取鼠标状态
    cmp ax, 000Bh
    je show_cursor ; 显示鼠标指针
    jmp int_end ; 不支持的功能
 
; 功能0000h:初始化鼠标
; 返回:BX=0(成功),BX≠0(失败)
mouse_init:
    ; 向鼠标控制器发送初始化命令(实际硬件需按协议操作)
    mov dx, MOUSE_CTRL_PORT
    mov al, 0Ah ; 复位命令
    out dx, al
 
    ; 等待鼠标响应(简化:假设初始化成功)
    mov bx, 0 ; BX=0表示成功
    mov [mouse_ready], 1 ; 标记鼠标就绪
    jmp int_end
 
; 功能0003h:获取鼠标状态
; 返回:BX=按键状态(bit0=左键,bit1=右键),CX=X偏移,DX=Y偏移
get_status:
    cmp [mouse_ready], 0
    je int_end ; 鼠标未初始化,直接返回
 
    ; 读取鼠标数据包(3字节:状态字节+X偏移+Y偏移)
    mov si, offset mouse_packet ; SI指向数据包缓冲区
    mov cx, MOUSE_PACKET_LEN
read_packet:
    mov dx, MOUSE_DATA_PORT
    in al, dx ; 从数据端口读取1字节
    mov [si], al
    inc si
    loop read_packet
 
    ; 解析数据包:第1字节=状态,第2字节=X偏移,第3字节=Y偏移
    mov al, [mouse_packet] ; 状态字节
    mov bl, 0
    test al, 01h ; 检测左键(bit0=1表示按下)
    jz no_left
    or bl, 01h
no_left:
    test al, 02h ; 检测右键(bit1=1表示按下)
    jz no_right
    or bl, 02h
no_right:
    mov bx, bl ; BX=按键状态
 
    mov cl, [mouse_packet+1] ; CX=X偏移
    mov ch, 0
    mov cx, cx
 
    mov dl, [mouse_packet+2] ; DX=Y偏移(注意Y方向通常与屏幕相反)
    mov dh, 0
    neg dx ; 反转Y偏移(适应屏幕坐标系)
    jmp int_end
 
; 功能000Bh:显示鼠标指针(简化为在指定位置画字符)
; 入口:CX=X坐标,DX=Y坐标
show_cursor:
    ; 保存当前光标位置
    push dx
    push cx
 
    ; 转换坐标为文本模式行列(假设80x25文本模式,每个字符8x16像素)
    mov ax, dx ; AX=Y坐标
    mov bl, 16
    div bl ; AL=行号(Y/16)
    mov dh, al
 
    mov ax, cx ; AX=X坐标
    mov bl, 8
    div bl ; AL=列号(X/8)
    mov dl, al
 
    ; 在计算出的行列位置显示鼠标指针(用'#'表示)
    mov ah, 02h ; 设置光标位置
    int 10h
    mov ah, 09h ; 显示字符
    mov al, '#'
    mov bl, 0Ch ; 红色属性
    mov cx, 1
    int 10h
 
    ; 恢复光标位置
    pop cx
    pop dx
    jmp int_end
 
; 中断结束:恢复寄存器并返回
int_end:
    pop bp
    pop ds
    pop es
    pop di
    pop si
    pop dx
    pop cx
    pop bx
    pop ax
    iret ; 中断返回
mouse_int endp
 
; 安装自定义鼠标中断向量(替换int 33h)
install proc
    cli ; 关中断
    mov ax, 0
    mov es, ax ; ES指向中断向量表(0段)
    mov di, 33h*4 ; int 33h向量地址:33h×4=0000:00D4
    mov ax, offset mouse_int ; 中断服务程序偏移
    stosw
    mov ax, cs ; 中断服务程序段地址
    stosw
    sti ; 开中断
    ret
install endp
 
; 主程序:初始化并测试鼠标中断
main:
    mov ax, data
    mov ds, ax ; 初始化数据段
 
    call install ; 安装自定义鼠标中断
 
    ; 测试1:初始化鼠标
    mov ax, 0000h
    int 33h ; 调用自定义中断
    cmp bx, 0
    jne exit ; 初始化失败则退出
 
    ; 测试2:循环获取鼠标状态并更新指针
loop_test:
    mov ax, 0003h ; 获取鼠标状态
    int 33h
    ; BX=按键状态,CX=X偏移,DX=Y偏移
 
    ; 更新鼠标绝对坐标(累加偏移)
    add [mouse_x], cx
    add [mouse_y], dx
 
    ; 限制坐标在屏幕范围内(320x200为例)
    cmp [mouse_x], 320
    jl x_ok
    mov [mouse_x], 320
x_ok:
    cmp [mouse_x], 0
    jge y_ok
    mov [mouse_x], 0
y_ok:
    cmp [mouse_y], 200
    jl y_ok2
    mov [mouse_y], 200
y_ok2:
    cmp [mouse_y], 0
    jge show
    mov [mouse_y], 0
 
show:
    ; 显示鼠标指针
    mov ax, 000Bh
    mov cx, [mouse_x] ; X坐标
    mov dx, [mouse_y] ; Y坐标
    int 33h
 
    ; 检测左键按下,按左键退出
    test bx, 01h
    jz loop_test
exit:
    mov ah, 4Ch
    int 21h ; 程序退出
 
code ends
 
; 数据段:保存鼠标状态和缓冲区
data segment
    mouse_ready db 0 ; 鼠标就绪标记(1=就绪)
    mouse_packet db 3 dup(0) ; 鼠标数据包缓冲区(3字节)
    mouse_x dw 160 ; 鼠标X坐标(初始中心)
    mouse_y dw 100 ; 鼠标Y坐标(初始中心)
data ends
 
    end main

代码说明

  1. 中断功能设计:模拟int 33h的核心功能,包括鼠标初始化(检测鼠标是否存在)、状态获取(按键和移动偏移)、指针显示(在指定坐标画字符模拟指针)。
  2. 鼠标数据处理:a.鼠标通过串行端口(如COM1,端口03f8h)通信,数据包为3字节(状态字节+X偏移+Y偏移)。b.状态字节的bit0表示左键按下,bit1表示右键按下;X/Y偏移表示相对移动量。
  3. 指针显示:简化为在文本模式下,将鼠标坐标转换为行列位置,显示字符 # 作为指针(实际图形模式需绘制鼠标形状)。
  4. 中断安装:修改中断向量表中int 33h的入口地址,指向自定义服务程序,安装时关中断以避免冲突。

前言

在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

代码说明

  1. 硬件交互基础:代码通过8253定时器(控制频率)和8255芯片(控制扬声器开关)实现声音输出。定时器通道2产生特定频率的方波,通过扬声器端口(61h)控制是否输出声音。
  2. 中断功能设计:a.支持设置频率(通过定时器计数初值计算)、开启/关闭声音(控制扬声器端口掩码)、外部触发(如按键触发固定频率声音)。b.频率计算公式为 计数初值 = 1193180 / 目标频率 (1193180是8086系统定时器的基准频率)。
  3. 中断安装:使用用户自定义中断号(int 60h),通过修改中断向量表(0段)将中断入口指向自定义服务程序,安装时关中断( cli )确保操作安全。
  4. 测试逻辑:主程序先测试固定频率播放,再通过键盘触发检测,按下任意键时播放预设频率的声音,演示中断的响应能力。