Using Arduino's Secret Voltmeter to Show Battery Level in OLED Display

Hello,

I am working with an SSD1306 screen that uses the U8Glib library. My goal is to have it show battery level as shown in the picture.

To measure voltage, I am using the internal voltage reference A.K.A "Arduino's Secret Voltage Meter."
Can somebody give me an advice to merge this two parts of my code together, in order to display battery life using the bars. I know that I have to use a conditional statement to set a value for each voltage range, then a switch case to set the display. But, I don't quite know where to begin to do so and could really use a hint.

I plan on using four AA batteries. Two pairs connected in parallel and then in series to get 3.0V. Then a boost converter will squeeze the life out of them.

My Arduino Uno is currently running at 5V and 16MHz, but I plan on lowering it to 3.0V @ 8MHz to save power and build a PCB.

Any advice is welcomed!
Thanks,
Angel

Screen Code:

#include "U8glib.h"

U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_NO_ACK);  // Display which does not send ACK

void draw(void) {
  // graphic commands to redraw the complete screen should be placed here
  u8g.setFont(u8g_font_unifont);
  //u8g.setFont(u8g_font_osb21);
  //This Part Dsiplays Battery Indicator
  u8g.drawFrame(14, 5, 22, 10);                   //Frame for battery sign
  u8g.drawFrame(17, 1, 5, 5);                     //Terminal for battery
  u8g.drawFrame(28, 1, 5, 5);                     //Terminal for battery
  u8g.drawFrame(10, 16, 30, 46);                  //Frame for battery indicator
  u8g.drawLine(19, 7, 19, 11);                    //Vertical line for positive battery sign
  u8g.drawLine(17, 9, 21, 9);                     //Horizontal line for positive battery sign
  u8g.drawLine(27, 9, 31, 9);
  u8g.drawBox(14, 20, 22, 8);
  u8g.drawBox(14, 30, 22, 8);
  u8g.drawBox(14, 40, 22, 8);
  u8g.drawBox(14, 50, 22, 8);
  //This Part Displays Dispensing Level
  u8g.drawFrame(46, 16, 30, 46);
  //This Part Displays Chalk Storage Level
  u8g.drawFrame(82, 16, 30, 46);


}

void setup(void) {

  u8g.getMode() == U8G_MODE_BW;
  u8g.setColorIndex(1);         // pixel on
}
void loop(void) {
  // picture loop
  u8g.firstPage();
  do {
    draw();
  } while ( u8g.nextPage() );

  // rebuild the picture after some delay
  delay(50);
}

Measuring Voltage Using Internal Reference:

float iREF = 1.24; //internal reference cal factor

void setup() {
  // put your setup code here, to run once:
  analogReference(EXTERNAL);
  //burn some ADC readings after reference change
  for (int i = 0; i < 8; i++) analogRead(A0);
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  delay(3000);
  Serial.print("Measured battery voltage is: ");
  Serial.println(fReadVcc());
  Serial.println();
}

//This function uses the known internal reference value of the 328p (~1.1V) to calculate the VCC value which comes from a battery
//This was leveraged from a great tutorial found at https://code.google.com/p/tinkerit/wiki/SecretVoltmeter?pageId=110412607001051797704
float fReadVcc() {
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  delay(3); //delay for 3 milliseconds
  ADCSRA |= _BV(ADSC); // Start ADC conversion
  while (bit_is_set(ADCSRA, ADSC)); //wait until conversion is complete
  int result = ADCL; //get first half of result
  result |= ADCH << 8; //get rest of the result
  float batVolt = (iREF / result) * 1024; //Use the known iRef to calculate battery voltage
  return batVolt;
}

My internet is a little slow (VERY SLOW) and I am not able to upload the picture. The image I wanted to show, basically displays a rectangle with four bars inside of it. Each bar represents 1/4 of the battery life.

To the OLED sketch, add the definition for

