My project is using almost all the pins on this board and I require an interrupt pin to read radio state (rather than polling). I'm using I2C, so that leaves INT2 and INT3, which are the TX and RX pins for USB/Serial1. According to the documentation, disabling serial, using Serial.end(), should allow me to take control of those pins. However, using the pins as interrupt handlers doesn't work. Here is a sample sketch:

static int ledpin = 13;
volatile byte state = LOW;

void func()
  state = !state; 

void setup() {

  pinMode(ledpin, OUTPUT);

  // INT2
  pinMode(0, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(0), func, CHANGE);

  // INT3
  pinMode(1, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(1), func, CHANGE);

void loop() {
  digitalWrite(ledpin, state); 

This example is mostly copy-pasted from the Arduino website. All the other interrupts work fine, only INT2 and INT3 don't.

Is there a way to use these interrupts?

  • 1
    How do you know that they don't work? If both interrupts are fired, then you can't notice it. "Serial" is the serial port via USB to the computer. "Serial1" is the hardware serial port at pin 0 and 1. If you don't use "Serial1", then pin 0 and 1 are not yet initialized as serial port and they are normal digital pins like any other. Remove the Serial.end. It should work, you could increment a byte and print the byte to the serial monitor (using the USB "Serial"). There are also pcint interrupts: pighixxx.com/test/portfolio-items/micro Is !LOW the same as HIGH, or is that a guess.
    – Jot
    Jan 27, 2018 at 21:26

2 Answers 2


You problem isn't with your pins or code, but with debouncing the signals. I've changed the "func()" method to read:

void func()
  static uint32_t lastChange = 0; // Note millis() don't change inside ISR, but can be read
  if (millis() - lastChange > 100)
    state = !state;
  lastChange = millis(); // Set new value

which will ignore spurious interrupts if they occur within 100ms of each other. This solves the issue that you are seeing, I've tested it on an Arduino Micro I have lying around.

   2019-08-29 Nicola Bernardelli. Going through the ATmega32U4 Datasheet and applying the steps
   to set up the analog comparator on a Pro Micro board.

   While doing this, I understand that the Analog to Digital Converter must be switched off.
   So, if you are needing to stick with ATmega32U4 but also need the ADC (as I do in my current project), you might have to add a
   circuit with a comparator, e.g. LM393 or LM339, instead of using the built-in Analog Comparator.
   Disabling this interrupt and reactivating the ADC has not been added to this sketch.

   Also, a "real" handling of the interrupt-triggered event has not been added and the sketch leaves the possibility of a very fast
   succession of interrupt requests. You might want to check the (currently only one) answer given here:

   [I wanted to ask/contribute here https://arduino.stackexchange.com/questions/17480/using-analog-comparator-on-atmega32u4
   (I see that it is 3 years 9 months old but it's still "searchable" on the Internet, which is how I went there. I think that keeping the
   information under that pertinent title is a better option than opening a new thread.)
   So I created an account, but it turns out that I don't have enough "reputation" there to comment, so I wrote into the edit field
   available to give an answer, and that did not work out either:
   "Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed,
   posting an answer now requires 10 reputation on this site (the association bonus does not count)."
   So... pretty much chessmate. Well... their board, their rules.]

#include "Arduino.h"

#error This sketch is meant for the Arduino Pro Micro, it is based on the ATmega32U4 Datasheet and the Pro Micro pinout. \
       You might decide to try it on a different ATmega32U4-based board if the pins choice is OK (please check/change the LED pin number).

#define LED_ON_DURATION 200

volatile bool analogCompInterruptToggled;
unsigned long millisLastTrigger;

void setup() {


  analogCompInterruptToggled = false;
  millisLastTrigger = 0;

  /* As per Atmega32U4 Datasheet starting pag 293 (and linked pages). */

  PRR0 &= ~bit(PRADC); // Disables power reduction for the ADC in order to use the ADC input MUX.

     ACME in ADCSRB: When this bit is written logic one and the ADC is switched off (ADEN in ADCSRA is zero),
     the ADC multiplexer is connected to the negative input to the Analog Comparator. When this bit is written
     logic zero, the Bandgap reference is connected to the negative input of the Analog Comparator
  ADCSRA &= ~bit(ADEN); /* Switches off the ADC so we can use the Muxer with the Analog Comparator instead of the ADC. */
  ADCSRB |= bit(ACME);  /* With the line above => the ADC multiplexer is connected to the negative input of the Analog Comparator. */
                        /* See table at page 295: ACME 0 or (ACME 1 and ADEN 1) => bandgap ref as the Analog Comparator Negative Input. */

  /*                                        ******** A0 NEGATIVE INPUT ********
     Let's select pin ADC7 = A0 as the negative input to the Analog Comparator, as per pag 295 of the ATmega32U4 DataSheet:
     ACME to 1 done above, ADEN to 0 done above, MUX2..0 to 111.
  ADMUX |= 0b00000111;

  /*                                        ******** D7 POSITIVE INPUT ********
     When this bit is set, a fixed bandgap reference voltage replaces the positive input to the Analog Comparator.
     When this bit is cleared, AIN0 is applied to the positive input of the Analog Comparator.
  ACSR &= ~bit(ACBG); // AIN0 = D7 => positive input of the Analog Comparator

  /* Pages 294-295 of the ATmega32U4 Datasheet. */
  ACSR &= ~bit(ACIC); /* Analog Comparator Input Capture disabled. */

  /* Comparator Interrupt trigger mode. 0-0 => TOGGLE, meaning any change; 1-0 => FALLING; 1-1 => RISING). */
  // ACSR &= ~bit(ACIS1); ACSR &= ~bit(ACIS0); // TOGGLE
  // ACSR |= bit(ACIS1);  ACSR &= ~bit(ACIS0); // FALLING
     ACSR |= bit(ACIS1);  ACSR |= bit(ACIS0);  // RISING

  DIDR1 &= ~bit(AIN0D); /* It's actually the rightmost bit, we could write DIDR1 &= ~1 */
     When this bit is written logic one, the digital input buffer on the AIN0 pin is disabled. [...]
     When an analog signal is applied to the AIN0 pin and the digital input from this pin is not needed,
     this bit should be written logic one to reduce power consumption in the digital input buffer.

  ACSR |= bit(ACIE);
  SREG |= bit(SREG_I);
  /* When the ACIE bit is written logic one and the I-bit in the Status Register is set,
     the Analog Comparator interrupt is activated. When written logic zero, the interrupt is disabled.

  analogCompInterruptToggled = true;

void loop() {
  // put your main code here, to run repeatedly:
  if (analogCompInterruptToggled) {
    analogCompInterruptToggled = false;
    digitalWrite(THIS_BOARD_LED_BUILTIN, LOW);
    millisLastTrigger = millis();
    Serial.print("toggled - millis() == ");
  else if (millis() > millisLastTrigger + LED_ON_DURATION) {

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.