An Analog comparator is a pretty simple peripheral, but it can give big benefits. Comparator module is included in all Mega series of AVR microcontrollers. Simply speaking, Comparator allows comparing voltage values applied to two pins of microcontrollers. The comparison results are a logical level, which can be read by the program(ACO- Analog Comparator Output bit). There is also the ability to generate an interrupt, which depends on the comparator resulting level. And more- timer T1 can capture this level what allows measuring the signal length of analog signals.
To use pins as comparator inputs, they must be prepared and configured as input(DDRx=0), and pull-up resistors must be disconnected (PORTx=0). In some models like Atmega48x/88x/168x, Atmega165x, Atmega325x,3250x,645x/6450x, and Atmega640x/128x/1281x/2560x/2561x, there is the ability to disconnect digital buffers of AIN0 and AIN1 pins that allows the use of these pins only for analog signal input – this minimizes overall power consumption.
Digital buffers can be disconnected by writing “1” where bits AIN0D and AIN1D are in register DIDR1:
The Comparator is controlled by one byte ACSR.
Bit No. | Name | Description |
7 | ACD | 0-ON, 1-OFF comparator |
6 | ACGB | 0 – AIN0 to the positive input of comparator; 1- reference voltage to positive comparator input |
5 | ACO | Result of comparing. |
4 | ACI | Interrupt flag |
3 | ACIE | Enable comparator interrupts |
2 | ACIC | Connect comparator to timer/counter T1 (1- connected, 0-not) |
1,0 | ACIS1:ACIS0 | Interrupt conditions select |
In general Comparator, the module is a simple comparator. If the voltage in input of AIN0 is bigger than in AIN1, then the result of comparing is equal to 1 and 0 otherwise. The result is stored in ACSR register bit ACO.
If the comparator is not used ACD bit should be set to 1 because it will reduce power consumption. Also, interrupt from the comparator should be disabled. As I mentioned, the comparator can compare voltage to reference voltage if bit ACBG is set. Then positive input of the comparator becomes 1.23V. The second comparator pin can be connected to any pin where ADC input is by using a multiplexer. If Multiplexer is enabled (bit ACME in SFIOR register) and ADC is off, then MUX2..0 in ADMUX register selects the input pin(refer to datasheet).
AVR Comparator C programming example
Let’s write a simple example of using the AVR comparator module. Program is written in C and compiled with AVR-GCC compiler(WinAVR). Program example illustrates when Positive Comparator input is connected to Internal voltage regulator 1.23V by setting ACGB bit in the ACSR register. Also, as negative comparator input is taken, ADC3 input via Multiplexer as indicator LED is connected to PORTD0 pin. If the input voltage is lower than 0.23V, then Diode is OFF, and if the voltage exceeds 1.23V, the diode lights ON. Diode state is changed with ANA_COMP_vect interrupt service routine on ACO bit toggle in ACSR register.
Working program code:
// ***********************************************************
// Project: Analog Comparator example
// Module description: Analog comparator example with positive comparator
// input connected to Vref 1.23V. When compared voltage exceed 1.23V LED lighst on.
// When voltage drops bellow - LED turns OFF. Comparator inputis connected to ADC3 pin.
// ***********************************************************
#include <avr\io.h>
#include <avr\interrupt.h>
#define AINpin PA3
#define LED PD0
void Init(){
DDRA&=~(1<<AINpin);//as input
PORTA&=~(1<<AINpin);//no Pull-up
DDRD|=(1<<LED); //Led pin as output
PORTD|=(1<<LED);//Initally LED is OFF
SFIOR|=(1<<ACME);//enable multiplexer
ADCSRA&=~(1<<ADEN);//make sure ADC is OFF
ADMUX|=(0<<MUX2)|(1<<MUX1)|(1<<MUX0); //select ADC3 as negative AIN
ACSR|=
(0<<ACD)| //Comparator ON
(1<<ACBG)| //Connect 1.23V reference to AIN0
(1<<ACIE)| //Comparator Interrupt enable
(0<<ACIC)| //input capture disabled
(0<<ACIS1)| //set interrupt on output toggle
(0<<ACIS0);
sei();//enable global interrupts
}
// Interrupt handler for ANA_COMP_vect
//
ISR(ANA_COMP_vect) {
if bit_is_clear(ACSR, ACO)
PORTD&=~(1<<LED);//LED is ON
else PORTD|=(1<<LED);//LED is OFF
}
// ***********************************************************
// Main program
//
int main(void) {
Init();
while(1) { // Infinite loop; interrupts do the rest