乐曲演奏程序.docx
《乐曲演奏程序.docx》由会员分享,可在线阅读,更多相关《乐曲演奏程序.docx(12页珍藏版)》请在冰豆网上搜索。
![乐曲演奏程序.docx](https://file1.bdocx.com/fileroot1/2023-1/27/cbb0f087-a424-4718-8296-cb8395437da2/cbb0f087-a424-4718-8296-cb8395437da21.gif)
乐曲演奏程序
学号:
课程设计
课程名称
汇编语言程丿予设计
题目
乐曲程序的设计与实现
学院
计算机科学与技术学院
专业
计算机科学与技术
班级
姓名
指导教师
杨青
2010年12月31日
课程设计任务书.……
1、设计原理及要求…..…
1.1通用发声程序原理
1.2乐曲的频率和节拍
1.3实验要求
错误!
未定义书签
..3
4
6
6
2、方案设计及说明7
2.1设计实现及功能7
2.2流程图7
2.3关键代码设计实现及分析8
2.3.1程序段说明9
2.3.2PLAY_MUSIC乐曲演奏程序的实现及分析9
2.3.3SOUNDF通用发声程序的实现及分析9
2.3.4WAITF延迟程序的实现及分析11
2.3.5KEYBOARD键盘发声程序的实现及分析11
3、调试过程及实验结果分析7
3.1调试过程7
3.2实验结果7
4、设计心得与改进方案7
4.1心得体会7
4.2注意事项11
4.3改进方案7
5、参考文献7
附录源程序7
课程设计任务书
学生姓名:
专业班级:
指导教师:
工作单位:
计算机科学与技术学院
题目:
乐曲程序的设计与实现
初始条件:
理论:
完成了《汇编语言程序设计》课程,对微机系统结构和80系列指令系统有了较深入的理
解,已掌握了汇编语言程序设计的基本方法和技巧。
实践:
完成了《汇编语言程序设计》的4个实验,熟悉了汇编语言程序的设计环境并掌握了汇编
语言程序的调试方法。
要求完成的主要任务:
(包括课程设计工作量及其技术要求,以及说明书撰写等具体要求)
进一步理解和掌握程序直接控制I/O方式,掌握计算机发声程序的设计。
具体的设计任务及要
求:
1采用位触发方式编写程序,使计算机发出音响并演奏乐曲(例如《两只老虎》等)。
1)进一步理解程序直接控制I/O方式和位触发方式控制声音的工作原理。
2)一首乐曲是由不同频率和节拍的音调组成,因此控制脉冲的频率和持续时间是编写乐曲程序的关键。
根据已知的音符频率对照表,设置乐曲的频率表和节拍时间表;
3)编写程序并调试通过。
2•了解定时器的工作原理,掌握利用定时器产生声音的方法,使计算机演奏乐曲(例如《两只老虎》等)。
编写程序并调试通过。
在完成设计任务后,按要求撰写课程设计说明书;对课程设计说明书的具体要求请见课程设计指导书。
阅读资料:
1)《IBM—PC汇编语言程序设计实验教程》3.1节
2)《IBM—PC汇编语言程序设计(第2版)》10.4节,10.5节
时间安排:
设计安排一周:
周1、周2:
完成系统分析及设计。
周3、周4:
完成程序调试,和验收。
周5:
撰写课程设计报告。
指导教师签名:
年
月
日
系主任(或责任教师)签名:
年
月
日
乐曲程序的设计与实现
1实验原理
1.1通用发声程序原理
PC机发声系统以8254的2号计数器为核心。
系统初始化时,2号计数器I作在“方波发生器”方式,初值为二进制数,,写入顺序为先低后高,CLK2为1193182MHz当计数初值为533H时,0UT2输出的方波大约为900Hz,经过简单的滤波之后,送至扬声器。
改变1.4号计数器的计数初值就可以使扬声器发出不同频率的音响。
ROMBIOS中有个BEEP子程序,这能根据BL中组出的时间计数值控制8254定时器,产生持续时间为1个或几个0.5秒,频率为896HZ的声音,我们可以利用并修改BEEP使其产生任一频率的声音。
为此我们需要做两点修改,首先,BEEPg序只能产生896HZ的声音,我们的通用发声程序应能产生任一频率的声音。
其次,BEEF产生声音的持续时间(音长)
只能是0.5秒的倍数,我们希望声音的持续时间更易于调整,例如可以是10ms的倍数。
我们知道BEE唯将计数值533H送给定时器2产生896HZ的声音的,那么产生其它频率声音的时间计数值应为:
533HX896-给定频率=1232804^给定频率
发声程序包括3个步骤:
(1)在8253中的42端口送一个控制字0B6H(10110110B,该控制字对定时器2进行初始化,使定时器2准备接收计数初值。
(2)在8253中的42H端口(Timer2)装入一个16位的计数值(533HX895/频率),以建立将要产生的声音频率。
(3)把输出端口61H的PB0PB1两位置1,发出声音。
对于发音部分。
PC机上的大多数输入/输出(I/O)都是由主板上的8255(或8255A)可编程序外围接口芯片(PPI)管理的。
PPI包括3个8位寄存器,两个用于输入功能,一个用于输出功能。
输入寄存器分配的I/O端口号为60H和62H,输出寄存器分配的I/O端口号为61H由PPI输出寄存器中的0、1两位来选择扬声器的驱动方式。
连接到扬声器上的是定时器2,从上图可以看到,GATE为端口61H的PBO相连,当PB0=1时,GATE2获得高电平,使定时器2可以在模式3(方波)下工作。
定时器2的0UT2与端口61H的PB1通过一个与门与扬声器的驱动电路相连。
当PB1=1时,允许0UT2的输
出信号到达扬声器电路。
因此,只有PBO和PB1同时为“1”时,才能驱动扬声器地声。
通过以下指令实现:
INAL,61H
ORAL,3
OUT61HAL
上面的指令用以打开扬声器,如要关闭扬声器时则为:
ANDA,OFCH
OUT61HAL
当从8255中采集到输入的数据时,需要确定相应的频率,所以在软件编程时要建立一个数据表:
TABLEDW493440,392,349,329,293,261
把相应的频率送到一个寄存器上,通过公式:
计数值=533HX896-f=12348CH十f
算出计数值,再把算得的计数值送给8253,就可产生所要频率的方波。
在把计数值送
8253前,必须先把8253进行初始化:
MOVAL0B6H
OUT43HAL
使其选用通道2,工作在方式3下。
就整个电路而言,接好电路后,通过软件编程不断地采集从8255口中输入的信号,而8
个开关都接在8255的A口上,只要有开关按下,就会采集到一个数据,根据这个数据与事先编好的表对应,得到一个计数值,把这个计数值送给8253的通道2,8253的通道2
工作的方式3下,这样就可以产生满足频率要求的发声方波。
这个方波经驱动放大就可以使扬声器发出相应的声音。
所以8255在这里完成两个任务,它不仅从A口中采集到数据,而且B口的PB1和PB0两个位要控制发声。
8253的主要任务就是产生所要求发声的不同频率的方波。
1.2乐曲的频率和节拍
乐曲是按照一定的高低、长短、强弱组成的音调。
在一首乐曲中,每个音符的音高
和音长和频率和节拍有关。
每个音符的频率值和持续时间是乐曲程序发声需要的两个必
要数据。
高音阶从中C(263)到高C(523),各个音阶对应的频率如下所示:
DW263C
DW294D
DW330E
DW349F
DW392G
DW440A
DW494B
DW523C
如果知道了乐曲的曲谱,就可以将每个音符的频率和持续时间定义为两个数据表,然
后通过调用子程序将表中数据取出,通过扬声器发声。
例如MERRYCHRISTMAS率表和
节拍表如下所示:
CHST_Fdw7dup(330),392,262,294,330,4dup(349),2dup(330),330,294,294,262,294,392
dw7dup(330),392,262,294,330,4dup(349),2dup(330),392,392,349,294,262,0
CHST_Tdw2dup(25,25,50),4dup(25),100,2dup(25,25,50)
dw4dup(25),2dup(50),2dup(25,25,50)
dw4dup(25),100,2dup(25,25,50),4dup(25),100
其中,CHST_F为频率表,CHST_T为节拍表,两个表中的数据一一对应,每一组
代表着乐曲中的一个音符。
1.3实验要求
1•进一步理解和掌握程序直接控制I/O方式,掌握计算机发声程序的设计。
具体的设计任务及要求:
1)采用位触发方式编写程序,使计算机发出音响并演奏乐曲(例如《两只老虎》等)。
4)进一步理解程序直接控制I/O方式和位触发方式控制声音的工作原理。
5)—首乐曲是由不同频率和节拍的音调组成,因此控制脉冲的频率和持续时间是编写乐曲程序的关键。
根据已知的音符频率对照表,设置乐曲的频率表和节拍时间表;
6)编写程序并调试通过。
2•了解定时器的工作原理,掌握利用定时器产生声音的方法,使计算机演奏乐曲(例如《两只老虎》等)。
编写程序并调试通过。
2、方案设计及说明
2.1要求及实现功能
了解了乐曲演奏的原理,就可以开始设计方案。
首先,明确整个程序的结构及各个程序段的结构和功能,然后设计流程图。
按照要求,程序需要完成的功能如下所示:
1.程序需要通过定时器原理完成播放乐曲的功能,这是最基本的功能。
2.在程序中添加一个键盘发声功能,即通过按键盘上不同的按键来发出不同频率的音符。
3.程序应该有判断用户输入是否符合规定,如果输入不正确,应该有所提示。
4.在用户输入较多的情况下,选择界面会显得较为凌乱,所以添加一个清屏功能
显得很有必要。
5.在主界面选择不同的选项时,应该跳转到不同的子界面,结束之后再返回主选
择界面。
2.2流程图
图表1主程序流程图
说明:
在进入主界面的时候有6个选项,分别是
1:
MUSIC1--MERRYCHRISTMAS
2:
MUSIC2-TAIHU
3:
MUSIC3--LITTLEBEE
4:
PLAYBYKEYBOARD
5:
PRESS5TOQUIT
6:
CLEARTHESCREEN
通过选择不同的选项进入其子界面来实现不同的功能
2.3关键代码设计实现及分析
231程序段说明
1)DATAS为数据段,
频率表和节拍表,
2)CODES为代码段,
要有一个代码段,
其中存放在程序中所要显示的提示选择信息,还有乐曲的和键盘控制发声对应的音符表。
由于在整个程序中各个子程序都定义为NEAR所以只需各个子程序的定义及实现都放在其中。
232PLAY_MUSIC乐曲演奏程序的实现及分析
“PLAY_MUS”为播放音乐的子程序,完成的功能是通过SI(频率表的偏移地址)BP(节拍表的偏移地址)(通过主程序传递过来的参数)找到对应的频率(DI)、节拍(BX),再以DI、BX为参数调用SOUND子程序来发出声音。
关键代码:
FREQ:
MOVDI,[SI]
CMPDI,0
JEEND_MUSIC
MOVBX,DS:
[BP]
CALLSOUNDF;以DI(频率)BX(节拍)为参数,调用SOUNDADDSI,2
ADDBP,2
JMPFREQ
SI,BP是频率表和节拍表的偏移地址,通过寄存器间接寻址方式找到数据
段中定义的数据,传递给BX和DI,然后调用SOUND发出一个频率为DI,节拍数为BX的声音。
注意:
在频率表中应该设置一个结束标志,“CMPDI,0”在这里以0作为结束标志。
233SOUNDF通用发声程序的实现及分析
SOUNDF”为以传递过来的频率和节拍数,发出一个音符的频率的子程序
关键代码分析:
MOVAL,0B6H
OUT43H,AL
置43H端口为0B6H选择计数器2,读/写LSB,MSB,模式3,计数值为二进制数。
MOVDX,12H
MOVAX,348CH
DIVDI
按照公式,计数值=12348CI+f,商存放在AX中。
OUT42H,AL
MOVAL,AH
OUT42H,AL
8253\54的数据总线为8位,而计数值为16位,所以应该分两次传递计数值。
INAL,61H
MOVAH,AL
ORAL,3
OUT61H,AL
将61H的后两位置1,打开扬声器,使其发声。
WAIT1:
CALLWAITF
DECBX
JNZWAIT1
用WAITF产生一个10ms的延时,BX是节拍(10ms的倍数)。
MOVAL,AH
OUT61H,AL
恢复寄存器状态
234WAITF延迟程序的实现及分析
“WAITF为通过监控端口
61H的PB4固定不变的触发时间来产生延迟时间的子程序。
关键代码分析:
MOVCX,663
WAITF1:
INAL,61H
CMPAL,AH
MOVAH,AL
LOOPWAITF1
一个10ms的延迟。
2.3.5KEYBOARD盘发声程序的实现及分析
“KEYBOARD?
程序,通过按不同的按键(1~8)来产生不同频率的音符。
关键代码分析:
PLAYBYKB:
MOVAH,7
INT21H
CMPAL,0DH
JEQT
MOVBX,OFFSETTABLE
CMPAL,'1'
JBPLAYBYKB
CMPAL,'8'
JAPLAYBYKB
输入按键,回车退出,如果不是1~8的话跳转到开始重新输入。
SHLAX,1
SUBAX,2
找到索引地址,是DW型的,所以需要乘2,而且是从0开始,应该减去2
MOVSI,AX
MOVDI,[BX][SI]
MOVBX,10
CALLSOUNDF
通过索引从符号表里面找到对应的频率,调用SOUND发出声音。
3、调试过程及实验结果分析
3.1调试过程
1:
在刚开始显示字符串的时候,应该加上0DH,0AH换行,而且在字符串的最
后应该以"$"来结尾,然后调用DOS调用INT21H,来显示字符串。
调试中发现,如果一个字符串末尾不加"$"的话,DOS调用会直接把之后定义的字符串也同时显示出来,直到遇到"$"为止。
这是由内存的分配模式所决定的,同时定义的变量在内存中会处于
相邻位置。
2:
在调试子程序KEYBOAF的时候,发现管输入‘0'程序不会返回,是因为在程序中直接CMPAL,0。
而从键盘输入的是ASC码,‘0'对应的ASC码为30H,所以修改语句如下:
CMPAL,'0'。
3:
在调试KEYBOAR的时候,发现输入1~8只有7会发出声音,检查后发现由于在TABLE表中定义的是DW字,而在程序中直接将输入符号作为索引值,应该将输入数字减一乘二才能得到正确的索引值。
4:
在调用CLEAR勺时候,发现每次显示的列表都会向下移动。
在清除前应该将光
标位置移动到第0行,第0列。
5:
在输入字符较多的情况下,界面显得较为凌乱,所以在程序中添加了一个清屏
子程序,每次在返回选择界面的情况下清屏,但是在调试过程中,每当调用CLEAR勺时候
就出现错误:
“C:
\WINDDOWS\system32\cmd.exeNTVDMCPUS到无效的指令CS:
01e7
IP:
018bOP:
dbfe06cd02”,查阅资料,发现是软件兼容问题。
最后查阅书本,发
现如果要实现清屏功能的话应该先把光标的位置定位到界面的开始位置(行、列号都为0),
然后参照书本P330的例9.11来实现清屏功能。
6:
刚开始时候,直接把延迟时间(15.08us)通过CX寄存器传递给子程序WAITF
这样会导致每次传递的时候都应该计算。
所以之后在WAITF中直接将CX初始化为663
(10ms/15.08us=663),每次调用WAITF就能产生10ms的延迟,但要特别注意的是,如果WAITF中用到CX首先应该将CX压栈(PUSHCX,返回之前出栈(POPCX。
7:
结果显示界面显得比较单调,为了增加程序美观性,定义了一个利用BIOS功能
调用来设置显示方式和背景色。
但要特别注意的是调用的时机,应该在每次刷新并且显示选择列表之前调用。
3.2实验结果
4、设计心得与改进方案
4.1心得体会
1.在程序中,各个变量及标号应该有统一且明确的命名规范,例如频率表的命名
规则为:
“歌曲名_F“,节拍表的命名规则为:
“歌曲名_T“这样能使代码的可读性大大增强,且在编程中也能使逻辑更加清晰,增加编程效率。
2.不能一开始就开始编写程序,而是应该首先分析问题,设计出程序的框架流程图,明确各个程序段的功能,这样能使效率提高并且能增强持续的逻辑性和可读性。
4.2注意事项
1:
刚开始设计流程图的时候,直接将内置的2首音乐分别定义一个子程序来演奏,在
之后的编程过程中,发现这样的设计不合理且会使代码变的更长且冗余,然后改进设计,
以一个SOUND子程序来演奏音乐,调用SOUND的时候直接将需要演奏的频率表和节拍表作为参数传递给SOUND程序,这样能使代码更简洁,可读性大大增强。
3:
如果需要播放其他音乐时,只要在数据段增加此音乐的频率表和节拍表,然后在
选择项中添加一个选项即可。
4.在调用子程序的过程中,应该注意保存寄存器中的内容,避免在子程序中破坏其中的数据
4.3改进方案
1:
在播放一首乐曲中,可以增加一个按ESC按键中断当前播放并返回到主选择界
面的功能,而且在播放歌曲的时候能同步显示歌词。
7、参考文献
[1]沈美明,温冬婵.IBM—PC汇编语言程序设计(第2版)[M].北京:
清华大学出版社,2001年8月.