Measure battery with adc internal in esp32

my circuit to measure battery right now is esp32, nrf24l01, and 18650. i powered up esp32 with 18650 3.6v norminal/4.2 max battery. run a voltage divider 100k, 27k then it's 0.893v a measure point. at 3.6v measure point like ~0.72.

i use internal 1.1v adc but why i only receive ~3v at monitor

adc1_config_width(ADC_WIDTH_BIT_11);
adc1_config_channel_atten(ADC1_CHANNEL_0,ADC_ATTEN_DB_0);
float battery_read()
{
    //read battery voltage per %
    long sum = 0;                  // sum of samples taken
    float voltage = 0.0;           // calculated voltage
    float output = 0.0;            //output value
    const float battery_max = 4.2; //maximum voltage of battery
    const float battery_min = 3.0; //minimum voltage of battery before shutdown

    float R1 = 100000.0; // resistance of R1 (100K)
    float R2 = 27000.0;  // resistance of R2 (10K)

    for (int i = 0; i < 100; i++)
    {
        sum += adc1_get_voltage(ADC1_CHANNEL_0);
        delayMicroseconds(1000);
    }
    // calculate the voltage*/
    
    voltage = sum / (float)100;
    Serial.println(voltage);
    voltage = (voltage *1.1) / 2047.0; //for internal 1.1v reference
    // use if added divider circuit
    voltage = voltage / (R2/(R1+R2));
}

// https://dl.espressif.com/doc/esp-idf/latest/api-reference/peripherals/adc.html
  // set up A:D channels
  adc1_config_width(ADC_WIDTH_12Bit);
  adc1_config_channel_atten(ADC1_CHANNEL_6, ADC_ATTEN_DB_11);
  //  adc1_config_width(ADC_WIDTH_12Bit);
  //  adc1_config_channel_atten(ADC1_CHANNEL_1, ADC_ATTEN_11db);
  /*
     When VDD_A is 3.3V: 11dB attenuation (ADC_ATTEN_11db) gives full-scale voltage 3.9V
  */

void TaskAnalogVoltRead_LIDAR( void *pvParameters )
{
  String localBuffer;
  localBuffer.reserve ( StringBufferSize300 );
  int iBit = 1;
  float ADbits = 4095.0f;
  float offSET = 1.0f;
  float r1 = 100800.0f; // R1 in ohm, 100k = 100,800.0 //
  float r2 = 38780.0f; // R2 in ohm, 38k = 38000.0 //actual 38780K
  float uPvolts = 3.3f;
  // ADC1 channel 0 is GPIO36
  // ADC1 channel 1 is GPIO37
  // ADC1 channel 6 is GPIO34
  // https://dl.espressif.com/doc/esp-idf/latest/api-reference/peripherals/adc.html
  // to get resistor R2 go to:
  // http://www.ohmslawcalculator.com/voltage-divider-calculator
  //   used 12 volts for the input voltage to calculate R2, used 100K for R1
  for (;;)
  {
    // group handle, WaitForBits, ClearOnExitBit, WaitForAllBits, TicksToWait
    xEventGroupWaitBits( eg, evtAnalogVoltReadTask_LIDAR, pdTRUE, pdTRUE, portMAX_DELAY );
    // read the input
    iBit = iBit << 1;
    if ( iBit == 1073741824 )
    {
      if ( xSemaphoreTake( sema_AnalogVoltRead_LIDAR, xSemaphoreTicksToWait ) == pdTRUE )
      {
        Vbatt_LIDAR += ( ((( uPvolts * adc1_get_raw(ADC1_CHANNEL_6)) / ADbits) / r2 * ( r1 + r2)) + offSET );
        Vbatt_LIDAR = Vbatt_LIDAR /2; // average readings
        xSemaphoreTake( sema_Time, xSemaphoreTicksToWait );
        fMakeTimeStamp ( localBuffer );
        xSemaphoreGive( sema_Time ); // give up semaphore
      } // if ( xSemaphoreTake( sema_AnalogVoltRead_LIDAR, xSemaphoreTicksToWait ) == pdTRUE )
      iBit = 1;
    } // if ( iBit == 1073741824 )
  }
  vTaskDelete( NULL );
}

Is what I use to read a supply voltage, works pretty good.

1 Like

Idahowalker:

// https://dl.espressif.com/doc/esp-idf/latest/api-reference/peripherals/adc.html

// set up A:D channels
 adc1_config_width(ADC_WIDTH_12Bit);
 adc1_config_channel_atten(ADC1_CHANNEL_6, ADC_ATTEN_DB_11);
 //  adc1_config_width(ADC_WIDTH_12Bit);
 //  adc1_config_channel_atten(ADC1_CHANNEL_1, ADC_ATTEN_11db);
 /*
    When VDD_A is 3.3V: 11dB attenuation (ADC_ATTEN_11db) gives full-scale voltage 3.9V
 */

void TaskAnalogVoltRead_LIDAR( void *pvParameters )
{
 String localBuffer;
 localBuffer.reserve ( StringBufferSize300 );
 int iBit = 1;
 float ADbits = 4095.0f;
 float offSET = 1.0f;
 float r1 = 100800.0f; // R1 in ohm, 100k = 100,800.0 //
 float r2 = 38780.0f; // R2 in ohm, 38k = 38000.0 //actual 38780K
 float uPvolts = 3.3f;
 // ADC1 channel 0 is GPIO36
 // ADC1 channel 1 is GPIO37
 // ADC1 channel 6 is GPIO34
 // https://dl.espressif.com/doc/esp-idf/latest/api-reference/peripherals/adc.html
 // to get resistor R2 go to:
 // Voltage Divider Calculator
 //   used 12 volts for the input voltage to calculate R2, used 100K for R1
 for (;:wink:
 {
   // group handle, WaitForBits, ClearOnExitBit, WaitForAllBits, TicksToWait
   xEventGroupWaitBits( eg, evtAnalogVoltReadTask_LIDAR, pdTRUE, pdTRUE, portMAX_DELAY );
   // read the input
   iBit = iBit << 1;
   if ( iBit == 1073741824 )
   {
     if ( xSemaphoreTake( sema_AnalogVoltRead_LIDAR, xSemaphoreTicksToWait ) == pdTRUE )
     {
       Vbatt_LIDAR += ( ((( uPvolts * adc1_get_raw(ADC1_CHANNEL_6)) / ADbits) / r2 * ( r1 + r2)) + offSET );
       Vbatt_LIDAR = Vbatt_LIDAR /2; // average readings
       xSemaphoreTake( sema_Time, xSemaphoreTicksToWait );
       fMakeTimeStamp ( localBuffer );
       xSemaphoreGive( sema_Time ); // give up semaphore
     } // if ( xSemaphoreTake( sema_AnalogVoltRead_LIDAR, xSemaphoreTicksToWait ) == pdTRUE )
     iBit = 1;
   } // if ( iBit == 1073741824 )
 }
 vTaskDelete( NULL );
}



Is what I use to read a supply voltage, works pretty good.

Seem your code is a bit difficult. what is your "offset"? is it the different value between the real measurement and the adc measurement? Like real measurement is 3.6v and the adc is 3.0v so offset is 0.6v