ITEEDU

4.2 精确定时

4.2节导航:第一页 第二页 第三页

在4.1节中我们已经讨论了如何通过定时器的通道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中断和这四字节的计数值。因此我们要想精确的定时,必须依靠时钟计数值才行。

程序PROG9.ASM是一个能准确发出1000Hz声音的程序,声音持续时间为5秒钟。这个程序中又出现了一条新的指令:

助记符:ADD(add)
用 途:将两个数据相加
格 式:ADD 寄存器,立即数
ADD 寄存器,存储单元
ADD 寄存器,寄存器
ADD 存储单元,立即数
ADD 存储单元,寄存器
执 行:两个数据相加,结果保存在左边的寄存器或存储单元中,右边数据不变。

PROG9.ASM
PORT_B	equ	61H
code	segment	
	assume	cs:code,ds:code
	org	100h
main 	proc 	near
		
	mov	al,10110110b
	out	43h,al
	mov	ax,4a9h
	out	42h,al
	mov	al,ah
	out	42h,al
	in	al,PORT_B
	or	al,3
	out	PORT_B,al
	mov	ah,0
	int	1ah
	add	dx,91
	mov	bx,dx
delay:	int	1ah
	cmp	dx,bx
	jne	delay
	in	al,PORT_B
	and	al,0fch
	out	PORT_B,al
	int	20h
main	endp	
code 	ends	
	end 	main 

ADD指令和我们前面讨论的SUB指令是相对的,这两条指令在应用时要注意这样一点--相加的两个数据位宽要一致。象这样的用法都是不对的:

ERROR!!!

ADD AH,0FC00H
DD AH,BX

程序使用了一个新的中断--INT 1AH的0号功能取得时钟计数值。1AH中断的用法如下所示:

功能号:0
用 途:读取时钟计数值
参 数:AH=0
调 用:INT 1AH
返 回:CX = 计数值高16位
DX = 计数值低16位
AL = 0 表示未过24小时
AL <> 0 表示已过24小时

这个中断还有一个设定计时值的功能,这里不再给出。

由于5秒钟对应计数值是91,因此这个程序先用1AH中断取得当前计数值,并在低16位上加了91,算出循环终止时的计数值并保存到BX寄存器中。而后在一个循环中反复取计数值,并将低16位同BX中的计数终值相比较,当两者相等时说明已经到了5秒,此时退出循环关闭定时器通道3。这样就完成了5秒钟的发声。

和用LOOP指令定时相比,这种新的定时方法有很大的优越性:首先这种方法编程方便;其次这种方法在不同的机型上延迟时间都相等,因为PC系列机的08H中断都是每秒18.2次。此方法唯一的不足是最短延迟时间是55Ms,如果想获得更短的延迟时间只能提高08H中断的产生频率,这样的问题比较复杂,本书将不再讨论。