1 秒计时器等待时间过长
1 second timer waiting too long
我制作了一个 1 秒计时器代码,它有 2 个程序,一个是计算结束时间,另一个总是检查时间以查看该时间是否发生。大多数情况下,1 秒计时器会起作用,但有时它不会等待 1 秒,而是等待 4 秒...任何
proc calculateNewCubeTime
pusha
mov ah, 2ch
int 21h
mov [drawTime], dl
cmp [drawTime], 0
je add99
dec [drawTime]
jmp endCalculateDrawTime
add99:
add [drawTime], 99
endCalculateDrawTime:
popa
ret
endp calculateNewCubeTime
proc checkIfTimeToDrawNewCube
pusha
mov ah, 2ch
int 21h
cmp dl, [drawTime]
jne endCheckDrawTime
mov [newDrawCube], 1
endCheckDrawTime:
popa
ret
endp checkIfTimeToDrawNewCube
尝试使用 dh
(秒)而不是 dl
(百分之一秒):
proc initNewCubeTime ; only called one time
pusha
mov ah, 2ch
int 21h
mov [drawTime], dh
waitForChange:
mov ah, 2ch
int 21h
cmp dh, [drawTime]
je waitForChange
mov [drawTime], dh
popa
ret
endp initNewCubeTime
proc checkIfTimeToDrawNewCube
pusha
mov ah, 2ch
int 21h
cmp dh, [drawTime]
je endCheckDrawTime
mov [drawTime], dh
mov [newDrawCube], 1
endCheckDrawTime:
popa
ret
endp checkIfTimeToDrawNewCube
示例测试程序。在它运行的 60 秒内似乎没有漂移。
.286
.model tiny,c
.code
org 0100h
main proc far
call init
main0: call chk ;wait for change (1 second)
mov dh,[flg]
cmp dh,0
je main0
xor dx,dx
mov [flg],dh
lea dx,msg0
mov ax,0900h
int 21h
mov dh,[loop0]
inc dh
mov [loop0],dh
cmp dh,60 ;run for 60 seconds
jb main0
mov ax,04c00h ;exit back to dos
int 21h
msg0 db '.','$'
secb db 0
flg db 0
loop0 db 0
main endp
init proc
pusha
mov ah, 2ch
int 21h
mov [secb], dh
wait0: mov ah, 2ch
int 21h
cmp dh, [secb]
je wait0
mov [secb], dh
popa
ret
init endp
chk proc
pusha
mov ah, 2ch
int 21h
cmp dh, [secb]
je skip0
mov [secb], dh
mov [flg], 1
skip0: popa
ret
chk endp
end main
我认为这种方法有几个问题。
我相信 INT 21h / AH=2Ch 返回的 DOS 时间由 18.2 Hz INT 08h 定时器保存。因此,虽然它以 1/100 秒(厘秒)为单位进行报告,但实际上并没有该分辨率,因此您可以预期它会以 5-6 厘秒的步长递增。特别是,由于 18.2 不是整数,它可能会超过您的目标时间戳。由于您只测试相等性,因此您会错过它。
即使没有这个问题,由于多种原因中的任何一个,您的代码总是有可能被中断超过一个计时器滴答(硬件中断风暴、慢 TSR 等),在在这种情况下,您的截止日期可能会在您不注意的情况下过去。
您可以尝试通过确定是否至少一秒已经过去来修复它,这意味着比较秒和厘秒字段,寻找“大于”而不是“等于”。但是,您必须小心谨慎,以正确处理在秒数即将结束时开始延迟的可能性。 (我认为 DOS 没有闰秒,但这会使事情变得更加复杂。)
但是您可以通过使用 BIOS 调用来延迟而不是您自己的循环来避免重新发明轮子,例如INT 15h / AH = 86h, provided you are running on a PC/AT or better. (If using an emulator, though, beware that .)
我制作了一个 1 秒计时器代码,它有 2 个程序,一个是计算结束时间,另一个总是检查时间以查看该时间是否发生。大多数情况下,1 秒计时器会起作用,但有时它不会等待 1 秒,而是等待 4 秒...任何
proc calculateNewCubeTime
pusha
mov ah, 2ch
int 21h
mov [drawTime], dl
cmp [drawTime], 0
je add99
dec [drawTime]
jmp endCalculateDrawTime
add99:
add [drawTime], 99
endCalculateDrawTime:
popa
ret
endp calculateNewCubeTime
proc checkIfTimeToDrawNewCube
pusha
mov ah, 2ch
int 21h
cmp dl, [drawTime]
jne endCheckDrawTime
mov [newDrawCube], 1
endCheckDrawTime:
popa
ret
endp checkIfTimeToDrawNewCube
尝试使用 dh
(秒)而不是 dl
(百分之一秒):
proc initNewCubeTime ; only called one time
pusha
mov ah, 2ch
int 21h
mov [drawTime], dh
waitForChange:
mov ah, 2ch
int 21h
cmp dh, [drawTime]
je waitForChange
mov [drawTime], dh
popa
ret
endp initNewCubeTime
proc checkIfTimeToDrawNewCube
pusha
mov ah, 2ch
int 21h
cmp dh, [drawTime]
je endCheckDrawTime
mov [drawTime], dh
mov [newDrawCube], 1
endCheckDrawTime:
popa
ret
endp checkIfTimeToDrawNewCube
示例测试程序。在它运行的 60 秒内似乎没有漂移。
.286
.model tiny,c
.code
org 0100h
main proc far
call init
main0: call chk ;wait for change (1 second)
mov dh,[flg]
cmp dh,0
je main0
xor dx,dx
mov [flg],dh
lea dx,msg0
mov ax,0900h
int 21h
mov dh,[loop0]
inc dh
mov [loop0],dh
cmp dh,60 ;run for 60 seconds
jb main0
mov ax,04c00h ;exit back to dos
int 21h
msg0 db '.','$'
secb db 0
flg db 0
loop0 db 0
main endp
init proc
pusha
mov ah, 2ch
int 21h
mov [secb], dh
wait0: mov ah, 2ch
int 21h
cmp dh, [secb]
je wait0
mov [secb], dh
popa
ret
init endp
chk proc
pusha
mov ah, 2ch
int 21h
cmp dh, [secb]
je skip0
mov [secb], dh
mov [flg], 1
skip0: popa
ret
chk endp
end main
我认为这种方法有几个问题。
我相信 INT 21h / AH=2Ch 返回的 DOS 时间由 18.2 Hz INT 08h 定时器保存。因此,虽然它以 1/100 秒(厘秒)为单位进行报告,但实际上并没有该分辨率,因此您可以预期它会以 5-6 厘秒的步长递增。特别是,由于 18.2 不是整数,它可能会超过您的目标时间戳。由于您只测试相等性,因此您会错过它。
即使没有这个问题,由于多种原因中的任何一个,您的代码总是有可能被中断超过一个计时器滴答(硬件中断风暴、慢 TSR 等),在在这种情况下,您的截止日期可能会在您不注意的情况下过去。
您可以尝试通过确定是否至少一秒已经过去来修复它,这意味着比较秒和厘秒字段,寻找“大于”而不是“等于”。但是,您必须小心谨慎,以正确处理在秒数即将结束时开始延迟的可能性。 (我认为 DOS 没有闰秒,但这会使事情变得更加复杂。)
但是您可以通过使用 BIOS 调用来延迟而不是您自己的循环来避免重新发明轮子,例如INT 15h / AH = 86h, provided you are running on a PC/AT or better. (If using an emulator, though, beware that