Sensor to measure voltage with ESP32

Currently I have this sensor: Amazon.com

It works perfectly, the use I give it is to measure the battery voltage and thus know the charge level.

My problem is that I am going to switch from Arduino UNO to ESP32, and ESP32 does not have an analog pin like the Arduino UNO which has multiple pins. So... I'm looking for a solution with digital pins.

I found these modules, but I don't know if they measure voltage, because they say they are current:
1- https://www.amazon.com/Adafruit-INA260-Voltage-Current-Sensor/dp/B07S8QYDF8/
2- Amazon.com

Regarding the 1st, I found this documentation: Arduino | Adafruit INA260 Current + Voltage + Power Sensor Breakout | Adafruit Learning System

  Serial.print("Bus Voltage: ");
  Serial.print(ina260.readBusVoltage());
  Serial.println(" mV");

I think it measures the voltage of the pin and not the battery, who can help me with my problem?

In short: I want to measure the voltage of a battery from ESP32 (it only has digital I/O).

I can be done with caveats:
ESP32 ADC Non-linear Issues - How do I fix / change Attenuation or width? - Page 3 - ESP32 Forum

1 Like

True, it has way more analogue pins.
Google something like "ESP32 pinout" (images).

They are mainly used to measure current,
but they also do measure voltage (on the current screw terminals).

We understand that you want to measure battery voltage.
Question is which battery, and how is it connected to the ESP32.
Leo..

1 Like

The sensor you have is fine as you know. It has a 1-5 ratio so 5V in gives you 1V out. The A/D on the other micros will not tolerate 5V. You will have to check what is allowed on the one you pick. Then divide your input voltage by 5 to see if it is in range of the A/D. If not you will have to either change one of the resistors or purchase a new one. The current modules do give you voltage but it is a waste of money to purchase them for just that.

1 Like

Look at the picture of ESP32 pins. No one says it's analog:

Note: I am not an expert, in Arduino it says: A0, A1, A2, etc. I'm guessing ESP32 doesn't have it because it doesn't say so, but, I'm reading it says ADC, is that the analog pin that does the same thing as A0?

Because if so I use the same code that I had in Arduino Uno.

I dare not connect anything so as not to burn my ESP32.

Look at all the orange ADC pins...

Problem is that the ESP32 is not an Arduino.
It has different I/O and requires different code.
Leo..

What do you think the pins labeled as ADC1_X are for?

Analog to Digital Converter (ADC) - ESP32 - — ESP-IDF Programming Guide latest documentation (espressif.com)

The ESP32's ADC works quite well.

#include <driver/adc.h> 

void setup()
{
  adc1_config_width(ADC_WIDTH_12Bit);
  adc1_config_channel_atten(ADC1_CHANNEL_6, ADC_ATTEN_DB_11);// using GPIO 34 wind direction
  adc1_config_channel_atten(ADC1_CHANNEL_3, ADC_ATTEN_DB_11);// using GPIO 39 current
  adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_DB_11);// using GPIO 36 battery volts

}


void fReadBattery( void * parameter )
{
  float adcValue = 0.0f;
  const float r1 = 50500.0f; // R1 in ohm, 50K
  const float r2 = 10000.0f; // R2 in ohm, 10k potentiometer
  float Vbatt = 0.0f;
  int printCount = 0;
  float vRefScale = (3.3f / 4096.0f) * ((r1 + r2) / r2);
  uint64_t TimePastKalman  = esp_timer_get_time(); // used by the Kalman filter UpdateProcessNoise, time since last kalman calculation
  SimpleKalmanFilter KF_ADC_b( 1.0f, 1.0f, .01f );
  TickType_t xLastWakeTime = xTaskGetTickCount();
  const TickType_t xFrequency = 1000; //delay for mS
  for (;;)
  {
    adc1_get_raw(ADC1_CHANNEL_0); //read and discard
    adcValue = float( adc1_get_raw(ADC1_CHANNEL_0) ); //take a raw ADC reading
    KF_ADC_b.setProcessNoise( (esp_timer_get_time() - TimePastKalman) / 1000000.0f ); //get time, in microsecods, since last readings
    adcValue = KF_ADC_b.updateEstimate( adcValue ); // apply simple Kalman filter
    Vbatt = adcValue * vRefScale;
    xSemaphoreTake( sema_CalculatedVoltage, portMAX_DELAY );
    CalculatedVoltage = Vbatt;
    xSemaphoreGive( sema_CalculatedVoltage );
    
      printCount++;
      if ( printCount == 3 )
      {
      log_i( "Vbatt %f", Vbatt );
      printCount = 0;
      }
    
    TimePastKalman = esp_timer_get_time(); // time of update complete
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );
    //log_i( "fReadBattery %d",  uxTaskGetStackHighWaterMark( NULL ) );
  }
  vTaskDelete( NULL );
}
////

