Download as pdf or txt
Download as pdf or txt
You are on page 1of 20

© Gooligum Electronics 2014 www.gooligum.com.

au

Introduction to PIC Programming


Enhanced Mid-Range Architecture and Assembly Language

by David Meiklejohn, Gooligum Electronics

Lesson 10: Analog Comparators

We’ve seen how to respond to simple on/off digital signals, but we live in an “analog” world; many of the
sensors you will want your PIC-based projects to respond to, such as temperature or light, have smoothly
varying outputs whose magnitude represents the value being measured; they are analog outputs.
In many cases, you will want to treat the output of an analog sensor as though it was digital (i.e. on or off,
high or low), without worrying about the exact value. It may be that a pulse, that does not meet the
requirements for a “digital” input, has to be detected: for example, the output of a Hall-effect sensor attached
to a rotating part. Or we may simply wish to respond to a threshold (perhaps temperature) being crossed.
In such cases, where we only need to respond to an input voltage being higher or lower than a threshold, it is
usually appropriate to use an analog comparator. In fact, analog comparators are so useful that most PICs
include them, as built-in peripherals.
This lesson explains how to use comparators, on enhanced mid-range PIC devices, to respond to analog
inputs.
In summary, this lesson covers:
 Using comparators to compare voltage levels
 Adding comparator hysteresis
 Comparator-driven interrupts
 Wake-up on comparator change

Comparators
A comparator (technically, an analog comparator) is a device which compares the voltages present on its
positive and negative inputs. If the voltage on the positive input is greater than that on the negative input, the
output is set “high”; otherwise the output is “low”.
An example is shown in the diagram on the right.
The two 10 kΩ resistors act as a voltage divider, presenting 2.5 V at the
comparator’s negative input. This sets the on/off threshold voltage.
The potentiometer can be adjusted to set the positive input to any
voltage between 0 V and 5 V.
When the potentiometer is set to a voltage under 2.5 V, the
comparator’s output will be low and the LED will not be lit. But when
the potentiometer is turned up past halfway, the comparator’s output
will go high, lighting the LED.

Enhanced Mid-Range PIC Assembler, Lesson 10: Analog Comparators Page 1


© Gooligum Electronics 2014 www.gooligum.com.au

Comparators are typically used when a circuit needs to react to a sensor’s analog output being above or
below some threshold, triggering some event (e.g. time to fill the tank, turn off a heater, or start an alarm).
They are also useful for level conversion. Suppose a sensor is outputting pulses which are logically “on/off”
(i.e. the output is essentially digital), but do not match the voltage levels needed by the digital devices they
are driving. For example, with VDD = 5 V, TTL-compatible digital inputs require at least 2 V (or 4 V for
Schmitt trigger inputs) to register as “high”. That’s a problem if a sensor is delivering a stream of 0 - 1 V
pulses. By passing this signal through a comparator with an input threshold of 0.5 V, the 1 V pulses would
be recognised as being “high”.

PIC16F1824 Comparator Module


The PIC16F1824 includes two comparators.
They operate identically, so this description applies to both – wherever an ‘x’ appears in a register, bit or pin
name, you can substitute ‘1’ for comparator 1, or ‘2’ for comparator 2.

The comparator input channels are selected via the CxPCH and CxNCH bits in the CMxCON1 register:
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
CMxCON1 CxINTP CxINTN CxPCH<1:0> – – CxNCH<1:0>

The CxPCH bits select the positive input, as follows:

CxPCH<1:0> Positive input Description Each comparator has a separate


pin which can be selected as its
00 CxIN+ pin C1IN+ (RA0) or C2IN+ (RC0) positive input: C1IN+ (shared
01 DAC Variable voltage reference with RA0 on the 16F1824) for
comparator 1, while C2IN+
10 FVR Fixed voltage reference (shared with RC0) is used with
11 VSS Ground (0 V) comparator 2.

It is also possible to use a fixed or variable voltage reference as the positive input on either comparator.
We’ll look at the voltage references in detail in the next lesson, but briefly they allow an internally-generated
voltage to be used as the comparator threshold, avoiding the need to use external circuitry to create the
threshold (as we will do in the examples in this lesson), simplifying your design and freeing an I/O pin.
Note that VSS (ground) can be selected as the positive input. This can be used to detect when an input
crosses 0 V, but note that the voltage on a PIC pin must never be allowed to go below -0.3 V.

The CxNCH bits select the negative input, as follows:

CxNCH<1:0> Negative input Shared with pin The two comparators share a set of four
input pins: C12IN0-, C12IN1-, C12IN2-
00 C12IN0- RA1 and C12IN3-, which on the 16F1824 share
01 C12IN1- RC1 their physical pin with RA1, RC1, RC2 and
RC3 respectively.
10 C12IN2- RC2
Each of these pins can be selected as the
11 C12IN3- RC3 negative input on either comparator.

Enhanced Mid-Range PIC Assembler, Lesson 10: Analog Comparators Page 2


© Gooligum Electronics 2014 www.gooligum.com.au

In summary, there are six physical comparator input pins.


Each comparator has its own separate positive input (C1IN+ and C2IN+) pin, while C12IN0-, C12IN1-,
C12IN2- and C12IN3- are shared and can each be used as the negative input for either comparator.
Note that, in order to use a pin as a comparator input, it must first be configured as an input by setting the
corresponding TRIS bit and analog input mode selected by setting the corresponding ANSEL bit.

Each comparator is controlled by its CMxCON0 register:


Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
CMxCON0 CxON CxOUT CxOE CxPOL – CxSP CxHYS CxSYNC

The CxON bit turns the comparator on or off: ‘1’ to turn it on, ‘0’ to turn it off.
Turning off the comparator saves power, which is especially important in sleep mode. Of course, if you’re
using the comparator to wake the device from sleep (see later in this lesson), you’ll need to leave it on.
However, comparator power consumption can be reduced by clearing the CxSP bit, which, for a 16F1824
with a 5 V supply in sleep mode, reduces the comparator current from 42 µA to 10 µA (typical). The trade-
off (yes, there is always at least one…) is that the comparator is slower in low-power mode. For example,
the time taken to respond to a rising edge increases from 400 ns to 1200 ns (typical).

