sagar saini
Published © GPL3+

1.5V Alkaline Battery SOC Measurement Technique

A simple yet effective method to measure the SOC of non rechargable batteries.

BeginnerFull instructions provided2 hours139
1.5V Alkaline Battery SOC Measurement Technique

Things used in this project

Software apps and online services

Justway

Story

Read more

Schematics

Circuit diagram

Code

Code

Arduino
/**************************************************
 * Alkaline Battery SoC Estimation
 * Method 1: I between 9.7 & 22
 * Method 2: Voltage-SoC LUT (with calibration)
 **************************************************/

#define ADC_PIN        A0
#define MOSFET_LOW     6     // 9.7 load
#define MOSFET_HIGH    7     // 22 load

#define R_LOW   9.7
#define R_HIGH  22.0

#define ADC_REF       4.83
#define ADC_RES       1023.0
#define DIVIDER_RATIO 1.0

// ---------- USER CALIBRATION ----------
#define VOLTAGE_GAIN   1.000   // slope calibration
#define VOLTAGE_OFFSET 0.000   // offset calibration (Volts)

// ---------- ADC SETTINGS ----------
#define ADC_SAMPLES   12

// ---------- TIMING (ms) ----------
#define LOAD_PULSE_MS 20
#define RECOVERY_MS   300

// ---------- I THRESHOLDS ----------
#define DI_MAX  81.0   // mA  100%
#define DI_MIN  61.0   // mA  0%

// ---------- VOLTAGESOC LUT ----------
#define VSOC_POINTS 11

const float voltLUT[VSOC_POINTS] = {
  1.60, 1.55, 1.50, 1.45, 1.40,
  1.35, 1.30, 1.25, 1.20, 1.10, 1.00
};

const float socLUT[VSOC_POINTS] = {
  100, 90, 80, 70, 60,
  50, 40, 30, 20, 10, 0
};

// -------------------------------------------------
// ADC voltage read with averaging
// -------------------------------------------------
float readBatteryVoltage()
{
  long sum = 0;
  for (int i = 0; i < ADC_SAMPLES; i++) {
    sum += analogRead(ADC_PIN);
    delay(2);
  }
  float adc = sum / (float)ADC_SAMPLES;
  return (adc * ADC_REF / ADC_RES) * DIVIDER_RATIO;
}

// -------------------------------------------------
// Voltage  SoC using LUT + interpolation
// -------------------------------------------------
float voltageToSoC(float V)
{
  if (V >= voltLUT[0]) return 100.0;
  if (V <= voltLUT[VSOC_POINTS - 1]) return 0.0;

  for (int i = 0; i < VSOC_POINTS - 1; i++) {
    if (V <= voltLUT[i] && V >= voltLUT[i + 1]) {
      float t = (V - voltLUT[i + 1]) /
                (voltLUT[i] - voltLUT[i + 1]);
      return socLUT[i + 1] +
             t * (socLUT[i] - socLUT[i + 1]);
    }
  }
  return 0.0;
}

// -------------------------------------------------
// I  SoC conversion
// -------------------------------------------------
float deltaIToSoC(float deltaI_mA)
{
  if (deltaI_mA >= DI_MAX) return 100.0;
  if (deltaI_mA <= DI_MIN) return 0.0;

  return 100.0 * (deltaI_mA - DI_MIN) / (DI_MAX - DI_MIN);
}

// -------------------------------------------------
// Full battery measurement
// -------------------------------------------------
void measureBattery()
{
  float Voc_raw, Voc_cal;
  float V_low, V_high;
  float I_low, I_high;
  float deltaI_mA;
  float soc_deltaI, soc_voltage;

  // ---- Open-circuit voltage ----
  Voc_raw = readBatteryVoltage();
  Voc_cal = (Voc_raw * VOLTAGE_GAIN) + VOLTAGE_OFFSET;

  soc_voltage = voltageToSoC(Voc_cal);

  // ---- 22 load ----
  digitalWrite(MOSFET_HIGH, HIGH);
  delay(LOAD_PULSE_MS);
  V_high = readBatteryVoltage();
  digitalWrite(MOSFET_HIGH, LOW);

  delay(RECOVERY_MS);

  // ---- 9.7 load ----
  digitalWrite(MOSFET_LOW, HIGH);
  delay(LOAD_PULSE_MS);
  V_low = readBatteryVoltage();
  digitalWrite(MOSFET_LOW, LOW);

  // ---- Currents ----
  I_high = V_high / R_HIGH;
  I_low  = V_low  / R_LOW;

  deltaI_mA = (I_low - I_high) * 1000.0;
  soc_deltaI = deltaIToSoC(deltaI_mA);

  // ---- Print ----
  Serial.println("===== Battery Measurement =====");

  Serial.print("Voc (raw): ");
  Serial.print(Voc_raw, 4);
  Serial.println(" V");

  Serial.print("Voc (cal): ");
  Serial.print(Voc_cal, 4);
  Serial.println(" V");

  Serial.print("SoC (Voltage): ");
  Serial.print(soc_voltage, 1);
  Serial.println(" %");

  Serial.print("V(22): ");
  Serial.print(V_high, 4);
  Serial.println(" V");

  Serial.print("I(22): ");
  Serial.print(I_high * 1000.0, 1);
  Serial.println(" mA");

  Serial.print("V(9.7): ");
  Serial.print(V_low, 4);
  Serial.println(" V");

  Serial.print("I(9.7): ");
  Serial.print(I_low * 1000.0, 1);
  Serial.println(" mA");

  Serial.print("I: ");
  Serial.print(deltaI_mA, 1);
  Serial.println(" mA");

  Serial.print("SoC (I): ");
  Serial.print(soc_deltaI, 1);
  Serial.println(" %");

  Serial.println("================================");
}

// -------------------------------------------------
// Setup & loop
// -------------------------------------------------
void setup()
{
  Serial.begin(9600);

  pinMode(MOSFET_LOW, OUTPUT);
  pinMode(MOSFET_HIGH, OUTPUT);

  digitalWrite(MOSFET_LOW, LOW);
  digitalWrite(MOSFET_HIGH, LOW);

  Serial.println("Alkaline Battery SoC Meter (Voltage + I)");
}

void loop()
{
  measureBattery();
  delay(5000);
}

Credits

sagar saini
98 projects • 103 followers
I am Sagar Saini an electronic hardware enthusiast

Comments