ITEEDU

有一点必须说明,定时器具有多种工作状态,并非每种工作状态都能产生声音,所以当我们想通过定时器产生声音时,我们应首先"初始化"定时器,为其建立正确的工作状态。初始 化定时器并不复杂,向端口43H输出数据0B6H即可。这个数据的二进制形式是10110110,有些书籍把这个数称为"幻数"(MAGIC BYTE)。用这样一个数的原因笔者不作过多讨论,大家可以查阅别的参考书。

C:\ASM\>DEBUG[Enter]
-O61 3[Enter]
-O42 0[Enter]
-O42 3[Enter]

有了上面介绍的这些知识,我们就可以编程控制定时器发出给定频率的声音。程序PROG6可以使喇叭发出1000Hz的声音,这个程序中有一个新的逻辑操作指令:

助记符:OR(or)
用 途:将两个数据作"或"逻辑操作
格 式:OR 寄存器,立即数
OR 寄存器,寄存器
OR 寄存器,存储器
OR 存储单元,寄存器
OR 存储单元,立即数

执 行:两个操作数进行"或"计算,结果保存在左边的寄存器或存储单元中

PROG6
-a100[Enter]
0A3E:0100 MOV AL,B6		;AL寄存器装入定时器初始化设置码
0A3E:0102 OUT 43,AL		;将设置码输出到43H端口
0A3E:0104 MOV AX,04A9	;AX寄存器置入N值
0A3E:0107 OUT 42,AL		;将N值分两次输出到42H端口
0A3E:0109 MOV AL,AH		
0A3E:010B OUT 42,AL	
0A3E:010D IN AL,61		;取得61H端口的当前状态
0A3E:010F PUSH AX		;在堆栈中保存61H端口的当前状态
0A3E:0110 OR AL,03		;准备将03H输出到61H端口
0A3E:0112 OUT 61,AL		;打开定时器及电子开关
0A3E:0114 MOV AH,01		;选择DOS API的01H功能
0A3E:0116 INT 21		;调用21H中断等待键盘输入
0A3E:0118 POP AX		;从堆栈中取回61H端口的原状态
0A3E:0119 OUT 61,AL		;恢复61H端口的原状态
0A3E:011B RET	        ;结束程序运行
0A3E:011C 	

4.1.2 编制源程序

我们已经用DEBUG编制了一些程序,相信大家对DEBUG已有了较深的了解。DEBUG虽然小巧,但它存在很多弱点。最明显的,当我们用"JMP"指令向高地址方向转移时,我们无法知道目的地址究竟是多少,只能先假设一个地址,等到全部程序输入完后在修改转移指令的目的地址。这个问题在DEBUG中无法解决,毕竟它不是一个真正的编译系统。那么如何应用汇编语言的编译系统?这就是我们现在要讨论的问题。先来看这样一个程序——PROG7.ASM:

PROG7.ASM
CODE	SEGMENT		;定义代码段
	ORG	100H			;设定偏移地址为0100H
MAIN	PROC	NEAR	;定义主过程开始
	MOV	AL,10110110B	;AL寄存器置入定时器初始化设置码
	OUT	43H,AL			;初始化定时器
	MOV	AX,4A9H			;设置N值为04A9H
	OUT	42H,AL			;输出N值
	MOV	AL,AH	
	OUT	42H,AL	
	 IN	AL,61H			;取得61H端口当前状态
	PUSH	AX			;将61H端口的当前状态存入堆栈
			
			
	OR	AL,3			;将61H端口的低2位改为1
	OUT	61H,AL			;打开定时器及与门
	MOV	AH,1			;选择DOS API的01号功能
	INT	21H				;调用21H中断等待键盘输入
	POP	AX				;取回61H端口的原状态
	OUT	61H,AL		;关闭定时器及与门
	 RET		
MAIN ENDP				;主过程结束
CODE ENDS				;代码段结束
	END 	MAIN 		;进程结束 

这个程序看上去很眼熟吧,它就是PROG6的源程序形式,不过和PROG6相比,它有点面目全非了。我们先来讨论一个简单的问题:源程序中的数。

采用DEBUG编程时所用的数都是16进制的,如果需要使用其它进制的数,程序员就必须自己将其转换为16进制。而编制汇编源程序则没有这个烦琐的问题,我们可以在源程序中使用任意进制的数,只需在数的末尾给出进制标识即可。