The comparator’s output appears as the CxOUT bit: it is normally set to ‘1’ if and only if the positive input
voltage is higher than the negative input voltage.
That’s the normal situation, but the operation of the comparator can be inverted by setting the CxPOL output
polarity bit:
CxPOL = 0 selects normal operation
CxPOL = 1 selects inverted operation, where CxOUT = 1 only if positive input < negative input.

The comparator output can also be made available externally, on the CxOUT pin, by setting the CxOE bit.
The C1OUT and C2OUT pins are shared with (and take priority over) RA2 and RC4 respectively.
Note that, to use a pin as an external comparator output, it must first be configured as an output by clearing
the corresponding TRIS bit.

It is often desirable to add some hysteresis to the comparator’s operation, to avoid its output randomly
changing states due to noise on its inputs, while the input levels are very close. A small amount of hysteresis
(typcially 45 mV) can be added to the comparator inputs by setting the CxHYS bit.

The CxSYNC bit is used to synchronise the comparator output with Timer1; we’ll see how it’s used when
we look at Timer1, in a later lesson.

Finally, it may be important, in some applications, to be able to sample the output of both comparators at the
same time. With the C1OUT bit being in the CM1CON0 register, and C2OUT being in CM2CON0, it is
not possible to read both bits at once – you can only read one register, and then the other.

Enhanced Mid-Range PIC Assembler, Lesson 10: Analog Comparators Page 3


© Gooligum Electronics 2014 www.gooligum.com.au

To address this problem, a copy (or mirror) of each comparator output bit is also made available in the
CMOUT register:

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0


CMOUT – – – – – – MC2OUT MC1OUT

The advantage of using the CMOUT register is that both comparator output bits can be read in a single
operation. Otherwise, whether you use these bits or the CxOUT bits in the CMxCON0 registers makes no
difference – they are mirror images of each other: MC1OUT = C1OUT, and MC2OUT = C2OUT.

Example 1: Basic comparator operation


We’ll start by demonstrating the comparator’s basic
operation with the circuit shown on the right.
As you can see, we’re essentially implementing the
comparator circuit shown on page 1. The two 10 kΩ
resistors create a 2.5 V reference, or threshold voltage
on the C12IN0- pin. The potentiometer provides a
variable voltage (the “signal” we’re measuring) on
C1IN+. We’ll light the LED on RA2 whenever this
input signal rises above the threshold level.

If you have the Gooligum training board, you can


build this circuit by placing a shunt across pins 1 and 2
(‘POT’) of JP24, connecting the 10 kΩ pot (RP2) to
C1IN+, and in JP13 to enable the LED on RA2.
The connection to C12IN0- (labelled ‘GP/RA/RB1’
on the board) is available as pin 9 on the 16-pin
header. +V and GND are brought out on pins 15 and
16, respectively, making it easy to use the solderless
breadboard to add the 10 kΩ resistors (supplied with the board).

The circuit can alternatively be built using the Microchip Low Pin Count Demo Board.
The 10 kΩ potentiometer on that board is already connected to C1IN+ (labelled ‘RA0’ on the board), via a 1
kΩ resistor (not shown in this diagram). But you must ensure that jumper JP5 is closed; it will be, if you
haven’t modified your demo board. You will need to connect an LED to RA2, as was shown in lesson 1.
You can connect 10 kΩ resistors via the 14-pin header on the demo board. C12IN0- (labelled ‘RA1’) is
available on pin 8, and +V and GND are pins 13 and 14 respectively.

It is straightforward to configure the PIC as a simple comparator, turning on the LED if the potentiometer is
turned more than halfway toward the +5V supply (right) side.
First, we need to configure RA2 as an output and RA0 (C1IN+) and RA1 (C12IN0-) as inputs:
; configure ports
movlw ~(1<<nLED) ; configure LED pin (only) as an output
banksel TRISA ; (RA0/C1IN+ and RA1/C12IN0- are inputs)
movwf TRISA

Enhanced Mid-Range PIC Assembler, Lesson 10: Analog Comparators Page 4


© Gooligum Electronics 2014 www.gooligum.com.au

where we have defined:


; pin assignments
#define LED LATA,2 ; indicator LED on RA2
constant nLED=2 ; (port bit 2)

Although analog is the default mode for all inputs with an associated analog input function, it is good
practice to explicitly select analog input mode for RA0 and RA1, to make it clear that these pins are being
used as analog inputs:
movlw b'000011' ; select analog mode for RA0 and RA1
banksel ANSELA ; -> RA0/C1IN+ and RA1/C12IN0- are analog
movwf ANSELA

Next, we can configure comparator 1:


; configure comparator 1
movlw b'10000100' ; configure comparator 1:
; 1------- comparator enabled (C1ON = 1)
; --0----- external output disabled (C1OE = 0)
; ---0---- output not inverted (C1POL = 0)
; -----1-- normal power mode (C1SP = 1)
; ------0- hysteresis disabled (C1HYS = 0)
; -------0 asynchronous output (C1SYNC = 0)
banksel CM1CON0
movwf CM1CON0
movlw b'00000000' ; select comparator 1 inputs:
; --00---- + in = C1IN+ pin (C1PCH = 00)
; ------00 - in = C12IN0- pin (C1NCH = 00)
movwf CM1CON1 ; -> C1OUT = 1 if C1IN+ > C12IN0-

This turns comparator 1 on, and configures it to test for C1IN+ > C12IN0-, with the external output disabled
and no additional “features” such as low-power, hysteresis or output synchronisation.
This is the default setting, so in theory it was only necessary to enable comparator 1, with:
banksel CM1CON0
bsf CM1CON0,C1ON ; enable comparator 1

But relying implicitly on default settings is obscure and error-prone; it is much clearer and safer to explicitly
initialise all of the register bits that affect the functions you are using.

To turn on the LED when the comparator output is high, repeatedly test C1OUT:
main_loop
; display comparator output
banksel CM1CON0
btfsc CM1CON0,C1OUT ; if comparator output high
bsf LED ; turn on LED
btfss CM1CON0,C1OUT ; if comparator output low
bcf LED ; turn off LED

; repeat forever
goto main_loop

