The comparator module(s) of a microcontroller is quite widely used to 'compare' two different levels of external voltages or to compare an external voltage to an internal reference voltage. It is a very useful module when we need, for instance, to control an external device allowing to the microcontroller to react in a proper way when the external device reaches some conditions.
For simplicity we are using a very common microcontroller, a pic 12F683, that has an internal comparator module, but the situation is very similar to any other pic microcontroller equipped with a comparator module.
A quick look at the datasheet (where we have got some images) will allow to verify that the internal comparator module can be configured in 8 different modalities (7 really, plus one given by the OFF state of the comparator). We'll quickly see only a couple of the most common, where:
![]() |
A) two external voltages are compared and the result (cout) is given by the state of the COUT pin (GP2); |
![]() |
B) an external voltage is compared to an internal reference voltage and the result is given by a bit of the register (CMCON.COUT).. |
![]() |
FIRST CASE: we have to compare two external voltages. Assuming a 5V VDD, we will position on GP1 (Cin-) to have a voltage of 2.5V and a trimmer on GP0(Cin+) 0-5V. A led on GP2 will complete the example. |
To set properly the comparator we have to set a register: CMCON0
Where:
COUT: Comparator output (not used now).
CINV: Will inverse the result
CM2-CM1-CM0 must be set (according to our examples)
001 - configure input pins (GP0-GP1 as analog) and COUT pin (Gp2 as output)
100 - GP1 (Cin-) if configured as analog, Vref will be internal, Gp0-GP2 as normal I/O
According to the schema and the example, we have to set the registers (using C):
void main() {
OSCCON = 0b01110000; // 8mhz internal oscillator
CMCON0 = 0b00000001; //CIN+andCIN- analog, COUT pin configured as Comparator output
TRISIO = 0b00000011; // gp0 gp1 = input gp2 = output
do {
} while(1);
}
That's All. Turning the trimmer the led will switch ON/OFF according to the voltage level on CIN+
|
SECOND CASE: we desire to use an internal Vref and an internal result to be managed by the software. In this case CIN- (GP1) will be used to provide the voltage to compare. All other pins can be used ad I/O. The main differences regarding the previous example regards the setting of the internal voltage reference.
|
The internal Vref can be set up according to the VRCON register where:
- VREN: Enable the internal Vref
- VRR: Range selection
- VR3...VR0: are bits used sets the internal Vref (with the weight: 8 4 2 1)
example:
- IF VRR=1 and VR3 ... VR0 = 1111 (15) with a VDD of 5V the Vref will be (15/24)*5 = 3,125V
- IF VRR=0 and VR3 ... VR0 = 1111 (15) with a VDD of 5V the Vref will be 5/4+(15/32)*5 = 3,593V
In this case the result will be available in the COUT bit of the CMCON0 register. Using C language we can write:
void main()
{
OSCCON = 0b01110000; // 8mhz internal oscillator
CMCON0 = 0b00000100; // CIN- analog, Internal VRef
TRISIO = 0b00000010; // gp1 = input
VRCON = 0b10101111; // sets Vref
do {
if (CMCON0.COUT == 1) // if cmcon0.cout=1 blink a led, else set led off
{
gpio.F2 =1;
delay_ms(500);
gpio.F2 = 0;
delay_ms(500);
}
} while(1);
}
That's all. Sometimes concepts are more difficult to explain than to realize.