Listening for a long or short signal from button: what's your approach? - Page 1
Forum section: electronics / general

author: jancumps
author_rank: Unknown
timestamp: December 12, 2013, 06:36:44 pm
content: When you use a pushbutton in a microcontroller managed user interface, what approach do you use?- start a timer on the falling edge and measure count on the raising edge- always keep a timer running and save the count on the falling edge?- something else?And do you stop other processing while the button is pressed or not?

author: Bored@Work
author_rank: Super Contributor
timestamp: December 12, 2013, 07:31:53 pm
content: Continuously sampling the keyboard matrix. Effectively undersampling with respect to most key bouncing but fast enough to detect changes originating from human interaction. Storing (shifting in) the sampling results in a bit-array, one per key. The lengths of such a bit-array defines the longest key-press history available for a key. Then checking for a continuous sequence of ones (indicating a long key press) in such an array, starting from what constitutes "now" or "latest" in the array, back to whatever would be the key press duration for which I want to check.E.g. sampling with 50 ms requires 20 bits (make it 24 bits = 3 bytes, or a single 32 bit variable) per key to keep a > 1 second history for a key. A simple testCode:if((value & 0x000FFFFF) == 0x000FFFFF) ...then tells me if a button has been pressed for at least 1s.For larger durations I accumulate e.g. 1s press-durations in a separate counting byte.

author: nctnico
author_rank: Super Contributor
timestamp: December 12, 2013, 08:17:57 pm
content: Use a timer and poll it. Never ever use interrupts for switches and buttons unless their signals are properly filtered and are run through buffers with schmitt-trigger inputs!I usually choose the polling interval so I can see a button is pushed for several timer intervals without making the user wait too long. This involves a counter to count the number of intervals. The number of intervals can be used to detect how long a button was pushed when it was released and/or whether a button was pushed long enough.

author: TheDirty
author_rank: Frequent Contributor
timestamp: December 13, 2013, 01:32:37 pm
content: I usually have an interval timer that updates general purpose counters and will poll the button presses. Then I have some hardcoded values to evaluate on button up. value 1 is very small and means false trigger or possibly a bounce, Value two is timed for short button press, and value three is long button press.

author: TMM
author_rank: Frequent Contributor
timestamp: December 13, 2013, 04:11:41 pm
content: Quote from: nctnico on December 12, 2013, 08:17:57 pmWhy not? Debouncing isn't hard to implement in software - I usually just implement a hold-off timer. You'd only want hardware debouncing if the processor was doing something absolutely time critical and you needed to minimize the number of unnecessary interrupts.

author: nctnico
author_rank: Super Contributor
timestamp: December 13, 2013, 05:00:46 pm
content: Quote from: TMM on December 13, 2013, 04:11:41 pmThat is EXACTLY what I'm typing...

author: mazurov
author_rank: Frequent Contributor
timestamp: December 14, 2013, 12:16:17 am
content: I generate separate events on press and release. What is going to happen on each event depends on the state of the state machine the application is in. If I need to react to long press I start a timer in that state. If I don't, I do nothing (or react on release instead of a press).

author: dannyf
author_rank: Super Contributor
timestamp: December 14, 2013, 12:25:05 am
content: QuoteWow!That's some advice we can do without,

author: Marco
author_rank: Super Contributor
timestamp: December 14, 2013, 12:59:57 am
content: For what it's worth in the few (as in 2 and in college/internship, so not worth much) embedded systems I made I just had a big old interrupt routine running at fairly high frequency and polled all the buttons with software debouncing and kept a timer for some to see how long they had been pressed for velocity based controls.I guess you could keep a separate counter for repeated button presses if you're interested in that and your UI code might not be fast enough to catch them.

author: dannyf
author_rank: Super Contributor
timestamp: December 14, 2013, 01:10:14 am
content: QuoteYou actually don't need a timer in that case: you can run a counter in the isr to detect long vs. short presses.