Note that there is no need to add ‘banksel LATA’ directives before accessing the LED output pin, because,
in enhanced mid-range PICs, the comparator and output data latch registers are all located in the same bank.

Enhanced Mid-Range PIC Assembler, Lesson 10: Analog Comparators Page 5


© Gooligum Electronics 2014 www.gooligum.com.au

This makes it possible to avoid having to use the more complex type of “copy a bit” routine, involving
‘goto’s and labels, that we’ve had to use before.

You should find that, as you turn the potentiometer past halfway, the LED turns on and off.

The RA2 pin, that we’ve used to drive the LED, can instead be used as the comparator 1 external output pin,
C1OUT. So, if we enable the external output, the comparator can drive the LED directly, independently of
our program code.
The comparator configuration becomes:
; configure comparator 1
movlw b'10100100' ; configure comparator 1:
; 1------- comparator enabled (C1ON = 1)
; --1----- external output enabled (C1OE = 1)
; ---0---- output not inverted (C1POL = 0)
; -----1-- normal power mode (C1SP = 1)
; ------0- hysteresis disabled (C1HYS = 0)
; -------0 asynchronous output (C1SYNC = 0)
banksel CM1CON0
movwf CM1CON0
movlw b'00000000' ; select comparator 1 inputs:
; --00---- + in = C1IN+ pin (C1PCH = 00)
; ------00 - in = C12IN0- pin (C1NCH = 00)
movwf CM1CON1 ; -> C1OUT pin = 1 if C1IN+ > C12IN0-

Once configured, the comparator output will appear on the C1OUT pin automatically, so the main loop is
left with nothing to do:
main_loop
; (do nothing)

; repeat forever
goto main_loop

To make the circuit a little more interesting, we’ll add


a light-dependent resistor (LDR, or CdS photocell), as
shown on the right.
As the light level increases, the resistance of the LDR
falls, and the voltage at the potential divider (formed
by the LDR and the 22 kΩ resistor) connected to
C1IN+ rises.
The exact resistance range of the photocell is not
important; the ones supplied with the Gooligum
training board have a resistance of around 20 kΩ or so
for normal indoor lighting conditions, which is why a
22 kΩ resistor is used for the lower arm of the potential
divider here – the voltage at C1IN+ will vary around
2.5 V or so when it’s not too bright, not too dark.
If you are using the Gooligum training board, you only
need to move the shunt in JP24 across to pins 2 and 3

Enhanced Mid-Range PIC Assembler, Lesson 10: Analog Comparators Page 6


© Gooligum Electronics 2014 www.gooligum.com.au

(‘LDR1’), connecting the photocell (PH1) and 22 kΩ resistor in the lower left of the board to C1IN+.
If you are using the Microchip Low Pin Count Demo Board, you can’t take the 10 kΩ potentiometer out of
the circuit – it, and the 1 kΩ resistor in series between it and C1IN+, must be used as the “fixed” resistance,
forming the lower arm of the potential divider. You must also remove jumper JP5 (you may need to cut the
PCB trace – ideally you’d install a jumper, so that you can reconnect it again later), to disconnect the pot
from the +5 V supply.
If you turn the pot all the way to the right, you’ll have a total resistance of 11 kΩ between C1IN+ and
ground. That means that ideally you’d use a photocell with a resistance of around 10 kΩ with normal indoor
lighting. The photocell can then be connected between pin 7 on the 14-pin header and +5 V.
If you don’t have a photocell, there is no problem with continuing to use the potentiometer-only circuit for
these lessons; but it’s certainly more fun to build a circuit that responds to light!

When you build this circuit and use the above code, you will find that the LED turns on when the LDR is
illuminated.
If you would prefer it to work the other way, so that the LED is lit when the light level falls (simulating e.g.
the way that streetlamps turn on automatically when it gets dark), there’s no need to change the circuit
connections or program logic. Simply change the comparator initialisation instructions to invert the output,
by setting the C1POL bit:
; configure comparator 1
movlw b'10110100' ; configure comparator 1:
; 1------- comparator enabled (C1ON = 1)
; --1----- external output enabled (C1OE = 1)
; ---1---- output inverted (C1POL = 1)
; -----1-- normal power mode (C1SP = 1)
; ------0- hysteresis disabled (C1HYS = 0)
; -------0 asynchronous output (C1SYNC = 0)
banksel CM1CON0
movwf CM1CON0
movlw b'00000000' ; select comparator 1 inputs:
; --00---- + in = C1IN+ pin (C1PCH = 00)
; ------00 - in = C12IN0- pin (C1NCH = 00)
movwf CM1CON1 ; -> C1OUT pin = 1 if C1IN+ < C12IN0-

Adding hysteresis
You will notice, as the light level changes slowly past the threshold where the LED turns on and off, that the
LED appears to fade in and out in brightness. This is caused by noise in the circuit and fluctuations in the
light source (particularly at 50 or 60 Hz, from mains-powered fluorescent lamps): when the input is very
close to the threshold voltage, small input voltage variations due to noise and/or fluctuating light levels cause
the comparator output to rapidly, and randomly, switch between high and low. This rapid switching, similar
to switch bounce, can be a problem if the microcontroller is supposed to count input transitions, or to
perform an action on each change.
To reduce this phenomenon, we can set the C1HYS bit to enable comparator hysteresis. In this mode, a
small separation voltage (typically 45 mV for the PIC16F1824) is added at the comparator inputs.
However, you will find that the effect is quite small – in some situations you may need more hysteresis than
this input separation voltage can provide.
Additional hysteresis can be created by adding positive feedback – feeding some of the comparator’s output
back to its positive input.

Enhanced Mid-Range PIC Assembler, Lesson 10: Analog Comparators Page 7


© Gooligum Electronics 2014 www.gooligum.com.au

Consider the comparator circuit shown on the right.


