# Low Power Coin Cell Voltage Logger

## Overview

![](https://cdn-learn.adafruit.com/assets/assets/000/002/410/medium800/microcontrollers_testing.jpg?1396782792)

In developing our new [TIMESQUARE watch](http://www.adafruit.com/products/1106 "Link: http://www.adafruit.com/products/1106"),&nbsp;we knew that power use would be a hairy issue.&nbsp;The entire circuit, including an ATmega328P microcontroller and an 8x8 LED matrix, is powered from a single CR2032 lithium coin cell.&nbsp;We obsessed over different LED multiplexing arrangements and processor sleep modes, always trying to trim the power draw just a little bit more.  
  
With the right tools such as the [EEVblog&nbsp;μCurrent](http://adafruit.com/products/882) and a good multimeter, measuring the most&nbsp;minute current changes is a simple task. But translating this into battery longevity isn’t so cut-and-dried…the stated capacity in the battery&nbsp;datasheet&nbsp;assumes a small and constant load, while the watch current can vary greatly.&nbsp;What’s more, the relationship between current draw and battery longevity isn’t necessarily linear. This gets messy. Sometimes you just need to put math and theory aside, plug the thing in and observe the actual outcome.  
  
To that end, we built&nbsp;a test fixture to simulate a consistent use case:&nbsp;activating the watch display once per minute and monitoring the battery voltage as it declines, allowing us to objectively compare different versions of the watch software. The raw data is logged to an SD card for later review and conversion into nice graphs. So this is primarily a tutorial on using the Data Logging Shield for Arduino, but along the way&nbsp;there are some good ancillary tidbits on hardware and software.# Low Power Coin Cell Voltage Logger

## Hardware

## Activating the watch…
The TIMESQUARE watch is activated by pressing either of the two side buttons. The time will be displayed for several seconds and the watch then turns off.  
  
The ATmega microcontroller (MCU) spends most of its time in a very low-current&nbsp;_power-down_&nbsp;mode. The MCU pins to which the two buttons are connected were very carefully chosen — only these two pins support&nbsp;_interrupt on change_ while asleep,&nbsp;which is used to revive the watch and enable the display.  
  
To minimize components, the _internal pullup resistors_ are used on these pins. The buttons then simply connect between the two pins and ground. When the switch is open (button not pressed), what would normally be an unstable “floating” input is instead “pulled up” to VCC, which the MCU reads as a high logic level. Pressing a button creates a much lower resistance connection to ground, which is read as a low logic level.

![](https://cdn-learn.adafruit.com/assets/assets/000/002/703/medium800/microcontrollers_pullup.png?1396785960)

Although the TIMESQUARE MCU _could_ monitor its own voltage, we’d prefer to keep the device running only the actual watch code being tested, so as not to color the results. A separate microcontroller — an Arduino Uno — will record the measurements to an SD card. The **+** output from the 3V battery is connected to an analog input pin on the Arduino, and the Arduino’s **3.3V** output is routed to the **AREF** pin.  
  
There are a couple of different ways this could be wired up. Given what we know from the pullup-vs-ground explanation above, we _might_ be inclined to connect the watch input pin to one of the Arduino’s digital output pins, then call the&nbsp;digitalWrite() function, passing HIGH or LOW to simulate an open or closed button state…but **this won’t work correctly!&nbsp;** Most microcontrollers are opportunistic in finding usable&nbsp;voltage, and the watch will be perfectly happy to use power from the default HIGH logic state on that pin instead of the battery! This will skew the results horribly…it’s worse than useless.  
  
The traditional way around this is to use an _optocoupler_ such as a 4N35 to _isolate_ the voltages. The digital output from the Arduino drives an infrared LED inside the 4N35,&nbsp;which activates a phototransistor on the opposite side — wired to the watch — effectively pressing the button without injecting additional&nbsp;current into that&nbsp;circuit. Cool.

![](https://cdn-learn.adafruit.com/assets/assets/000/002/704/medium800/microcontrollers_circuit1.png?1396785976)

We could just do that and call it done, but:

- I had no optocouplers on-hand, and didn’t want to wait for an order to arrive.
- There’s a technique I’ve been wanting to use in a tutorial forever…

Connecting directly to an Arduino digital pin (as was “wrongly” proposed), there is a way to simulate the button press without feeding current into the watch circuit. It’s not&nbsp;suited for every situation, but here it’s a fortunate side-effect of the pullup-and-button design of the circuit. The trick is to never set the output pin HIGH. Yet we can still control the watch. _Buhhh?_![](https://cdn-learn.adafruit.com/assets/assets/000/002/705/medium800/microcontrollers_circuit2.png?1396785992)

## Mental models…
As a “software guy” who only&nbsp;stumbled into electronics much later, the implication of an MCU pin’s&nbsp;“tri-state output” and “high-impedance state” eluded me for the longest time…my eyes would glaze over at the jargon.&nbsp;If you’re in that same boat, hopefully this will clarify the situation, while also solving the problem at hand…  
  
My naïve interpretation of HIGH and LOW pin states used to imagine&nbsp;HIGH as providing 5 Volts out, and LOW as being essentially an open circuit, passing no voltage. Such a&nbsp;model makes perfect&nbsp;sense when you’re blinking an LED (a favorite pastime!), but it’s **not accurate**.&nbsp;Rather, HIGH is a connection to VCC, LOW is a&nbsp;connection&nbsp;to ground…or, in jargon terms, they _source_ and _sink_ current, respectively.&nbsp;To _block_ the flow of current, we have to&nbsp;set the pin as an INPUT. <u>That’s</u> the third state in “tri-state output.”  
  
Or picture it this way:&nbsp;in school they made us watch dull fire safety films, where we learned not to throw doors open, but feel for heat first (indicating fire on the other side). That’s a fair model for voltage and MCU pins. As an INPUT — door closed —&nbsp;we can sense heat (or not) outside without letting fire pass through; the door _impedes_ the fire’s progress. The _high-impedance state._&nbsp;As an OUTPUT — door open — fire can now pass <u>either</u> way, whether flowing&nbsp;in (LOW) or out (HIGH). Three states. _Tri-state._  
  
So that’s how we control the watch. Setting and leaving the Arduino pin’s&nbsp;state LOW, then switching between INPUT (open circuit) and OUTPUT (closing the connection to ground), we’re performing the very same function as the button, without passing any voltage from the Arduino to the watch. Our battery measurements should be fairly accurate now.  
  
Do keep that optocoupler technique in mind though…it’s still a valid approach,&nbsp;and there are many other situations where they can be quite handy!  
  
Here’s the completed testing fixture. It’s not much to look at…an Arduino, a Data Logging Shield, and wires soldered to the watch circuit’s positive and negative connections, and one button:

![](https://cdn-learn.adafruit.com/assets/assets/000/002/706/medium800/microcontrollers_testing.jpg?1396786000)

(Ignore the extra components in the prototyping area on the shield…it was previously in use for another project, but those have no influence here.)

# Low Power Coin Cell Voltage Logger

## Software

Here’s the complete sketch. This requires the SD card library, and a FAT-formatted SD card installed in the shield.  
  
Every 60 seconds, the software takes two voltage measurements from the watch. The first is taken while the watch is still in the power-down state, indicating the resting voltage of the battery. The second reading is taken two seconds later, after the watch “marquee” display has been running (which drags down the voltage…so many&nbsp;LEDs!).  
  
The minute counter (starting from zero) and two voltages are written to a line in&nbsp;a text file in CSV (comma-separated value) format, which can then be directly imported into most spreadsheet applications, or it’s fairly easy for other software to parse.  
  
Since we’re just counting the _passage_ of minutes, the counter value is written to the file; it’s <u>not an absolute time stamp</u>. If a project requires proper time/date stamps, we’d want to tie into RTClib (an Arduino realtime clock library)&nbsp;for reading the shield’s clock.

```auto
// Watch battery voltage logger.  Activates watch circuit every
// 60 seconds and records voltages (sleep and running) to SD card.
// Based on Tom Igoe's Datalogger example from the SD library.

// Connections:
// Arduino GND to watch battery -
// Arduino analog 0 to watch battery +
// Arduino digital 2 to pull-down switch on watch
// 3.3V to AREF (both on Arduino)

#include <SD.h>

long minutes = 0; // Elapsed time / line number

void setup() {
  Serial.begin(9600);

  // Use 3.3V analog reference for better resolution on 3V battery
  analogReference(EXTERNAL);

  // Watch is awakened with button tap which ties pin (w/internal
  // pullup) to ground.  Rather than write high/low levels to this
  // wire, a pin is set LOW and switched between input (high
  // impedance) and output states to approximate the button press
  // without introducing voltages into the watch circuit.
  pinMode(2, INPUT);
  digitalWrite(2, LOW);

  Serial.print("Initializing SD card...");
  Serial.println(SD.begin(10) ? // 10 = card sel. pin (4 on Arduino Ethernet)
    "card initialized." :
    "card failed, or not present.");

  // Sketch continues even if SD init fails...may just want to
  // read output in serial monitor for debugging.
}

void loop()
{
  long     mVsleep, mVrun;
  char     dataString[40];
  File     dataFile;
  uint32_t start = millis();

  mVsleep = 3300L * analogRead(A0) / 1023L; // Millivolts while asleep

  pinMode(2, OUTPUT); // Pull watch button LOW
  delay(100);         // Hold a moment
  pinMode(2, INPUT);  // and release

  delay(2000);  // Let the watch run for a couple seconds...

  mVrun = 3300L * analogRead(A0) / 1023L; // Millivolts while running

  sprintf(dataString, "%ld,%ld,%ld", minutes++, mVsleep, mVrun);

  if((dataFile = SD.open("datalog.csv", FILE_WRITE))) {
    dataFile.println(dataString);
    dataFile.close();
  } else {
    Serial.println("error opening datalog.csv");
  }
  Serial.println(dataString);

  // Serial and SD card access times may vary.  Rather than delay(),
  // monitor time to allow remainder of 1 minute to pass.
  while(millis() < (start + 60000L));
}
```

# Low Power Coin Cell Voltage Logger

## Results

Here are some results after importing the resulting CSV files into a _Numbers_ spreadsheet, and producing a chart:

![](https://cdn-learn.adafruit.com/assets/assets/000/002/707/medium800/microcontrollers_vgraph.png?1396786021)

The jumps in the green line are due to&nbsp;the content of the watch display at the moment the reading was taken; some digit combinations simply scroll by quicker than others. A blank display draws less current, and the voltage reading will be slightly higher.&nbsp;It’s surprisingly sensitive…in another test, the resting battery voltage was seen rising slightly right when the thermostat kicks on in the morning. (Batteries are mildly sensitive to temperature. This is why your smoke alarm waits until you’re sleeping to start that “low battery” beep…the cooler nighttime air brings the already weak battery’s&nbsp;voltage just below the warning&nbsp;threshold.)  
  
Notice at 140 minutes the two lines merge. This is what we dubbed the&nbsp;“death spiral.” The battery voltage has dropped low enough that the watch executes a brown-out reset. This restarts the code, which restarts the display, causing another brown-out…repeating until the battery gives out fully.  
  
(For the record, battery life has been improved substantially since this early graph was taken, so you should get well more than 140 viewings from your watch!)

![](https://cdn-learn.adafruit.com/assets/assets/000/002/708/medium800/microcontrollers_vgraph2.png?1396786037)

Here you can see the battery voltage gradually recover following an initial time display. This is chemistry, and is why there isn’t a linear relationship between current draw and battery longevity.  
  
The stuttering parts of the&nbsp;line are due to the limited resolution of the Arduino’s analog-to-digital converter. Those could be filtered out by taking multiple voltage readings and averaging the results, but it wasn’t necessary to go to that level of detail here; seeing the trend was sufficient.

# Low Power Coin Cell Voltage Logger

## Other Lessons

![](https://cdn-learn.adafruit.com/assets/assets/000/002/709/medium800/microcontrollers_bluesmoke.png?1396786057)

The key to making TIMESQUARE practical was to trim the power-down current as much as possible. Certainly, the running current is important too, but&nbsp;the power-down state is where the watch will spend most of its time by far. There may be idle times&nbsp;when it’s left in a drawer for days or weeks…maybe even months, though we hope not…and it has only a single coin cell to draw from. As you can imagine, considerable effort was spent testing and measuring&nbsp;sleep modes and disabling every possible peripheral to reduce the idle current.  
  
One of the more power-hungry peripherals on the ATmega 328P is the _brown-out detect_ circuit, which senses a low voltage condition and calls an interrupt function, the _brown-out reset_ (BOR) handler. This feature is used in products&nbsp;for such things as storing state information in EEPROM before gracefully shutting down. The BOR circuit is enabled by default on the Arduino…and this is very important.  
  
Certain Atmel chips…the 328P among them…can disable the brownout circuit in software (rather than&nbsp;configuration fuses), potentially saving many microamps of current. <u>If</u> you’re programming a “raw” chip via the ISP header, that’s fantastic…if you need to save every last bit of power, and <u>if</u> you don’t need the brownout detection, have at it. But if you’re using a bootloader-based programming system like Arduino, <u>disabling BOR can have disastrous results!</u>  
  
As the supply voltage dips below the brownout threshold, without BOR the chip will start to behave erratically, and may spontaneously jump to <u>any</u>&nbsp;random memory location. And if that code eventually leads into any bootloader function that erases or writes a flash page, the application — or much worse, the bootloader itself — can become corrupted, leaving no easy way to re-flash the watch.  
  
This is NOT the unlikely one-in-a-million change you might think!&nbsp;First, the watch WILL repeatedly brown out any time the battery runs low.&nbsp;Second, keep in mind that it _doesn’t_ have to jump _exactly_ to the start of a block-erasing function, just to any code that may _eventually_ lead there.&nbsp;The odds of this happening during an unprotected brownout seem to be about 1 percent…the phenomenon has been observed in the wild with other projects and even while developing this code…it’s a real thing! So BOR is left enabled to provide a proper safety net. If you’re programming for an Arduino bootloader-based board, you should too.  
  
Really, resist the allure of the nano-amps,&nbsp;DO NOT go blindly adding BOR-disabling code to your project, you'll regret it later. Just don't. Okay? Don't. Thanks.


## Featured Products

### EEVblog uCurrent - Precision nA Current Measurement Assistant

[EEVblog uCurrent - Precision nA Current Measurement Assistant](https://www.adafruit.com/product/882)
An essential companion when working on a ultra-low-power projects! If you've ever used a portable multimeter (even your $300 Fluke!) to measure sub-uA currents - say for a low power microcontroller or sensor project - you may notice that you're not getting the precision you expect, or...

No Longer Stocked
[Buy Now](https://www.adafruit.com/product/882)
[Related Guides to the Product](https://learn.adafruit.com/products/882/guides)
### Breadboarding wire bundle

[Breadboarding wire bundle](https://www.adafruit.com/product/153)
75 flexible stranded core wires with stiff ends molded on in red, orange, yellow, green, blue, brown, black and white. These are a major improvement over the "box of bent wires" that are sometimes sold with breadboards, and faster than stripping your own solid core wires. Makes...

In Stock
[Buy Now](https://www.adafruit.com/product/153)
[Related Guides to the Product](https://learn.adafruit.com/products/153/guides)
### Shield stacking headers for Arduino (R3 Compatible)

[Shield stacking headers for Arduino (R3 Compatible)](https://www.adafruit.com/product/85)
_“How could something so simple be so useful?”&nbsp;_

We heard once that&nbsp;in the 4th millennium B.C.&nbsp;some guy asked the person who invented the wheel that question.&nbsp; The person who invented the wheel’s answer, we were told, was...

In Stock
[Buy Now](https://www.adafruit.com/product/85)
[Related Guides to the Product](https://learn.adafruit.com/products/85/guides)
### Adafruit METRO 328 Fully Assembled - Arduino IDE compatible

[Adafruit METRO 328 Fully Assembled - Arduino IDE compatible](https://www.adafruit.com/product/50)
We sure love the ATmega328 here at Adafruit, and we use them&nbsp;_a lot_&nbsp;for our own projects. The processor has plenty of GPIO, Analog inputs, hardware UART SPI and I2C, timers and PWM galore - just enough for most simple projects. When we need to go small, we use a <a...></a...>

Out of Stock
[Buy Now](https://www.adafruit.com/product/50)
[Related Guides to the Product](https://learn.adafruit.com/products/50/guides)
### CR2032 Lithium Coin Cell Battery

[CR2032 Lithium Coin Cell Battery](https://www.adafruit.com/product/654)
A perfect match for our [sew-able coin cell holder](http://www.adafruit.com/products/653). This non-rechargeable coin cell is CR2032 sized: 20mm diameter, 3.2mm thick. It has a nominal voltage output of 3V (although it starts a little high at 3.2V and slowly drifts down to 2.5V as...

In Stock
[Buy Now](https://www.adafruit.com/product/654)
[Related Guides to the Product](https://learn.adafruit.com/products/654/guides)
### TIMESQUARE DIY Watch Kit - Red Display Matrix

[TIMESQUARE DIY Watch Kit - Red Display Matrix](https://www.adafruit.com/product/1106)
Show up stylish AND on time to any event with this awesome looking DIY watch. We have a few watch kits here at Adafruit but we finally have one that looks good and fits well, even for ladies and kids and others with smaller wrists and hands. Its got an 8x8 bit matrix display and a repurposed...

No Longer Stocked
[Buy Now](https://www.adafruit.com/product/1106)
[Related Guides to the Product](https://learn.adafruit.com/products/1106/guides)

## Related Guides

- [Remote controlled door lock using a fingerprint sensor & Adafruit IO](https://learn.adafruit.com/remote-controlled-door-lock-using-a-fingerprint-sensor-and-adafruit-io.md)
- [Photocells](https://learn.adafruit.com/photocells.md)
- [How to Find Hidden COM Ports](https://learn.adafruit.com/how-to-find-hidden-com-ports.md)
- [Arduino Lesson 5. The Serial Monitor](https://learn.adafruit.com/adafruit-arduino-lesson-5-the-serial-monitor.md)
- [Bluefruit LE Connect for iOS and Android](https://learn.adafruit.com/bluefruit-le-connect.md)
- [Adafruit Motor Shield](https://learn.adafruit.com/adafruit-motor-shield.md)
- [Multi-tasking the Arduino - Part 1](https://learn.adafruit.com/multi-tasking-the-arduino-part-1.md)
- [Arduino Lesson 14. Servo Motors](https://learn.adafruit.com/adafruit-arduino-lesson-14-servo-motors.md)
- [Arduino Lesson 15. DC Motor Reversing](https://learn.adafruit.com/adafruit-arduino-lesson-15-dc-motor-reversing.md)
- [Tiny Arduino Music Visualizer](https://learn.adafruit.com/piccolo.md)
- [A REST API for Arduino & the CC3000 WiFi Chip](https://learn.adafruit.com/a-rest-api-for-arduino-and-the-cc3000-wifi-chip.md)
- [Arduino Lesson 3. RGB LEDs](https://learn.adafruit.com/adafruit-arduino-lesson-3-rgb-leds.md)
- [Adafruit Analog Accelerometer Breakouts](https://learn.adafruit.com/adafruit-analog-accelerometer-breakouts.md)
- [Nokia 5110/3310 Monochrome LCD](https://learn.adafruit.com/nokia-5110-3310-monochrome-lcd.md)
- [Arduino Lesson 1. Blink](https://learn.adafruit.com/adafruit-arduino-lesson-1-blink.md)
