Time-based and Low Power Techniques for Arduino

This article will show you how to power up Arduino boards only when needed to perform tasks like periodic data logging, sprinkler control, or unattended, remote transmission of data back to a central station.  The key component in this is the AutoPower circuit, which you can read about in my article on "Pushbutton Power On/Off for Arduino" combined with a Real Time Clock (RTC) such as the Maxim DS3231.  I recommend you read, or at least skim my previous article on pushbutton Arduino control before you continue with this one, as it covers the basic principles of how the AutoPower circuit works, which I will cover only briefly here.  I addition, you should also read the article on my "Arduino Library for the DS3231 Real Time Clock" and download and install it into your Arduino IDE, as I will be using it here to periodically power up the Arduino.

The following diagram shows the basic circuit needed to connect together the AutoPower module, a DS3231 Real Time Clock module and an Arduino Pro Micro.  I chose to use an Arduino Pro Micro because it was what I had lying around and also because its boot loader does not create a several second delay each time it's powered on (you can read more about "boot loader delay" in the "pushbutton power" article linked above.)  You can use any other Arduino board that runs on 5 volts for the example, but you may need to connect to different pins for the I2C bus (Arduino Wire library) that's used to talk to the DS3231.  You'll also have to live with the boot loader delay if you pick an Arduino that's not based on the 32u4 processor used in the Pro Micro (and also in the Leonardo.)  Also, as you can see, the BTN pin on the AutoPower module is not used, as this circuit is designed to be switched on only by the DS3231.

Here's the assembled circuit on a solderless breadboard.  Note: you can't see the CR2023 coin cell because it's on the backside of the PCB that holds the DS3231 RTC IC, which is a module I bought on eBay for about $3. 

Click Image for larger view

Note: to reduce power consumption, I removed the power indication LED on the DS3213 board, the AT24C32D EEPROM, two 4.7K 4x resistor packs that were used as I2C pull up resistors (replaced these with 10K resistors on the breadboard, which you can see just to the left of the AutoPower module) and another resistor that implemented a crude charger circuit for the CR2032 (bad idea!)  The photo below shows modified module where the components that were removed are circled in yellow.  In retrospect, it would have probably been easier just to buy the DS3231 chip, and mount it on an appropriate SMD adapter board, as the IC includes everything you need except for a few bypass caps.  The DS3231M version also comes in an 8 pin form factor, but this version is rated as slightly less accurate than the DS3231.

Click Image for larger view

A Simple Example Program

Here's a simple test program you can use to see the AutoPower module and DS3231 in action (Note: you can download the complete Arduino Sketch from the link at the bottom of this page but you'll also need to download and install my DS3231 library.)  Once you have everything ready, you'll actually need to upload and run this code twice.  For the first upload, set the defined value SET_TIME to 1 (one).  This will compile and upload a portion of the code that's used to configure the RTC module by setting a starting time and date for the clock and calendar (an arbitrary date and time for this example, but you can edit the code to set the proper date and time before you upload and run the code) and program and enables alarm2 to power up the circuit once a minute.  Note: once programmed, the DS3231 will retain these settings as long as the CR2032 backup battery is not removed.  Next. change SET_TIME to 0 (zero) and upload again.  This will compile and upload the portion of the code that resets the alarm, waits 1 second (to simulate the code doing something important) and then powers itself off until the next alarm wakes it one minute later.  Once the second upload is complete, disconnect the USB cable used to program the Pro Micro and connect the 4.5 volt battery, as shown in the diagram above.  You should then observe the Arduino power up once a minute, pause for one second and then switch off.  Note: I connected an LED and current limit resistor (not shown in diagram above) to the OUT pin of the AutoPower module to more easily tell when the Arduino powered on.

Note: to install the DS3231 Arduino Library needed by this sketch, please download it from the link at the bottom of the page this link goes to and then follow the instructions in the section "Importing a .zip Library" on the "Installing Additional Arduino Libraries" page. 

#include <DS3231.h>

