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);
}
}
}