原文:https://blog.csdn.net/xiaolanmyself/article/details/16927161

在介绍音乐的播放之前,先来说说如何用汇编发出声音,之后在介绍如何用发出有频率的声音。

喇叭的构造大致如下图所示,主要由纸盆、线圈、永久磁铁等组成。当有电流通过线圈时,线圈产生的磁场和永久磁铁的磁场相互作用,从而使线圈产生振动。和线圈相连的纸盆也随之移动,若通过线圈的电流时连续变化的,则线圈移动的幅度也会变化,从而牵动纸盆振动,产生声音。

那么PC机的小喇叭是怎样与机器相连的呢?图2-2表示了喇叭与机器简单的相连情况。喇叭的一端连接在电源正极,另一端与机器的61H端口的bit位相连。可以想象,若能连续改变61H端口的bit位0,1状态,就可以使喇叭线圈内的电流时有时无,从而使喇叭发声。我们编制的汇编程序的工作,就是连续改变61H端口的bit位状态。

上面介绍了通过端口61H的bit位发出声音的技术时遗留下一个问题,那就是如何精确的控制声音的频率。现在就解决这个问题。

早期的PC机有一个专门用于定时的电路,型号为8253/8254。它有三个通道,第一个通道用于控制始终正常运转;第二个通道用于存储器刷新;这两个通道与我们现在要讨论的问题无关。第三个就是一组电路域喇叭相连。

如下图所示就是PC机中完整的发声电路,定时器通道3的G端与61H端口的bit0位相连,如果把61H端口的bit0位置为1,那么定时器通道3就会被启动,此时将有一组信号从OUT输出,信号的频率可以用程序控制;若61H的端口bit0位为0,则定时器被关闭,out端就恒为1.

发声程序设计原理:

PC机发声系统以8254的2号计数器为核心。系统初始化时,2号计数器I作在“方波发生器”方式,初值为二进制数,,写入顺序为先低后高,CLK2为1.193182MHz,当计数初值为533H时,OUT2输出的方波大约为900Hz,经过简单的滤波之后,送至扬声器。改变1、4号计数器的计数初值就可以使扬声器发出不同频率的音响。

ROM BIOS 中有个BEEP子程序,这能根据BL中组出的时间计数值控制8254定时器,产生持续时间为1个或几个0.5秒,频率为896HZ的声音,我们可以利用并修改BEEP,使其产生任一频率的声音。为此我们需要做两点修改,首先,BEEP程序只能产生896HZ的声音,我们的通用发声程序应能产生任一频率的声音。其次,BEEP产生声音的持续时间(音长)只能是0.5秒的倍数,我们希望声音的持续时间更易于调整,例如可以是10ms的倍数。

我们知道BEEP能将计数值533H送给定时器2产生896HZ的声音的,那么产生其它频率声音的时间计数值应为:

533H×896÷给定频率=123280H÷给定频率

发声程序包括4个步骤:

(1)在8253中的42端口送一个控制字0B6H(10110110B),该控制字对定时器2进行初始化,使定时器2准备接收计数初值。

(2)在8253中的42H端口(Timer2)装入一个16位的计数值(533H×895/频率),以建立将要产生的声音频率。

(3)把输出端口61H的PB0、PB1两位置1,发出声音。

对于发音部分。PC机上的大多数输入/输出(I/O)都是由主板上的8255(或8255A)可编程序外围接口芯片(PPI)管理的。PPI包括3个8位寄存器,两个用于输入功能,一个用于输出功能。输入寄存器分配的I/O端口号为60H和62H,输出寄存器分配的I/O端口号为61H。由PPI输出寄存器中的0、1两位来选择扬声器的驱动方式。

(4)注意音乐节拍表的频率表的设定。一个频率对应一个节拍,如果频率表和节拍表有问题,同样不会发出声音。

对于发音部分。PC机上的大多数输入/输出(I/O)都是由主板上的8255(或8255A)可编程序外围接口芯片(PPI)管理的。PPI包括3个8位寄存器,两个用于输入功能,一个用于输出功能。输入寄存器分配的I/O端口号为60H和62H,输出寄存器分配的I/O端口号为61H。由PPI输出寄存器中的0、1两位来选择扬声器的驱动方式。连接到扬声器上的是定时器2,从上图可以看到,GATE2与端口61H的PB0相连,当PB0=1时,GATE2获得高电平,使定时器2可以在模式3(方波)下工作。定时器2的OUT2与端口61H的PB1通过一个与门与扬声器的驱动电路相连。当PB1=1时,允许OUT2的输出信号到达扬声器电路。因此,只有PB0和PB1同时为“1”时,才能驱动扬声器地声。通过以下指令实现:

IN AL,61H
OR AL,3
OUT 61H,AL 

