How to detect multiple simultaneous button presses

How would I detect if a user has pressed (and held for a few moments) two buttons. I really can't think of a reliable way.

Additionally, what's the most reliable way to detect if a button has been held down for, say, 2 seconds. Of course, you could detect the beginning of the press, pause 2 seconds and see if the button is still down, but what's to say the user hasn't briefly released and pressed the button again? I would not want this to be considered a two second push.

Thanks!
 

nick12ab

Senior Member
You could use the timer or time variable to time two seconds in a loop from when the button press has started and whether the buttons are still held or not can be checked during the loop using IF.
 

BeanieBots

Moderator
Hmm, yes, true, thanks. Any ideas on the two buttons down at once problem?
Create an interrupt routine that is triggered by ANY button push (setint NOT or use diode OR)
Arrange for all buttons to be on the same input port.
Wait a nominal time to ensure all buttons have been pushed (typically ~30mS)
Then test the port to see what buttons have been pushed.
As already described, check that the port remains the same for the required period.
 

hippy

Ex-Staff (retired)
The BUTTON command in a loop can be used for determining when a button has been pressed and/or held for a certain amount of time.

The code required and the best way to do things would depend on exactly what functionality you need. If it is to test both buttons are held together for a certain time I'd probably use a timing loop, restart the loop if either are not held. When the loop completes and continues beyond that you know both have been held for the required time.

You might want to wait for one or both to be released before testing buttons again.
 

rossko57

Senior Member
If you can more closely define what you want from the buttons, it may help you to create code.

Should we assume "buttons" are connected to individual PICAXE inputs, or something else?
Is there any hardware debouncing on the buttons, e.g. small capacitor?
Is it the intent to completely ignore "short" button presses, and only act on "long" ones? or is the intention to carry out different actions?
Is it intended that button A alone causes action X, button B alone causes action Y, but button A+B together cause action Z?
Or something else?
 

geoff07

Senior Member
If you use interrupts to detect leading and trailing edge events you can assemble any logic you like for button presses. Just record the time a leading edge event occurs, then when the corresponding trailing edge event occurs you can calculate the interval i.e. the time the button was held for. You can do this for any number of buttons as long as you have the pins and interrupts available. Diode multiplexing can simplify the interrupt mechanism though detecting both edges might need a little thought.

The ISR itself simply detects the event, stores the time, resets and exits. Perhaps best to debounce electrically (RC) to avoid delays in the code when you should be listening for button events.

What may seem simultaneous to a user won't to a Picaxe. especially at a high clock rate.
 

g6ejd

Senior Member
Observations/questions:

When an interrupt occurs, doesn’t the PICAXE disable interrupts until that event has been serviced/cleared? Thereby preventing multiple edges from being detected.

Being a Von-Neumann architecture you can't really do two things at once.

I suspect a good scheme will be to poll each button at predefined intervals, perhaps 100mS apart (maybe less) and count for how long each is held down, then from the time determine which was pushed first by the duration recorded. You coudl put this routine in parallel task and use your foreground task to process the button responses.

logic-
'Background routine
interrupt every 100mS:
on interrupt, poll each button, if pressed (say low) then increment button pressed count
return from interrupt

'Foreground Routine
start:
if button1_location > 0 then buttonpressedflag = true
if button2_location > 0 then buttonpressedflag = true

if button1_location > button2_location then gosub button1_pressed_first
if button2_location > button1_location then gosub button2_pressed_first
if buttonpressedflag = true then goto buttons_pressed
goto start

button1_pressed_first:
button1_location = 0
button2_location = 0
do something
return

button2_pressed_first:
button1_location = 0
button2_location = 0
do something
return

buttons_pressed:
button1_location = 0
button2_location = 0
do something
return

Offered as a thought. Needs more work, but not far off.
 

John West

Senior Member
How many buttons are involved in this system? It may not be possible for a PICAXE to monitor two buttons at the same time in the digital realm, but it is possible using a PICAXE in the analog realm. Monitoring a PICAXE analog input that is connected to a voltage source via switched resistors in a fashion similar to the "resistor divider keypad" method discussed in other threads might provide an easy solution to the problem.
 

Jaden

Senior Member
I have done it with IF 'button A = 1' AND 'button B = 1' then goto ........

But like stated you may need to do it in a loop as the little buggers go pretty fast.
 

fernando_g

Senior Member
I like John's idea. With two different resistor values for SW1 and SW2, you can detect either switch one, switch 2, or both have been pressed.

But hey, as my signature says, my brain cells are still mostly analog. And the digital brain part still uses magnetic core memory.
 

hippy

Ex-Staff (retired)
When an interrupt occurs, doesn’t the PICAXE disable interrupts until that event has been serviced/cleared? Thereby preventing multiple edges from being detected.
If you re-enable the interrupt for the same trigger without waiting for it to be cleared you will likely go straight back into the interrupt as soon as you leave on RETURN. So it's common to wait until cleared if you want to interrupt on the same again, a button being pushed for example.

If you don't re-enable interrupts you can exit before the condition has cleared and won't go back in until another SETINT and a condition which matches.

You can however re-enable on the opposite condition that got you there, so can interrupt initially on a push going high, then re-enable on the pin going low and exit while still high, and vice-versa when you enter the interrupt again.
 

kevrus

New Member
What other connections/functions will these buttons be used for? If purely used as inputs into the picaxe, can you not connect both buttons in series and then just use one input configured as an interupt?
 

inglewoodpete

Senior Member
My preferred method of reading multiple input button or keypad is to use interrupts from a background timer. It is not important to capture the edges of a keypress but that its state has changed since the previous time that inputs were read. I use couple of byte registers, with one byte broken into bits to indicate the status of the inputs (Eg Pressed, (Held), Released, Used).

I use a fairly slow interrupt (50 or 100mS) and require two consecutive, matching readings for a valid input. Optionally, after 700-1000mS, the "Held" bit can be set to get alternate Key input values. The "Released" state indicates that the input is resolved and can be used by the foreground task. The "Used" state is effectively the same at a keypad reset, waiting for a new input.

I have used the same timer interrupt principle to read a 9-input "Touch" pad on a 28X2.
 

Marcwolf

Senior Member
One possibility is to have the buttons on a resistor network and use the ADC to works out what is being pushed. There are some code and examples around of having a 12 button Keyboard on one ADC.
 
Top