/*

 * Example code showing how to use the DS3231 library to power up an Arduino once

 * a minute (presumably to do something useful, such as log data) and then power

 * it back off.  In order to set the current time and configure the alarm, you

 * must first change SET_TIME to 1 and download and run the code with the Arduino

 * completely disconnectd from the power up circuit to avoid a reverse current path

 * back through the circuit via the protection diodes.  Then, set SET_TIME to 0 and

 * download again and then connect the Arduino to the circuit and apply power.

 */

 

#define SET_TIME  0                               // Set to 1 to set RTC, 0 to run code

#define HOLD      4                               // Pin used to power down

DS3231  rtc;

void setup () {

  digitalWrite(HOLD, HIGH);                       // Set HOLD to maintain power

  pinMode(HOLD, OUTPUT);                          // until code decides to turn it off

  rtc.begin();

#if SET_TIME

  byte time[7]; 

  rtc.parseDateTime("5/16/17 11:59:55P", time);   // Set DS3231 to 5/16/17 11:59:55 PM

  rtc.setDateTime(time);

  rtc.clearAlarms();

  rtc.setAlarm(time, ALARM2_EVERY_MINUTE);        // Set Alarm 2 to trigger every minute

  rtc.enableAlarmInt(2, true);                    // Enable Alarm2

  rtc.enableAlarmInt(1, false);                   // Not using Alarm1, so disable it

#else

  rtc.clearAlarms();                              // Clear timer interrupt pin

  delay(1000);                                    // Delay to simulate doing something useful

  digitalWrite(HOLD, LOW);                        // Clear HOLD to shut off power

#endif

}

void loop () {

}

How It Works

Each time Alarm2 trips, the DS3231 pulls its INT pin to LOW (Note: INT is labeled SQW on the eBay DS3231 module I bought since the same pin can be set to output a square wave signal.)  The INT line is, in turn, connected to the ~EN pin on the AutoPower module which, when taken LOW, causes the AutoPower module to power up the 5 volt boost converter which, in turn, powers up the Arduino.  Once powered on, the Arduino immediately configures pin D4 as an output pin and sets it HIGH to cause the AutoPower module to maintain power even if the ~EN line goes HIGH again, as will happen when the code calls the clearAlarms() function.  After this, the code simply waits one second to simulate doing something useful, such as writing a log entry to a memory card, then sets the D4 line to LOW, which takes the HOLD line on the AutoPower module to LOW which, in turn, switches off the power.

Note: Using a boost regulator to power the Arduino board means that we can potentially use a variety of voltages as input to the BAT+ pin on the AutoPower module.  However, since the DS3231 is powered directly from the battery, it will usually operate at a lower voltage.  The DS3231 is very flexible and can operate from as little as 2.3 volts, but we should consider the potential for latch up of the I2C inputs when the pull up resistors are taken to 5 volts when the boost converter engages.  Fortunately, the designers of the DS3231 thought of this issue as the data sheet states that the "pullup voltage can be up to 5.5V, regardless of the voltage on VCC" for both the SDA and SCL pins.  (Reference page 9 of the 19-5170; Rev 10; 3/15 version of the DS3231 data sheet.)  However, if you try to adapt this design to use a different RTC IC, please check its data sheet to see if latch up might be an issue.

The above example, is very simple, as it only uses the "once a minute" feature of Alarm2 to wake up the module.  However, the DS3231 library I wrote (see link at the start of this article) also lets you implement more complex alarms, such as waking up once a day at a specific time.  For example, you can change the setAlarm() call in the above code to power on, once a day at 1:15 PM, like this:

rtc.parseTime("1:15:0P", time);

rtc.setAlarm(time, ALARM2_HOUR_MIN_MATCH);

However, this assumes you set the DS3231's clock to the proper date and time when you loaded and ran the code with SET_TIME set to 1.  If not, you'll need to repeat this step after changing the "5/16/17 11:59:55P" string in the code to the proper date and time.  Obviously, for a polished application, you'd implement an interface of some sort that would let you set the clock and program alarms without having to recompile and reupload code.  However, these are all things you'll have to work out for yourself, as they are beyond the scope of this tutorial.