Be sure to research the caveats of the ESP32's A/Ds. For example, ADC2 is unavailable once you've started WiFi. It's also difficult to get stable 12-bit readings with WiFi running due in part because the WROOM/WROVER modules don't separate logic and analog grounds.

https://deepbluembedded.com/esp32-adc-tutorial-read-analog-voltage-arduino/

This is a fairly good tutorial.

before you try reading analog voltage directly with an ESP32, research 1NA2219 and 1NA3221 modules

I've had very good results with the ESP32's A:D converter using the ESP32's API, a software filter, and a variable 10K resistor.

Perhaps I will repeat something that I have already said above, but I want to clarify my doubts 100%.

I just found another sensor similar to the one I wrote in my initial question, it measures the current. The INA219: https://www.amazon.com/-/es/HiLetgo-bidirectional-continuous-current-rupture/dp/B01ICN5OAM/

As I mentioned before, my main objective is to know the battery voltage to know the charge. My battery is 12v.

My connections will be to my ESP32 will be to SCL, SDA, 5V, GND, as the following image shows:

Ask:
If at the input vin- and vin+ (the ones that are not connected above in the image), if I connect it to my battery, is the voltage that the following code will tell me the voltage of my battery?

#include "Wire.h"
#include "Adafruit_INA219.h"

Adafruit_INA219 ina219;

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  if (! ina219.begin()) {
    Serial.println("Failed to find INA219 chip");
    while (1) { delay(10); }
  }

  Serial.print("BV"); Serial.print("\t"); // Bus Voltage
  Serial.print("SV"); Serial.print("\t"); // Shunt Voltage
  Serial.print("LV"); Serial.print("\t"); // Load Voltage
  Serial.print("C"); Serial.print("\t");  // Current
  Serial.println("P");  // Power
}

void loop() {
  float shuntvoltage = 0;
  float busvoltage = 0;
  float current_mA = 0;
  float loadvoltage = 0;
  float power_mW = 0;

  shuntvoltage = ina219.getShuntVoltage_mV();
  busvoltage = ina219.getBusVoltage_V();
  current_mA = ina219.getCurrent_mA();
  power_mW = ina219.getPower_mW();
  loadvoltage = busvoltage + (shuntvoltage / 1000);

  Serial.print(busvoltage); Serial.print("\t"); 
  Serial.print(shuntvoltage); Serial.print("\t");
  Serial.print(loadvoltage); Serial.print("\t");
  Serial.print(current_mA); Serial.print("\t");
  Serial.println(power_mW);

  delay(1000);
}

I'm just asking to see if I can measure the voltage or not before I buy it. I think so, but I want to ask because I'm not an expert.

The INA219 will do what you ask, but I never used the board with an ESP32.
I suppose it will work with this or with code for an ESP32.

busvoltage will give you battery voltage if you connect +12volt to V+ of the INA219.
You must of course also have 12volt ground connected to INA219 ground.
Leo..

1 Like

Thanks for your answer.

Just to clarify and double check... battery + and - are connected to vin + and -, right?

No. See a tutorial on how to use the sensor. INA219 Current Sensor with Arduino circuit and code explained (electroniclinic.com)

1 Like

The problem is that the tutorials don't show exactly what I'm looking for, just one battery. That is, only measure the voltage, not the current that X device consumes.

I can try without knowing when the order arrives, but I'm afraid of burning something because I'm inexperienced, that's why I'm looking for assurance and that's why I ask:

A current sensor does not measure current? Tell that to my battery powered solar charged weather station.