上面的指令用以打开扬声器,如要关闭扬声器时则为:

AND AL,0FCH
OUT 61H,AL 

当从8255中采集到输入的数据时,需要确定相应的频率,所以在软件编程时要建立一个数据表:

TABLE DW 493,440,392,349,329,293,261 

把相应的频率送到一个寄存器上,通过公式:

计数值=533H×896÷ f=1234DCH÷ f

算出计数值,再把算得的计数值送给8253,就可产生所要频率的方波。在把计数值送8253前,必须先把8253进行初始化:

MOV AL,0B6H
OUT 43H,AL 

使其选用通道2,工作在方式3下。 就整个电路而言,接好电路后,通过软件编程不断地采集从8255口中输入的信号,而8个开关都接在8255的A口上,只要有开关按下,就会采集到一个数据,根据这个数据与事先编好的表对应,得到一个计数值,把这个计数值送给8253的通道2,8253的通道2工作的方式3下,这样就可以产生满足频率要求的发声方波。这个方波经驱动放大就可以使扬声器发出相应的声音。 所以8255在这里完成两个任务,它不仅从A口中采集到数据,而且B口的PB1和PB0两个位要控制发声。8253的主要任务就是产生所要求发声的不同频率的方波。

;定义数据段
data segmentinfor1 db 0Dh, 0AH, "welocom you to come here listeng! $"mus_freg  dw 330,294,262,294,3 dup (330)     ;频率表dw 3 dup (294),330,392,392dw 330,294,262,294,4 dup (330)dw 294,294,330,294,262,-1mus_time  dw 6 dup (25),50                   ;节拍表dw 2 dup (25,25,50)dw 12 dup (25),100
data ends;栈段定义
stack segment stackdb 200 dup(?)
stack ends;--------字符串输出宏----------
SHOWBM MACRO bLEA DX,bMOV AH,9INT 21HENDM;----------音乐地址宏-----------
ADDRESS MACRO A,BLEA SI,ALEA BP,DS:B
ENDM
;-------------------------------;代码段定义
code segmentassume ds:data, ss:stack, cs:code
start:mov ax, datamov ds, axmov ax, stackmov ss, axmov sp, 200address mus_freg, mus_timecall musicexit:     mov ah, 4cHint 21h;------------发声-------------
gensound proc nearpush axpush bxpush cxpush dxpush dimov al, 0b6Hout 43h, almov dx, 12hmov ax, 348chdiv diout 42h, almov al, ahout 42h, alin al, 61hmov ah, alor al, 3out 61h, al
wait1:mov cx, 3314call waitf
delay1:dec bxjnz wait1mov al, ahout 61h, alpop dipop dxpop cxpop bxpop axret
gensound endp;--------------------------
waitf proc nearpush ax
waitf1:in al,61hand al,10hcmp al,ahje waitf1mov ah,alloop waitf1pop axret
waitf endp
;--------------发声调用函数----------------
music proc nearxor ax, ax
freg:mov di, [si]cmp di, 0FFFFHje end_musmov bx, ds:[bp]call gensoundadd si, 2add bp, 2jmp freg
end_mus:ret
music endpcode endsend start

注意:在实现过程中可能会遇到这样的情况:你用的是DOSBOX虚拟机进行编程,然后进行测试之后,一切通过。但是移植到32位win7的虚拟8086就没有任何声音了。这是我亲身体会的经历。自己也不是很清楚这到底是问什么,会因为声卡的设计不一样?还是说不同的声卡有不同的控制方式?就是建议大家如果合作用汇编编写程序时,要注意平台的统一,不然会出现许多问题。(上面的程序实在DOSBOX中测试成功的~~)

ps:2013/11/27 :经过努力的调试和发现,结果找到了为什么在dosbox下可以发声在cmd中不能的原因。因为dosbox虚拟机的cpu频率比较小,所以可以一次顺利的读取到每个频率点,但是在windows xp下运行时,cpud的频率要比dosbox下的频率快的多,所以当读到第一个频率还没有来得及发声,有读到了下一个频率,以至于频率表已经不是一个完整的频率了,所以不能发声。所以如果要在windows xp下运行发声,必须给每一次读取频率的下一条语句添加一个延迟函数。

