# Smart ways to detect a button (less power consuming)

During a meeting for a particular project I was asked to think about the way to detect a push on a button with a MCU. The detection should consume as little power as possible. At the first glance, I thought the typical circuit with a pull-up or a pull-down :

simulate this circuit – Schematic created using CircuitLab

I don't account for some anti-bounce features here, as that is beyond this question's scope. In either case, when the button is pushed, the total current value that flows depends on the resistor value. To minimize it (the current), I could increase the resistor value but not so much since, if I am right, it also depends on the input pin leakage value. Plus, a large resistor would recover slowly.

My question is the following one : what are the smart ways to detect a button pressed that doesn't consume power (typically for a high power consuming application)? Are there any methods that are barely power-consuming when the button is pressed?

• A pull-down of 10k consumes nearly no power. 3.3V gives 330uA. And on most modern MCUs you have the option to set one internally, which will have even higher resistance. That being said, you can activate the button supply from a MCU pin through a BJT or MOSFET. Only activate it during the read, and read with polling. – Lundin Dec 12 '17 at 15:14
• @Lundin In "modern" terms, 330 $\mu$A may be a high current... – awjlogan Dec 12 '17 at 16:15
• indeed, many microcontrollers can get sleep currents as low as 2-10 μA. Wasting 30x that on a single pull-down is kind of sad, especially in a battery powered situation. – whatsisname Dec 12 '17 at 22:11
• How big a resistor you can use on a pull down depends on the pin impedance and at what voltage they switch. Let's say you have a 3.3v pin in a high impedance state that switches at 2.4v, all you really need is slightly lower impedance than the input. I would recommend you attach a potentiometer and measure how high value of a resistor you can use for the pin to keep working reliably, and then go 20% lower in value to keep a margin. – Drunken Code Monkey Dec 13 '17 at 5:40

A low-current method I used once was to connected a switch between two microcontroller I/O pins.

One I/O was configured as an output (SWO). The second was configured as an input (SWI) with its programmable internal pull-up enabled.

The switch state was sampled infrequently (every 10 ms) by a software interrupt routine. The reading sequence was: drive SWO low, read SWI, drive SWO high.

This meant that a pressed switch only drew the SWI pull-down current through itself and SWO for less than 1 us during scanning, while an unpressed switch drew no current. This current draw for <1 us every 10 ms resulted in a tiny average average current consumption.

• It is questionable why you need the pull-up using this technique. Sequence SWO Low, Read SWI, SWO High, SWI Read might be sufficient to tell if the pins are connected together. You can also share the SWO between numerous switches. – Trevor_G Dec 12 '17 at 12:53
• @Trevor Leaving the input floating when the switch is open is not a particularly good idea. Depending on the technology it can cause the input buffer to consume power if its input is in an intermediate state. – RoyC Dec 12 '17 at 13:22
• @Trevor Effectively multiplying the pull up resistor by the sw1 sw2 duty cycle. Still a pull up taking us back to the OP's scheme 1. It may work in a low noise environment. – RoyC Dec 12 '17 at 14:37
• Doesn't the fact that the MCU has to stay awake to do the polling instead of relying on an interrupt completely cancel out any saving from shorter switch duty cycles? – AndreKR Dec 13 '17 at 5:39
• Hi @AndreKR, we had a battery-powered microcontroller application and it needed several switches connected so we used this technique as it was fairly effortless. We hadn't put in an MCU just for switch detection. The MCU drew something like 900nA in sleep mode between its 10ms interrupts so the pull-up savings were worthwhile. – TonyM Dec 13 '17 at 7:15

A SPDT (Single Pole Double Throw) button would be your ultra efficient button.

In your case the 1P would go to the MCU, the 1T to VCC, the 2T to GND.

• +1.. it has always bugged me that subminiature SPDTs are either very hard to find or cost way too much... – Trevor_G Dec 12 '17 at 16:03
• @Trevor Yeah... some things are sadly very overpriced. While other items are underpriced (MCU for an example). You can't have it all. – Harry Svensson Dec 12 '17 at 18:16
• This is a great idea. Sadly I didn't manage to find a SPDT CMS button that fit my needs. I'll keep this circuit in mind though – vionyst Dec 21 '17 at 7:57

One method I have used takes advantage of the capacitive nature of CMOS inputs.

simulate this circuit – Schematic created using CircuitLab

In the circuit above the switch, when closed, allows the pull-down resistor to charge/discharge the input capacitances of the GPIO down to ground level.

The trick with this circuit is to use the bidirectional nature of a GPIO to keep the input charged to a logic high level when the switch is open.

The control routine periodically turns the pin out as a high level, or briefly enables the pull-up, long enough to maintain a charge the caps. The input pin then acts like a dynamic memory bit and will, with most devices, hold that charge for a considerable and usable amount of time.

When configured properly, if the button is pressed the charge on the pin will discharge faster than the refresh rate. That condition can then be detected as part of the refresh algorithm as a read before refresh operation, or used to drive an interrupt.

Power is briefly used during the refresh pulse, both to recharge the capacitors and through the resistor and switch if it is closed. However, the length of the refresh pulse is short and the polling frequency results in the refresh current being relatively insignificant.

Obviously this method is an active one. If the micro is put to sleep, the state of the switch will be indeterminate on waking. The first refresh cycle after wake-up must ignore the pin read. Also, this method should not be used to wake the micro. Before going to bed, it is also wise to enable the pin as a low output to park it in a zero current state.

