惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - Franky
N
Netflix TechBlog - Medium
Google Online Security Blog
Google Online Security Blog
月光博客
月光博客
量子位
酷 壳 – CoolShell
酷 壳 – CoolShell
V
V2EX
腾讯CDC
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 聂微东
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
M
MIT News - Artificial intelligence
Vercel News
Vercel News
The GitHub Blog
The GitHub Blog
Hugging Face - Blog
Hugging Face - Blog
博客园 - 【当耐特】
Apple Machine Learning Research
Apple Machine Learning Research
aimingoo的专栏
aimingoo的专栏
博客园 - 三生石上(FineUI控件)
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
MongoDB | Blog
MongoDB | Blog
H
Help Net Security
The Cloudflare Blog
Blog — PlanetScale
Blog — PlanetScale
F
Full Disclosure
G
Google Developers Blog
罗磊的独立博客
Jina AI
Jina AI
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Y
Y Combinator Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
J
Java Code Geeks
A
About on SuperTechFans
IT之家
IT之家
大猫的无限游戏
大猫的无限游戏
S
SegmentFault 最新的问题
有赞技术团队
有赞技术团队
GbyAI
GbyAI
雷峰网
雷峰网
T
The Blog of Author Tim Ferriss
The Register - Security
The Register - Security
U
Unit 42
D
Docker
Martin Fowler
Martin Fowler
L
LINUX DO - 热门话题
NISL@THU
NISL@THU
阮一峰的网络日志
阮一峰的网络日志
C
Cybersecurity and Infrastructure Security Agency CISA
博客园_首页
Google DeepMind News
Google DeepMind News

faryou的博客

5月月考 - faryou的博客 - 日记 faryou的博客-五一回老家 【汇编 - 功能】中断安装中断实现 【汇编&硬件】时钟中断的具体实现 faryou的博客-这些年,我不再看《熊出没》 【汇编&硬件】关机中断的具体实现 【汇编&硬件】网络连接相关中断的具体实现 faryou的博客-年初小记 【汇编&硬件】鼠标控制中断的具体实现 【汇编&硬件】屏幕输出中断的具体实现 【汇编&硬件】磁盘读取中断的具体实现 【汇编&硬件】键盘读取中断的具体实现 【汇编】汇编环境的搭建及Debug的使用教程 【汇编】漫谈:学习汇编后的一些思考 faryou的博客-关于本站即日起实行“一站三体”运营制度 【汇编基础教程】完结篇 写在最后:前言 【汇编基础教程】使用BIOS的中断实现键盘输入及磁盘I/O 【汇编基础教程】中断 【汇编基础教程】端口 【汇编基础教程】标志寄存器 【汇编基础教程】再谈栈 【汇编基础教程】段 【汇编基础教程】来存一些数据! 【汇编基础教程】寄存器和内存&一些基本命令的说明 【汇编基础教程】来写个“函数” 【汇编基础教程】更灵活的定位内存 【汇编基础教程】理解一下[bx]和loop指令 【汇编基础教程】跳一跳! faryou的博客-我的竞赛经历&对人生的一些思考 faryou的博客-关于现在中小学计算机课的一些想法及思考 faryou的博客-2025年度总结 faryou的博客-临平山下十五年 faryou的博客-Windows 10即将停止支持,谈谈自己从小到大用电脑的感受 faryou的博客-谈谈一名10后的怀旧情怀 【汇编基础教程】8086CPU工作原理 【C语言】指针的理解与应用 【算法教程】【C/C++】DP(动态规划):区间DP——程序设计思路与代码实现 【算法教程】【C/C++】BFS(广度优先搜索)——程序设计思路与代码实现 【算法教程】【C/C++】DFS(深度优先搜索)——程序设计思路与代码实现 【算法教程】【C/C++】单源最短路径——程序设计思路与代码实现 【算法教程】【C/C++】最小生成树——程序设计思路与代码实现 【算法教程】【C/C++】并查集——程序设计思路与代码实现 【算法教程】【C/C++】DP(动态规划):背包DP——程序设计思路与代码实现 【算法教程】【C/C++】DP(动态规划):简单动规问题——程序设计思路与代码实现 【算法教程】【C/C++】递推——程序设计思路与代码实现 【算法教程】【C/C++】三分算法——程序设计思路与代码实现 【算法教程】【C/C++】二分答案——程序设计思路与代码实现 【算法教程】【C/C++】二分查找——程序设计思路与代码实现 【算法教程】【C/C++】贪心算法——程序设计思路与代码实现 【算法教程】【C/C++】基础数学:快排——程序设计思路与代码实现 【算法教程】【C/C++】基础数学:快速幂——程序设计思路与代码实现 【算法教程】【C/C++】基础数学:进制转换——程序设计思路与代码实现 一文弄懂C++中的自定义函数 faryou的博客-2024年度总结
【汇编&硬件】声音输出中断的具体实现
作者: faryou · 2026-03-07 · via faryou的博客

前言

在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. 测试逻辑:主程序先测试固定频率播放,再通过键盘触发检测,按下任意键时播放预设频率的声音,演示中断的响应能力。