Using the PIC Comparator


Every mid-range PIC MCU has an analog comparator. The two analog inputs are VIN+ and VIN-, and the digital output is COUT. If VIN+ > VIN-, then COUT = 1, while if VIN+ < VIN-, COUT = 0. The comparator can be configured so that the output is inverted, igf this is convenient. The comparator is configured with the CMCON register, where bit 6 is COUT. If bit 4 is set, the output is inverted. Bits 0-2 select one of eight comparator modes, while bit 3 selects one of two inputs for VIN- in two of the modes.

The pins GP0-GP2 are by default assigned to the comparator. GP0 or CIN- is usually connected to VIN-, GP1 or CIN+ to VIN+, and GP2 to COUT. In some of the configurations one or more of these pins is released for digital I/O. Comparator mode 7 or 111 turns the comparator off and all the pins are digital I/O. On power-on reset, the mode 000 is set with the comparator off and GP2 a digital I/O pin. COUT reads as 0 in this mode. In mode 001 the comparator is turned on, with VIN- connected to GP0, VIN- to GP1, and COUT available at GP2 as well as in CMCON. Mode 010 is similar, but COUT is only available in CMCON and GP2 is digital I/O.

In the remaining 4 modes, VIN+ is connected to an internal voltage reference, VREF. Mode 3 is like mode 1, and mode 4 is like mode 2, with this modification. The input that is not used becomes a digital I/O. In modes 5 and 6, the analog input to VIN- can be chosen to be either GP0 or GP1, by selecting the CIS bit in CMCON. CIS = 0 selects GP0, while CIS = 0 selects GP1. Mode 5 is like mode 1, mode 6 like mode 2, with respect to COUT.

The reference voltage is controlled by VRCON. Setting bit 7 turns the voltage source on. Bits 0-3 control the voltage, which is proportional to VDD, in two ranges. The low range is selected by setting bit 5, and the reference voltage is (N/24)VDD, where N is the number given by bits 0-3. Clearing bit 5 gives the high range, (1/4 + N/32)VDD. For VDD = 5 V, the low range is 0-3.125 V and the high range is 1.250-3.746 V. This is certainly not ideal, but gives enough flexibility for many applications.

The comparator will generate an interrupt when COUT changes, setting the flag CMIF in the PIR1 register. The request is based on a discrepancy between the instantaneous value of COUT and the old value in CMCON. A read or write to CMCON must be made to remove the discrepancy before clearing CMIF to avoid a race. The interrupt occurs if enabled by setting the bits CMIE in PIE1, PEIE in INTCON, and GIE in INTCON.

Testing the Comparator

First, let us see how the comparator functions. Apply VDD/2 to GP0, using a voltage divider made from two 4.7kΩ resistors. Apply a variable voltage to GP1, using a 10kΩ potentiometer. Connect an LED in series with a 330Ω resistor to GP2.

The program is very simple. Clear bit 2 in TRISIO for the digital output. Load CMCON with 0x01 to select mode 1. Then enter an infinite loop with goto $. When power is applied, the LED will light whenever the potentiometer voltage is greater than VDD/2. We will show a more complicated way to achieve the same result later.

Remove the voltage divider. Use mode 3, loading VRCON with 0x88, which supplies VREF 2.5 V. Reprogram the MCU and test the program again, which should behave the same way. Finally use the low range of the VREF to supply the same reference voltage.

Testing the Comparator Interrupt

Let us now do this the hard way, letting an interrupt routine control the LED. Move the LED to GP5, but leave the potentiometer wiper connected to GP1. Use comparator mode 4, which will release GP0 and GP2 as digital I/O. TRISIO should be loaded with 00011111, and CMCON with 00000100. VRCON should still hold 0x88 to provide VREF = 0.5 VDD. In the initialization, we should control the LED according to the value of COUT, and we may also maintain a location with the value of COUT, though this variable will not be used in this test. We can test the value of COUT after initializing CMCON. Finally, we should clear CMIF (we have just written CMCON, so there will be no discrepancy). Now CMIE, PEIE and GIE should be set (setting the bank properly in each case), and we can jump into an infinite loop to wait for interrupts. In an actual application, the processor could now handle its other duties while waiting.

The ISR should first check CMIF to see whether it is set. It should then read CMCON to remove the discrepancy, and test the value of COUT to set or clear the LED as approprate, and maintain the variable showing the state if it is used. Finally, CMIF should be cleared and the ISR should return. Context saving can be included for practice, though it is not necessary in this case. Note that we do modifiy W and STATUS in the ISR, so in general context saving is necessary.

If the MCU is devoted entirely to monitoring COUT, it will be more convenient simply to poll COUT (instead of an infinite loop) in place of using an interrupt.

Designing a Controller

A closed-loop controller compares a voltage describing the state of a system, called the feedback voltage, with a target voltage, and takes action to decrease the difference between them. An example is a temperature controller, where the controller turns on a heater when the temperature of the system falls below the desired temperature, and turns it off when the temperature rises above the target temperature.

One problem that may occur is hunting, when the on-off cycling is too frequent. This may be cured by raising the target temperature slightly when the temperature falls below the target, then lowering the target temperature when the temperature rises above the new target. This is called hysteresis, and is usually necessary in closed-loop controllers. It is easily implemented when the target level is set by the reference voltage provided by VRCON. The N value is simply incremented when the feedback voltage falls below the target, and decremented when the feedback voltage rises above it, by a suitable increment. This is a relatively coarse control, but may be adequate in many applications.

For finer control, the feedback voltage can be digitized by the AD converter, and compared with target values by subtraction. Hysteresis can be implemented by choosing the two variables properly. The target value can also be determined by an AD conversion, since the AD converter has selectable inputs. It is also easy to make the degree of response depend on the amount of difference, if this is possible. In fact, the response can be made proportional to the difference (P), to the integral of the difference (I) or to the differential (D) of the difference, creating a PID controller response. In this case, the comparator is not used.


The programs are prepared with the MPLAB IDE, and the MCU's are programmed with a PICkit 2 and LPC board.

Return to Electronics Index

Composed by J. B. Calvert
Created 25 September 2010
Last revised