Home > Software engineering >  1 second timer waiting too long
1 second timer waiting too long

Time:03-09

I made a 1 second timer code that has 2 procedures, One is calculating the end time and the other is always checking the time in order to see if that time happened. Most of the times the 1 second timer works but sometimes it doesn't wait 1 second but 4... Any

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

CodePudding user response:

I think there are a couple of problems with this approach.

  • I believe that the DOS time as returned by INT 21h / AH=2Ch is kept by the 18.2 Hz INT 08h timer. So although it's reported in 1/100ths of a second (centiseconds), it doesn't actually have that resolution, and so you can expect it to increment in steps of 5-6 centiseconds. In particular, since 18.2 is not an integer, it could step past your target timestamp. Since you only test for equality, you'd miss it.

  • Even without this issue, it is always possible that for any of a number of reasons, your code gets interrupted for longer than one timer tick (hardware interrupt storm, slow TSR, etc), in which case your deadline could go by without you noticing.

  • You could try to fix it by determining whether at least one second has passed, which would mean comparing both the seconds and centiseconds fields, looking for "greater than" instead of "equal to". However, you'll have to be a little careful to correctly handle the possibility that you started delaying near the end of a minute, when the seconds counter is about to wrap around. (I don't think DOS did leap seconds, but that would complicate things further.)

But you could avoid reinventing the wheel by using a BIOS call to delay instead of your own loop, e.g. INT 15h / AH = 86h, provided you are running on a PC/AT or better. (If using an emulator, though, beware that DosBox is buggy with int 15h ah = 86h .)

CodePudding user response:

Try using dh (seconds) instead of dl (hundredths of a second):

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

Example test program. Doesn't appear to drift over the 60 seconds it runs for.

        .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
  • Related