Creating "Software" Timers in your program.
Sometimes a (high) number of different timed activities has to be performed, e.g. creation of timeouts for expected events.
Since the number of timers in a PIC is limited, the trick is to use one hardware timer and derive a number of SW timers from it.
The SW timers will of course always have a longer "time" than the HW timer.
2. How to do it?
One hardware timer has to be used to be able to derive SW timers from it. The HW timer has to run fast enough for the fastest SW timer you want to create, e.g. 1000Hz (one millisecond).
The HW timer will use its interrupt to update the SW timers.
For every software timer you need 2 variables: a "flag" signalling the SW timer has expired and a "timer" counter.
In the HW timer interrupt routine the SW timers are decremented (on the HW timer frequency) until they reach zero, in which case the expiration "Flag"
will be set.
In the main program loop SW timers can be started by giving a non zero value to the "Timer"(counter) variable.
Expiration of a SW timer can be tested by testing its "Flag" (and resetting it of course).
b. The SW timer variables
var Flag1, Flag2, Flag3, ... : boolean; // Signalling flag "GLOBAL" variables (declared outside any procedure or function)
// You should give more meaningfull names to the signalling flags!
var Tim1, Tim2, Tim3, ... : byte; // The variables that will function as SW timer registers
c. The timer interrupt routine
if TimerX.InterruptFlag = 1 then // replace this name by the real name of the timer interrupt flag you use
TimerX.InterruptFlag = 0; // reset the timer interrupt flag before returning from the interrupt service routine. (do not forget).
// update SW timer 1
if Tim1 > 0 then
dec(Tim1); // decrement counter
if Tim1 = 0 then Flag1 := true; // timer has expired
// update SW timer 2
if Tim2 > 0 then
dec(Tim2); // decrement counter
if Tim2 = 0 then Flag2 := true; // timer has expired
// ... etc
d. The main loop
Its task is to start the times, check the flags, to execute what should be executed, and to reset the "Flag" when it is done. So, it will look like this:
while true do begin // endless loop
// Starting of the timers
if ... then // some event occurred that needs SW timer 1 to be started up
Tim1 := 20; // start timer 1 with an expiration time of 20 times that of the HW timer
if ... then // some event occurred that needs SW timer 2 to be started up
Tim2 := 50; // start timer 2 with an expiration time of 50 times that of the HW timer
// ... etc
// Test timer expiration
if Flag1 then
Flag1 := false; // reset the flag (otherwise the actions would be executed every loop round, do not forget)
... // here come the actions to be done when SW timer 1 has expired
if Flag2 then
Flag2 := false; // reset the flag (otherwise the actions would be executed every loop round, do not forget)
... // here come the actions to be done when SW timer 2 has expired
if Flag3 then
Flag3 := false; // ...
... // ...
// ... etc
As simple as that! Again: make sure that the main loop goes round fast enough to not miss any Flag settings.
e. Program initialization
Of course, till now only the "operational" parts of the code have been shown, but there is also the program and PIC initialization to take care of.
It looks like this:
(1) Several tools have been developed to calculate the settings of timers, see Tools .
- Initialization of the "Timer" Variables to zero (stop timers)
- Initialisation of all "Flags" to false
- Setting the correct registers for the timer, so it will overflow at the desired timing rate (1)
- Enabling the timer interrupt of the timer used, the enabling of the peripheral interrupts, plus the general enabling of interrupts (if not already the case)