问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

汇编语言 音乐动画程序设计(急用)

发布网友 发布时间:2022-05-18 23:25

我来回答

1个回答

热心网友 时间:2023-11-20 05:58

早期的PC系列机中有一个专门用于定时的集成电路,型号是8253/8254。它有三个通道,第一个通道用于控制系统时钟正常运转;第二个通道用于存储器刷新;这两个通道与我们现在讨论的问题无关。第三个通道是最有意思的,它通过一组电路与喇叭相联。
图4-1所示即为PC机中完整的发声电路。定时器通道3的G端与61H端口的bit0位相联,如果将61H端口的bit0位置成1,那么定时器通道3就被启动,此时将有一组信号从OUT端输出,信号的频率可以用程序控制;若61H端口bit0位为0,则定时器被关闭,OUT端就会恒定为1

此电路用在这里相当一个"可控开关",如果将61H端口的bit0、bit1位都置成1,则相当于既打开了定时器又打开了开关,这时候定时器产生的声音信号就会送到放大器推动喇叭发声;若将bit0位置0,则定时器关闭,此时OUT端为1,这时候如果连续改变bit1位的状态,也可以从喇叭中听到声音,这就是我们在第二章中所用的方法;若将bit1位置0,则开关关闭,此时即使打开定时器也不能听到声音。
这一点可以通过DEBUG加以验证:进入DEBUG,在"-"后打入"O61 3",即可听到喇叭发出连续的叫声。(在纯DOS下实验)
向61H端口输出"03",相当于打开定时器和开关,此时将有连续的声音发出,这个声音的频率约是896Hz,和我们刚开机时听到的蜂鸣音频率一样。
有趣的是声音一旦发出就不会停止,而且不干扰用户的任何操作。
停止这种声音的唯一方法就是进入DEBUG,打入命令"O61 0(也可以是1或2)"。之所以有这种现象是因为定时器的工作并不需CPU直接参与,CPU只要给定时设定好工作状态和频率值并打开定时器,此时定时器就会自主工作,CPU即可去做别的事情。这个特性十分有用,它是实现"背景音乐"的前提。
那么如何改变声音的频率呢?请注意定时器的通道3还有一个输入端CLK,这一端输入了一个固定的信号,频率是1193181.6Hz。输出信号与此信号具有如下关系:

--------------------------------------------------------------------------------
F(OUT)=F(CLK)/N
--------------------------------------------------------------------------------

其中N是一个16bit数据,它的值可以由程序设定。方法很简单:将此16位数据分成高、低两个8位,先把低8位送至42H端口,紧接着再把高8位送至42H端口,输出信号的频率就会改变。我们可以试一下:
C:\ASM\>DEBUG[Enter]
-O61 3[Enter]
-O42 0[Enter]
-O42 3[Enter]
设定新的N值是300H,对应的F(OUT)是1193191.6/300H=1553Hz。声音马上变尖了。
有一点必须说明,定时器具有多种工作状态,并非每种工作状态都能产生声音,所以当我们想通过定时器产生声音时,我们应首先"初始化"定时器,为其建立正确的工作状态。初始化定时器并不复杂,向端口43H输出数据0B6H即可。这个数据的二进制形式是10110110,有些书籍把这个数称为"幻数"(MAGIC BYTE)。

