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