msTimerBYTE  and  SecTimerBYTE

Purpose: Determine if a desired short time period has passed.
Assumes: System interrupts are enabled, so the Operating System is able to update ulT0_Millis and ulT0_Seconds.
Passed:    R24  BYTE   bStart the millisLowBYTE() value saved at the starting time, OR
the SystemSecondsLowBYTE() value saved at the starting time
R22  BYTE bDuration   the timer delay time, 0 to 250 milliseconds (for msTimerBYTE), OR
the timer delay time, 0 to 250 Seconds (for SecTimerBYTE)
Returns: R24  BYTE bIfDone 0 (or FALSE) if the specified amount of time has NOT passed OR
1 (or TRUE) if the specified amount of time has passed
FLAGS  ZERO flagset (TRUE) when the time has NOT expired (i.e., when R24 is 0) OR
clear (FALSE) when the timer has timed out (i.e., when R24 is 1)
Alters: R22, R23, R24, and the FLAGS
Example:  This is more an example of what NOT to do in a multitasking environment, since this code "blocks" and becomes, in effect, a delay function. That is one reason why the millisecond version was chosen for this example. It can be invoked from the command line and is printing a character while waiting, however. Examine Timers for non-blocking, but more intricate, example code.
BlockingTimerExample:
   MOVW    R24, R26               ; In the parsing buffer, find the first space
   LDI     R22, ' '               ;  character and parse the value after it
   CALL    AParseValueAfter       ; Returns a ULONG value in R25:R24:R23:R22
   SBRS    R21, BIT_PV_VALID      ; If a value was found, skip past the exit
   RET

   MOV     R31, R22               ; Transfer the mSec delay value to R31
   CALL    AmillisLowBYTE         ; Obtain the starting time and save it in R30,
   MOV     R30, R24               ;  since R24 will be changed each time checked

DelayLoop:                        ; This is like "delay" since it blocks, but
   LDI     R24, '#'               ;  printing a character just illustrates that
   CALL    APrintCHAR             ;  we can do something else while waiting
   MOV     R24, R30               ; Set the Starting time in R24
   MOV     R22, R31               ; Set the Delay in mSec in R22
   CALL    AmsTimerBYTE           ; See if the mSec timer has expired and loop
   BREQ    ADelayLoop             ;  back if the "ZERO" flag is set (not expired)
   CALL    AmillisLowBYTE         ; Get the LSByte of ulT0_millis right now
   MOV     R27, R24               ;  and save it in R27 to print as last value

PrintResults:
   LDI     R19, ' '               ; The character between each string and BYTE
   LDI     R24, ACSZ_Start & 0xFF ; Point to the LSByte of the first string and
   MOV     R22, R30               ;  print it, then the starting ulT0_millis
   RCALL   ACommonPrintRoutine    ;  value, using the local subroutine
   LDI     R24, ACSZ_Delay & 0xFF ; Print the "; delay:" string and the delay
   MOV     R22, R31               ;  time parsed from the user input buffer
   RCALL   ACommonPrintRoutine
   LDI     R24, ACSZ_Done & 0xFF  ; Print the final string and the ulT0_millis
   MOV     R22, R27               ;  value saved after exiting the timer loop
   RCALL   ACommonPrintRoutine
   JMP     APrintNewLine          ; Advance to the next line and exit

CommonPrintRoutine:
   LDI     R25, ACSZ_Start >> 8   ; The strings all started with the same MSByte
   JMP     APrintDescAndHexBYTE   ;  of their address, used a single subroutine

CSZ_Start: .STRING " Started at:"
CSZ_Delay: .STRING "; delay:"
CSZ_Done:  .STRING "; done at:"
Notes: A delay() function would defeat the purpose of a cooperative multitasking Operating System. Still, there must be some way to selectively defer program execution until a later time; enter timers. A time delay of zero is considered to ALWAYS be timed out. This means that a routine can change a timer delay to zero and have it "fire" (or time out) the next time it's checked.
Dropin: 
(setup
code)
;   Setup for the msTimerBYTE() or SecTimerBYTE() call:
; Passed:  R24 BYTE  the initial millisLowBYTE() or SystemSecondsLowBYTE value
;          R22 BYTE  the delay duration (0 to 250, milliseconds or Seconds)
;                     Note: values from 251 to 255 may be passed, will be
;                           limited to 250, and will not cause an error.
; Returns: R24 BYTE  0 if the time delay is not done yet OR
;                    1 if (at least) the desired amount of time has passed
;  (Also): ZERO FLAG TRUE when the time has NOT passed yet OR
;                    FALSE when the time has passed
; Alters:  R22, R23 and FLAGS (in addition to the return value in R24)
Also see:  The millis and SystemSeconds variables, the msTimerWORD, SecTimerWORD, and msTimerULONG timers.