Shop OBEX P1 Docs P2 Docs Learn Events
Button Handler — Parallax Forums

Button Handler

Mag748Mag748 Posts: 266
edited 2013-08-06 13:14 in Propeller 1
Hi there,

I'm working on a project that will involve lots of button input. So I'd like to design a really efficient button handler. I have already gotten the actual reading of the buttons and debouncing code. I'd like to now move onto the "event handling" portion. What I mean is the code that actually monitors the debounced button data to determine when a button is pressed once, pressed and held, and double pressed. This handler needs to be able to monitor up to 24 individual buttons simultaneously.

The simplest way would be to just loop through each button, set timers and whatnot, and maybe set a flag when a button press, or double press or whatever happens. But then I need flags for each buttons x 24. And I feel like that would be clunky. I was thinking maybe a better way would be to create an event buffer. So, this method could monitor all buttons simultaneously, and when is detects that button 6 was just double pressed, is adds a "button 6 double press" to a stack or something. How does this idea sound? And does anyone have any examples of something like this that already exists?

Thanks a lot,
Marcus

Comments

  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2013-08-01 21:01
    Mag748 wrote: »
    Hi there,

    I'm working on a project that will involve lots of button input. So I'd like to design a really efficient button handler. I have already gotten the actual reading of the buttons and debouncing code. I'd like to now move onto the "event handling" portion. What I mean is the code that actually monitors the debounced button data to determine when a button is pressed once, pressed and held, and double pressed. This handler needs to be able to monitor up to 24 individual buttons simultaneously.

    The simplest way would be to just loop through each button, set timers and whatnot, and maybe set a flag when a button press, or double press or whatever happens. But then I need flags for each buttons x 24. And I feel like that would be clunky. I was thinking maybe a better way would be to create an event buffer. So, this method could monitor all buttons simultaneously, and when is detects that button 6 was just double pressed, is adds a "button 6 double press" to a stack or something. How does this idea sound? And does anyone have any examples of something like this that already exists?

    Thanks a lot,
    Marcus
    Sounds like a matrix keyboard really, however the reality is that you normally would only have one button pressed at a time I guess so there would be no need for individual timers. If you are detecting long presses and double presses etc then you must defer buffering anything until your action timer which is triggered by a press, has expired. If your action timer is too long then responses seem delayed to the user so you sometimes want to know about the initial event and then find out a bit more after providing some feedback. So if I wrote an application I would only want to know about make and break but futher than that is really application specific. Your application can choose to ignore a break and only look for a make on certain switches while others it's important to know when it's released.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-08-01 21:21
    I hesitate to use this as an example since I wrote when I was just learning to use the Propeller (I think it was my one hundredth forum post). I wrote an object to buffer the keypresses of a 16 button keypad. The program includes a timeout feature which will drop keypresses from the buffer once a specified time has elapsed. Otherwise the object will output the keypresses when requested from the FIFO buffer.

    I'm afraid the program may have likely has bugs. I'll likely revisit the object soon since I have another 16 key keypad I'm using in one of my current projects.

    Another option to using a matrix to detect the button presses, is to use '165 parallel to serial shift registers. You could shift in the bits to obtain the current button states and use only three I/O pins on the Propeller.
  • phatallicaphatallica Posts: 64
    edited 2013-08-03 14:02
    A GPIO has more setup than the '165 shift register, but I have used MCP23S17 for keypad inputs before. The ability to trip an interrupt for each set of 8 inputs was a nice feature for me.

    The trick for me was deciding what is reasonable in terms of timing. For instance, I remember selecting 100msec as a reasonable time between button presses. Deciding how long is "holding" the button and how long much time between presses defines a "double tap", then the rest of the code almost writes itself.

    I am converting some of my code from BS2p to PropBASIC for MCP23S17, if an example of initializing at setting the various registers would help. In fact, the next thing that I will be cleaning up is a 8-input scheme (3 push-buttons and 5 lines from HT12 Decoder).
  • kwinnkwinn Posts: 8,697
    edited 2013-08-03 20:58
    Mag748 wrote: »
    Hi there,

    I'm working on a project that will involve lots of button input. So I'd like to design a really efficient button handler. I have already gotten the actual reading of the buttons and debouncing code. I'd like to now move onto the "event handling" portion. What I mean is the code that actually monitors the debounced button data to determine when a button is pressed once, pressed and held, and double pressed. This handler needs to be able to monitor up to 24 individual buttons simultaneously.

    The simplest way would be to just loop through each button, set timers and whatnot, and maybe set a flag when a button press, or double press or whatever happens. But then I need flags for each buttons x 24. And I feel like that would be clunky. I was thinking maybe a better way would be to create an event buffer. So, this method could monitor all buttons simultaneously, and when is detects that button 6 was just double pressed, is adds a "button 6 double press" to a stack or something. How does this idea sound? And does anyone have any examples of something like this that already exists?

    Thanks a lot,
    Marcus

    IMHO the determination of whether the button is pressed once, pressed and held, or double pressed should be done in the button reading/debouncing code, and the result returned in some manner. Perhaps you could return a byte with 5 bits indicating the button and 3 bits used for how it was pressed.

    Is the button reading/debouncing done in spin, pasm, or something else?
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-08-03 21:07
    It sure seems like unnecessary work to check for double presses when you have 24 buttons. The whole idea behind a double-click was to let your single left mouse button do more than just one thing. The double-click was kind of like adding an extra button. With a 24 buttons you're closer to a keyboard than a mouse. I think you're asking for trouble trying to distinguish between a double click on button 6 rather than button 6 having been pushed twice.

    Could you imagine if your keyboard used double clicks? You'd have to be very careful whenever typing words with double letters.
  • kwinnkwinn Posts: 8,697
    edited 2013-08-03 21:14
    Duane, that's a valid point if held/double clicks are used on every key, however if only a few keys (like the * and # on a phone) are all that use double clicks it is not much of a problem. A lot of equipment uses one or two keys to enter menus or special functions by double clicking on one or two keys. Saves having a very large keypad and hides those functions from the uninitiated.
  • kwinnkwinn Posts: 8,697
    edited 2013-08-03 21:17
    PS, I wonder if double clicking on a keyboard instead of holding down a shift key would make for faster data entry.
  • Mag748Mag748 Posts: 266
    edited 2013-08-05 07:46
    Peter, Duane,

    I like the idea of using the FIFO to buffer button events. Instead of worrying about the "timeToLive" timer, I'll probably just circle around and over write the oldest event if the buffer is not read fast enough. Are there any robust example of FIFO buffers out there? Maybe that use ASM as well? Duane, I will look through your example because it does look promising.


    phatallica, kwinn,

    I am going to keep the button state gathering/debouncing completely separate from the event handler. That way I can pass any type of input to the handler, whether it from from a Prop pin, a '165 or any other input device. I'm trying to may this as universal and plug and play as possible.

    Duane,

    I do agree that it seems unnecessary to have the ability of a double press/long press on every single input. But I thought for simplicity and "expandability", creating the system to work with 1 button should be the same for as many buttons as you need. It would just be a matter of requiring more memory and maybe a little more processing time per additional button. I don't want the method I write to be too specialized and specific to one application.


    Thanks for the input. I will go with a circular buffer and try and figure out how to make this object modular enough to be useful. I'll update this thread with progress I make.

    Thanks,
    Marcus
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-08-05 10:30
    Mag748 wrote: »
    Peter, Duane,

    I like the idea of using the FIFO to buffer button events. Instead of worrying about the "timeToLive" timer,

    The idea was, if the keypad were pressed accidentally when data isn't expected, the key press wouldn't remain in the buffer. I didn't want an old key press to be the first entry when I switched the device to a mode expecting data.
    Mag748 wrote: »
    I'll probably just circle around and over write the oldest event if the buffer is not read fast enough. Are there any robust example of FIFO buffers out there? Maybe that use ASM as well?

    Most (probably all) of the serial objects use circular buffers. All the objects I've looked at (I've looked at many) drop all the data in the buffer once the head meets the tail. It would require some additional code to have the buffer drop the oldest data and preserve the rest. I can't think of many situations where you would want to keep partial data.
    Mag748 wrote: »
    Duane, I will look through your example because it does look promising.

    As I mentioned previously, it was a very early attempt. I'm pretty sure it's buggy.

    I look forward to seeing what you come up with.
  • kwinnkwinn Posts: 8,697
    edited 2013-08-06 08:08
    Mag748 wrote: »
    Peter, Duane,

    .........


    phatallica, kwinn,

    I am going to keep the button state gathering/debouncing completely separate from the event handler. That way I can pass any type of input to the handler, whether it from from a Prop pin, a '165 or any other input device. I'm trying to may this as universal and plug and play as possible.

    ........

    Thanks,
    Marcus

    I am just wondering how you plan to distinguish between a single button press, a button being held down, or a button being pressed twice if it is not done in the button reading/debouncing routine. I can see that having the same key code appear twice in the buffer could indicate a button was pressed twice, but how will you tell if it was pressed and held?
  • phatallicaphatallica Posts: 64
    edited 2013-08-06 09:15
    kwinn wrote: »
    I am just wondering how you plan to distinguish between a single button press, a button being held down, or a button being pressed twice if it is not done in the button reading/debouncing routine. I can see that having the same key code appear twice in the buffer could indicate a button was pressed twice, but how will you tell if it was pressed and held?

    This is why I suggested that the trick is defining a reasonable human interface input. Once you plot out the timing for each, I suspect that it will be a graphical representation of the pseudocode. For instance (arbitrary values):

    1msec = software debounce
    1sec = duration of press & hold
    500msec = allowable gap between presses for double press.
    100msec = minimum time between different button presses (rate of 10/sec).

    Maybe Marcus has a better plan already?
  • tonyp12tonyp12 Posts: 1,951
    edited 2013-08-06 13:14
    >appear twice in the buffer
    The program that reads the buffer would need more info than just the key, a double click key should have an extra MSBit set.
    If your buffer can store key 0-127, but with bit 7 set (now a value between 128-255) represent the same key but double clicked.
Sign In or Register to comment.