Non-interrupt X2 code for 500ms timed loops with second, 2 second, minute flags

lbenson

Senior Member
The following code loops every 500ms based on "setfreq M8", "settimer t1s_4" and a check for a change in the value of "timer". The two commands function so that the system variable, "timer" increments every half second.

Code:
' 20timertest tests 500ms timing
#picaxe 20x2
#terminal 9600
#no_data
#no_table

symbol nLoopsPerSecond = 2

symbol bSecondFlag  = bit2
symbol b2SecondFlag = bit3
symbol bMinuteFlag  = bit4

symbol ticksRemainder = b4 ' used for minutes division

symbol wLapsedMin = w26
symbol wLastTimer = w27

setfreq M8
settimer t1s_4 ' timer variable ticks every half second (at M8)
wLapsedMin=0
wLastTimer=timer

main:  ' loops every 500ms
  do   '   depends on code called during loop taking less than 500ms
    do while wLastTimer=timer : loop ' wait until timer is incremented--M8, tls_4
    wLastTimer=timer ' reset
    inc bSecondFlag  ' toggles between 0 and 1
    if bSecondFlag = 1 then ' one second has elapsed
      inc b2SecondFlag  ' toggles between 0 and 1 every 2 seconds
      if b2SecondFlag = 1 then ' two seconds have elapsed
        ' do something
        high B.5
      endif
      high B.1
    else ' do things on the half-second (e.g. turn off camera)
      low B.1
      low B.5
    endif
    ticksRemainder = timer / nLoopsPerSecond // 60 ' every 60 seconds equals 0
    if ticksRemainder = 0 then : bMinuteFlag = 1 : else : bMinuteFlag = 0 : endif
    if bMinuteFlag = 1 then
      inc wLapsedMin ' minutes counter
      high B.7
    else
      low B.7 ' redundant most of the time
    endif
loop
The first statement in the main do-loop, "do while wLastTimer=timer : loop" idles until an increment occurs. "inc bSecondFlag" causes a bit variable to toggle on once a second. The test for that variable going to "1" enables you to do things which are supposed to happen every second. "inc b2SecondFlag" toggles another flag every two seconds. Similar additional code could toggle a bit flag every 4,8,16, etc. seconds.

A second way to mark a lapsed time with a bit variable is to divide the "timer" variable by the number of seconds you want to look at times 2, and view the remainder. Thus when, as in this case, nLoopsPerSecond is equal to 2, "ticksRemainder = timer / nLoopsPerSecond // 60" will give a value of 0 for ticksRemainder once every minute. "if ticksRemainder = 0 then : bMinuteFlag = 1 : else : bMinuteFlag = 0 : endif" sets the bit flag, bMinuteFlag, to 1 when this occurs--otherwise its value will be 0 (for 119 out of 120 passes through the main loop).

When bMinuteFlag=1, a wLapsedMinutes WORD variable could be incremented. This would allow 65,536 minutes to be counted before rollover--1,092 hours, over 45 days.

The timing requires that any code that you call from this main loop executes in less than 500ms. That means no long PAUSE statements, and no READTEMP statements (these may take up to 750ms to complete), among others. (READTEMP can be replaced with the one-wire statements, OWIN and OWOUT--there are examples in Manual 2.) At maybe 4000 statements per second with "setfreq M8", you should be able to accomplish a lot within these constraints.
 
Last edited:

hippy

Technical Support
Staff member
Sounds good but I think you missed two tricks - That the 'toFlag' can be used to poll timer ticks and the SETTIMER preload value can be easily calculated by PE6 ...

Code:
#Picaxe 28X2
#Terminal 9600
#No_Table
#No_Data

Symbol TICK_TIME = 250000    ; 250000 us
Symbol MHZ       = 8         ; 8 MHz

Symbol kLoopMs   = TICK_TIME / 1000
Symbol kTickUs   = 256       / MHZ
Symbol kTickNum  = TICK_TIME / kTickUs
Symbol kPreload  = 65536     - kTickNum

Symbol ms        = w1
Symbol secs      = w2
Symbol mins      = w3

SetTimer kPreload
Do
  toFlag = 0
  timer  = $FFFF
  Gosub MainCode
  Do : Loop Until toFlag = 1
  Gosub UpdateTime
Loop

UpdateTime:
  ms = ms + kLoopMs
  If ms >= 1000 Then
    ms = ms - 1000 
    secs = secs + 1 // 60
    If secs = 0 Then
      mins = mins + 1
    End If
    If secs < 10 Then
      SerTxd( #mins, ":", "0", #secs, CR, LF )
    Else
      SerTxd( #mins, ":",      #secs, CR, LF )
    End If
  End If
  Return

MainCode:
  SerTxd( "." )
  Return
 

lbenson

Senior Member
Thanks, hippy. One advantage to posting sample code is that improvements are likely to be elicited. I had made an attempt at using toflag but didn't get it to work.
 
Top