Elapsed Timer Demo

For 14-bit core PICS (12F, 16C and 16F)
DT 3-Jan-2015

Attached to this post is a Zip file that contains a "Drop-In" elapsed timer that uses Timer1 and interrupts. It's waaay down there at the bottom of all this dribble. This may get rather long winded, so my first suggestion is to scroll down to the bottom of this post and check out the file then come back and read this post later.

Elapsed Timer Demo.zip


The files contained in the Zip are:

  • Test_Elapsed_SER.pbp ' Demo of Elapsed Timer using serout2 command and HyperTerminal
  • Test_Elapsed_LCD.pbp ' Demo of Elapsed Timer using an LCD
  • Elapsed.bas ' Elapsed Timer include file
  • ASM_INTS.bas ' Assembly language Interrupt Stubs

Note1: These files are intended to be used on 14-bit core PICS (12F, 16C and 16F) that have a TIMER1 module.
Note2: They are written for use as the only interrupt in the program. If you need to use other interrupts as well, the program will have to be modified before it will work.
Note3: It will NEVER work in conjunction with PBP's ON INTERRUPT statement.

In it's simplest form, this is all it takes to use the Elapsed Timer:

    Include "Elapsed.pbp"

    Gosub ResetTime    ' Reset Time to  0d-00:00:00.00
    Gosub StartTimer   ' Start the Elapsed Timer

This will create a Clock counting at 1/100 seconds. It runs in the background of PBP without any other program intervention required.

The time is kept in the variables:

    Ticks    var byte   ' 1/100th of a second
    Seconds  var byte   ' 0-59
    Minutes  var byte   ' 0-59
    Hours    var byte   ' 0-23
    Days     var word   ' 0-65535

The time can be easily displayed with a single line:

    LCDout $FE,2, dec Days,"d-",dec2 Hours,":",dec2 Minutes,":",dec2 Seconds

For each of the variables (Seconds, Minutes, Hours and Days) there is a flag that indicates when the value of that variable has changed. The Flags are:

    SecondsChanged   var bit
    MinutesChanged   var bit
    HoursChanged     var bit
    DaysChanged      var bit

So, if you wanted to display the time like a clock, you could wait until SecondsChanged = 1, display the time, then reset the flag.

    Loop:
        if SecondsChanged = 1 then
           LCDout $FE,2, dec Days,"d-",dec2 Hours,":",dec2 Minutes,":",dec2 Seconds
           SecondsChanged = 0
        endif
    Goto Loop

If you only wanted to display the time each minute instead of every second just do the same thing using the MinutesChanged flag.

    Loop:
        if MinutesChanged = 1 then
           LCDout $FE,2, dec Days,"d-",dec2 Hours,":",dec2 Minutes
           MinutesChanged = 0
        endif
    Goto Loop

The timer can be Stopped and Started, like a stopwatch.

    Gosub StopTimer
    Gosub StartTimer

The Elapsed.bas include file also Includes another file, ASM_INTS.bas This file can also be used in your other programs as well. It handles the "Context Saving" that is required for any Assembly language interrupt.

It contains 2 macros:
INT_START
Saves the W, STATUS, PCLATH and FSR registers. This can be used at the beginning of your Interrupt routine.

INT_RETURN
Restores the W, STATUS, PCLATH and FSR registers after the Interrupt routine is finished and then returns from the Interrupt (RETFIE).

Using it in a normal Assembly language interrupt might look something like this:

    Define  INTHAND  INT_CODE    ' Tell PBP Where the code starts on an interrupt


    ASM
    INT_CODE
        INT_START                ' Save Context
        ... Your Interrupt routine goes here ...
        INT_RETURN               ' Restore Context
    EndAsm


Using PBP statements in an ASM type interrupt

Looking at the Elapsed.bas file, you'll see that even though the interrupt is being handled as an "ASM" type interrupt. The Handler is mostly PBP statements.

A while back, Tim Box found out that it's possible to use PBP statements in assembly language interrupts, as long as you save any PBP system variables that may get overwritten by the interrupt routine. But instead of using up a lot of cycles saving variables that won't get overwritten, all you really need to do is save just the system vars that are actually used by the interrupt. In this case, the routine only uses R0 and R1. Finding out which system vars are used by the interrupt routine can be done a couple different ways. The first way is to compile the routine, and search thru the .LST file to see which system vars are used. This can be pretty difficult, especially since you have to follow any CALLS and look up their code in the PBPPIC14.LIB file. If your lucky, it won't take longer than several hours to find them all

Another way is to set each of the system variables to a known value at the start of the interrupt routine, then see if any of them have been changed after the routine is finished. It's probably a good idea to try it with several different starting values, just in case. Doing it this way is a little more risky. Unless all possibilities are tested in the interrupt routine, some of the system vars may not get changed during the test. They may come back to haunt you later on. I plan on making another post related to this topic. So if this doesn't make sense right now, Hang in there. Hopefully it will later.

Page last modified on March 07, 2018, at 05:11 PM