Close

Battery Voltage Measurement

A project log for ESP32 - LoRa - OLED Module

Get the most out of your (heltec/ttgo/aliexpress) ESP32 LoRa OLED development board

datadata 10/23/2017 at 10:588 Comments
ADC / Battery Voltage measurement:

So far, I had no luck in getting proper voltage readings from one of the ADC inputs. Since there is no documentation, I simply queried all ADC pins in a hope to get one with some voltage readings. Here's part of the code: 

...

 int pinCount = 11;  int ADCpins[] = {2,12,13,32,33,34,35,36,37,38,39}; // these are the ADC pins

float VBAT;  // battery voltage from ESP32 ADC read float ADC_divider = 250/30;  // voltage divider proportions - hypothetical so far :-)

void setup(){

 for (int thisPin = 0; thisPin < pinCount; thisPin++) {

    Serial.print(thisPin, DEC);     Serial.print(" = ");     Serial.print(ADCpins[thisPin], DEC);     Serial.print(" => ");

    pinMode(ADCpins[thisPin], INPUT);

    VBAT = ADC_divider * (float)(analogRead(ADCpins[thisPin])) / 1024.0; // LiPo battery voltage in volts     Serial.print("Vbat = "); Serial.print(VBAT); Serial.println(" Volts"); }   

}

And this is, what I get: 

0 = 2 => Vbat = 0.00 Volts

1 = 12 => Vbat = 0.00 Volts

2 = 13 => Vbat = 0.00 Volts

3 = 32 => Vbat = 3.52 Volts

4 = 33 => Vbat = 1.16 Volts

5 = 34 => Vbat = 0.00 Volts

6 = 35 => Vbat = 0.00 Volts

7 = 36 => Vbat = 0.00 Volts

8 = 37 => Vbat = 0.00 Volts

9 = 38 => Vbat = 0.00 Volts

10 = 39 => Vbat = 0.00 Volts

So I do get some reading on ADC pin 32 and 33 but it does not really make sense so far.

The value remains more or less the same when I remove the battery...

Discussions

Alexander Ose wrote 12/11/2020 at 05:49 point

I was able to get the example code running on my Heltec ESP32 LoRa board.  It seems to work well, although it doesn't report the right values.  It seems to be off by roughly 25%.  Consistently so, however-- as if the multiplier value is wrong.

Anyway, here's a screenshot of the discharge and charge cycle.  The gap in the middle is where the low voltage cutoff kicked in and brought the board offline.  

Looks very much like any typical LiPo charge curve to me.

https://imgur.com/a/4GL4ajK.jpg

  Are you sure? yes | no

Rick Pannen wrote 11/06/2020 at 23:00 point

This is super old but I just got one of these boards. In order to measure the voltage on the ADC you have to set pin 21 to low. This switches on the FET on the voltage divider.

  Are you sure? yes | no

Christian González Di Antonio wrote 07/25/2020 at 16:34 point

/*
 * HelTec Automation(TM) Electricity detection example.
 *
 * Function summary:
 *
 * - Vext connected to 3.3V via a MOS-FET, the gate pin connected to GPIO21;
 *
 * - Battery power detection is achieved by detecting the voltage of GPIO13;
 *
 * - OLED display and PE4259(RF switch) use Vext as power supply;
 *
 * - WIFI Kit series V1 don't have Vext control function;
 *
 * HelTec AutoMation, Chengdu, China.
 * 成都惠利特自动化科技有限公司
 * https://heltec.org
 * support@heltec.cn
 *
 * this project also release in GitHub:
 * https://github.com/Heltec-Aaron-Lee/WiFi_Kit_series
 * 
*/
#include "Arduino.h"
#include <Wire.h>
#include "heltec.h"

#define Fbattery    3700  //The default battery is 3700mv when the battery is fully charged.

float XS = 0.00225;      //The returned reading is multiplied by this XS to get the battery voltage.
uint16_t MUL = 1000;
uint16_t MMUL = 100;

void setup()
{
   Heltec.begin(true /*DisplayEnable Enable*/, false /*LoRa Enable*/, true /*Serial Enable*/);

Heltec.display->init();
Heltec.display->flipScreenVertically();
Heltec.display->setFont(ArialMT_Plain_10);
Heltec.display->drawString(0, 0, "OLED Start");
Heltec.display->display();
delay(1000);
Heltec.display->clear();

adcAttachPin(13);
analogSetClockDiv(255); // 1338mS

Serial.begin(115200);
}

void loop()
{
   //WiFi LoRa 32        -- hardare versrion ≥ 2.3
   //WiFi Kit 32         -- hardare versrion ≥ 2
   //Wireless Stick      -- hardare versrion ≥ 2.3
   //Wireless Stick Lite -- hardare versrion ≥ 2.3
   //Battery voltage read pin changed from GPIO13 to GPI37
   uint16_t c  =  analogRead(37)*XS*MUL;
   Serial.println(analogRead(37));
   // uint16_t c  =  analogRead(13)*XS*MUL;
   // Serial.println(analogRead(13));

   Heltec.display->drawString(0, 0, "Remaining battery still has:");
   Heltec.display->drawString(0, 10, "VBAT:");
   Heltec.display->drawString(35, 10, (String)c);
   Heltec.display->drawString(60, 10, "(mV)");
   Heltec.display->display();
   delay(2000);
   Heltec.display->clear();
}

  Are you sure? yes | no

Christian González Di Antonio wrote 07/25/2020 at 14:23 point

Hi @piat.jonathan 

As you mentioned before, here is the schematic:
 https://heltec-automation-docs.readthedocs.io/en/latest/esp32+arduino/frequently_asked_questions.html#vext-control 

and its  have an n-fet into the voltage divider as you mentioned, but I found this:

https://fettricks.blogspot.com/2014/01/reducing-voltage-divider-load-to-extend.html 

which explains how to proceed when you have n-fet in the voltage divisor

  Are you sure? yes | no

piat.jonathan wrote 03/20/2020 at 10:52 point

The heltec v2 schematic shows that pin 13 is to be used for vbat but i cannot get this to work. The schematic also shows that the voltage divider ties the adc pin to vbat through a 220kohm resistor and on my board the only pin that could match this is the one labelled 37.  Unfortunately i cannot measure the bottom resistor of the volltage divider because it is tied to gnd through a MOSFET controled by pin 21.

It seems that i can get a measurement to work using the following code :

//setup

adcAttachPin(37);
analogSetClockDiv(255)

//read

float val = analogRead(37);
val = val * (3.3/4095) * ((220+100)/100) ;

the measurement is still off, and using a bottom resistor value of 82ohm in computation gives a more accurate result or you can calibrate the multiplier value.

val = val * (3.3/4095) * ((220+82)/82) ;

  Are you sure? yes | no

erik wrote 02/02/2018 at 13:39 point

Congrats, you have found two pins set to floating mode!

To read battery levels you will most likely want a voltage divider and input directly from the battery.

The math is also very wrong, by default the board uses 12-bit accuracy, with the upper limit at 3.3v (why we need a voltage divider). So the math for normal ADC  is `analogRead(32) * (3.3 / 4095.0);`, if we use same value resistors for a voltage divider the 3.3 doubles, to `analogRead(32) * (6.6 / 4095.0);`

  Are you sure? yes | no

data wrote 11/13/2017 at 12:06 point

What board do you have? heltec or TTGO? 433 or 868/915MHz?
Since there are different versions out now, can you perhaps post a photo?

  Are you sure? yes | no

SarahC wrote 11/13/2017 at 11:54 point

Same here - I wonder what the issue is?

  Are you sure? yes | no