The threshold voltage, Vt, is set by a voltage divider, formed by
resistors R1 and R2.
R2
This would normally set the threshold at Vt  Vdd .
R1  R 2
However, resistor Rh feeds some of the comparator’s output back,
increasing the threshold to some higher level, Vth, when the
output is high, and decreasing it to a lower level, Vtl, when the
output is low.
Now consider what happens when Vin is low (less than Vtl) and
begins to increase. Initially, since Vin < Vt, the comparator output
is high, and the threshold is high: Vt = Vth.
Eventually Vin rises above Vth, and the comparator output goes
low, lowering the threshold: Vt = Vtl.
Now suppose the input voltage begins to fall. As it falls past the high threshold, Vth, nothing happens. It
has to keep falling, all the way down to the low threshold, Vtl, before the comparator output changes again.
There are now two voltage thresholds: one (the higher) applying when the input signal is rising; the other
(lower) applying when the input is falling. The comparator’s output depends not only on its inputs, but on
their history – a key characteristic of hysteresis.
The voltage difference between the two thresholds is known as the hysteresis band: Vhb = Vth – Vtl.
This is the amount the input signal has to fall, after rising through the high threshold, or rise, after falling
through the low threshold, before the comparator output switches again. It should be higher than the
expected noise level in the circuit, making the comparator immune to most noise.

To calculate the high and low thresholds, recall Thévenin’s theorem,


which states that any two-terminal network of resistors and voltage
sources can be replaced by a single voltage source, Veq, in series with a
single resistor, Req.
Thus, the circuit above is equivalent to that on the left, where
R2
Veq  Vdd
R1  R 2
R1 R 2
and Req is the parallel combination of R1 and R2: Req 
R1  R 2
Therefore, when the comparator’s output is low (= 0 V):
Rh
Vtl  Veq (thus Vtl < Veq)
Rh  Req
and, when the comparator’s output is high (= Vdd):

Vth  Veq 
Req
Vdd  Veq  (thus Vth > Veq)
Rh  Req

As we’ve seen, each comparator’s output can be made available externally; the external outputs can be used
to add additional comparator hysteresis, as appropriate.

Enhanced Mid-Range PIC Assembler, Lesson 10: Analog Comparators Page 8


© Gooligum Electronics 2014 www.gooligum.com.au

Example 2: External comparator hysteresis


We’ll use the circuit on the right to show
how external feedback can create comparator
hysteresis – using comparator 2 in this
example to demonstrate that it operates the
same way as comparator 1.
In this case, the comparator’s positive input
(C2IN+) is being used as the threshold (Vt)
while the signal being measured (Vin) is on
one of the negative inputs (C12IN0-).
This is consistent with common comparator
usage – note that the internal voltage
references, which as we’ll see in the next
lesson can be used to establish the threshold
voltage level, can only selected as positive
inputs.
The comparator output on C2OUT is fed
back into the positive input via a 22 kΩ
resistor.
Finally, we’ll use the LED on RC1 to indicate when the LDR is in darkness (i.e. when the input voltage on
C12IN0- is less than the threshold voltage on C2IN+).

If you are using the Gooligum training board you can build this circuit by placing a shunt in position 3
(labelled ‘C1IN-’) of JP25, connecting a photocell (PH2) and 22 kΩ resister to C12IN0-, and in JP17 to
enable the LED on RC1. You can use the solderless breadboard to add the supplied 4.7 kΩ, 10 kΩ and 22
kΩ resistors; C2IN+ (labelled ‘RC0’) and C2OUT (‘RC4’) are available via pins 10 and 6, respectively, on
the 16-pin header.

Using these voltage and resistance values in the formulas above gives, for this circuit:
Veq = 1.6 V Req = 3.2 kΩ Rh = 22 kΩ
Vtl = 1.40 V Vth = 2.03 V Vhb = 0.63 V
Thus, the upper and lower voltage thresholds are either side of 1.6 V.
The hysteresis band of 0.63 V represents around 13% of the input voltage range of 0 – 5 V, which is quite
large but makes it easy to observe the effect.

The code is essentially the same as before, but modified to work with comparator 2 and an LED on RC1.
Our port initialisation becomes:
; configure ports
movlw ~(1<<nLED|1<<4) ; configure LED pin and RC4/C2OUT as outputs
banksel TRISC ; (RA1/C12IN0- and RC0/C2IN+ are inputs)
movwf TRISC
banksel ANSELA ; select analog mode for RA1 and RC0
bsf ANSELA,1 ; -> RA1/C12IN0- and
bsf ANSELC,0 ; RC0/C2IN+ are analog inputs

Note again that, to allow C2OUT to drive the RC4 pin, RC4 must be configured as an output.

Enhanced Mid-Range PIC Assembler, Lesson 10: Analog Comparators Page 9


© Gooligum Electronics 2014 www.gooligum.com.au

The comparator configuration becomes:


; configure comparator 2
movlw b'10100100' ; configure comparator 2:
; 1------- comparator enabled (C2ON = 1)
; --1----- external output enabled (C2OE = 1)
; ---0---- output not inverted (C2POL = 0)
; -----1-- normal power mode (C2SP = 1)
; ------0- hysteresis disabled (C2HYS = 0)
; -------0 asynchronous output (C2SYNC = 0)
banksel CM2CON0
movwf CM2CON0
movlw b'00000000' ; select comparator 2 inputs:
; --00---- + in = C2IN+ pin (C2PCH = 00)
; ------00 - in = C12IN0- pin (C2NCH = 00)
movwf CM2CON1 ; -> C2OUT = 1 if C12IN0- < C2IN+

Note that it is very important to clear the C2POL bit. If it is not cleared, the comparator output, appearing
on C2OUT, will be inverted, and the feedback will be negative, instead of the positive feedback needed to
create hysteresis.

The LED is then lit in the main loop, whenever the C2OUT bit is high (indicating that the LDR is in
darkness), in the same was as in example 1.

Complete program
Here is how these pieces fit into the basic comparator example program:
;************************************************************************
; *
; Description: Lesson 10, example 2 *
; *
; Demonstrates basic use of Comparator 2 *
; with hysteresis added via feedback from external output *
; *
; Turns on LED when input on C12IN0- < threshold on C2IN+ *
; *
;************************************************************************
; *
; Pin assignments: *
; C12IN0- = voltage to be measured (e.g. pot output or LDR) *
; C2IN+ = threshold voltage (set by voltage divider resistors) *
; C2OUT = comparator output (fed back to threshold via resistor)*
; RC1 = indicator LED *
; *
;************************************************************************