For reading more static switches, like set-up dip-switches, a dedicated routine can be used rather than a continuous refresh cycle. After reading, the GPIO pins should then be "parked" in an active low output state (zero current) to avoid the floating inputs issue.

NOTE: This technique does suffer a little from noise sensitivity if the trace lengths are long and travel through a noisy area. As such R1 should be close to the input pin. However, I would not recommend it for hooking up a switch some distance away on a front panel somewhere unless you add extra capacitance close to the pin.

• This looks very vulnerable to EMI indeed. If any form of radio energy getting inside that circuit and I think all bets are off. Good thing wireless stuff isn't that common nowadays :) – Lundin Dec 12 '17 at 15:22
• @Lundin it's not as bad as you might think. 30pF and a meg make a rather good filter. – Trevor_G Dec 12 '17 at 15:39

How long will the button be pressed? If it is not a toggle switch (which keeps its state) but a momentary switch then the current flowing when the button is pressed is largely irrelevant due to the short time that the button is actually closed.

Either of the two circuit you show is OK, it does not matter.

You can assume that the input leakage and/or current into a MCU input is negligible. All MCUs are in CMOS technology these days and have a practically zero input current. So stop considering it, it is not there.

Instead of using an external resistor you could also use the internal pull-up resistor build into many MCU's inputs. This resistor might have a relatively low value (50 kohm perhaps) so a small current will flow when the button is pressed.

You can safely use even 1 Mohm resistor for a pull-up/pull-down. Only in very "dirty" (electrically speaking) environments you might need a lower value. You can also place a 100 nF capacitor in parallel with the switch to suppress interference from other circuits nearby.

Pro tip: Reserve a place for such a capacitor on the PCB, but do not mount a cap. yet. In case of issues: place it and see if that helps.

To detect the state of the switch, either use polling (as in TonyM's answer) or use an interrupt. It depends on the application which one is better for power consumption (of the MCU).

• Actually the button will be a momentary one but the time it will be pressed may be long enough (minutes) – vionyst Dec 12 '17 at 9:38
• If the device is on 24/7 then a couple of minutes still might not amount to a lot. What is important is the duty cycle, 5 minutes each hour is 5 x 60 / 3600 = 8.3 %. So even at a 100 uA current the switch would consume 8.3 uA on average in my scenario. My message is: don't focus too much on the current the switch uses when pressed without comparing it to the complete system's current consumption. Only when the contributions are the same, then it makes sense to improve the switch's current consumption. It's no use making a 0.1 uA switch when the MCU uses 1uA continously. – Bimpelrekkie Dec 12 '17 at 9:51
• "It's no use making a 0.1 uA switch when the MCU uses 1uA continuously." that sounds off. I think you mean 1uA peak. 10% just for the switch would be excessive ;) – Trevor_G Dec 12 '17 at 12:15
• Yup it just read like you meant 0.1uA average on the switch. Which would not be unreasonable for like a dip-switch. – Trevor_G Dec 12 '17 at 12:50
• @Bimpelrekkie A mechanical button on an interrupt is asking for trouble unless it's very carefully debounced... – awjlogan Dec 12 '17 at 16:23

If your button is a piezo switch, then the only power required is the power generated by pressing the button.

For example: R2/C1 collect the energy produced by pressing the piezo. D1 prevents the C1 voltage getting too high. R1 drains C1 when the button is released. The MCU GPIO must be in input, no pull mode. Voilà, button detect with zero current draw from the supply.

simulate this circuit – Schematic created using CircuitLab

• Hmm, can you to make/design a working prototype of that and show the benefit from the solutions with a normal switch we've been using for the last 30 years? – Bimpelrekkie Dec 12 '17 at 12:43
• Sure. I've added an example schematic. Simply build that. Benefit is that there is zero current draw from the supply in either closed or open state. Disadvantages include poor control of the effort required to activate the switch (an active circuit would be better, but that foils the circuit's very marginal benefit), and it being a novel design compared to the 30 (300?) year old normal switch design. – Heath Raftery Dec 12 '17 at 19:19
• Still, my calculator has lots of buttons and runs at least 5 years on a coin cell. Still not seeing how your solution would bring any benefit to that. I still think it is a "solution" to a non-existing problem. And more costly as well. – Bimpelrekkie Dec 12 '17 at 21:06
• Oh I agree! It meets the original criteria "consume as little power as possible", but why saving less than a millijoule is actually useful is hard to imagine. – Heath Raftery Dec 13 '17 at 22:23
• Doesn't the input impedance of the MCU do nasty stuff because of the high output impedance of the piezo? – Scott Seidman Dec 14 '17 at 3:38

If the device needs to be able to stay in either state indefinitely, using an SPDT switch will be the lowest-power approach, since a static circuit can be made to draw no current beyond its own internal leakage and that of the switch. An additional advantage of SPDT switches is that they can be almost perfectly debounced, no matter how quickly they are operated or how crummy the contacts might be, provided only that one contact stops bouncing before the other one first reads as closed.

There are two good approaches to wiring up such switches:

simulate this circuit – Schematic created using CircuitLab

The first approach requires one less resistor than the second, but the second will be more tolerant of overlap between the two poles (it will draw higher than usual current, but won't put a dead short across the supply). Note that if the switch can enter a state which is moderately resistive for a prolonged period of time, that could burn a significantly more current than usual, but during normal usage none of the resistors will carry any significant current except during the brief moment between the time the switch changes state and the output responds.

Use the microcontroller's internal pull-up and when the press is detected disable the pull-up. Then occasionally reenable it briefly to check the button state.