attachInterrupt mode CHANGE behavior

Hi everyone,

I am having some strange behavior (at least to me) with attachInterrupt which i can't seem to figure out. I have two buttons attached (up and down) once pressed it will pull the signal low.

If i set the attachInterrupt mode to LOW, pressing (and hold) the A button will spam "A press", same for B.
However if i set attachInterrupt to CHANGE and press (and hold) the A button the result is:
"Press A"
"Press B"

I don't understand how the CHANGE mode causes both interrupts to trigger, while pressing only one of the buttons.

#include <Arduino.h>

void PressA();
void PressB();

void setup()
{
  Serial.begin(9600);

  pinMode(2, INPUT);
  pinMode(3, INPUT);

  digitalWrite(2, HIGH);
  digitalWrite(3, HIGH);

  attachInterrupt(digitalPinToInterrupt(2), PressA, LOW);
  attachInterrupt(digitalPinToInterrupt(3), PressB, LOW);

  Serial.println("Running");
}

void PressA() {
  Serial.println("A Press");
}

void PressB() {
  Serial.println("B Press");
}

void loop()
{

}

Thanks for reading!

How about INPUT_PULLUP, or do you have external pull-ups attached?

Same result with INPUT_PULLUP, unfortunately I can't dissemble the buttons housing so I unsure about the pull-ups.
The button housing has 3 wires, 2x 5v and a ground once pressed the voltage drops to 0.
So one wire is attached to pin 2 and the other button to pin 3 and the third wire to ground.

What I don't understand is how come it seems to differentiate the buttons properly when the mode is set to LOW, but setting the mode to CHANGE causes the arduino causes both interrupts to trigger on a single button.

CHANGE fires on an edge, however short, because the edge-detection fires a flip-flop to record the event. LOW fires when the signal is low for a certain length of time determined by how often the hardware polls the pin for interrupts (once per instruction executed, typically). In CHANGE mode the hardware polls the flip-flop so it won't miss a short pulse.

When you press one switch this couples a pulse on the other wire for a few nanoseconds, enough to trigger a CHANGE interrupt (but not reliably trigger LOW it seems). Strong pullup resistor on the signals will probably quell this, adding some capacitance to the signals definitely will.

BTW you shouldn't use Serial in an ISR, it can lock up the entire microcontroller as Serial relies on other interrupts.

Thanks for the information Mark. The serial was mostly to test the system before i start soldering, Ill try to write the code without the interrupts.

@scale0
1. This is the switch connection (Fig-1) with internal pull-up resistors enabled.

sw2
Figure-1:

2. Your sketch of Post-1 is expected to have the following format:

volatile bool flagA = false;
volatile bool flagB = false;

void setup()
{
  Serial.begin(9600);

  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);

  attachInterrupt(digitalPinToInterrupt(2), PressA, LOW);
  attachInterrupt(digitalPinToInterrupt(3), PressB, LOW);

  Serial.println("Running");
}

void loop()
{
  if(flagA == true)
  {
    Serial.println("A Press");
    flagA = false;
  }
  if(flagB == true)
  {
    Serial.println("B Press");
    flagA = false;
  }
}

void PressA() 
{
  flagA = true;
}

void PressB() 
{
  flagB = true;
}

Really? I don't think LOW is a good idea.

The LOW trigger level originally belongs to @scale0.

No, it is from your example titled as follows

Who would 'expect' such a bad example?

The ATmega328P documents tell us about three possible trigger levels of an incoming interrupting sign, which are shown in Fig-1 and they all seem to be good in respect of thier applications.

Figure-1:

And you think a button is one of "those applications" for a LOW level interrupt?

A bad example could be nourished by a veteran to have good shape.

If you have an alternative way of injecting low level interrupting signal, then post it please.

A level interrupt is useful for external interrupts that can be switched off or masked.
We could attach a switchable high voltage generator to the button to achieve that,
would that be acceptable?

Would appreciate to see diagramatic representation of the above quoted statement.

While i barely follow what is being discussed because I lack allot of knowledge in the electronics department, I thought if i explain further that might clear up some confusion. I am working on a project with an IKEA standing desk, the rodulf to be exact.

When i started this project I assumed it would be the same as a IKEA bekant table which looks the same, someone had done a project with this table before. He found out the buttons communicate to the motor unit using a LIN bus. I wanted to expand on his creation without having to modify the table itself.

Using a logic analyzer I found out my table doesn't use a LIN bus at all. The table controls connect to the motor unit using an RJ-45 jack, with only 3 wires inside. Using the logic analyzer I found out that two of the wires were always 5V in idle state and would go down to 0V once pressed. Basically 1 Up wire, 1 Down wire, hotwire it to the the ground wire and it would go up or down.

My plan is to cut a network cable in half, insert the arduino in the middle and use an RJ-45 extender block to attach it back to the original cable.

So what I attached the button wires to pin 2 and 3, set them to high to have them at 5V as they would be if connected to the motor unit.
I attached the motor unit to pin 4 and 5, Now when pin 2 goes low I set pin 4 low and the table moves.

Basically i Man-in-the-middled the buttons, but now I would also be able to move the table from software over serial. I intend to add an Ultrasonic Sensor so that I can create position memory in software.

The only issue that remained was that when the arduino powered down, the motor unit wires on pin 4 and 5 would go low and the table would raise to the lowest or highest point. I resolved this by adding 2 optocuplers, pin 4 and 5 now trigger the optocuplers. This way the table won't move when the arduino is powered off. I tried using an BC547B NPN transitor, mostly to save space on my prototype board but i couldn't get it work.

The prototype works the MITM part at least, now I have to add the ultra sonic sensor and some code that would allow me to sent a certain height to the arduino over serial.