void fReadCurrent( void * parameter )
{
  const TickType_t xFrequency = 1000; //delay for mS
  const float mVperAmp        = 185.0f;
  float    ADbits             = 4096.0f;
  float    ref_voltage        = 3.3f;
  float    mA                 = 0.0f;
  float    adcValue           = 0.0f;
  float    Voltage            = 0.0f;
  float    Power              = 0.0f;
  float    offSET             = 0.0f;
  int      printCount         = 0;
  uint64_t TimePastKalman     = esp_timer_get_time(); // used by the Kalman filter UpdateProcessNoise, time since last kalman calculation
  SimpleKalmanFilter KF_I( 1.0f, 1.0f, .01f );
  /*
     185mv/A = 5 AMP MODULE
     100mv/A = 20 amp module
     66mv/A = 30 amp module
  */
  String powerInfo = "";
  powerInfo.reserve( 150 );
  while ( !MQTTclient.connected() )
  {
    vTaskDelay( 250 );
  }
  TickType_t xLastWakeTime = xTaskGetTickCount();
  for (;;)
  {
    adc1_get_raw(ADC1_CHANNEL_3); // read once discard reading
    adcValue = ( (float)adc1_get_raw(ADC1_CHANNEL_3) );
    //log_i( "adcValue I = %f", adcValue );
    Voltage = ( (adcValue * ref_voltage) / ADbits ) + offSET; // Gets you mV
    mA = Voltage / mVperAmp; // get amps
    KF_I.setProcessNoise( (esp_timer_get_time() - TimePastKalman) / 1000000.0f ); //get time, in microsecods, since last readings
    mA = KF_I.updateEstimate( mA ); // apply simple Kalman filter
    TimePastKalman = esp_timer_get_time(); // time of update complete
    printCount++;
    if ( printCount == 60 )
    {
      xSemaphoreTake( sema_CalculatedVoltage, portMAX_DELAY);
      Power = CalculatedVoltage * mA;
      //log_i( "Voltage=%f mA=%f Power=%f", CalculatedVoltage, mA, Power );
      printCount = 0;
      powerInfo.concat( String(CalculatedVoltage, 2) );
      xSemaphoreGive( sema_CalculatedVoltage );
      powerInfo.concat( ",");
      powerInfo.concat( String(mA, 4) );
      powerInfo.concat( ",");
      powerInfo.concat( String(Power, 4) );
      xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY );
      MQTTclient.publish( topicPower, powerInfo.c_str() );
      xSemaphoreGive( sema_MQTT_KeepAlive );
      powerInfo = "";
    }
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );
  }
  vTaskDelete( NULL );
} //void fReadCurrent( void * parameter )
////
void fReadBattery( void * parameter )
{
  float adcValue = 0.0f;
  const float r1 = 50500.0f; // R1 in ohm, 50K
  const float r2 = 10000.0f; // R2 in ohm, 10k potentiometer
  float Vbatt = 0.0f;
  int printCount = 0;
  float vRefScale = (3.3f / 4096.0f) * ((r1 + r2) / r2);
  uint64_t TimePastKalman  = esp_timer_get_time(); // used by the Kalman filter UpdateProcessNoise, time since last kalman calculation
  SimpleKalmanFilter KF_ADC_b( 1.0f, 1.0f, .01f );
  TickType_t xLastWakeTime = xTaskGetTickCount();
  const TickType_t xFrequency = 1000; //delay for mS
  for (;;)
  {
    adc1_get_raw(ADC1_CHANNEL_0); //read and discard
    adcValue = float( adc1_get_raw(ADC1_CHANNEL_0) ); //take a raw ADC reading
    KF_ADC_b.setProcessNoise( (esp_timer_get_time() - TimePastKalman) / 1000000.0f ); //get time, in microsecods, since last readings
    adcValue = KF_ADC_b.updateEstimate( adcValue ); // apply simple Kalman filter
    Vbatt = adcValue * vRefScale;
    xSemaphoreTake( sema_CalculatedVoltage, portMAX_DELAY );
    CalculatedVoltage = Vbatt;
    xSemaphoreGive( sema_CalculatedVoltage );
    
      printCount++;
      if ( printCount == 3 )
      {
      log_i( "Vbatt %f", Vbatt );
      printCount = 0;
      }
    
    TimePastKalman = esp_timer_get_time(); // time of update complete
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );
    //log_i( "fReadBattery %d",  uxTaskGetStackHighWaterMark( NULL ) );
  }
  vTaskDelete( NULL );
}
////

I measure the current between the load and the battery, which excludes the battery charging current.

The current sensor is wrapped up in electric tape but its there.

Like I said before... I want to measure the battery voltage, that is my current main problem, because I want to know the charge level. Later I will see how to know how much is being consumed, but now I am only concerned with the voltage.

This question still worries me:

Then use a voltage divider. I'm measuring battery volts. See the code from post#17, the function fReadBattery? That function reads battery volts.

See the image? See the 12V battery?

1 Like

Thanks for your answer. I already know that volts can be read, thanks to @Wawa. Now my question is regarding the connections. After I have it well connected I will experiment with the code, but I must have it well so as not to burn anything.

I just want to know if this is how I ask, I want to know that I am right. Because I see that there are 2 connections of vin + and vin -. Where does the battery go? In the connections above or in those below?