#include "p16f1824.inc"

errorlevel -302 ; no warnings about registers not in bank 0


errorlevel -303 ; no warnings about program word too large

;***** CONFIGURATION
; ext reset, internal oscillator (no clock out), no watchdog,
; brownout resets on, no power-up timer, no code or data protect,
; no failsafe clock monitor, two-speed start-up disabled
; no write protection, 4xPLL off, stack resets on,
; low BOR threshold, high-voltage programming

Enhanced Mid-Range PIC Assembler, Lesson 10: Analog Comparators Page 10


© Gooligum Electronics 2014 www.gooligum.com.au

__CONFIG _CONFIG1, _MCLRE_ON & _FOSC_INTOSC & _CLKOUTEN_OFF & _WDTE_OFF &
_BOREN_ON & _PWRTE_OFF & _CP_OFF & _CPD_OFF & _FCMEN_OFF & _IESO_OFF
__CONFIG _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_ON & _BORV_LO & _LVP_OFF

; pin assignments
#define LED LATC,1 ; indicator LED on RC1
constant nLED=1 ; (port bit 1)

;***** RESET VECTOR *****************************************************


RES_VECT CODE 0x0000 ; processor reset vector

;***** MAIN PROGRAM *****************************************************

;***** Initialisation
start
; configure ports
movlw ~(1<<nLED|1<<4) ; configure LED pin and RC4/C2OUT as outputs
banksel TRISC ; (RA1/C12IN0- and RC0/C2IN+ are inputs)
movwf TRISC
banksel ANSELA ; select analog mode for RA1 and RC0
bsf ANSELA,1 ; -> RA1/C12IN0- and
bsf ANSELC,0 ; RC0/C2IN+ are analog inputs

; configure comparator 2
movlw b'10100100' ; configure comparator 2:
; 1------- comparator enabled (C2ON = 1)
; --1----- external output enabled (C2OE = 1)
; ---0---- output not inverted (C2POL = 0)
; -----1-- normal power mode (C2SP = 1)
; ------0- hysteresis disabled (C2HYS = 0)
; -------0 asynchronous output (C2SYNC = 0)
banksel CM2CON0
movwf CM2CON0
movlw b'00000000' ; select comparator 2 inputs:
; --00---- + in = C2IN+ pin (C2PCH = 00)
; ------00 - in = C12IN0- pin (C2NCH = 00)
movwf CM2CON1 ; -> C2OUT = 1 if C12IN0- < C2IN+

;***** Main loop


main_loop
; display comparator output
banksel CM2CON0
btfsc CM2CON0,C2OUT ; if comparator output high
bsf LED ; turn on LED
btfss CM2CON0,C2OUT ; if comparator output low
bcf LED ; turn off LED

; repeat forever
goto main_loop

END

Enhanced Mid-Range PIC Assembler, Lesson 10: Analog Comparators Page 11


© Gooligum Electronics 2014 www.gooligum.com.au

Comparator Interrupts
Each comparator can be selected, independently, as an interrupt source. This is similar to the interrupt-on-
change (IOC) facility described in lesson 8, except that, instead of an IOC interrupt being generated when a
defined edge is detected on a digital input, the comparator interrupt is triggered whenever the comparator’s
output changes in a defined way.
This means that, if you wish to respond to a change in the comparator output, there is no need to continually
poll the CxOUT flag, as we have been doing. Instead, you can choose to generate an interrupt whenever
CxOUT transitions from low to high and/or from high to low, and handle the “comparator change” event in
your interrupt service routine (ISR) – much as we did for pin change interrupts in lesson 8.

As with all other interrupts (see lesson 7), the comparator interrupt has an associated enable bit, which has to
be set to allow the comparator to trigger interrupts, and an interrupt flag bit, which is set whenever the
comparator’s output changes.

So far, all of the interrupt enable and flag bits we’ve looked at have been in the INTCON register. But the
comparator module is considered to be a peripheral (not part of the PIC core), and its interrupt bits are held
in peripheral interrupt registers.
Each comparator interrupt is enabled by setting the corresponding CxIE bit in the PIE2 (peripheral interrupt
enable 2) register:
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0

PIE2 OSFIE C2IE C1IE EEIE BCL1IE – – CCP2IE

We saw in lesson 7 that, to enable any interrupts to occur, it is necessary to set the GIE (global interrupt
enable) bit in the INTCON register, as well as the enable bits (such as C1IE or C2IE) for whichever
interrupt sources you wish to use.
However, to enable any peripheral interrupt (where the enable bit is in one of the PIE registers), you must
also set the PEIE (peripheral interrupt enable) bit in INTCON:
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0

INTCON GIE PEIE TMR0IE INTE IOCIE TMR0IF INTF IOCIF

So, to enable comparator interrupts, we must set C1IE and/or C2IE, PEIE and GIE.

The comparator interrupt flags, CxIF, are located in PIR2 (peripheral interrupt register 2):
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0

PIR2 OSFIF C2IF C1IF EEIF BCL1IF – – CCP2IF

Each of the CxIF flags are set whenever an enabled edge (positive or negative transition) is detected on the
corresponding comparator output (CxOUT).
As with other interrupt sources, the comparator interrupt flags are active, whether or not comparator
interrupts are enabled. This means that you could, in principle, poll C1IF to detect defined changes in
C1OUT – although it would normally make more sense to simply poll C1OUT directly.

Enhanced Mid-Range PIC Assembler, Lesson 10: Analog Comparators Page 12


© Gooligum Electronics 2014 www.gooligum.com.au

The type(s) of change (or edge) that can trigger each comparator interrupt are selected via the CxINTP and
CxINTN interrupt enable bits in the CMxCON1 register:

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0

CMxCON1 CxINTP CxINTN CxPCH<1:0> – – CxNCH<1:0>

Setting the CxINTP bit to ‘1’ enables the detection of positive edges: the CxIF flag will be set whenever
CxOUT transitions from low to high.
Similarly, setting the CxINTN bit to ‘1’ enables the detection of positive edges: CxIF will be set whenever
CxOUT transitions from high to low.
Thus, it is possible to selectively detect positive and/or negative transitions on either comparator. And if
these interrupt enable bits are both clear, the comparator interrupt flag will not be affected by any transition.

