Timers
Most microcontroller applications must respond to temporal events. The timers subsystem allows an application to have multiple timers running concurrently, each with a different duration before expiration. This implementation is very simple, in that timers can be started, stoped, and polled for expiration (fired). By integrating with tasks, a timer expiration can post an event.
Timers are identified by a timer id. A timer started will fire at the end of the time period specified in the timer start call. A timer may also be started via startPeriodic(), which will fire the timer periodically according to the timer period specified in the call.
Implementation
The timer subsystem is implemented through the use of the PIC16 TMR0. It is configured to trigger a hardware interrupt every 32.768 milliseconds. Within each interrupt, the status of the currently active timers is updated. This is a very simplistic approach. A better solution would be to use a timer compare feature, which would dramatically reduce the number of ISR events and therefore servicing overhead for the timer subsystem.
Periodically the application can poll for timer fired by the tmr_fired() call. A good time to do this is in the ISR, and timers that fire can post tasks. The comments in tmr.h gives a complete example. Check the repository.
Timer and low power modes
Unfortunately, the PIC16 has limitations when it comes to using timers in sleep. While it is true that Timer 1 can run when the PIC16 is in sleep using an external 32 kHz crystal, no timer compare feature is possible in sleep. Therefore, the only timer inerrupt that can wake the micro is the overflow. This overflow happens every 2 seconds. In fact, the lamp code uses this behavior to handle the long term timer events via the tmr32 module. Specifically, this is used for the auto-off and auto-on events.
It is possible to get different overflow periods by programmatically setting the Timer 1 register. Since this is a 16 bit value implemented in 2 8-bit registers, there are race conditions that challenge this use. But the ability to support variable timer periods in sleep is possible.
When it comes to managing temporal events and deep sleep, the MSP430, the EFM32, and the STM32L are superior processors.