3.7v LiPo readings is Correct?

Hi, i'm making a project that include a reading from 3.7v lipo battery, the board is nano v3. And external battery plus pin goes to 5V & A0 pin to get external reading of the battery. Battery - to GND.

Originally i use this sketch in my code. But its always show battery as 100%.

int value = 0;
float voltage;
float perc;

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

void loop(){
  value = analogRead(A0);
  voltage = value * 5.0/ 1023;
  perc = map(voltage, 3.6, 4.2, 0, 100);
  Serial.print("Voltage= ");
  Serial.println(voltage);
  Serial.print("Battery level= ");
  Serial.print(perc);
  Serial.println(" %");
  delay(500);
}

I try change the value

voltage = value * 3.7/1023;

Now its reads voltage as 3.7v+-, but battery level is NOT showing.

Then i change the value to,

voltage = value * 3.7/765.0;

that shows the battery reading, but voltage is now showing 4.91v+-.

There is no resistor between batt+ to A0 because its only 3.7v.

What i'm doing wrong here? Or does its normal to voltage showing 4.91v+- and not 3.7v+-?

Thanks in advance to anyone could help me understand this :slight_smile:

Don't you want the battery -ve to be connected to GND, and the battery +ve connected to A0?

For debugging purposes, put two more println() statements in, to show value and voltage. It should highlight what's going on.

Ahhh yes forgot to mention that, yes battery - is connect to GND, if not it will not turn on the board.

To put what TWO statement?

If the battery is used as supply for the arduino, you cannot reliably read its voltage from an analog input since the reference voltage equals the analog input voltage and thus always reads 1023. Try to look at the "secret arduino voltmeter" which will allow you to read the supply voltage.

The code i use is from a googled to many forum boards online. It is mean to read the voltage while supplying power to the board.

If you had not mentioned it, I would never have guessed it... :stuck_out_tongue:

Ah, you didn't say that! If the battery is the same one as is powering the board, then the ADC reference voltage will change as the battery flattens, so it will always read 1023 (or very close).

To make it work you have to use a different reference voltage (such as the internal one, which is stabilised and will stay the same regardless of Vcc). Then use a resistor divider to divide down the battery voltage to within the range between GND and the reference voltage.

There's nothing wrong with the code, except it won't work if you are trying to read the supply voltage.

The ADC needs a reference voltage (which it uses for the value 1023). By default, that reference voltage is taken from Vcc. Thus you can't measure Vcc with the ADC because it will always be the same as the reference voltage. Does that make sense?

Actually i'm not going to read the supply voltage to the board. What i want to be doing here is to read the battery power. When its full and when its drop until i need to recharge it when its drop to below 10% or so.

So you're connecting the battery to Vin, and running the Arduino at 3.3V?

In that case, the battery voltage will always read higher than the reference voltage, for the reasons I've explained, and you'll just see 1023 all the time. You need to divide it down with a pair of resistors.

If I've still not understood your layout correctly, please draw a full schematic.

Nope, it is powered from 5v pin. As i know vin pin is to power over 5V.

Sorry cant upload a schematic now but its like this.

LiPo 3.7v,

Ve+ > 5V
Ve+ > A0

Ve- > GND

I'm going to step out of this discussion now as I still don't understand what you are trying to achieve, and how.

Hopefully someone will be along soon who can interpret what you are saying. All the best.

These statements make no sense at all. Try again.

Here is a tutorial to measure the voltage of a battery used to power the Arduino. Replace all the "1023" values with "1024".

// Here is a trick that allows you to check the
// power rail voltage against the 1.1V (+/- 10%)
// internal reference.
// Run the sketch, send 'R', and use a good meter
// to measure the voltage from the AREF pin to
// Ground.  Put the measured reference voltage
// in millivolts (should be between 1000 and 
// 1200) into the sketch as 
// 'InternalReferenceMillivolts'.
//
// Upload the (now-calibrated) sketch again and
// send 'V' to read the current "+5V" voltage 
// (should be around 5000 mV).  Compare that to
// the voltage measured at the +5V pin.  If the 
// answer is not close enough, adjust the
// InternalReferenceMillivolts to get a closer
// result.
//
// Now you can use "(getVccMillivolts()/1000.0)" 
// in place of "5.0" in your sketch to get analog
// readings less dependent on fluctuations in the
// "5V" line.

void setup()
{
  Serial.begin(115200);
  while (!Serial); // Wait for USB connection on Leonardo/Micro

  delay(1000);
  Serial.println("Send 'R' to put reference voltage on AREF pin for measurement.");
  Serial.println("Send 'V' to measure supply voltage.");
}

void loop()
{
  switch (Serial.read())
  {
    case 'r':
    case 'R':
      analogReference(INTERNAL);
      delay(500);
      Serial.println("Now measure the voltage at the AREF pin.");
      Serial.println("Put that value in this sketch as InternalReferenceMillivolts.");
      break;

    case 'v':
    case 'V':
      analogReference(DEFAULT);
      Serial.print("Power rail (millivolts): ");
      Serial.println(getVccMillivolts());
      break;
  }
}

/*VVVVVVVVVVVVV  The part below here goes into your sketch  VVVVVVVVVVVV*/

// Adjust this value to your boards specific
// internal bandgap reference voltage in millivolts
const unsigned long InternalReferenceMillivolts = 1080UL;

// Returns actual value of Vcc in millivolts
int getVccMillivolts()
{
  // Set the analog reference to DEFAULT (AVcc == Vcc power rail)
  // REFS1 REFS0          --> 0b01   -Selects DEFAULT (AVcc) reference
  // Set the analog input to channel 14: the INTERNAL bandgap reference (1.1V +/- 10%)
  // MUX3 MUX2 MUX1 MUX0  --> 0b1110 -Selects channel 14, bandgap voltage, to measure
  ADMUX = (0 << REFS1) | (1 << REFS0) | (0 << ADLAR) | (1 << MUX3) | (1 << MUX2) | (1 << MUX1) | (0 << MUX0);

  delay(50);  // Let mux settle a little to get a more stable A/D conversion

  // Start a conversion to measure the INTERNAL reference relative to the DEFAULT (Vcc) reference.
  ADCSRA |= _BV( ADSC );
  // Wait for it to complete
  while (ADCSRA & (1 << ADSC));

  // Calculate the power rail voltage (reference voltage) relative to the known voltage
  return (InternalReferenceMillivolts * 1024UL) / ADC;
}

Thanks, i will try that. Few question, parts below VVVVVVV is to add to my project sketch, and parts above VVVVVVV id to get the reading one time before i edit the below code to add into my sketch right?

And this code is to soldered battery Ve+ = 5v & Ve- = GND without spliting Ve+ to A0 pin?

Sorry im not quite understand the step LoL, is there any step by step tutorial how to use this?

Also how to call it when i want to display on oled lcd?

map is defined only for integers.

You could do this:


long float_map(float x, float in_min, float in_max, float out_min, float out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

void loop(){
  value = analogRead(A0);
  voltage = value * 5.0/ 1023;
  perc = float_map(voltage, 3.6, 4.2, 0, 100);
  ....
  ....

Blockquote so i have try the code, unluckily it show battery 100% all the time

So i have try the code, but it still show battery as 100% all the time

  1. Run the sketch
  2. send 'R'
  3. use a good meter to measure the voltage from the AREF pin to Ground.
  4. Put the measured reference voltage in millivolts (should be between 1000 and 1200) into the sketch as 'InternalReferenceMillivolts'.

float batteryVotage = getVccMillivolts()/1000.0;