In the interrupt service routine, you should clear whichever CxIF flag has been set. And to avoid false
triggering (an interrupt occurring because of a previous change), you would usually also clear the CxIF flags
immediately before enabling comparator interrupts – but see the example below.

Example 3: Comparator interrupts


To demonstrate comparator interrupts, we can re-implement the last example, using interrupts.
Instead of polling C2OUT, we’ll configure the comparator module to trigger an interrupt whenever the input
(light level) passes through the threshold, and have the ISR turn on or off the LED. Note that we’ll need to
enable both rising and falling edge detection, because the ISR has to respond to both types of transition.
This then leaves the main program code free to perform other tasks – although in this example, we don’t
have anything else to do!

We can keep the circuit and comparator configuration the same as before. It’s a good idea to leave the
hysteresis in place, as this minimises the number of comparator transitions – limiting the number of times the
interrupt will be triggered.

The comparator configuration is the same as in the previous example, except that we must also enable the
positive (rising) and negative (falling) edge detectors:
; configure comparator 2
movlw b'10100100' ; configure comparator 2:
; 1------- comparator enabled (C2ON = 1)
; --1----- external output enabled (C2OE = 1)
; ---0---- output not inverted (C2POL = 0)
; -----1-- normal power mode (C2SP = 1)
; ------0- hysteresis disabled (C2HYS = 0)
; -------0 asynchronous output (C2SYNC = 0)
banksel CM2CON0
movwf CM2CON0
movlw b'11000000' ; select comparator 2 interrupts and inputs:
; 1------- enable rising edge detection (C2INTP = 1)
; -1------ enable falling edge detection (C2INTN = 1)
; --00---- + in = C2IN+ pin (C2PCH = 00)
; ------00 - in = C12IN0- pin (C2NCH = 00)
movwf CM2CON1 ; -> C2OUT = 1 if C12IN0- < C2IN+,
; C2IF set on all transitions

Enhanced Mid-Range PIC Assembler, Lesson 10: Analog Comparators Page 13


© Gooligum Electronics 2014 www.gooligum.com.au

We also need to enable peripheral and global interrupts:


movlw 1<<PEIE|1<<GIE ; enable peripheral and global interrupts
movwf INTCON

Then we can enable the comparator interrupt, by setting the C2IE bit.
As mentioned earlier, it is common practice to clear the associated interrupt flag immediately before
enabling an interrupt source, to avoid a previous event, which had set the interrupt flag, triggering the
interrupt prematurely.
However, in this example – how is our light/dark indicator LED to be initialised? We often simply clear the
LED pin (RC1 in this case), so that the LED is initially not lit. But what if the photocell is initially in
darkness? We should start with the LED lit in that case. And if we simply wait for comparator changes to
be detected, the LED will remain unlit until the photocell cycles from dark to light then back to dark.
We could solve this problem by including initialisation code which checks the comparator output on start-up
and then initialises the LED appropriately. But a simpler solution is to force the ISR (which checks the
comparator and updates the LED) to run immediately after interrupts are enabled. And we can do that by
setting the C2IF flag before enabling the compactor interrupt:
banksel PIR2 ; enable comparator 2 interrupt:
bsf PIR2,C2IF ; set interrupt flag (to force immediate
banksel PIE2 ; interrupt to set initial LED state)
bsf PIE2,C2IE ; set enable bit

In the interrupt handler, we must (as always) clear the interrupt flag:
banksel PIR2
bcf PIR2,C2IF ; clear interrupt flag

Since the comparator interrupt is triggered by any comparator output change, we can’t know whether the
interrupt was caused by the comparator input going high or low.
So, we check the value of C2OUT, and update the LED output accordingly:
; display current comparator 2 output
banksel CM2CON0
btfsc CM2CON0,C2OUT ; if comparator output high
bsf LED ; turn on LED
btfss CM2CON0,C2OUT ; if comparator output low
bcf LED ; turn off LED

The main loop is then left with nothing to do:


main_loop
; (do nothing)

; repeat forever
goto main_loop

This may seem to be a complicated way of achieving the same result as in the previous example. The
advantage (which we haven’t exploited here) of this approach is that the processor only has to test the
comparator output and update the LED when an input transition occurs – leaving the processor largely idle
and able to do perform other tasks in the main loop and/or service other interrupt sources.

Enhanced Mid-Range PIC Assembler, Lesson 10: Analog Comparators Page 14


© Gooligum Electronics 2014 www.gooligum.com.au

Complete program
Here is how it all fits together:
;************************************************************************
; *
; Description: Lesson 10, example 3 *
; *
; Demonstrates use of comparator interrupt *
; (assumes hysteresis is used to reduce triggering) *
; *
; Turns on LED when input on C12IN0- < threshold on C2IN+ *
; *
;************************************************************************
; *
; Pin assignments: *
; C12IN0- = voltage to be measured (e.g. pot output or LDR) *
; C2IN+ = threshold voltage (set by voltage divider resistors) *
; C2OUT = comparator output (fed back to threshold via resistor)*
; RC1 = indicator LED *
; *
;************************************************************************

#include "p16f1824.inc"

errorlevel -302 ; no warnings about registers not in bank 0


errorlevel -303 ; no warnings about program word too large

;***** CONFIGURATION
; ext reset, internal oscillator (no clock out), no watchdog,
; brownout resets on, no power-up timer, no code or data protect,
; no failsafe clock monitor, two-speed start-up disabled
; no write protection, 4xPLL off, stack resets on,
; low BOR threshold, high-voltage programming
__CONFIG _CONFIG1, _MCLRE_ON & _FOSC_INTOSC & _CLKOUTEN_OFF & _WDTE_OFF &
_BOREN_ON & _PWRTE_OFF & _CP_OFF & _CPD_OFF & _FCMEN_OFF & _IESO_OFF
__CONFIG _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_ON & _BORV_LO & _LVP_OFF

; pin assignments
#define LED LATC,1 ; indicator LED on RC1
constant nLED=1 ; (port bit 1)

;***** RESET VECTOR *****************************************************


RES_VECT CODE 0x0000 ; processor reset vector
pagesel start
goto start

;***** MAIN PROGRAM *****************************************************