In addition, my DS3231 library has functions which support doing simple, time-based math.  Using this, you can read the current time and then compute and set a new alarm setting that's so many hours, minutes, or seconds in the future.  So, even though the DS3231 doesn't have an "every hour" setting, you can create one by advancing the alarm by one hour each time it triggers.

How Much Current Does It Draw When Off?

According to the DS3231 data sheet, it should draw about 100-170 uAmps (depending on supply voltage) in standby mode.  Before I removed the unneeded components from the eBay-purchased DS3231 module, I measured a standby draw of about 4 mA (milliAmperes.) But, after removing these components, I measured only about 113 uA (microAmperes) (see photo below), which is a little better than the data sheet says it should be given that the battery voltage is around 4.5 volts.

I measured the Arduino Pro Micro drawsing about 36 milliAmperes when running at 5 volts.  So, assuming I'm using garden variety alkaline AAA cells with a capacity of 750 mA (but derating this to %70 to account for aging and other losses), the fully powered on Pro Micro would drain the AAA cell pack in about 15 hours.  However, using AutoPower and assuming a 1 second on, 59 seconds off duty cycle, the average current drain would be about 700 uA, which should provide an approximate run time of 750 hours, or about 31 days.  The following chart shows estimated battery life using a few other sizes and types of alkaline batteries:

 

Power Up from an External Event

For situations where you only want the Arduino board to power up in response to an external event, you can combine an AutoPower module with a simple Set/Reset (SR) Latch to create acircuit that will respond to a positive-going pulse.  Because it can take a few seconds for the Arduino to start running its code (boot loader delay) we need to make sure the ~EN pin to the AutoPower module is held LOW long enough for the Arduino to start running and send a HIGH level to the AutoPower's HOLD pin.  The circuit below shows how you can use to do just that using two cross-coupled NOR gates to form an SR Latch.  The SR latch runs from battery power so it is always active, so you should use NOR gates with a low quiescent current draw.  Once choice is the Texas Instruments SN74LVC2G02DCTR dual NOR gate which comes in an 8 pin, DCT package.  It operates from 1.65 - 5.5 volts and has a current draw of about 10 uA (microAmperes.)  

In the Off state, the output of the upper NOR gate is HIGH and the output from the lower NOR gate is LOW.  However, a short, positive-going pulse will flip this state making the output of the top NOR LOW and the bottom output HIGH.  The LOW output from the top NOR pulls the ~EN pin low via the diode which, in turn, will power up the Arduino in same manner as the RTC-based circuit.  Once running, the Arduino should set pin D4 to HIGH to asset HOLD and maintain power.  Then, it should pulse D3 to HIGH and then LOW again to reset the SR latch.  Finally, when the Arduino has completed its task, it should set D4 to LOW to power off.  Here's a short sketch to show the coded needed to handle the steps described above:

/*

 * Example code showing how to use an SR altch and the AutoPower module to power up

 * an Arduino in response to an external event.

 */

 

#define HOLD      4                               // Pin used to power down

#define SR_RESET  3                               // Pin used to reset SR latch

void setup () {

  digitalWrite(HOLD, HIGH);                       // Set HOLD to maintain power

  pinMode(HOLD, OUTPUT);                          // until code decides to turn it off

  digitalWrite(SR_RESET, LOW);

  pinMode(SR_RESET, OUTPUT);                      // Setse SR_RESET pin LOW

}

void loop () {

  digitalWrite(SR_RESET, HIGH);                   // Pulse SR_RESET pin HIGH to reset SR latch

  digitalWrite(SR_RESET, LOW);

  delay(1000);                                    // Delay to simulate doing something useful

  digitalWrite(HOLD, LOW);                        // Clear HOLD to shut off power

}

Important:  The latch needs to be reset before the HOLD line will be able to power down the system.  So, I've placed the code that resets the latch by pulsing D3 low inside the loop() method.  This is a precaution against the PWR ON pulse lasting longer than the time it takes the Arduino to power up, complete its task and power down.  If the PWR ON pulse does last too long, placing the code in loop() will assure that it keeps trying to reset the latch and power down the circuit.