This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Battery percentage measurement fluctuation

We are having some trouble with battery percentage measurement. The battery percentage being reported, keeps fluctuating. Earlier the fluctuations were as large as 3% to 100%.

After averaging across three points, the fluctuations are between 45% and 90%.

We are using ADC measuring the voltage drop on an external voltage divider or resistor / diode divider across the battery. We have the following sample code that we are using for battery percentage calculation.

    #define ADC_REF_VOLTAGE_IN_MILLIVOLTS        1200

    #define ADC_PRE_SCALING_COMPENSATION         3 
    #define DIODE_FWD_VOLT_DROP_MILLIVOLTS       270
    #define ADC_RESULT_IN_MILLI_VOLTS(ADC_VALUE)\
            ((((ADC_VALUE) * ADC_REF_VOLTAGE_IN_MILLIVOLTS) / 255) * ADC_PRE_SCALING_COMPENSATION)

    static __INLINE uint8_t battery_level_in_percent(const uint16_t mvolts)
    {
        uint8_t battery_level;
    
        if (mvolts >= 3000)
        {
            battery_level = 99;
        }
        else if (mvolts > 2900)
    {
        battery_level = 100 - ((3000 - mvolts) * 58) / 100;
    }
    else if (mvolts > 2740)
    {
        battery_level = 42 - ((2900 - mvolts) * 24) / 160;
    }
    else if (mvolts > 2440)
    {
        battery_level = 18 - ((2740 - mvolts) * 12) / 300;
    }
    else if (mvolts > 2100)
    {
        battery_level = 6 - ((2440 - mvolts) * 6) / 340;
    }
    else
    {
        battery_level = 0;
    }

    return battery_level;
}

void ADC_IRQHandler(void)
{
    if (NRF_ADC->EVENTS_END != 0)
    {
        uint8_t adc_result;
        uint16_t batt_lvl_in_milli_volts;
        uint8_t percentage_batt_lvl;
        static uint8_t p_percentage_batt_lvl=75;
        uint32_t err_code;

        NRF_ADC->EVENTS_END     = 0;
        adc_result              = NRF_ADC->RESULT;
        NRF_ADC->TASKS_STOP     = 1;

        batt_lvl_in_milli_volts = ADC_RESULT_IN_MILLI_VOLTS(adc_result) +
                                  DIODE_FWD_VOLT_DROP_MILLIVOLTS;
        percentage_batt_lvl     = battery_level_in_percent(batt_lvl_in_milli_volts);
        percentage_batt_lvl = (percentage_batt_lvl+p_percentage_batt_lvl)/2;
        p_percentage_batt_lvl = percentage_batt_lvl;

        err_code = ble_bas_battery_level_update(&bas, percentage_batt_lvl);
        if (
            (err_code != NRF_SUCCESS)
            &&
            (err_code != NRF_ERROR_INVALID_STATE)
            &&
            (err_code != BLE_ERROR_NO_TX_BUFFERS)
            &&
            (err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING)
        )
        {
            APP_ERROR_HANDLER(err_code);
        }
    }
}
  • Hi

    Without taking a deep dive into your code, I suspect the voltage divider to be the cause for the problem. A voltage divider will cause error on the ADC, both offset error and gain error. The error is larger the larger resistance values you use in the voltage divider. Read about the ADC and voltage divider in section 31.1.2 in the nRF51 Reference Manual v3.0. See this thread for recommended voltage divider for Lithium battery measurements. Also take a look at these answers: (1) (2) . This thread also includes a formula for calculating capacitor size for arbitrary voltage divider.

    For debugging suggestion, I recommend to take one step at a time, first see that the readings from the ADC is as expected before converting the ADC value into battery level. You can output the ADC reading either out on LEDs or out on UART to see live ADC reading.

    Update 3.3.2015 The fluctuations. Have you tried to measure the actual voltage on the pin you measaure, if the voltage is stable or not?

Related