MAIN CODE

;***** Initialisation
start
; configure ports
movlw ~(1<<nLED|1<<4) ; configure LED pin and RC4/C2OUT as outputs
banksel TRISC ; (RA1/C12IN0- and RC0/C2IN+ are inputs)
movwf TRISC
banksel ANSELA ; select analog mode for RA1 and RC0
bsf ANSELA,1 ; -> RA1/C12IN0- and
bsf ANSELC,0 ; RC0/C2IN+ are analog inputs

Enhanced Mid-Range PIC Assembler, Lesson 10: Analog Comparators Page 15


© Gooligum Electronics 2014 www.gooligum.com.au

; configure comparator 2
movlw b'10100100' ; configure comparator 2:
; 1------- comparator enabled (C2ON = 1)
; --1----- external output enabled (C2OE = 1)
; ---0---- output not inverted (C2POL = 0)
; -----1-- normal power mode (C2SP = 1)
; ------0- hysteresis disabled (C2HYS = 0)
; -------0 asynchronous output (C2SYNC = 0)
banksel CM2CON0
movwf CM2CON0
movlw b'11000000' ; select comparator 2 interrupts and inputs:
; 1------- enable rising edge detection (C2INTP = 1)
; -1------ enable falling edge detection (C2INTN = 1)
; --00---- + in = C2IN+ pin (C2PCH = 00)
; ------00 - in = C12IN0- pin (C2NCH = 00)
movwf CM2CON1 ; -> C2OUT = 1 if C12IN0- < C2IN+,
; C2IF set on all transitions

; enable interrupts
movlw 1<<PEIE|1<<GIE ; enable peripheral and global interrupts
movwf INTCON
banksel PIR2 ; enable comparator 2 interrupt:
bsf PIR2,C2IF ; set interrupt flag (to force immediate
banksel PIE2 ; interrupt to set initial LED state)
bsf PIE2,C2IE ; set enable bit

;***** Main loop


main_loop
; (do nothing)

; repeat forever
goto main_loop

;***** INTERRUPT SERVICE ROUTINE ****************************************


ISR CODE 0x0004

; *** Service comparator 2 interrupt


;
; Triggered on any comparator 2 output change
;
; Turns on indicator LED if C2OUT is high
; (-> input on C12IN0- < threshold on C2IN+)
;
; (only comparator 2 interrupts are enabled)
;
banksel PIR2
bcf PIR2,C2IF ; clear interrupt flag

; display current comparator 2 output


banksel CM2CON0
btfsc CM2CON0,C2OUT ; if comparator output high
bsf LED ; turn on LED
btfss CM2CON0,C2OUT ; if comparator output low
bcf LED ; turn off LED

isr_end ; *** Exit interrupt


retfie

END

Enhanced Mid-Range PIC Assembler, Lesson 10: Analog Comparators Page 16


© Gooligum Electronics 2014 www.gooligum.com.au

Wake-up on Comparator Change


As we saw in lesson 8, enhanced mid-range PICs can be put into standby, or sleep mode, to conserve power
until they are woken by an external event. We also saw that that event can be any which is capable of
triggering an interrupt (without the oscillator running), such as a change on an IOC-enabled digital input; it
can also be a change on a comparator output.
That’s useful if, for example, your application is battery-powered and has to spend a long time waiting to
respond to an input level change from a sensor.

Recall that, if an enabled interrupt source is triggered while the PIC is in sleep mode, the device will wake
from sleep, set the corresponding interrupt flag to indicate which event occurred, execute the instruction
following ‘sleep’ and, if global interrupts are enabled (GIE = 1), then enter the interrupt service routine.
If you only want to use an external event, such as a comparator change, to wake the device from sleep,
without actually triggering an interrupt, simply disable interrupts (clear GIE) before entering sleep mode.

Example 4: Wake on comparator change


To demonstrate this, using the same circuit as in the last two examples, we’ll configure the PIC to wake
when the comparator output transitions from low to high (corresponding to the photocell moving from light
to dark), and then go to sleep. When the input signal (light level) falls below the threshold, the comparator
output will go high, and the PIC will wake. To indicate that it has become darker, we can turn on the LED
for one second. The PIC can then go back to sleep, to wait until a fall in light level is detected again.
Note that the feedback resistor providing hysteresis should be left in place, to make the comparator less
sensitive to small variations – we only want the PIC to wake on a significant change, as the light level falls.

The comparator can be configured as we did in example 3, except that we now want to detect only rising
comparator output transitions (corresponding to a falling light level):
; configure comparator 2
movlw b'10100000' ; configure comparator 2:
; 1------- comparator enabled (C2ON = 1)
; --1----- external output enabled (C2OE = 1)
; ---0---- output not inverted (C2POL = 0)
; -----0-- low-power mode (C2SP = 0)
; ------0- hysteresis disabled (C2HYS = 0)
; -------0 asynchronous output (C2SYNC = 0)
banksel CM2CON0
movwf CM2CON0
movlw b'10000000' ; select comparator 2 interrupts and inputs:
; 1------- enable rising edge detection (C2INTP = 1)
; -0------ disable falling edge detection (C2INTN = 0)
; --00---- + in = C2IN+ pin (C2PCH = 00)
; ------00 - in = C12IN0- pin (C2NCH = 00)
movwf CM2CON1 ; -> C2OUT = 1 if C12IN0- < C2IN+,
; C2IF set only on rising output transitions

Note that low-power mode has been selected, by clearing the C2SP bit, which is usually more appropriate
for operation in sleep mode, where we presumably want to reduce power consumption.

A short delay (10 ms or so) should be added to allow the comparator to settle before entering standby. This
is recommended because signal levels can take a while to settle after power-on, and if the comparator output
was transitioning from low to high while going into sleep mode, the PIC would immediately wake and the
LED would flash – a false trigger.

Enhanced Mid-Range PIC Assembler, Lesson 10: Analog Comparators Page 17


© Gooligum Electronics 2014 www.gooligum.com.au

To enable wake on comparator change, we need to enable the comparator interrupt, but not global interrupts
(since we’re not actually using interrupts here; we’re only using an interrupt source to wake the device):
; enable comparator 2 interrupt (for wake on change)
bsf INTCON,PEIE ; enable peripheral interrupts
banksel PIE2
bsf PIE2,C2IE ; and comparator 2 interrupt

