Arduino based NiMh AA battery tester

As part of my photography hobby, I use NiMh AA batteries in my flashes. Occasionally, it happens that my flash won’t recharge very quickly, if at all. I’d always believed this to be caused by having one or two dead/weak batteries. Most flashes use 4 cells in series. If one is no good, nothing works. Most sites I’ve read recommend always using batteries as a set. Always use the same four together. I wasn’t doing this and that’s probably a large part of my problem.

But now I have ~20 batteries of unknown condition. How to test?

After googling around a bit, I came across some Arduino based testers. The ones I found had some great features, like the ability to handle battery packs, identify batter type and more. I just needed a AA NiMh tester that could handle multiple cells. In the end, I brewed my own.

IMG_3349IMG_3348

My design is pretty basic. I discharge a cell through a 1 ohm resistor. Since these batteries typically run at about 1.2v while loaded, this translates into approximately 2 hours to discharge. Since I am discharging each cell independently, I don’t need to worry about over-discharge.

The green wires measure the voltage drop across the resister which is used to track the current flowing. The code checks the current every 10 seconds and displays the milli-amp-hours. The lcd displays the four values.

The software considers a cell discharged when the voltage drops below .6v. After this when it sees a voltage above .8v it resets the data for that channel. These are probably not the best values to use, but they work.

As a voltage reference, I use 4 1kohm resisters in series and tap off of one of them. This yielded a ref voltage of 1,237 when measured with my voltmeter. I’m not too concerned about accuracy. I just want consistency to enable me to pair cells into sets of four.

 

Here’s the source code

#include "Streaming.h"
#include <LiquidCrystal.h>

float aref = 1.237;
int interval = 10;

// Connections:
// rs (LCD pin 4) to Arduino pin 12
// rw (LCD pin 5) to Arduino pin 11
// enable (LCD pin 6) to Arduino pin 10
// LCD pin 15 to Arduino pin 13
// LCD pins d4, d5, d6, d7 to Arduino pins 5, 4, 3, 2
LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);

void setup()
{
  analogReference(EXTERNAL);
 
  // start serial port at 9600 bps:
  Serial.begin(9600);
  
  lcd.begin(16, 2);
  
  lcd.clear();                  // start with a blank screen
 
}

class Battery {
  public:
  enum States { EndDischarge, Discharging };
  Battery(int pinin, float res) {
    pin = pinin;
    resistance = res;
    reset();
  };

  void reset() {
    state = EndDischarge;
    as = 0;
    elapsed = 0;
  }; 
 
  float getmAh() {
    return float(as*interval)/3600.0*1000.0;
  };
 
  States getstate() {
     return state;
  }
 
  int getpin() {
     return pin;
  }
 
  void tick() {
    int val = analogRead(pin);
    float volts = float(val)/1024.0*aref;
    float current = volts/resistance;
   
    switch (state) {
     case EndDischarge:
      if (volts > .8) {
        reset();
        state = Discharging;
       
        Serial << pin << " battery connectedn";
        break;
      } 
      return;
      break;
    
     case Discharging:
      if (volts < .6) {
         Serial << pin << " battery discharged with " << getmAh() << " mAhn";
         state = EndDischarge;
         return;
      }
      break;
     
    }
   
    elapsed += interval;
    as += current;
   
   
    Serial << pin << " volts " << volts << " current " << current << " mAh " << getmAh() << "n";
  };
 
  private:
  int pin;
  float as;
  long elapsed;
  float resistance;
  States state;
};

Battery batteries[] = {
    Battery(0, 1.0),
    Battery(1, 1.0),
    Battery(2, 1.0),
    Battery(3, 1.0)
};

void loop()
{
  delay(interval*1000);
 
  lcd.clear();
  for(int i=0; i<sizeof(batteries)/sizeof(Battery); i++) {
    batteries[i].tick();
    lcd.setCursor((batteries[i].getpin()%2)*5, batteries[i].getpin()/2);
    lcd.print(int(batteries[i].getmAh()));
    if (batteries[i].getstate() == Battery::EndDischarge) {
      lcd.print("d");
    }
  }
}