Fork me on GitHub

Project Notes

#139 AnalogComparator

Testing the Atmega328 built-in analog comparator

Here’s a quick video of the circuit in action:



So today I learned (from this question ) that the Atmega328 chip has a built-in analog comparator. That’s neat!

The Analog Comparator is introduced in section 23 of the AVR datasheet:

The Analog Comparator compares the input values on the positive pin AIN0 and negative pin AIN1. When the
voltage on the positive pin AIN0 is higher than the voltage on the negative pin AIN1, the Analog Comparator
output, ACO, is set. The comparator’s output can be set to trigger the Timer/Counter1 Input Capture function. In
addition, the comparator can trigger a separate interrupt, exclusive to the Analog Comparator. The user can
select Interrupt triggering on comparator output rise, fall or toggle.

Note that it’s not just the Atmega328 that supports this feature.

The ACSR (Analog Comparator Control and Status Register) determines the behaviour of the Analog Comparator. In the program setup, we:

  • disable multiplexed input to the comparator, so AIN1 is used as negative input
  • clear any existing comparator interrupts
  • enable Analog Comparator interrupts
  • select rising-edge interrupt

The code defines an interrupt service routine on ANALOG_COMP_vect.

Now that’s all well and good, but “pin AIN0” and “pin AIN1” sound pretty alien to most Arduino users! A quick check of the ATmega168/328-Arduino Pin Mapping verify:

  • Arduino digital pin 6 = AIN0 = pin 12 of the DIP28 chip
  • Arduino digital pin 7 = AIN1 = pin 13 of the DIP28 chip

The Test Circuit

This is simple test:

  • a voltage divider sets up a ~2.5V reference on AIN1
  • an LDR/resistor pair provide a light-dependent voltage input to AIN0

The particular LDR used has a range of about 200Ω (bright light) to 20kΩ (dark). However the ambient light conditions used for testing the circuit exhibits a typical range of 2kΩ-5kΩ, so I’m using a 3.3kΩ as its reference mate.

So the expected behaviour is that we get a comparator threshold rising edge crossing when the LDR goes dark, and a comparator threshold falling edge crossing when the LDR goes light.

Rising, Falling, Change Interrupts?

Setting ACIS1, ACIS0 bits select the interrupt to trigger:

ACIS1 ACIS0 Trigger
0 0 Toggle
1 0 Falling
1 1 Rising

In practice, the comparator can be extremely bouncy. This can cause rising interrupts when only falling are expected, and vice versa. Some measure of debouncing appears to be essential.

So Does it Work?

Yes! The comparator interrupt is excellent, and beats any other approach for speed, processing overhead and lack of external circuitry.

Debouncing is likely essential, unless your application does not care about the number or direction of interrupts raised.



The Schematic

The Build

Typical Console Output

Console Output

Credits and References

About LEAP#139 ArduinoSensorOpAmp
Project Source on GitHub Return to the LEAP Catalog

This page is a web-friendly rendering of my project notes shared in the LEAP GitHub repository.

LEAP is my personal collection of electronics projects, usually involving an Arduino or other microprocessor in one way or another. Some are full-blown projects, while many are trivial breadboard experiments, intended to learn and explore something interesting (IMHO!).

The projects are usually inspired by things found wild on the net, or ideas from the sources such as:

Feel free to borrow liberally, and if you spot any issues do let me know. See the individual projects for credits where due. There are even now a few projects contributed by others - send your own over in a pull request if you would also like to add to this collection.