Within the main loop, we can start by turning off the LED, because we don’t want it lit on start-up:
; turn off LED
banksel LATC
bcf LED

Before entering sleep mode, it is very important to clear the interrupt flag, to ensure that the PIC won’t wake
immediately (due to an earlier comparator change):
; go into standby (low power) mode
banksel PIR2
bcf PIR2,C2IF ; clear comparator 2 interrupt flag
sleep ; enter sleep mode

The PIC will now sleep until it is woken by a comparator change, which we wish to show by lighting the
LED for one second:
; turn on LED for 1 second
banksel LATC ; turn on LED
bsf LED
DelayMS 1000 ; delay 1 sec

Note that the delay is generated by the DelayMS macro, introduced in lesson 6.

Complete program
Here is the complete comparator wake-up example program:
;************************************************************************
; *
; Description: Lesson 10, example 4 *
; *
; Demonstrates wake-up on comparator change *
; *
; Turns on LED for 1 sec when comparator output goes high *
; then sleeps until the next rising output transition *
; (assumes hysteresis is used to reduce false triggering) *
; *
;************************************************************************
; *
; Pin assignments: *
; C12IN0- = voltage to be measured (e.g. pot output or LDR) *
; C2IN+ = threshold voltage (set by voltage divider resistors) *
; C2OUT = comparator output (fed back to threshold via resistor)*
; RC1 = indicator LED *
; *
;************************************************************************

#include "p16f1824.inc"

Enhanced Mid-Range PIC Assembler, Lesson 10: Analog Comparators Page 18


© Gooligum Electronics 2014 www.gooligum.com.au

#include "stdmacros-enh.inc" ; DelayMS - delay in milliseconds


; (calls delay10)
EXTERN delay10 ; W x 10ms delay

errorlevel -302 ; no warnings about registers not in bank 0


errorlevel -303 ; no warnings about program word too large

radix dec

;***** CONFIGURATION
; ext reset, internal oscillator (no clock out), no watchdog,
; brownout resets on, no power-up timer, no code or data protect,
; no failsafe clock monitor, two-speed start-up disabled
; no write protection, 4xPLL off, stack resets on,
; low BOR threshold, high-voltage programming
__CONFIG _CONFIG1, _MCLRE_ON & _FOSC_INTOSC & _CLKOUTEN_OFF & _WDTE_OFF &
_BOREN_ON & _PWRTE_OFF & _CP_OFF & _CPD_OFF & _FCMEN_OFF & _IESO_OFF
__CONFIG _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_ON & _BORV_LO & _LVP_OFF

; pin assignments
#define LED LATC,1 ; indicator LED on RC1
constant nLED=1 ; (port bit 1)

;***** RESET VECTOR *****************************************************


RES_VECT CODE 0x0000 ; processor reset vector

;***** MAIN PROGRAM *****************************************************

;***** Initialisation
start
; configure ports
movlw ~(1<<nLED|1<<4) ; configure LED pin and RC4/C2OUT as outputs
banksel TRISC ; (RA1/C12IN0- and RC0/C2IN+ are inputs)
movwf TRISC
banksel ANSELA ; select analog mode for RA1 and RC0
bsf ANSELA,1 ; -> RA1/C12IN0- and
bsf ANSELC,0 ; RC0/C2IN+ are analog inputs

; configure oscillator
movlw b'00111010' ; configure internal oscillator:
; -0111--- 500 kHz (IRCF = 0111)
; ------1- select internal clock (SCS = 1x)
banksel OSCCON ; -> 8 us / instruction cycle
movwf OSCCON

; configure comparator 2
movlw b'10100000' ; configure comparator 2:
; 1------- comparator enabled (C2ON = 1)
; --1----- external output enabled (C2OE = 1)
; ---0---- output not inverted (C2POL = 0)
; -----0-- low-power mode (C2SP = 0)
; ------0- hysteresis disabled (C2HYS = 0)
; -------0 asynchronous output (C2SYNC = 0)
banksel CM2CON0
movwf CM2CON0
movlw b'10000000' ; select comparator 2 interrupts and inputs:
; 1------- enable rising edge detection (C2INTP = 1)
; -0------ disable falling edge detection (C2INTN = 0)

Enhanced Mid-Range PIC Assembler, Lesson 10: Analog Comparators Page 19


© Gooligum Electronics 2014 www.gooligum.com.au

; --00---- + in = C2IN+ pin (C2PCH = 00)


; ------00 - in = C12IN0- pin (C2NCH = 00)
movwf CM2CON1 ; -> C2OUT = 1 if C12IN0- < C2IN+,
; C2IF set only on rising output transitions

; delay 10 ms to allow comparator and voltage ref to settle


DelayMS 10

; enable comparator 2 interrupt (for wake on change)


bsf INTCON,PEIE ; enable peripheral interrupts
banksel PIE2
bsf PIE2,C2IE ; and comparator 2 interrupt

;***** Main loop


main_loop
; turn off LED
banksel LATC
bcf LED

; go into standby (low power) mode


banksel PIR2
bcf PIR2,C2IF ; clear comparator 2 interrupt flag
sleep ; enter sleep mode

; turn on LED for 1 second


banksel LATC ; turn on LED
bsf LED
DelayMS 1000 ; delay 1 sec

; repeat forever
goto main_loop

END

Conclusion
We saw in this lesson that the comparators on enhanced mid-range PICs can be used to compare the voltages
on various input pins. We also saw how to use the external comparator output to generate hysteresis. And
we saw that the comparators can be used as interrupt sources, and to wake the device from sleep.

This lesson also mentioned that that the comparators can be configured with flexible combinations of inputs,
including internal fixed and variable voltage references – but it didn’t provide any detail on how those
features are used.
So in the next lesson we’ll look at the fixed voltage reference and digital-to-analog converter (DAC) and see
how they can be used with the comparators, avoiding the need to use external voltage dividers to generate
threshold voltages, as we did in this lesson.

Enhanced Mid-Range PIC Assembler, Lesson 10: Analog Comparators Page 20

You might also like