汇编语言(十四)8086汇编实现音乐的播放相关推荐

  1. 十四、汇编指令(存储、加法、减法、乘法、除法、跳转、子程序、if判断、中断)

    0. 存储指令 语法: mov 寄存器,寄存器 mov 寄存器,[偏移地址] mov [偏移地址],寄存器 mov ds:[偏移地址],寄存器 1. 加法指令 add 加法 语法: add 目的操作数 ...

  2. 李忠汇编语言-初学-第十四天

    学习目标 第十五章 学习小结 游戏不能入库的两个遗憾,已经达成了.虽然说,不用再在这里浪费时间了,可是自学真的很难,基础太差,耐心太差,加油吧!又荒废了一天 学习内容 类型:汇编语言 进度:初学 天数 ...

  3. 智能化软件开发微访谈·第二十四期 大模型时代的智能化软件生态(讨论汇编)...

    CodeWisdom "智能化软件开发沙龙是由CodeWisdom团队组织的围绕智能化软件开发.数据驱动的软件开发质量与效能分析.云原生与智能化运维等相关话题开展的线上沙龙,通过微信群访谈交 ...

  4. 8086汇编学习小记-王爽汇编语言实验12

    8086汇编学习小记-王爽汇编语言实验12 0号中断处理程序,开始安装在0000:0200处的程序最后用死循环导致显示不出'divided error',改成直接退出就正常显示了.注意修改ss,sp之 ...

  5. CYQ.Data 轻量数据层之路 使用篇-MAction 取值赋值 视频[带音乐] F (二十四)

    CYQ.Data 轻量数据层之路 使用篇-MAction 取值赋值 视频[带音乐] F (二十四) 说明: 本次录制主要为使用篇:CYQ.Data 轻量数据层之路 使用篇三曲 MAction 取值赋值 ...

  6. 【汇编语言】8086汇编,快速搞定各种寻址方式:立即数寻址 / 寄存器寻址 / 存储器寻址

    0 前言 众所周知,对于8086汇编语言,有几大寻址方式,不过我觉得这个好墨迹,会用就可以了,为什么命名这么多,这次只说本质,不说命名,至于命名,还是得知道,毕竟是大部分人公认的,不能反抗这点哦,但是 ...

  7. 【汇编语言】8086汇编字符串定义为何使用DB?其他数据类型不可以吗?(20200515复盘)

    目录 0 前言 0.1 先告诉你结论 1 8086汇编语言中的字符串 1.1 字符串的定义与使用 1.2 直接定义的细节 1.2.1 使用DB数据类型 1.2.2 使用其他数据类型 1.3 直接使用的 ...

  8. 8086汇编实验(十题可用)

    一.前言 1.这学期学8086汇编,所做的四次实验十个题目(前8手写,后2摘录后修改,时间久远未找到原文链接,愿理解),亲测可用,码住,希望能对将来的读者有所帮助. 2.有的需要在debug中根据段地 ...

  9. 《汇编语言》王爽(第四版) 第十四章 检测点及实验14

    文章目录 目录 前言 一.检测点 1.检测点14.1 (1)检测点14.1.(1) (2)检测点14.1.(2) 2.检测点14.2 (1)实验任务 (2)实现代码 二.实验14 访问CMOS RAM ...

最新文章

  1. Angular 变化检测详解
  2. Pci设备驱动:设备枚举
  3. 点云配准网络 PCRNet: Point Cloud Registration Network using PointNet Encoding 2019
  4. FindBugs工具常见问题
  5. mysql5.6 忘记root密码后,如何找回密码?
  6. 戴琼海:人工智能的几点思考
  7. RabbitMQ指南之二:工作队列(Work Queues)
  8. 微软下周将发布重磅安全公告 修复40个漏洞
  9. linux脚本ipddr.sh 是什么,MTK DDR调试
  10. 入门 | 从文本处理到自动驾驶:机器学习最常用的50大免费数据集
  11. winRAR 破解注册码
  12. QQ空间爬虫分享(2016年11月18日更新)
  13. 求素数 java 101 200_JAVA编程题2 101——200素数个数
  14. 服务器摆放需要预留U位么_让客厅大一倍的小户型沙发摆放技巧,赶快收藏好!
  15. ap导入 ebs oracle_Oracle EBS Interface/API(1)--AP Invoice费用报表类型导入
  16. 量化投资 -- 技术篇(6)投资组合策略性能评价(上)
  17. 拉格朗日Lagrange插值多项式
  18. gpedit.msc打不开的解决办法
  19. 网站安全狗安装时服务器名,解决网站安全狗安装后访问网站需要用户名密码的方法...
  20. OCR -上传图片 自动识别文字并填充

热门文章

  1. 原创|一气呵成|多组动图|揭秘仓储物流中的自动化包装技术
  2. 音视频行业不可或缺的功能-云端录制
  3. android seetaface6_中科视拓宣布开源SeetaFace6人脸识别算法(附相关课程)
  4. 食品安全培训PPT模板
  5. 风场仿真---随机风速仿真
  6. 十年了!曾经火爆的Lindows操作系统死灰复燃,还有人记得吗?
  7. 优化问题---凸优化基本概念
  8. 熊厂实习生招聘面试经验
  9. 有什么视频转文字软件?快把这些方法收好
  10. 精益思想Lean thinking