Creating "Software" Timers in your program.


1. Introduction

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?

a. Overview

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

procedure interrupt
begin
  if TimerX.InterruptFlag = 1 then	// replace this name by the real name of the timer interrupt flag you use
  begin
    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
    begin
      dec(Tim1);                      // decrement counter
      if Tim1 = 0 then Flag1 := true; // timer has expired
    end;
    
    // update SW timer 2
    if Tim2 > 0 then
    begin
      dec(Tim2);                      // decrement counter
      if Tim2 = 0 then Flag2 := true; // timer has expired
    end;

    // ... etc
    
  end;
end

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
  begin
    Tim1 := 20; // start timer 1 with an expiration time of 20 times that of the HW timer
  end;
  
  if ... then   // some event occurred that needs SW timer 2 to be started up
  begin
    Tim2 := 50; // start timer 2 with an expiration time of 50 times that of the HW timer
  end;
  
  // ... etc
  
  
  // Test timer expiration
  
  if Flag1 then
  begin    
    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
  end;

  if Flag2 then
  begin    			
    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
  end;

  if Flag3 then
  begin    
    Flag3 := false;     // ...
    ...                 // ...
  end;

  // ... etc

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



-------------------------------------------