In this Arduino Analog Comparator example we will illustrate how to use the Analog Comparator Interrupt. In the previously arduino analog comparator tutorials we described how to use analog comparator with polling method, where the CPU periodically monitors the ACO bit in the ACSR register and take action accordingly. Here we will use the interrupt feature, wherein, the Arduino microcontroller automatically executes Interrupt Service Routine(ISR) depending on the comparison of positive and negative inputs to the internal analog comparator.
See also previously posted Arduino Analog Comparator examples.
- How to use Arduino Analog Comparator?
- Using Analog Input as Analog Comparator Input of Arduino
Circuit Schematic for Interrupt based Arduino Comparator Circuit
In the circuit, we have applied the external voltage to the +ve input to the analog comparator AIN0 using 10KOhm potetiometer. Similarly we have applied external voltage source to the -ve input of the analog comparator on the analog input A1. A LED with 220Ohm resistor is connected to the PD4 pin.
How the circuit works?
Whenever the +ve input at the AIN0(PD6) is higher or equal to the voltage on the -ve input A1 pin, an interrupt by the analog comparator will be called. Hence ISR routine will be called within which we will turn on the LED at PD4. Otherwise the LED will be off.
Program Code/Sketch for Arduino Analog Comparator with Interrupt
Below is C/C++ program code/sketch to use Arduino Analog Comparator in Interrupt mode.
void setup () {
DDRD |= (1<<PD4);
DIDR1 |= (1<<AIN0D); // Disable Digital Inputs at AIN0 and AIN1
ADCSRA &= ~(1<<ADEN);
ADCSRB |= (1<<ACME); //Set ACME bit in ADCSRB to use external analog input at AIN1 -ve input
ADMUX = 0x01; //select A1 as input
ACSR =
(0 << ACD) | // Analog Comparator: Enabled
(0 << ACBG) | // Clear ACBG to use external input to AIN0 +ve input
(0 << ACO) | // Analog Comparator Output: OFF
(1 << ACI) | // Analog Comparator Interrupt Flag: Clear Pending Interrupt by setting the bit
(1 << ACIE) | // Analog Comparator Interrupt: Disabled
(0 << ACIC) | // Analog Comparator Input Capture: Disabled
(0 << ACIS1) | (0 << ACIS0); // Analog Comparator Interrupt Mode: Comparator Interrupt on Output Toggle
sei();
}
void loop() {
}
ISR(ANALOG_COMP_vect)
{
if(ACSR & (1<<ACO))
PORTD |= (1<<PD4);
else
PORTD &= ~(1<<PD4);
}
In the above program code, we do the following.
- In the setup() function,
- the PD4 pin is configured as output
- the AIN0 pin digital input buffer is disabled for power consumption using: DIDR1 |= (1<<AIN0D)
- since we are using A1 as the -ve input to the analog comparator, we do the followings:
- disable the ADC using: ADCSRA &= ~(1<<ADEN)
- set the ACME bit to use the analog input using: ADCSRB |= (1<<ACME)
- select the A1 pin using the MUX2:0 bits using: ADMUX = 0x01
The ACSR register bits are configured to:
- enable the analog comparator by clearing the ACD bit
- configure to use AIN0 pin as +ve input instead of bandgap internal input by clearing the ACBG bit
- clearing the ACO bit at setup
- clear the interrupt flag by setting the ACI bit
- enable the analog comparator interrupt by setting the ACIE bit
- disable the analog comparator input capture feature by clearing the ACIC bit
- configure the ACIS0 and ACIS1 bits to select interrupt mode
In the main() loop we do nothing.
Once the voltage at the A1 is equal or lower than at the AIN0 pin, the interrupt service routine ISR(ANALOG_COMP_vect) is called. Within the ISR routine, we check whether the ACO bit in the ACSR register is high or low. If it is high then we turn on the LED otherwise we turn off the LED.
Video Demonstration:
Watch the following video demonstration of the above arduino analog comparator circuit with interrupt.
Why are you testing for (ACSR & (1<<ACO)) in the ISR? That has been done in hardware and is the reason why the ISR has fired in the first place.
As configured, the interrupt will fire when the value _changes_. The test is necessary to see which way it changed.
One could also configure to fire only on rising or falling edge.