有了上面介绍的这些知识,我们就可以编程控制定时器发出给定频率的声音。程序PROG6可以使喇叭发出1000Hz的声音
------------------------------------------------
0A3E:0100 MOV AL,B6 ;AL寄存器装入定时器初始化设置码
0A3E:0102 OUT 43,AL ;将设置码输出到43H端口 初始化
0A3E:0104 MOV AX,04A9 ;1193181.6Hz/1000=1193hz =04A9 hexadecimal AX寄存器置入N值
0A3E:0107 OUT 42,AL ;将N值分两次输出到42H端口 因为是8位
0A3E:0109 MOV AL,AH
0A3E:010B OUT 42,AL
0A3E:010D IN AL,61 ;取得61H端口的当前状态
0A3E:010F PUSH AX ;入栈
0A3E:0110 OR AL,03 ;0111
0A3E:0112 OUT 61,AL ;打开定时器及电子开关
0A3E:0114 MOV AH,01 ;AH = 01h Return: AL = character read 等待输入
;character is echoed to standard output(回显)
0A3E:0116 INT 21
0A3E:0118 POP AX ;恢复61H
0A3E:0119 OUT 61,AL
0A3E:011B RET
0A3E:011C
我们已经讨论了如何通过定时器的通道3发出确定频率的声音,这一节我们要一起学习怎样精确地定时,这样才能解决演奏音乐的问题。
PC中的定时电路有三个通道,通道3用于发声,通道1用于控制系统内部的时钟。大家都十分清楚用DOS的"TIME"命令可以观察并修改系统内部的一个时钟,这个时钟之所以能连续运转主要依靠定时器的通道1。
通道1的工作方式和通道3一样,但是系统启动时设定其发出一个频率固定为18.2Hz的信号,这个信号直接送到系统中的"中断控制器"。每一个"Hz"都产生一个硬件中断,一般称这个硬中断为"IRQ0",对应的中断号是08H。也就是说,当计算机启动后,我们的机器看上去十分平静,但实际上CPU非常忙碌。在定时器的控制下每隔55毫秒就要执行一个08H号中断,这个中断的主要工作就是连续地计数。
在内存"0040H:006CH"处有四字节的存储空间专门用于保存计数值,CPU每执行一次08H中断,这四字节的计数值就被加1,不难算出这个计数值每增加1091后时间恰好过了1分钟,每增加65454后时间恰好过了1小时。系统内部的时钟之所以能准确走时,靠得就是08H中断和这四字节的计数值。因此我们要想精确的定时,必须依靠时钟计数值才行
;---一个能准确发出1000Hz声音的程序,声音持续时间为5秒钟---------------
PORTB equ 61H
code segment
assume cs:code,ds:code
org 100h
main proc near
mov al,10110110b ;初始化定时器
out 43h,al
mov ax,4a9h ;设置N值为04A9H
out 42h,al
mov al,ah
out 42h,al
in al,PORT_B ;打开定时器及与门
or al,3
out PORT_B,al
;------------------以下为定时部分---------------

mov ah,0 ;选择1AH中断的0号功能
int 1ah ;调用1AH中断取得当前时钟计数
add dx,91 ;在当前时钟计数上加91---5秒
mov bx,dx ;保存定时终了时的计数值
delay: int 1ah ;两次调用1AH中断取得时钟计数值
cmp dx,bx ;到达定时终了时的计数值了吗?
jne delay ; 没有到达,则返回DELAY处继续
;----------------------------------------------------
in al,PORT_B ;定时终止,关闭定时器及与门
and al,0fch ;1111 1100
out PORT_B,al
int 20h ;结束程序
main endp
code ends
参考资料:PC机汇编语言实践精解/李春生编著。
data segment
freq dw 196,220
dw 262,262,262,262,262,220,196
dw 262,262,262,262,294,262,220,262
dw 294,294,294,294,294,262,220
dw 294,294,294,294,330,294,330,392
dw 440,440,392,440,392,330
dw 294,294,330,294,262,220,196,220
dw 262,262,262,262,262,220
dw 262,196,220
dw 440,440,392,440,524,440
dw 392,330,294,262,220,196,220
dw 262,262,262,262,294,262
dw 262,330,392
dw 440,440,440,440,524,440
dw 392,392,392,440,392,330,294
dw 262,262,262,262,294
dw 330,330,294
dw 262,262,262,262,524,440
dw 392,392,392,440,392,330,392
dw 440,524,524,440,392
dw 392,330,392
dw 440,440,440,440,524,440
dw 392,392,392,440,392,330,294
dw 262,262,262,262,392
dw 330,330,294
dw 262,262,262,262,294,330
dw 392,392,330,392,330,392
dw 440
dw 9,9,196,660,294,294,262
dw 262,-1

time dw 400,400
dw 400,200,400,400,800,400,400
dw 400,200,400,200,200,800,400,400
dw 400,200,400,400,800,400,400
dw 400,200,400,200,200,800,400,400
dw 400,800,400,800,400,400
dw 400,200,200,400,400,800,400,400
dw 400,200,400,400,800,800
dw 1600,800,800
dw 400,800,400,800,400,400
dw 400,400,400,400,800,400,400
dw 400,800,400,800,400,200
dw 2400,400,400
dw 400,800,400,800,400,400
dw 400,800,200,200,800,400,400
dw 400,800,400,800,800
dw 2400,400,400
dw 400,800,400,800,400,400
dw 400,800,200,200,800,400,400
dw 800,400,800,400,200
dw 2400,400,400
dw 400,800,400,800,400,400
dw 400,800,200,200,800,400,400
dw 400,800,400,800,800
dw 2400,400,400
dw 400,800,400,800,400,400
dw 400,800,400,800,400,400
dw 3200
dw 800,400,400,400,400,400,400
dw 4000
data ends

