Tons and tons of interesting applications depend upon time or frequency. Obvious time-based ones would include alarm clocks, camera shutter delays, telescope controllers and metronomes. Or at the workbench, circuits to create waveforms of predictable frequency have no end of uses, such as homemade function generators, clocks for digital breadboards and even simple oscilloscopes configured around matrix LEDs.
Not so long ago, one would need to be fairly adept at analog design to handle the examples just mentioned, but now it’s far faster, easier and in many cases more accurate, to simply let a microcontroller take on the duties. The ubiquitous PIC microcontroller is particularly attractive since most variants contain a module expressly devoted to time-or frequency-based applications.
Called the Capture/Compare/Pulse Width Modulation unit (CCP for short), as the name suggests, this internal subcircuit is designed to handle three somewhat related operations. Pulse width modulation (PWM) is perhaps the best known. In this case, the duty cycle of a pulse wave is varied, which is handy for efficiently controlling motor speed or dimming lamps, among other things. The capture mode is primarily employed to sense the period or duty cycle of an incoming waveform.
And that leaves the compare mode, the subject of this tutorial. Think of it as the complement to the above. If capture mode is inputting a signal and reading off its period, then compare mode does just the reverse. We use it to create an output signal of a desired period and duty cycle. In a nutshell, then, we’ll explore how to use the compare mode to generate accurate timing pulses or repeating waveforms of a specified frequency.
The Big Picture
The main ingredients of the compare module are a counter always running in the background and some combinatoric logic to check when that counter has hit a desired number. If a match is detected, then your program can decide what to do next, typically changing the state of some output pin.
To keep things specific, let’s look in particular at the PIC16F88, which is not only common and inexpensive, but fairly representative of many microcontrollers.
Refer to the figure below now.
This depicts the functional arrangement of the components comprising the compare module. You’ll note a timer—really, just a binary counter, always incrementing, then rolling over to zero, only to continue—chugging away in the background. In the PIC, this is Timer1, and is sixteen bits in size, composed of the two bytes TMR1H and TMR1L concatenated. The value contained within the timer at any given moment is applied to one input of the numeric comparator.
At the other input is a fixed number provided by the Compare Register, made up of CCPR1H and CCPR1L. As the designer, you get to decide what this number should be. And now it becomes clear what’s going to happen. The timer keeps incrementing one step at a time but sooner or later must become equal to the number you stuffed into the Compare Register. When that occurs, the output of the comparator goes high, indicating a match has been made.
Let’s continue to trace the output of the comparator. A software switch determines whether the signal should set or reset a flip-flop, or perhaps just do nothing. In the figure above, when the switch is in the top position, the flip-flop will be reset (cleared), in the second position it will be set, and in the bottom position with the no-connection (n.c.), no action is taken, at least not at the port level.
The flip-flop output is routed to yet another switch, and its job is to connect to one of two port lines, B.0 or B.3. Think of the switch as a multiplexer, giving you the freedom to decide which pin you want to be using here. This decision must be made when you flash (burn) the PIC, since your choice is set in one of the configuration bits.
Whichever pin you decide upon will be referred to as the CCP1 pin from now on. It should be clear now that CCP1 can be toggled back and forth under control of the timer; this will be the source of the pulses, either single or repeating. We’ll see exactly how to set all these options in just a moment.
Back up to the output of the comparator. Note that it also gets routed around to a switch-selectable clear input. If you so choose, you can have the timer reset or clear itself whenever it hits the target value.
Lastly, observe that the comparator output is also sent to the so-called CCP1IF flag. This is an interrupt flag maintained by the PIC and when acted upon will cause the main program to be put on the backburner while a more pressing interrupt routine is attended to. This may sound mysterious just now, but as we’ll find out shortly, it all works quite slickly.
Making Your Choices
With the overview out of the way, let’s inch a little closer to the practical details and see how to set up the various options.
The first step is to decide which port line, B.0 or B.3, you’d like to connect to the output of the compare module. As mentioned earlier, this is locked into place when you flash the PIC. The choice is made in the CCPMX bit of configuration word CONFIG1. The next figure shows the particulars.
When we look into the experiments ahead, you’ll get to see examples of this in action. Incidentally, don’t forget that you always have the option to completely bypass connecting the compare module to a pin, in which case B.0 and B.3 are free for any other use you have in mind.
But if you are connecting to a pin, then be sure your program sets it to be an output. Even if all you’ve ever done is blink an LED, you’ll be aware of this requirement. Look to the TRISB register which sets the data direction of the port line.
Next on the agenda is to get Timer1 counting. Once revved up, it will continue to run and take care of itself. The following figure shows what you need to know, but here’s a brief run-through of the salient features.
Timer1 can be clocked from the main system oscillator (divided by four, for technical reasons), an external source or from an appended crystal or ceramic resonator. Moreover, if things are running too quickly for your application, you have the ability to slow it all down by setting a prescaler of 2, 4 or 8. Lastly, the TMR1ON bit lets you turn the timer on and off as needed. Again, read over the figure and you’ll see the specifics aren’t too grisly when taken in bite-sized chunks.
Now it’s time to decide upon a mode of operation, and this is detailed next.
Observe the big picture here: the first two modes do something to the CCP1 pin you declared earlier, while the last two leave it unaffected. If you are indeed pressing the CCP1 pin into service, then the first mode sets it on when a match is made, while the second turns it off again.
Now here’s a key point. In all four of these modes, the CCP1IF flag is set whenever the comparison is good. In the third mode, that’s all that happens. No pin action, nothing else! So, if you’d like, you can think of this as being a software-generated interrupt.
But in the fourth mode, one additional thing of interest occurs. Besides the flag being set, Timer1 is also cleared when a valid match is made. This is exceedingly useful and a super-fast way to begin counting from zero again.
The next figure describes what you need to know in order to do interrupt things with the compare module.
Take the time to look this over now. In a just a moment when we get into the experiments, we’ll put all this stuff into action. Truly, it’s very straightforward even if all the letters seem to be brewing up a pot of alphabet soup.
If you’d like to see the forest for the trees right now, though, here you go. As mentioned, the TMR1IF flag is always set when a match occurs. Whether it’s acted upon or not depends upon three interrupt enable bits (sometimes called masks). GIE is the global interrupt enable and as the name suggests, can be used to disable all interrupts in one fell swoop. PEIE on the other hand enables or disables only the peripheral generated interrupts, and the compare module is indeed considered a peripheral. Finally, CCP1IE is a mask which applies specifically to the CCP module. All three of these should be enabled, then, in order to respond to interrupts.
Enough Theory—Let’s Build Something!
Really, the only decent way to learn electronics is by doing electronics. So let’s head to the workbench and fire up the breadboard. Here are four experiments for you to try, the very ones I whipped up for myself when first learning how the compare module works. Begin by fetching the source code for these experiments, written in the powerful PIC Micro Pascal language.
In Experiment 1, the compare module is used to generate the frequencies 1 kHz on up to 16 kHz, in 1 kHz steps. The following schematic shows the circuit, and an easy one it is.
Four switches are used to select the desired frequency. With these, then, you can create the binary numbers 0 through 15, corresponding to the frequencies just mentioned. I decided to clock the PIC on a 20 MHz ceramic resonator, since that’s what I had handy.
If you check out the source, you’ll see that the fourth mode is being used, which automatically clears Timer1 when a match occurs. Moreover, an interrupt routine sets or clears port line B.0 on appropriate half-cycles. When monitoring the results with a homemade frequency counter, I found that the unit was fairly accurate, generating frequencies within 0.6%, about what you’d expect with a ceramic resonator. A crystal would give even more precise results.
The breadboard looks like this:
Experiment 2, whose schematic appears below, probably seems like a step back into your past.
Here we’re simply going to flash an LED once a second, but now using everything we’ve learned about the compare module. So, don’t let its simplistic nature fool you: the journey is far more important than the destination. Notice how the program changes modes to alternately set or clear the CCP1 pin.
On the workbench, it appears thus:
Experiment 3 uses the same circuitry, and accomplishes the same goal. But in this case we’re using software-generated interrupts only.
Experiment 4 is particularly interesting, as it uses an outboard crystal to generate one-second interrupts independently of the PIC’s main internal system clock. This could serve as the heart of a realtime clock.
The seven-segment LED unit displays the digits 0 through 9, incrementing once per second. When I ran it, I found that it lost four seconds in a day, probably due to stray capacitance on the breadboard, among other things. Wristwatch type (tuning fork) crystals really do require careful circuit board layouts for optimal accuracy. Here's how the rig appears:
And with that, we’re out of space, but certainly not further experiments and applications of the compare module. If you take the time to review the figure above, then study the heavily commented PMP source code and, finally, actually run the experiments, you should have a good grasp of the compare module and be all set to continue on your own, even taming that daunting PIC data sheet!
Next Tutorial: Analog Comparators