42H 选中计数器2:用来控制扬声器发声 43H 公用的控制器:分别对三个寄存器和控制器寻址
那么,如何触动扬声器发出声音呢?原来PC机的主音箱上装有一只小喇叭,由定时器8253和并行接口芯片8255(可编程外围接口芯片)控制其发声,8255包括三个8位寄存器,两个用于输入功能,一个用于输出功能。输入寄存器分配的I/O端口地址为60H和62H,输出寄存器分配的I/O端口地址为61H。8253定时器计数器2连接到扬声器,其电路如下:
8253 DRIVER 1.9318MHZ CLK 喇叭 OUT2 与门 8255
PB0 GATE2 PB1
装入计数器2的计数初值为533H(1.19318MHz/896Hz=1331=533H),这样,得到的控制字为10110110B=0B6H,即选中计数器2,读/写,工作方式三(方波发声器),二进制。
计数器2的初始化程序为: MOV AL,0B6H OUT 43H,AL
1)计算计数值程序段: MOV DI, 给定频率 MOV DX, 12H MOV AX, 34DCH DIV DI
AX中即为计数值。
2)打开扬声器发声,8255PB0,PBI送出高电平: IN AL , 61H OR AL , 3 OUT 61H , AL
3)关闭扬声器,停止发声: IN AL ,61H AND AL , 0FCH OUT 61H, AL
两只老虎的音频表定义在数据段中,如下:
STACK SEGMENT
DW 100 DUP(?) STACK ENDS
DATA SEGMENT
MUSIC DW 2 DUP(262,294,330,262) ; 频率表,1231;1231 DW 2 DUP(330,349,392) ;345;345;
DW 2 DUP(392,440,392,349,330,262) ;565431;565431 dw 2 dup(294,196,262),0 ;251;251,0表示结束
TIME DW 10 DUP(250*50),500*50,250*50,250*50,500*50 ;节拍表 DW 2 DUP(120*50,120*50,120*50,120*50,250*50,250*50) DW 2 DUP(250*50,250*50,500*50)
N EQU 32 ;32个音符 DATA ENDS
二.实验目的:
学习8253计数器2输出方波信号用以驱动扬声器发声的原理,通过程序设置计数器2的输出波形的频率和延续时间,控制扬声器的音调和发生长短。
三.实验内容:
1.设计程序让微机演奏一段两只老虎的乐曲。
2.思考如何让PC机演奏一遍,两遍以及数遍这段两只老虎的乐曲,并修改程序实现。
四.实验报告:
整理出运行正确的源程序清单(加以中文注释),并给出详细程序流程图。
三.程序代码 DATAS SEGMENT
BG DB 0AH,0DH,”TWO TIGER:$” FREQ DW 2 DUP(262,294,330,262) DW 2 DUP(330,349,392)
DW 2 DUP(392,440,392,349,330,262)
DW 2 DUP(294,196,262),0 ;频率表 TIME DW 10 DUP(250*50),500*50,250*50,250*50,500*50 DW 2 DUP(120*50,120*50,120*50,120*50,250*50,250*50) DW 2 DUP(250*50,250*50,500*50) NUM DB 3 DATAS ENDS
STACK SEGMENT PARA STACK 'STACK'
DB 200 DUP(?) ;堆栈段定义并分配存储空间 STACK ENDS
ASSUME CS:CODE,DS:DATA,SS:STACK STAT PROC FAR
PUSH DS ;DS中包含的是程序段前缀的起始地址 MOV AX,0 PUSH AX MOV AX ,DATA MOV DS,AX MOV DX,OFFSET BG MOV AH,09
INT 21H ; 输出字符串“TWO TIGER” LP0: MOV SI,OFFSET FREQ MOV BP,OFFSET TIME
CALL SING ;调用子程序,开始演奏 DEC NUM
CMP NUM,0 JNZ LP0 RET STAT ENDP
SING PROC NEAR ;演奏子程序 PUSH DI PUSH SI PUSH BP PUSH BX
REPTO: MOV DI,[SI] CMP DI,0
JE END_SING MOV BX,DS:[BP] CALL SOUND ADD SI,2 ADD BP,2 JMP REPTO
END_SING:POP BX POP BP POP SI POP DI RET SING ENDP SOUND PROC NEAR PUSH AX PUSH BX PUSH CX PUSH DX PUSH DI
MOV AL,0B6H DI指向频率表首地址 若DI=0,则演奏结束;扬声器发声子程序 ;开始计算计数值
; OUT 43H,AL MOV DX,12H MOV AX 34DCH DIV DI OUT 42H,AL MOV AL,AH OUT 42H,AL
IN AL,61H ;打开扬声器发声 MOV AH,AL OR AL,3 OUT 61H,AL
DELAY: MOV CX,20000 ;延时10MS DL 10MS:LOOP DL10MS DEC BX JNZ DELAY MOV AL,AH
OUT 61H,AL ;关闭扬声器 POP DI POP DX POP CX POP BX POP AX RET SOUND ENDP CODE ENDS END STAT
四.实验感想和收获
这个程序最初一直存在输出乱码的情况,后来经过单步调试,发现是通用子程序时没有进行现场的保护,几个存储器被多次赋值,导致最后不能输出正确的结果。因此我之后增加了堆栈段的定义,对几个寄存器进行了入栈保护,对子程
序的调用进行了现场保护。计数器2的计数初值为533H,控制字为10110110B=0B6H,这个控制字切记不能搞错,同时也要清楚地区分各个计数器的端口地址以及控制口的端口地址。在播放音乐的子程序中,应当将数值传到端口42H,打开扬声器,延时,关闭扬声器的顺序执行,最初我在编程时漏掉了延时的过程,导致无法得到正确的结果。另外,在SOUND子程序末尾一定要记住返回中断点,因为这是一个循环,不是只出现一个音符,而是要一直播放整个音乐。
通过这个试验,我对子程序调用,堆栈段使用有了更深的理解,通过自己编译,调试,一步步找到自己的不足,这是一个学习的过程,也是对知识的探求。这次试验老师给了我们很多的资料和一些源代码,我要做的不仅是将他们拼接起来,是要根据自己的设计对他们加以运用,并补充很多的子程序,现场保护代码等,将其完善,变为自己的程序。子程序调用必须先进行现场保护,这是非常重要的,也是汇编语言和高级语言一大不同所决定的。
编程需要耐心和决心,只有一步步检查,才能使程序正确,达到想要的结果,正因为这样,当程序编译成功,电脑开始播放音乐时,那种成功地满足感不是用语言形容的,这让我对这门课程有了更多地兴趣。
百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说综合文库四川大学微机原理实验报告(4)在线全文阅读。
相关推荐: