The timer modules in PICs and other microcontrollers are useful for most applications; however, they are not true hardware timers in the sense that they are not edge-aligned to start on a rising or falling edge (unless they have a gating or enable feature), and cannot be synchronized to a clock edge to stop when generating a precise period.
A recent project required a precise one-second pulse derived from a precise 10 kHz clock source supplied to the CCP module timer. Code was written to initialize the timer to zero, clear the CCP pin, and when the preset count of 10000 was reached the CCP pin would clear, generating a one-second pulse. The results were variable — greater or less than one second by enough margin to be unacceptable in the application. The variation was made worse with the PIC running on the internal oscillator, whose frequency varied over temperature.
The fix: one D flip-flop
Connecting an SN74LVC1G374DCKR D flip-flop with the clock source on the clock pin and the CCP output on D resulted in a precise one-second pulse. There are a few instruction clocks between setting the CCP pin high, preloading and initializing the timer, and the point at which the timer begins to clock. When CCP does go high, the flip-flop Q output follows CCP on the next positive edge of the clock source. When the timer reaches the compare value, instruction clocks are needed to clear the CCP pin; Q then clears on the next rising clock edge. The flip-flop syncs the CCP output to the clock edges and allows a precise period based on the timer count.
This also worked on the delay instruction, as shown by the exact 300 ms pulse width. As long as the clock is an order of magnitude less than the instruction clock this method works well. I had no problem varying the clock from hundreds of Hz to 200 kHz, and varying the preset count — in all cases the width was precise.
The frequency counter and the function generator used as the clock source were both locked to my GPS-disciplined 10 MHz reference for this experiment. Changing which part of the period is high or low is a matter of using the Q-not output, or changing the C code from CCP_COMPARE_CLR_ON_MATCH to CCP_COMPARE_SET_ON_MATCH and changing the initial pin state prior to counting.