The current version is 1.5.
Overview
Notice! Even though this appears to be a huge file, that's simply because I've tried to cover as many PIC variations as possible. The actual code generated by this library unit for your programs will consist of just a handful of instructions.
Please report any PICs or timers you encounter that don't work as expected, and also the ones that work well. Use the comments box, below, to let me know not only what didn't work for you, but also what worked. And don't forget to mention if the extensive error detection I've worked in is picking up on illegal choices or not.
Compilation Constants
To use a timer in your programs, you first need to define which it is with a conditional compilation constant in your main program. For example:
{$DEFINE TIMER0}
Timer names are given by TIMERx, where the suffix 'x' may be 0 through 8, 10 and 12, e.g., TIMER0, TIMER1, TIMER2, etc.
Of course, not all timers are necessarily available on all PICs, and you'll get an error message if you attempt to specify one not present in the current chip.
On some PICs, timers 2, 4, 6, 8, 10 and 12 are permanently fixed to be clocked by Fosc/4. In other cases in which you have a choice for a clock source, specify the timer clock source, e.g.,
{$DEFINE SOURCE0 'FOSC_4'}
establishes that you wish Timer0 to be clocked by Fosc/4. Don't forget the single quotes. Some of the sources available are
FOSC_4 (Fosc/4, i.e., instruction counter)
FOSC (Fosc, i.e., PIC clock oscillator)
EXT (external TxCKI pin, x = timer number)
EXT_INV (external and inverted)
SOSC (secondary oscillator)
(the rest are somewhat exotic; see the data sheet):
NCO1_OUT
ZCD1_OUT
LC4_OUT
LC3_OUT
LC2_OUT
LC1_OUT
T0_OVERFLOW
CLKR_OUT
MFINTOSC_32
MFINTOSC_500
LFINTOSC
HFINTOSC
CAPOSC
If no source is specified, then it will default to FOSC_4.
The most commonly used and (generally available on all PICs) are FOSC_4, which clocks the timer from the instruction counter, EXT which clocks the timer from a pin, and SOSC which clocks the timer from a secondary oscillator.
Obviously, not all choices are available on all PICs, so refer to your data sheet to see which you can use. However, I have worked in some error detection which should catch an illegal choice.
Observe that on some PICs, Timer0 may run either in 8-bit mode (the default) or 16-bit mode. To enable the latter, you'll want:
{$DEFINE TIMER0_SIZE 16}
Next, you'll set the associated prescaler for the timer you specified. The compilation constant name is PRESCALERx, where 'x' is a suffix as described above. This followed by a prescaler value, which is a power of 2.
Prescaler values are:
1, 2, 4, 8, 16, ..., 32768
If no prescaler is defined, then it will default to 1.
Again, not all prescaler values are available on all PICs. This library unit can catch many illegal choices, but probably not all (due to the many types of PICs extant), flagging them with an error message. So you'll want to check the data sheet for details.
Here's an example,
{$DEFINE PRESCALER2 16}
Postscalers are handled in a similar way, with the usual caveats. Legal values are 1, 2, 3, ..., 15. For example,
{$DEFINE POSTSCALER2 3}
If no postscaler is defined, then it will default to 1.
Based upon these compiler constants, this library unit creates the necessary setup code and executes it automatically at PIC power-up or reset. Note that the timer is not started by default; use the timerStart() command in your code to do so. (And remember that some timers are free-running.)
Putting it altogether then, the following definitions in your program will ready Timer0 for use, clock it by Fosc/4, run in 8-bit mode, with a prescaler of 1 and a postscaler of 1:
{$DEFINE TIMER0}
{$DEFINE SOURCE0 'FOSC_4'}
{$DEFINE TIMER0_SIZE 8}
{$DEFINE PRESCALER0 1}
{$DEFINE POSTSCALER0 1}
Or you could just rely on the defaults and simply use:
{$DEFINE TIMER0}
which will do the same thing.
Of course, you may use more than one timer at time. Just repeat these definitions, but for the other timers you need.
Global Variables
Once a timer is running, you may read it via a convenient alias of the associated register, e.g., Timer0, Timer1, etc. These are defined as byte- or word-sized, depending on the timer. So, for example:
if (Timer0 = 128) then
LED := true;
Commands
As mentioned, timer setup is automatically taken care of. Once the program is running, you may then use these four procedures at will. Their purposes should be obvious.
procedure timerStart(timer : byte);
procedure timerStop(timer : byte);
procedure timerClear(timer : byte);
procedure timerLoad(timer : byte; value : word);
However, I've also optimized the code so that when you're only using one timer, the parameters are reduced/eliminated, and the internal case structure also eliminated. In particular, if you're only employing one timer, use these four commands instead and reap the savings. The library unit will know which timer you mean, since it's the only one.
procedure timerStart;
procedure timerStop;
procedure timerClear;
procedure timerLoad(value : word);
Add It to Your Library Collection
You can get the Timers library unit "Timers.pas" by clicking the following link:
Be sure to read over the source code for additional details on how to use it.
Try It Out
If you poke around in the exercises (use the menu bar at the top of the screen), you'll find a dozen or so projects that use timers. I'll post some new ones once I get some feedback from others on how this unit is performing.
I've compiled for the PIC12F683 and PIC16F88. The code for Timer0, Timer1 and Timer2 looks correct. So far, so good. Will try some other PICs tomorrow.
ReplyDeleteOkay, test-compiled for the PIC16F1825 with timers 0, 1, 2, 4 and 6, and everything seems fine.
ReplyDeleteTest-compiled on a PIC18F5K22 tonight, and all okay with timers 0, 1, 2, 3, 4, 5 and 6.
ReplyDelete