code segment
assume cs:code,ds:data
main proc far
start:mov ax,data
mov ds,ax
mov si,offset freq
mov di,offset time
l1: mov cx,[si]
cmp cx,-1
je exit
mov bx,[di]
call gensound
add si,2
add di,2
jmp l1
exit:mov ax,4c00h
int 21h
main endp

gensound proc near
push dx
mov al,0b6h
out 43h,al
mov dx,08h
mov ax,3208h
div cx
out 42h,al
mov al,ah
out 42h,al
in al,61h
mov ah,al
or al,3
out 61h,al
l2: push dx
push ax
mov dx,8h
mov ax,0f05h
s1: sub ax,1
sbb dx,0
jnz s1
pop ax
pop dx
dec bx
jnz l2

mov al,ah
out 61h,al
pop dx
ret
gensound endp
code ends
end start
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
我爱我校征文800字 建行聚财宝少一万时5小时内补上会怎样 咪哩乡文化教育 咪哩乡基础设施 咪哩村云南省玉溪市元江县咪哩乡咪哩村 咪哩乡历史文化 元江咪哩中心小学怎么样? 原神 原神胡桃进阶材料是什么? 原神 原神呢胡桃材料有哪些? 原神 原神胡桃的突破材料是什么? IBM PC汇编语言题 求IBM PC汇编语言程序设计的答案 (第二版) (清华大学出版社) 谁有IBM-PC汇编语言程序设计(第2版)-沈美明-清华大学出版社 的课件? 上海移动套餐,谢谢大家帮忙推荐个适合自己的 急求《IBM-PC汇编语言程序设计》(沈美明,温冬婵)第一版书源,电子版或者购买渠道 求《IBM-PC汇编语言程序设计》电子书下载 谢谢 <IBM-PC汇编语言程序设计>这本书有几个版本,哪个版的比较好?谢谢 英语必修四单词表? 谁知道《微机原理与接*术》和《计算机组成原理》和《IBM—PC汇编语言程序设计》的区别吗? 天拖1304拖拉机离合器怎么调证 下班的搞笑心情说说心情短语 IBM-PC汇编语言程序设计第二版(清华大学的) ( )的世界 填上形容词 物联卡怎么用,有没有知道的人给我介绍下 绑定QQ号,在用QQ号登陆不了,怎么办? pascal编程:1900年1月1日(星期一)的n年当中,每个月的13号这一天的星期一星期二...星期天次数分别是多少 问:编写 万年历java代码例如1900年一月一日是星期一。用for if 语句 c语言求某年的一天是星期几 Java实现以1900年1月1日是给定一个年月日,然后显示对应星期几,要求使用基本语法,大体程序我都弄出来了 用c语言确定某一年一月一日是星期几 东方红1304拖拉机带多宽的旋耕机呀?玉柴4105机器和一拖机器4105以样马力吗? 这道IBM PC汇编语言的题目怎么做啊 东方红1304拖拉机热车液压不给油不提升是怎么回事??? 求IBMPC汇编语言清华第二版(沈美明)视频教程下载地址?或者哈工大汇编语言视频下载地址! 东方红1304拖拉机质量行吗?能用住吗? 1304拖拉机带多宽的粉碎机好 东方红1304拖拉机挂不上高低挡怎么回事? 东方红1304拖拉机启动预热器 东方红拖拉机1304 东方红1304拖拉机升不起来什么毛病。。 东方红1304拖拉机挂接前驱用踩离合器吗 新课标必修四单词表,单词表哦! 东方红1304拖拉机如何补贴 东方红1304拖拉机型号相同钥匙相同吗 东方红拖拉机1304B新发电机,新电瓶,不充电是什么原因 是不是联通手厅开发票有活动啊? 拔了水平阻生智齿出现白色的骨刺怎么办? 拔牙(智齿)后牙花子内壁上长骨刺儿 淘宝流量说的是什么意思啊 海拔最高的大城市是哪个?