What is best method to multiplex many buttons with only 2 interrupts available?

In my first Arduino Mega project I had 4 buttons that needed to have a fast hardware interrupt so I used INT-0 and connected all 4 buttons to INT-0 (with blocking diodes on each button circuit) and after a INT-0 was triggered, the interrupt routine would check via digitalRead which button was pressed.

I now need to increase the number of buttons to 6. Will I miss a button press reading pin state for 6 pins sequentially? I guess I should split the buttons and use two separate interrupts?

How fast do you need to react to the buttons? I typically use a 500Hz tick interrupt to poll buttons and rotary encoders, which can gives you a response time as low as 2ms, depending on how you program it.

In my first Arduino Mega project I had 4 buttons that needed to have a fast hardware interrupt

How fast are these buttons being pressed and released and what is the shortest interval between pressing 2 different buttons ?

If you triggered the check for button presses using an interrupt then polled the buttons using digitalRead() it seems to me that you may as well have just polled them anyway.

Will I miss a button press reading pin state for 6 pins sequentially?

That depends on what else you are doing in loop() and how you are doing it. Seeing your program would help.

To read the state of multiple buttons at once in loop() you could use an analogue input and a resistor ladder to give a different value for each button.

If the buttons are being pressed by a person the process will be so slow that interrupts will be unnecessary.

...R

My apologies to all, the devil is always in the details and I didnt provide enough. My program Loop is spending its time processing realtime changing compass heading sensor data being received wirelessly (RF69 with a Moteino from another Moteino). There is a lot going on in the loop particularly handshaking acknowledgements with the other Moteino sending the data on the other end plus floating point math that takes up a lot of time. I originally used pinchanges but unless I gave the button a 'generous' push, it would miss button presses so I went to the interrupt method which works perfectly. After posting the thread question, I realized I have no other use for the second interrupt so why not split out the 6 buttons between INT0 and INT1. Anyone disagree?

To be honest, your loop probably needs rewriting if so much is going on you miss button presses. It should be non-blocking.

However if that isn't possible, once an interrupt arrives you should be able to work out which one in a few microseconds (even for 6 buttons) .

I originally used pinchanges but unless I gave the button a 'generous' push ...

Pinchanges are* interrupts, what is the difference? Or did you mean something else?

  • = can generate (however not on all pins on the Mega).

On the Mega only some pins are usable with pin change interrupts, and you have
to look up the pin-port assignments to figure out which and what port/mask-bit
is needed, but pin-change interrupts allow many more pins to be interrupt-sensed
and might be a solution here.

Basically ports B J and K are used (there's one or two exceptions) for pin change ints.
You need to code an ISR for each port used, and there's a mask of bits to say which
pins you are interested in. You figure out what happened by reading the relevant
port input register.

The Arduino pin / port mappings are documented in variants/mega/pins_arduino.h

On the Uno all pins are on pin-change interrupts (ports B, C, D).

Thanks Mark, Nick. On the MegaMoteino (Atmega1284p microcontroller) there are fewer available Port/pins and its mapping is not the same as the Arduino Mega plus there is substantial overhead due to the wireless RF69 transceiver. Given RF noise - RX/TX retries, handshaking is pretty basic and slow and the loop needs to spend most of its time listening for packets with little receive buffer space. I implemented the extra buttons with INT1 and based on interrupt flags I set in the INT0 or INT1 ISR I then check for either bank 0 or bank 1 of buttons in my main Loop. It seems to be working fine and my RF transceiver seems happy as well with data flow from almost 1000' away :slight_smile: