Using analogRead() and attachInterrupt() on same pin


I noticed that if I use (with MKR1000) analogRead() and attachInterrupt() on the same pin it disables the interrupts from coming in. Is this generally not possible or am I doing something wrong?


#define cityACPin A2
#define inverterACPin A1

void cityZeroCross()
  unsigned long ms = millis();

void inverterZeroCross()
  unsigned long ms = millis();
    Serial.print(" ");

void setup()

    pinMode(cityACPin, INPUT_PULLUP);
    pinMode(inverterACPin, INPUT_PULLUP);

    attachInterrupt(digitalPinToInterrupt(cityACPin), cityZeroCross, FALLING);
    attachInterrupt(digitalPinToInterrupt(inverterACPin), inverterZeroCross, FALLING);

void loop()
  Serial.print(analogRead(cityACPin)); // comment this out and the interrupt works
  Serial.print(analogRead(inverterACPin)); // comment this out and the interrupt works


My first question would be why do you want to do this ?

An interrupt is only digital. If you have some slowly-varying voltage coming in on that pin then you can't control the exact voltage level that triggers the interrupt. (Other non-Arduino chips have "comparators" which will allow you to set an interrupt at a specific analog voltage.) So it's like asking why your soft measuring tape can't be used to draw a straight line.

The other strange thing you're doing is turning on the pullup for the pin. analogRead() will helpfully turn that off for you.

If you still want the fixed-voltage interrupt and/or the pullup, then I would suggest wiring this input to two pins. One analog and one interrupt.

Thanks for explaining the behavior. Would an external pull-up circumvent this?

More on the reason for this:

I need to measure phase-shift between to AC signals AND detect if the AC is present at all. I am having a problem with missing some of the sine cycles by just using the interrupt. I am suspecting the serial- and 1Wire-communication that is happen frequently to be the cause for this because they turn off interrupts.

I don't have more spare pins on the MKR1000 so I need a different solution.

The interrupts never really get turned off. If an interrupt occurs while noInterrupts() is active, then the interrupt will be serviced as soon as the code calls interrupts() to turn them back on.

Now if it's possible to get two events during that time, then you don't get two interrupts - you only get one. That's why the usual instruction is to only turn off interrupts for the shortest possible time. If Wire.h is sending a byte, then that might be 8/100,000ths of a second which would not mask two of your zero crossings (assuming 50-60Hz.) Wire.h uses the hardware I2C anyway, so it doesn't need to turn off interrupts.

But phase difference is just time, isn't it? If you got a zero crossing for one signal at 1234 milliseconds and then the other signal had a zero crossing at 1245 then you've got the phase difference right there.

But phase difference is just time, isn't it? If you got a zero crossing for one signal at 1234 milliseconds and then the other signal had a zero crossing at 1245 then you've got the phase difference right there

That is correct and for phase difference this is OK but I also use the time between two interrupt to detect if the AC line lost power. So in theory I should get every 16.6666 ms an interrupt.
But once or twice in a day it happens that this delay is longer than 200 ms for which I don't have any explanation except that the interrupts must have been disabled during serial or 1Wire communication.

In fact, line power may have been interrupted for 200ms. There is no promise of 100% continuity. There is switching on the grid that can cause this.

200ms seems like a long time. You would definitely notice all the lights flicker for that period. Unless it's daytime and you have no lights on in your workshop.

200ms is an absurdly long time for interrupts to be off. What possible libraries might be doing this? It may be easy to fix.

I don’t think the grid has had any brown outs in my neighborhood lately so the cause must be something else.

But coming back to the original questions about using an interrupt and analogRead on the same pin:

If I use the same code but with digitalRead() instead then it works without destroying the interrupt. Why does that work and not analogRead()?

Because analogRead() is a relatively complex function. It messes with lots of options on the pin before it attempts to read it. It turns off the pullup. It turns off any PWM timers that might be connected to the pin. There's probably more.

Find the source code for analogRead() and see for yourself. C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino\wiring_analog.c on my system.

That makes perfect sense - Thank you for the source link :slight_smile: