Pushbutton Power Switch for Arduino

This article show how you can use a simple, ultra low current pushbutton, an LED and a few I/O lines to implement pushbutton power switch for an Arduino.  Simply press the pushbutton for a few seconds and the Arduino will power on and run code.  Then, push and hold the pushbutton until the LED illuminates and then release the button to switch power off.  And, to make it easy, I've written an Arduino library, with example code, you can use to quickly get all this working (see download link below.)

Hmm... why not just use a switch?

There a several reason why you might prefer using this circuit over a slide switch, or a toggle switch.  First, the electronic switch used as the core of this design, the Texas Instruments TPS27081A IC, is rated to continually handle up to 3 Amps of current, or up to 9 Amps pulsed (2% duty cycle) which is far more than many small switches can handle.  Slide switch of the type commonly used on PCBs are often rated to handling 300 mA (.5 Amps), or less.  In addition, the software used to control this circuit can be configured to define an optional timeout period after which the Arduino with automatically switch itself off to conserve battery power.  Or, by making use of one of the Arduino's analog inputs you can monitor battery voltage and switch off the system when it gets dangerously low, or even prevent the Arduino fro powering off it has completed an important task, such as storing data.  Finally, pushbutton power control is just plain cooler than stodgy ol' mechanical power switches.

This circuit described here adapts a technique I demonstrated previously in my article and video called "The Useless Machine and the Sonic Grenade".  However, this new design has several refinements, such as changing the circuit so the pushbutton now connects the power up "enable" input to ground to switch on power rather than connecting it to the positive battery connection.  With this change, the circuit can now be triggered by open-collector or open-drain outputs from devices such as a DS3231 Real Time Clock in order to power up an Arduino at a specific time, or date.  Note: I'll have a future article showing how to do this using the new Arduino library I wrote for the DS3221.

The circuit is packaged up as a small, breadboard-friendly PCB you can build and use to add pushbutton power control to virtually any Arduino.  The same circuit can be used with other microprocessors, but the companion code library I present here was written to work with Arduino so you would need to adapt  this code, or write your own to use it with another type of microprocessor.  Here's a photo showing the bottom side of the completed module, which I call the "AutoPower" module, and an image showing the top of the PCB:

  

Click Here to Order the PCB from OSH Park

The PCB is designed to have male header pins soldered into the holes shown such that the circuitry is on the bottom side and the silkscreen legend showing the connections is on the top. If you'd like to order this PCB, I've made it available on OSH Park.  Simply click the link below the images above to go to the OSH Park order page.  You can get 3 copies of the board for less that $1 (including free shipping, so it's quite a bargain.)  Note: the image on the left does not show an additional component, a .1uF capacitor that was added the latest and most current version of the PCB, version 5.  Here is the schematic for the above module:

Here's is a parts list along with clickable order links to both Mouser and DigiKey:

Pushbutton Power for an Arduino Pro Mini

The following diagram show how to connect the AutoPower module to an Arduino Pro Mini.  I chose the 3.3v, 8 mHz version of the Pro Mini because it can run on voltages from as low as 3.3 volts up to 5 volts, which makes it easier to run from a 4.5 volt (nominal) battery pack made of 3 AAA cells.

The Schottky diode designated as D1 is included to prevent power from flowing back into the TPS27081A in the AutoPower module and causing a latch up when the Pro Mini is connected to an FTTI adapter for programming.  Alternately, you could just remove the connection from the OUT pin to VCC on the Pro Mini when using the programming adapter, but I recommend the diode (at least during code development), as it can be easy to forget to remove the connection wind up destroying the TPS27081A IC.

Alternately, diode D1 can be replaced with a 5 volt boost switching converter if you want to use an Arduino that requires 5 volt power and connect BAT+ to a 4.2 volt (nominal) power source, such as Li-Poly battery.  I purchased a 5 volt boost converter on eBay for about $2.20 that comes in the form of a small, 13x8 mm PCB with three pins (in, and and out) that can supply about 300-500 mA when supplied with 3.7 volts on the input pin.  This makes it perfect to pair with an 18650 cell, or a small, LiPoly battery.

Or, use a step down switching converter to run an Arduino at 3.3 volts, as the TPS27081A can take up to 8 volts via the BAT+ input pin on the AutoPower module.  However, you should make sure the switching converter you use will not latch up when you connect an FTDI programming cable, or add a Schottky diode to its output, or disconnect the output of the switching converter from VCC when programming the Arduino.

Example Code using the AutoPower Library

Here's a simple example sketch that shows how to implement basic power on/off functions as well as a 30 second timeout power off.  The call to setTimeout() is optional and you cal skip this call is you do not need the Arduino to automatically power down after a timeout period.  If you do use a timeout and your design has a input controls, you should call resetTimeout() whenever the user presses an input button in order to reset the timeout countdown.  Alternately, a quick press the power button will also reset the timeout countdown.

The choice of pins 9, 11, and 12 is arbitrary and you can use any of the Arduino's I/O pins.  However, I would avoid using pin used for the LED in the Blink example (usually pin 13 for most Arduino boards, but it may vary with others, such as the Adafruit Gemma.)

#include <AutoPower.h>

/*

 * AutoPower Library Test Code running on Ardino Pro Mini (3.3v 8mHz version)

 *

 * When user presses button, Pro Mini powers on and asserts the HOLD pin to HIGH to maintain power

 * and also sets LED pin HIGH to show powered up state.  To power off, press and hold button until

 * LED goes out, then release button.  Optionally, call setTimeout() to set a period (milliseconds)

 * after which the system will power off automatically.  Note: pressing the button resets the timeout

 * period.  See AutoPower circuit writeup for details on how it works.

 *

 * Due to the Ardunio bootloader delay you must press and hold the button until the LED illuminates

 * in order to power up the Pro Mini.

 */

#define LED   9   // Connects to LED wired to Gnd via suitable resistor, such as 220 Ohms

#define HOLD  11  // Connects to HOLD pin on AutoPower module

#define BTN   12  // Connects to BTN pin on AutoPower module

// Note: last parameter is optional (defaults to 2 seconds if omitted)

AutoPower power(HOLD, BTN, LED, 2);   // Hold button 2 seconds to power off

void setup () {

  power.setTimeout(30);               // 30 second power off timeout

}

void loop () {

  power.updatePower();                // Call if setTimeout() used

}

Important: as noted in the source code above, you'll need to press and hold the button until the LED lights in order to power up most Arduino systems.  This is due to a startup delay that's coded into the Arduino's boot loader code and that's used to wait a few seconds to see if the Arduino IDE is trying to upload new code.  You can avoid this delay if you directly program the Arduino using an ICSP (in-circuit serial programming) adapter.  However, if you do this, your code will overwrite the boot loader for that Arduino board and you'll have to reprogram the boot loader using the same ICSP adapter in order to restore the boot loading function.  This is an advanced topic which I can't cover in detail, here, but this article shows the process in some detail and also show how to use another Arduino as the ICSP adapter.

In addition, it's important that your code periodically call updatePower() as this call is needed to make manual power off and the timeout function work.  The best way to do this is to place the call to updatePower() somewhere in the Arduino's loop() method, as is done in the example code above.  Also, don't use any long calls to delay() in the loop() method, as these calls can disrupt the timing calculations used to switch off the Arduino when you press and hold the button and the timeout calculations.  For more information about why calling delay() can be harmful and ways to work around this, see the article "How and Why to avoid delay()".  If you take a look at the source code for the AutoPower library I wrote, you can see I used these same techniques.

The AutoPower API

Here's a complete list of the functions provided by the AutoPower API along with a brief description of the purpose for each method call:

AutoPower varName(byte pwrPin, byte butPin, byte ledPin, byte seconds) or:

AutoPower varName byte pwrPin, byte butPin, byte ledPin)