author: Marco
author_rank: Super Contributor
timestamp: December 14, 2013, 01:14:32 am
content: Sorry I didn't make myself clear, that is what I meant.

author: Rufus
author_rank: Super Contributor
timestamp: December 14, 2013, 01:17:10 am
content: Quote from: dannyf on December 14, 2013, 12:25:05 amIt is generally good advice. I have never wanted or needed to generate interrupts from switches or buttons except when required to wake up a sleeping processor.

author: nctnico
author_rank: Super Contributor
timestamp: December 14, 2013, 01:17:31 am
content: Quote from: dannyf on December 14, 2013, 12:25:05 amPeople using interrupts for stuff like uncontrolled signals (usually) attached to long wires will crash and burn at a some point. I've seen it happen several times with damages into 6 figures behind a € sign as a result in some cases... Better be safe than sorry!

author: c4757p
author_rank: Super Contributor
timestamp: December 14, 2013, 01:25:08 am
content: I have never, ever needed to interrupt on a user input, except for the aforementioned case of waking from sleep (in which case I implement a policy of disabling that interrupt immediately after wake and not returning to sleep for at least a second). The amount of time it takes a human to interact with a device is aeons in microcontroller time! It's too easy to screw up and too useless to bother.

author: jancumps
author_rank: Unknown
timestamp: December 14, 2013, 10:14:43 am
content: Texas Instruments give this advice on the e2e forum:http://e2e.ti.com/support/microcontrollers/msp430/f/166/t/54539.aspxQuote

author: nctnico
author_rank: Super Contributor
timestamp: December 14, 2013, 01:12:50 pm
content: Quote from: jancumps on December 14, 2013, 10:14:43 amMajorMake a note of the author and put that name on your 'these people are complete idiots' list. Its probably a software guy/girl who thinks hardware always does what its supposed to do, a button doesn't bounce or a signal can't contain noise.

author: jancumps
author_rank: Unknown
timestamp: December 14, 2013, 01:20:38 pm
content: He has given the debounce logic too in that same forum post.

author: dannyf
author_rank: Super Contributor
timestamp: December 14, 2013, 01:31:13 pm
content: QuoteIt is the drunk who always insist that others are drunk.

author: arcom
author_rank: Contributor
timestamp: December 14, 2013, 03:34:47 pm
content: I use a counter for each button along with rising/falling edge detection to handle button states. In addition to that, each button has it's own status variable and entire processing is inside a single function which is called in 10-20ms intervals. That function does something like this:1. reset button status variable2. detect rising and falling edges3. on rising edge3.1. reset counter3.2. set "pressed" bit4. on falling edge4.1. set "released" bit4.2. if counter <= short_press_limit, set "short press" bit5. if button is pressed5.1. if counter >= long_press_limit, set "long press" bit5.2. else increment counter"Short press" state will be triggered only on button release and "long press" state will be set as long as the button is held pressed which is handy for scrolling purposes (eg. incrementing/decrementing a value by holding a button pressed). Good thing about this approach is that there are no delays or waiting loops so that the rest of the code can run. Also, calling the function in regular intervals debounces the buttons quite effectively.

author: Rufus
author_rank: Super Contributor
timestamp: December 14, 2013, 03:44:49 pm
content: Quote from: nctnico on December 14, 2013, 01:12:50 pmThe second line of code associated with that post says"// Go to sleep, wait for port pin interrupt"So he was quoted without the context of minimizing power consumption.

author: JohnnyGringo
author_rank: Regular Contributor
timestamp: December 14, 2013, 04:21:13 pm
content: Quote from: nctnico on December 14, 2013, 01:12:50 pmHardware shouldn't be bouncing or noisy before it gets to the software guy/girl. That's a problem that should be taken care of in the hardware design. You don't really want your average coder having to worry about piss-poor hardware.

author: nctnico
author_rank: Super Contributor
timestamp: December 14, 2013, 05:20:18 pm
content: And make the bean counters come downstairs saying the competition is making a cheaper product with a PCB which contains 10 times less components than yours?

author: jancumps
author_rank: Unknown
timestamp: December 14, 2013, 06:22:29 pm
content: Quote from: Rufus on December 14, 2013, 03:44:49 pmMy excuses if my quote is incomplete. I did quote this part of his text though:QuoteI'm not looking for consensus on the solution on the internet. I'm going to try out all the approaches mentioned above and see how each of them performs.

author: Bored@Work
author_rank: Super Contributor
timestamp: December 14, 2013, 06:41:45 pm
content: Quote from: JohnnyGringo on December 14, 2013, 04:21:13 pmHello?

author: madires
author_rank: Super Contributor
timestamp: December 14, 2013, 07:55:40 pm
content: I use whatever fits the requirements and the program flow. If I have a battery powered device with an one-button interface I'd use an interrupt. It doesn't make much sense to have the MCU wasting power for waiting hours, days or weeks for the user to press the button. There's no this-is-the-right-method-and-everything-else-is-BS method.

author: JohnnyGringo
author_rank: Regular Contributor
timestamp: December 14, 2013, 08:02:24 pm
content: Quote from: Bored@Work on December 14, 2013, 06:41:45 pmListening. And quite frankly, I'm rather ignorant when it comes to hardware issues (obviously). But I don't see the point of the "Hello?". What am I missing?

author: Neverther
author_rank: Regular Contributor
timestamp: December 14, 2013, 08:19:58 pm
content: I run the input with interrupts mainly due to the instant need for shutoff.The interrupt waits couple milliseconds before sampling the input port (poor mans debounce) and the functions are processed in priority order.Long/short press for last two buttons is simply while loop for input state and counter to add up and break the loop if it gets too high.If the loop is not broken, it was a short press.And the fact it is running in avr pin change interrupt means that keeping the buttons pressed does not affect the control loop after the first run, where the maximum time is known.Would not work on fast systems but on mine the control response is only required within 0.5s to 1s so it does not matter.

author: nctnico
author_rank: Super Contributor
timestamp: December 14, 2013, 08:36:18 pm
content: Yet one of the problems of using interrupts for wake-up is that when the battery lifetime is based on 1 push per day a bad switch and/or moisture could easely cause several false presses (interrupts) per second. That would shorten the lifetime significantly. A couple of months ago I designed a battery (coin cell) powered gadget. I simply poll the buttons a few times per second. This solution exceeded the battery lifetime requirement more than twice (worst case) AND I can guarantee it will meet the battery lifetime under any circumstance.

author: Bored@Work
author_rank: Super Contributor
timestamp: December 14, 2013, 09:29:16 pm
content: Quote from: JohnnyGringo on December 14, 2013, 08:02:24 pmE.g. because even quality switches bounce. You can now waste money on hardware debouncing or handle it with a few lines of code. More hardware does not come for free, and it adds more potential failure points. Further, your hardware does not run in an ideal world. You need to be prepared for spurious events. You can sort them out in software the same way you sort out bounces - in fact, it is the same code, killing two birds with one stone.And you can never make hardware idiot-proof for the software guy. If the software guy is an idiot he'll find other ways to code stupid things. Like using interrupts or setting all outputs to the fastest rise time.

author: JohnnyGringo
author_rank: Regular Contributor
timestamp: December 14, 2013, 11:27:14 pm
content: Quote from: Bored@Work on December 14, 2013, 09:29:16 pmYes, I see your point. But, wouldn't that mostly apply to microprocessor world? I.e. Systems/Designs with no device drivers?If I'm coding on a device with an OS, I'd certainly expect hardware malfunctions to be handled by the hardware or device drivers. Having a crappy-hardware design with the expectation that the device drivers will sort it all out, is still just a crappy-hardware design. NOT THAT YOU would personally design crappy-hardware.

author: nctnico
author_rank: Super Contributor
timestamp: December 15, 2013, 11:30:59 am
content: Quote from: JohnnyGringo on December 14, 2013, 11:27:14 pmThat is a pretty naive approach which could get you (and your boss) in serious trouble. Hardware (silicon bugs!) and their drivers have short deadlines so they have bugs by definition when they are just released. Every now and then I do development for embedded Linux systems and I usually have to fix some bugs in the kernel (and drivers) to get the platform running reliably. If you are writing software which interacts with hardware you need an embedded software engineer with a strong electronics background. One who knows how to use an oscilloscope. And even then you might run into trouble.

author: JohnnyGringo
author_rank: Regular Contributor
timestamp: December 15, 2013, 01:53:28 pm
content: Quote from: nctnico on December 15, 2013, 11:30:59 am+1 nctnico! Fortunately for me, I have no boss <grin>. Yea, I've had my fair share of embedded device drivers, and it always drove me nuts when just a few simple parts would had made my job simpler. That is why this was such a hot-button topic for me.

author: Jeroen3
author_rank: Super Contributor
timestamp: December 15, 2013, 07:40:50 pm
content: If you are on a 32 bit platform...Sample button status every 20 ms and perform this:Code:history = (history<<1) | ((bool)button & 1)Then you can check the amount of cleared bits (buttons always go low when pressed) and detect short press (0xFFFFFFF0), long press (0x00000000), medium press (0xFFFF0000), double press (0xFF00FF00) you name it.All in the software, I've only used long and short press, double and medium are a lot more effort to program.But now I have a flawless relay control button with mode select when you hold it.Tip, use the setbits instruction to prevent useless comparisons... If you target has such instruction.

author: NiHaoMike
author_rank: Super Contributor
timestamp: December 16, 2013, 12:11:58 am
content: You could have the buttons trigger an interrupt, but mask the interrupt in its ISR. Then use a timer interrupt to unmask the button interrupt. That way, it can still respond almost instantly but if noise tries to cause an interrupt storm, it would be self limiting. Using low priority interrupts on a processor that supports it also works.

author: dannyf
author_rank: Super Contributor
timestamp: December 16, 2013, 12:20:23 am
content: QuoteI have a lot of trouble trying to figure out how that might work.

author: nctnico
author_rank: Super Contributor
timestamp: December 16, 2013, 02:00:36 am
content: Quote from: NiHaoMike on December 16, 2013, 12:11:58 amI see the idea. The problem is that when dealing with noise you could get a false positive if you sample only once after a delay. IMHO you should sample a signal from a button/switch a few times so you know it is a stable signal and not noise.

author: jancumps
author_rank: Unknown
timestamp: December 16, 2013, 11:00:34 am
content: What abouthaving a clock defined but not runningreact on button gio interrupts to register that a certain button is pushedand start the clock (say 10/20 ms) and start polling the registered button(s) as explained by others here - to debounce and check short/long pusheswhen the push(es) are completely handled, stop the clock untill a new button interrupt arrives?In that case the processor does no have to reside to endless polling, it gets a wake up from the button, and I deal with the remarks from other posters here about noisy interrupts because polling is done with a timer.Thought?

author: nctnico
author_rank: Super Contributor
timestamp: December 16, 2013, 01:00:33 pm
content: The problem is that every time you get a pulse you have the clock running for a relatively long period. You could setup a scheme where you poll the buttons for a short period of time with a timer interrupt but then again your battery life estimates can be way off. If you really need ultra low power I'd use hardware filtering using ultra low power CMOS logic (maybe even the 4000 series).

author: jancumps
author_rank: Unknown
timestamp: December 16, 2013, 01:38:10 pm
content: When I used the word clock I should have used Timer with interrupt.If the gio interrupt was a glitch then the timer can stop after the first tick because it would find immediately when polling that the button is not pressed and that it was a glitch?Wouldn't the battery last longer because I only have a timer running when needed, and for the shortest possible period?The real polling would still happen on timer interrupts as explained by you, but the timer and its interrupt would only be activated if a button trigger occurs, and stop polling if all handling is processed.Am I looking too far?