fReadVcc

Call it every iteration through loop and store result in a global variable (either a float, or multiply the value by 1000 before casting to an int)

Then check that in your drawing code. You can pull the datasheet for the batteries to get the discharge curve so you can map the battery voltage to state of charge in a vaguely accurate manner (it's not linear - it's not that bad for AA's, but for some chemistries, it's more complicated)

But if you're using a boost converter, and are measuring Vcc you'll be getting the output of the boost converter, which will be 3v until the batteries are so dead that the boost converter isn't able to get enough current from them to generate 3v at load current, at which point the batteries are really dead, and then it will start cycling on and off as the load is removed, and the weak battery voltage rises above the UVLO voltage, the converter tries to turn on, and then the battery voltage collapses (the batteries are dead, remember), and it turns off again.... If you're using a boost converter, all you do is take the output of the battery stack and run it to your Arduino's analog pin and measure it with Vcc as reference, and that should give you enough warning that the batteries are dying before the ouput of the boost converter starts wilting.

Be careful when putting batteries in parallel - it's okay, but only if the batteries you have are in the same state fo charge when you connect them, and are similar (ie, same brand/batch/age). Actually, same goes for series ones, except that just hammers the weakest battery and raises risk of it leaking, rather than discharging (possibly fast enough to be damaging) both the new and old battery you put in parallel. (these comments are for alkaline batteries like AA's - LiPo batteries require significantly more care. On the other hand, you can run most arduino projects straight off a LiPo battery (at the battery voltage).

And "secret volt meter"?! It's no secret, it's right in the datasheet - black and white, clear as crystal!

You are absolutely right. It appears that I won't be able to use the internal voltage as a reference, if I also plan on using a boost converter. (I now feel like slapping myself :cry: )

I think I will do exactly as you recommend by using an analog pin to take my reading. I think I will also throw in a P-MOSFET connected to digital input, a voltage divider, and feed it into my analog pin to be able to take the reading for a very short amount of time. Thus, saving energy.

I'm afraid I can't use LiPo batteries, as AA batteries are a requirement for my project. However, I will certainly look for a way to make it safe, and if putting the batteries in parallel make it dangerous; then, I'll have to think of something else.

Do you know of any other feasible ways of powering a 3.3V Arduino @ 8MHz, without using a voltage regulator and staying with AA batteries?

It was kinda secret to me lol

Here's where I got it from:

https://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/

You see, it's kinda secretive :stuck_out_tongue:

Again, thank you very much for your valuable advice!

I built a 16bit wireless meter, It can measure up to +-/100V. It consists of 1 x 8x2 LCD, MCP3426(16Bit ADC),NRFL2401 and couple of op-amps with accurate results matches my fluke meter readings.
I run it at 5V of 2 AA batteries with a boost convertor off E-bay for £1.80GBP(you can get them cheaper is you can wait). The boost convertor is very similar to this one

The ones I ordered had the USB socket which I just removed next batch will be without USB socket.
http://www.ebay.co.uk/itm/5Pcs-New-600mA-0-9V-5V-to-5V-DC-DC-Converter-Step-Up-Boost-Module-with-USB-TE110-/401105234145?hash=item5d63bc28e1:g:E78AAOSwTM5Y4Fpv
Very cheap, It was lots cheaper than trying to build my own version of it, I get about 50hrs continuous use out of a set of AA batteries, May be able to get longer but my design I've got an automatic switch off with a low voltage mosfet. The only draw back is I can get down to about 2.4 volts before it will not switch on unless I hold the button down. so the run time could be even longer as they run from .9V to produce 5V without the automatic switch off. But these only get used for about 30mins to 1Hr or so at a time may be 2-3 times a week. In the mean time I'm now looking into power saving methods to get even better runtime out of the batteries.
I cannot see no reason why not to parallel the batteries up from new like I have done with another project.
It all depends how much run time you need to read your voltages.