The constructor used to initialize the AutoPower library.  This is used to define the pins used to connect to the button (BTN), Power Hold (HOLD), and the LED.  There are two forms of the constructor available.  One takes an optional value (in seconds) that defines how long you need to hold down the button to power off the Arduino.  If not specified, this defaults to 2 seconds.  Because seconds is a byte value the maximum period you can define is 255 seconds, but I do not recommend using values larger than 3 or 4 seconds, unless you want to make it very difficult to turn the device off.

Note: "varName" can be any variable name you choose, but you must prefix your method calls to the other functions in the AutoPower library with the name and a period (.), such as varName.updatePower().

void varName.updatePower(void)

You must call this function periodically to update the timing calculations used to detect a power off button press or a timeout.  See source code above and the notes that follow for more details.  You should not call updatePower() when your code is in the middle performing some process that should not be interrupted by a possible loss of power, such as writing to EEPROM, or a memory card, etc.  Instead, only call this function at times when it's safe for AutoPower to power down the Arduino.  Normally, you shouldn't have to worry about this, as most Arduino libraries that do things like write to EEPROM, or memory cards do not return until the operation is complete.  The exception is when you use code that performs these kinds of tasks in the background using interrupts.  In these cases, you may have to call a "busy" function that tells you if the operation is complete and skip calling updatePower() when it is not.

void varName.powerOff(void)

Optional: You can call this function at any time to immediately power off the Arduino.  You might use this, for example, to power down the Arduino when battery voltage drops too low.  However, you should consider coding some way to notify the user and give then a change to abort the operation.  For example, use a periodic beep sound to count down the interval before power is cut, or display a countdown on the GUI display.  In addition, if volatile data could be lost, you might want to consider saving it before initiating a forced power down.

void varName.setTimeout(unsigned int seconds)

Call this to define a timeout period (in seconds) after which the library will automatically power down the Arduino.  Note: this time out period is reset if the user quickly presses the power button, or if your code calls resetTimeout().  If you never call setTimeout() no automatic timeout will take place.  In addition, you can disable a previously defined timeout by calling setTimeout()again and passing in a value of zero (0) seconds,

void varName.resetTimeout(void)

Optional: Call this function to reset the timeout period and start the timeout count from the beginning.  Usually, you'll want to call this function when your code detects input from some user control that indicates that someone is actively using whatever device AutoPower is controlling.  In this way, the device stays powered on as long as someone is using it, much in the way a screensaver works.  Ideally, you should only call this function when a user control changes state, such as when a button is pressed, or released.