Introduction: One Night Battery Monitor for Wireless Headphones

About: Recent graduate from CMU, now working at Northrop Grumman. Mostly inactive at this point, but still around occasionally.
A few days ago at m local RadioShack, I noticed a pair of wireless headphones on clearance for about $12. They work and sound pretty good, but contain a rechargeable battery and no battery monitor except a low-battery warning. I figured there's got to be an better way. I figured tonight is as good as any, and resolved to do the project, start to finish, in one night.

Step 1: The Parts

This has only four parts
-an attiny 85/45/25. Any will work, I used an 85
-7 segment display, or 5 LEDs.
-Button, momentary, n/o
-whatever things battery you're monitoring (note that this only works up to ~3.5v as is, you'll need resistors to go to 5v, and a 5v regulator and resistors above 5v).

You will also need an arduino, but it won't be left in the project, just used as an ISP.

Step 2: The Attiny and the Code

If you haven't already, find and download the attiny cores from high low tech. Hook up your arduino to the attiny and get an example running (there are dozens of guides for this, many right here on instructables. They explain it much better than I would). If you've got an example running, then you're ready for the code. Set the interface to attiny 85, 1 MHz internal oscillator, BOD disabled and press tools->burn bootloader. This will set the fuse bits as we need them for this project. Then, just copy and past the following code into the IDE and upload.

#include
#ifndef cbi//this and sbi are for messing with bits in registers.
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
void setup(){//everything is in setup, as we only need to read once. The processor is reset instead for additional readings
analogRead(2);//take a bunch of readings, as sometimes the first reading from analogRead is unreliable
analogRead(2);
analogRead(2);
analogRead(2);
analogRead(2);
analogRead(2);
analogRead(2);
analogRead(2);
DDRB = 0x1f;//set out 5 outputs to output. This is the equivalent of pinMode 5 times
delay(1);//several waits here just to make sure that the read is a good one. It isn't looping, so a few milliseconds of delay here and there won't be a problem
uint8_t low, high;//the low and high bytes from the ADC
ADMUX = 0b00001100;//the value of the Analog to Digital MUltipleXer (hence, ADMUX). This reads an internally generated ~1.1V refernce
delay(10);//wait a while for the change to work
sbi(ADCSRA, ADSC);//start the "analogRead()"
while (bit_is_set(ADCSRA, ADSC));//wait for the processor to finish reading
low = ADCL;//read the output once it's done
high = ADCH;
int volts = (high << 8) | low;//shift the high bits over, as it's a 10 bit read, and therefore you need two bytes
unsigned long voltage = 1125300L / volts;//convert it to voltage (in millivolts)
voltage-=1500;//this is the "empty" voltage, 0 on the display
voltage/=50;//divider, find the top of your range, subtract the bottom, and divide by 30 to get this number.
PORTB=(voltage & 0b00011111);//mask the output to just the five lower bits (which is probably unnecessary, but can't hiurt), and put it out to the pins
delay(3000);//give us three seconds to see the output
PORTB=0;//and turn the LEDs off.
DDRB = 0;//set them to high imedence to save power
cbi(ADCSRA,ADEN);// turn the Analog to Digital converter off
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // set it to power down as completely as possible, for minimal power usage
PRR = PRR | 0b00001111;//this line shuts down basically everything once it enters sleep mode
sleep_enable();//allow the device to enter sleep mode,
sleep_mode();//and finally, shut it off. We never need to exit sleep mode, as it does so automatically when reset.
}

void loop(){};//we don't need this to do anything




Step 3: Wiring

The wiring for this is very simple and a pretty good first or second soldering project. If using a seven-segment display, find the pinout and connect the cathode to ground, and the top and bottom pairs of vertical lines. Connect them going from either end (top line, top pair of vertical lines, middle line, bottom pair, bottom line) to attiny pins 8,7,6,2,3, respectively. Drawing a little wiring diagram as shown above usually helps, that diagram is for the 7 segment display sold at RadioShack. For regular LEDs, just connect all the negatives, and run each positive to pins 8,7,6,2,3, in that order. Each will give a 5 bit binary output proportional to the voltage of the battery. Binary is used to increase the resolution by a factor of about 5 (32 possible values instead of 6 if it just displayed the value sequentially).

Connect the attiny + and - to the battery + and -, taking care not to short the leads to each other or anything else. Finally, connect the switch between reset and ground. Pressing the button should make some of the LEDs come on for about 3 seconds.
Once completed and tested, it usually helps to coat the whole circuit liberally in hot glue to protect and insulate it.

Step 4: How Does It Work?

Since all pins are used for he led display, it would seem that none is left to read the voltage. If using a voltage above 5v, then it wouldn't work, but below 5v, there's another way. Though not mentioned in documentation, or seemingly by anyone on the Internet (at least as far as I could find), the attiny can measure its own supply voltage. It internally measures an internally generated reference voltage, and from that extrapolates the supply voltage. On the data sheet, we can see that in addition to reading from the standard analog pins, the 85 can also compare, read from ground, and read 'Vbg'. All we care about is Vbg. This will always be about 1.1v, and by using Vcc as the reference voltage, it will change proportionally. A value of 512, for instance, means a Vcc of 2.2v, whereas 256 means 4.4v. The exact voltage is calculated and mapped between 0 and 30 for the range we want, then stored to the 'b' data register to display it.
But wait, wouldn't leaving it connected to the battery drain it quickly?
No. After displaying the charge for three seconds, the attiny sleeps, and consumed little power. By little I mean VERY little. A thousand of these connected through your heart wouldn't affect it. When fully powered down, the attiny consumes about 0.1uA. At that rate of consumption, an iPhone battery would last about 1,600. Years. Yes, as in one made and left running since just 400 would have about enough juice to turn on one more time before dying. It's so efficient because we can turn off everything inside the chip. Since we use reset to get a new reading, everything from the ADC to the watchdog is shut down when it's not being used.

Step 5: Finishing

I was lucky to have a fair amount of space in the battery compartment to fit the monitor, right next to the battery itself. The switch was wounded outside the case, with wires going through a hole.
Once tested electronically and test fit, hot glue the display in place, and close it up.

It's read in binary, but if you're unfamiliar, it's still easy to get the gist of the value. The bottom of the display carries the most weight, the top the least. Each subsequent led carries more weight than the last. Therefore, if only the bottom led is lit, that indicates a higher charge than if every other led was lit, but a lower charge than if it and another led were lit. Basically, the more light down low, the more the charge. The last picture which shows a 'u' shape in the lights indicates a fairly well-charged battery, about 75%.