1.2V battery capacity tester

Hi.
I'm wanting to try build a 1.2V NiMh battery capacity tester.

Looking at other projects online, it seems I essentially need to measure the battery voltage accurately, set the minimum voltage to be achieved (0.9V), apply an appropriate resistance load across the battery, include calculations in the code to know when to stop and then display the results on a small display.

I've spent quite a bit of time trying to adapt a circuit I found on line (https://www.instructables.com/DIY-Arduino-Battery-Capacity-Tester-V20/), however when I try to drain the battery via the mosfet suggested (IRLZ44N), a 1.2V battery doesn't seem to open the gate. I think I read it needs around 3 or 4 volts.

What I'd like to know is, could I create a circuit using parts that I have - either Darlington Arrays (UNL2003A) or power shift registers (TPIC6B595). The darlingtons seem to be able to handle 500mA per driver(?) and the shift registers 350mA per output.

I thought that I could maybe write to use a combination of outputs in parallel to drain the battery at the rate I nominate via a number of resistors. Could someone please let me know if this is possible and if so a hint of where I can start. Note, I'm a bit of an electronics novice.

The battery doesn't drive the gate, the opamp does.
That circuit should work, even with the limited (2.5volt) gate drive the opamp can provide.

Forget about ULN2003 darlington arrays.
They also have a current limitation for the whole chip, and that's a lot lower than you might think.
About 80mA per output if all outputs are used (see the graph in datasheet).

The author used a metal screw on the fet without plastic TO-220 spacer.
That could easilly short the battery (to the grounded heatsink).
Leo..

1 Like

Thanks Leo for the reply.
My issue with the mosfet was that it wasn't even getting warm when draining the 1.2V battery. However, when I connected a 3.7V Li-ion battery, it then started to heat up (needed a sink). So I have no idea why it's not working.

Not "getting warm" does not mean "not working".

Hint: power (heat dissipated) = V^2/R, where R = MOSFET on resistance.

1 Like

The LM358 will not give you VCC on its output, it is not a rail to rail output. You could add a pull up resistor to accomplish this. The ground of R3 should be also connected directly to the DUT ground. Check you gate voltage without a battery, if it is wired correctly it should be about 5V (VCC). If not you either have a bad part or it is miswired. I would not recommend this circuit without some protection for A0, it will be fried if a good 9V battery is connected.

Hi,
I use this circuit:
Battery_test

with the code attached. Sorry but the comments of the lines are in Portuguese.
It can test NIMH or LI-ion batteries.
Selection is automatic.
Maybe someone criticizes the MOSFET circuit, but I know it can be improved. :grinning: :grinning: :grinning:
It works very well the way it is.
(The MOSFET I removed from a broken motherboard, it has several 090N03L).

#include <LiquidCrystal.h>                                // LCD Lib
LiquidCrystal lcd(4, 5, 6, 7, 8, 9);                      // Ports parra o LCD
#define sensorPin A0                                      // Port para leitura analogica
#define MOSFET 10                                         // Port para MOSFET controle da carga
#define LED 13                                            // Port indiucador de fim de leitura
int valorADC = 0;                                         // Valor lido no port ADC
float voltagem;                                           // Valor calculado da votagem
float minVolt = 0;                                        // Valor da voltagem minima  2,7*1,79/3,96 = 1.22
bool feito = false;                                       // Controle de Leitura
bool parado = false;                                      // Controle de execucao com FET ligado
int minuto = 0;                                           // Tempos de leitura em segundos
float factor = 0.004959;                                  // Fator de calculo do  ADC
float intervalo = 2000;                                   // Valor de calculo do intervalo de leitura
int segundo = intervalo / 1000;                           // Tempos de leitura em minutos
float resistor = 2.2 / 1000;                              // Valor do resistor de carga
float accCorrente = 0;                                    // Valor de corrente acumulado
float corrente = 0;                                       // Valor de corrente calculada
int tentativa = 0;                                        // Tentativas de leitura com valor abaixo do minimo
int overide = 3;                                          // Numero de tentativas abaixo do limite
unsigned long newMillis;                                  // Calculo de segundos
unsigned long tempo = 3600000;                            // 1 hora em milisegundos
//---------------------------------------------------------------------------
void setup()
{
  pinMode(sensorPin, INPUT);                              // Port ADC como entrada
  pinMode(MOSFET, OUTPUT);                                // Port MOSFET como saida
  pinMode(LED, OUTPUT);                                   // Port LED como saida
  Serial.begin(115200);                                   // Inicializa Serial
  lcd.begin(16, 2);                                       // Inicializa o LCD
  lcd.print("Bat PWR Tester[Active]");                    // Imprime LCD
  lcd.setCursor(0, 1);                                    // linha 1 posicao 0
  lcd.print("Detecting Bat Type...");                     // Imprime LCD
  delay(200);                                             // Aguarda
  digitalWrite(MOSFET, LOW);                              // Desliga MOSFET
  lcd.clear();                                            // Limpa o LCD
  valorADC = analogRead(sensorPin);                       // Le ADC
  if (valorADC >= 400 )                                   // Se > 350 é bateria tipo LI-ION
  {
    minVolt =  1.220;                                     // Calcula limite minimo   2,7*1,79/3,96 = 1.22
  }
  if (valorADC < 400 )                                    // Se > 350 é bateria tipo NI-MH
  {
    minVolt = 0.900;                                      // Limite minimo
  }
}
//---------------------------------------------------------------------------
void loop()
{
  if (feito == false)                                     // Se e pra continuar
  {
    digitalWrite(MOSFET, HIGH);                           // Liga MOSFET
    valorADC = analogRead(sensorPin);                     // Le ADC
    voltagem = valorADC * factor;                         // Valor = ADC * o fator do ADC em mili  x.xxx
    corrente = voltagem / resistor;                       // Calcula corrente sobre o resistor
    accCorrente = accCorrente + corrente;                 // Acumula corrente
    if (millis() - newMillis > intervalo)                // A cada segundo
    {
      newMillis = millis();
      segundo += intervalo / 1000;
      if (segundo > 59)
      {
        segundo = 0;
        minuto++;
      }
    }
    lcd.clear();
    lcd.setCursor(0, 0);                                  // linha 0 posicao 0
    if (minVolt >  1.000)                                 // Se Litio
    {
      lcd.print("L ");                                    // Imprime L  pos 0 e 1
//      voltagem =  (resistor + (1.94 / 1000)) * corrente;
    }
    else                                                  // Se nao,  NI-MH
      lcd.print("N ");                                    // Imprime N  pos 0 e 1
    lcd.print("T");                                       // Imprime N  pos 2
    lcd.print(minuto);                                    // Imprime minuto decorridos pos 4 e 5
    lcd.print(":");                                       // Imprime serial pos 6
    lcd.print(segundo);                                   // Imprime LCD segundo pos 7 e 8
    lcd.setCursor(9, 0);                                  // linha 0 posicao 9
    lcd.print(voltagem  * 1.778, 2);                               // Imprime LCD voltagem 9,10,11,12
    lcd.print("V ");                                      // Imprime LCD pos 13 e 14

    lcd.setCursor(0, 1);                                  // linha 1 posicao 4
    lcd.print(corrente, 0);                               // Imprime LCD voltagem 9,10,11,12
    lcd.print("mA  ");                                    // Imprime LCD  pos 4, 5, 6, 7
    lcd.setCursor(9, 1);                                  // linha 1 posicao 9
    lcd.print((accCorrente / (tempo / intervalo)), 0);    // Imprime LCD corrente/hora  pos 9, 10, 11,12
    lcd.print("mA/H ");                                   // Imprime LCD  pos 13, 14, 15, 16

    //if ((segundo %10) == 0)                             // A cada 10 segundos
    Serial.print(minuto);
    Serial.print(" ");
    Serial.print(segundo);
    Serial.print(" ");
    Serial.print(voltagem * 1.778 , 4);                           // Imprive serial voltagem    x.xxxx
    Serial.print(" ");
    Serial.print(corrente, 4);
    Serial.print(" ");
    Serial.println((accCorrente / (tempo / intervalo)), 4);

    delay(intervalo);                                     // Aguarda nova leitura
  }
  else                                                    // Se nao e pra continuar
  {
    if (parado == false)                                  // Se ainda nao parou
    {
      digitalWrite(MOSFET, LOW);                          // Desliga MOSFET
      Serial.println(" Leitura Terminada  ");             // Imprime Serial
      lcd.setCursor(15, 1);                                // linha 1 posicao 0
      lcd.print("F");                                  // Imprime LCD
      parado = true;                                      // Informa que e para parar
    }
  }
  if (voltagem < minVolt)                                 // Se voltagem abaixo do limite
  {
    tentativa ++;                                         // Incrementa tentativas
    if (tentativa >= overide)                             // Se estourou tentativas
    {
      digitalWrite(LED, HIGH);                            // Acende LED indicando fim de leitura
      feito = true;                                       // Informa que leituras feitas
    }
  }
  else                                                    // Se voltagem acima do limite
  {
    tentativa = 0;                                        // Zera tentativas
  }
}

I think what you really want here is the ability to select a discharge rate that is based on a fixed resistance, or constant current, or constant power.

In the first case, voltage and current will both decline. In the second case, voltage will decline until the battery can't produce the set current any more. And in the last case, voltage will decline and current will increase, until the battery can't produce the desired current. All interesting data!

When you discharge a 1.2volt battery with 1Amp with a mosfet and a fixed 1 ohm resistor,
then the 1 ohm resistor gets 1 volt and the fet gets 0.2 volt.
0.2volt 1A is only 0.2watt. Not enough to heat up a heatsink.
The heatsink only gets hot with higher battery voltages.

~3.5 volt from the LM358 minus ≤1volt when the source resistor has 1volt across (1 Amp discharge) is still 2.5 volt left to drive the gate. That should be enough for 1A through a logic level fet.

Good point on adding a 10k resistor between battery and A0. You should never connect a battery directly to an I/O pin.

That circuit has no constant current control, and can't discharge a 1.2 volt battery with 1A.
Leo..

Hi,
Who said it needs to be constant current?
When a battery is in a normal circuit for any use, the current is not constant.
My code calculates the power every second, based on the voltage measured across the resistor and using Ohm's law.
The power is accumulated and displayed on the LCD in mA/H, and when the battery reaches the minimum battery limit, the current is turned off by the FET.

The schematic looks great, nice job. R1 will give you a very soft turn and off with that MOSFET causing it to get much warmer. I suggest something in the 25-50 Ohm range. Place something no more than 10K in the A0 lead to protect the analog input. Adding a small cap will help stabilize the readings but to large will mess them up. Placing a shockley diode Anode on A0 and Cathode on 5V will give a lot of protection and protect from a 24V battery. Place something in the 10K range from D10 to ground, that will keep the MOSFET off during reset and initialize until your code gets control of it.

2 Likes

150-220ohm in series with the gate (for a switching mosfet) and 10k from pin to ground is normally recommended. 25-50 ohm results in ~100mA peak pin current, which you probably don't want.
See this page. Diagram#1.

Shockley diodes are a thing of the past.
You probably mean Schottky diode :slight_smile:
Leo..

Hi Gil(?).
Thanks for your reply, but I do have some questions if I may. Please see code at the end of this reply.

I'm using an Nano, 3.3V unit. I'm supplying external power from an adapter (5.15V).
The arduino is being powered via the "RAW" pin and "GND".

  1. Am I correct in saying that the LM385 is used as a constant reference voltage (read in pin A1 - Vref_Pin - line 94)?

  2. Is it correct to have only 2 pins of the voltage reference connected - Pin 1 & 2?

  3. The voltage across GND and this Pin 2 is 3.90V. It that what it should be? How can I check?

  4. You mentioned the ground of R3 should also be connected to DUT ground. I've connected all grounds together (including the battery). Is that correct?

  5. I measured the Gate voltage without a battery as you suggested. It's 4.12V. With the battery, it's 1.816V. When connected and running, it measures 1.920V at the lowest mA setting and 4.12V at the highest mA setting.

  6. Your suggestion for protection of the A0 pin? Is this a 10K as Wawa noted? Do I connect it btwn GND and pin A0?

  7. Lastly, I don't get what line 31 to 33 in the code are doing - how they are adjusting the current/PWM values. When I toggle with SW2 button, it goes from Curr = 51mA & PWM=3 to Curr = 103mA & PWM=7, up to Curr = 999mA and PWM=76. I assume that 76 is the "duty cycle" ranging from 0 to 255?

If I have a AA NiMh that is 2800mA, should I be discharging it at 280mA (1/10 capacity)? If I discharge it faster or slower, would the capacity read about the same? What if I then connect my 10,000mA D size batteries. What discharge should these use?

Sorry for the zillion questions. I'm a bit of a newby here and wanting to make sure this is accurate. My long term is to build one of these for each of my 4 kids as well as an inbuilt charger to handle 4 AA's. I'd also like the unit to display the internal resistance of the battery to show if their still ok.

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// ARDUINO BATTERY CAPACITY TESTER
//Version-2.1
//by deba168,INDIA // The code is taken from Hesam Moshiri ( https://www.pcbway.com/blog/technology/Battery_capacity_measurement_using_Arduino.html )
//Dated : 02/02/2022
//
//Dated : 29/02/2020
//Added code to read a band gap reference connected to analog pin A1,
// thus allowing measurement of Vcc and avoiding the need to measure it using a multimeter
//Replaced 1 ohm 5% resistor with 1 ohm 1% power resistor
//Modified code to compute actual current draw based on desired values. Measurements
// using ammeter show computed values within 2 milliamps of measured
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

#include<JC_Button.h>
#include <Adafruit_SSD1306.h>

#define DEBUG 0 // Binary Treatment 0=Nothing, 1=Early, 2=Running Voltages, 4=Finish
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

void timerInterrupt();
void Display_UP_DOWN();//Debugging support
void Print_DEBUG_4();//Debugging support

const float Low_BAT_level = 0.90;// Threshold for stopping test
int Current [] = {0, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000};
int PWM [] = {0, 2, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50};
int Array_Size;// calculated during setup
const byte PWM_Pin = 10;
const byte Buzzer = 9;
const int BAT_Pin = A0;
const int Vref_Pin = A1;//Pin to which Band Gap Reference is attached
int Current_Value = 0; // Selected Current value for test
int PWM_Value = 0;// Value of PWM during test
int PWM_Index = 0;// Index into PWM array during test
unsigned long Capacity;
float Capacity_f;
int ADC_Value = 0;
float Vref_Voltage = 3.32; // LM385BLP-1.2 Band Gap Reference voltage
float Vcc = 5.14; // Voltage of Arduino 5V pin ( Measured during setup using Band Gap Reference )
float BAT_Voltage = 0;
float Resistance = 1.0; // Value of R3 Power Resistor
float sample = 0;
byte Hour = 0, Minute = 0, Second = 0;
bool calc = false, Done = false, Report_Info = true;
Button UP_Button(2, 25, false, true);
Button Down_Button(3, 25, false, true);

// string values for reporting intermediate information
const int VAL_MAX = 10;
char val_0[VAL_MAX] = {""};
char val_2[VAL_MAX] = {""};

void setup () {//Setup

  Serial.begin(38400);
  pinMode(PWM_Pin, OUTPUT);
  pinMode(Buzzer, OUTPUT);
  analogWrite(PWM_Pin, PWM_Value);
  UP_Button.begin();
  Down_Button.begin();
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextColor(WHITE);
  display.setTextSize(1);
  display.setCursor(12, 25);
  display.print("Open Green Energy");
  display.display();
  delay(3000);
  display.clearDisplay();
  display.setTextSize(2);
  display.setCursor(2, 15);
  display.print("Adj Curr:");
  display.setCursor(2, 40);
  display.print("UP/Down:");
  display.print("0");
  display.setCursor(2, 55);
  display.setTextSize(1);

#if (DEBUG == 1 || DEBUG == 5)
  Serial.println("\nStart of calculations");
#endif

  Array_Size = sizeof(Current) / 2;
  //Read voltages of Band Gap Reference and use it to calculate actual Vcc
  float fTemp = 0.0;
  for (int i = 0; i < 100; i++)
  {
    fTemp = fTemp + analogRead(Vref_Pin); //read the Band Gap Reference voltage
    delay (2);
  }
  fTemp = fTemp / 100.0;
  Vcc = Vref_Voltage * 1024.0 / fTemp;

  // Convert desired current levels to PWM using actual Vcc
  // Convert PWM values back to actual current levels
  // While measuring actual current I discovered that the actual draw is
  // (PWM + 1)/256 rather than PWM/255 as indicated in Arduino documentation
  int iTemp;
  for (int i = 0; i < Array_Size; i++)
  {
    iTemp = int( Resistance * Current[i] * 256.0 / Vcc / 1000.0 - 1.0 + 0.5 ); // desired current to nearest PWM
    iTemp = min(iTemp, 255);
    iTemp = max(iTemp, 0);
    Current[i] = int( (iTemp + 1) * Vcc / 256.0 / Resistance * 1000.0); // actual current for PWM
    PWM[i] = iTemp;//Save PWM in array
  }

  //Include Threshold and Vcc in startup display
  dtostrf(Low_BAT_level, 5, 3, val_0);
  dtostrf(Vcc, 5, 3, val_2);

  display.print("Thr=");
  display.print(val_0);
  display.print("v, Vcc=");
  display.print(val_2);

  display.display();
  display.setTextSize(2);

}//Setup

//************************* End of Setup function *******************************

void loop() {

  if (Report_Info)
  { //Report_Info
    Serial.flush();
#if (DEBUG == 1 || DEBUG == 5)
    // Serial.println("Measured Vcc Voltage: " + String(Vcc) + " volts");
    Serial.print("Threshold: ");
    Serial.print(Low_BAT_level, 3);
    Serial.println(" volts");
    Serial.print("R3 Resistance: ");
    Serial.print(Resistance, 3);
    Serial.println(" ohms");
    Serial.print("Measured Vcc Voltage: ");
    Serial.print(Vcc, 4);
    Serial.println(" volts");
    sample = 0.0;

    Serial.println("Index Actual(mA) PWM");
    for (int i = 0; i < Array_Size; i++)
    {
      // Serial.println( "["+String(i)+"]="+String(Current[i])+" mA PWM["+String(i)+"]="+String(PWM[i]) );
      Serial.print("[");
      Serial.print(i);
      Serial.print("]");
      Serial.print(" ");
      Serial.print(Current[i], DEC);
      Serial.print(" ");
      Serial.print(PWM[i], DEC);
      Serial.println(" ");
    }
#endif
    Report_Info = false;
  }//Report_Info

  UP_Button.read();
  Down_Button.read();
  if (UP_Button.wasReleased() && PWM_Index < (Array_Size - 1) && calc == false)
  {
    PWM_Value = PWM[++PWM_Index];
    analogWrite(PWM_Pin, PWM_Value);

    Display_UP_DOWN();
  }

  if (Down_Button.wasReleased() && PWM_Index > 0 && calc == false)
  {
    PWM_Value = PWM[--PWM_Index];
    analogWrite(PWM_Pin, PWM_Value);

    Display_UP_DOWN();
  }

  if (UP_Button.pressedFor (1000) && calc == false)
  {
    digitalWrite(Buzzer, HIGH);
    delay(100);
    digitalWrite(Buzzer, LOW);
    display.clearDisplay();
    timerInterrupt();
  }
}

//************************* End of Loop function *******************************

void timerInterrupt() {
  calc = true;
  while (Done == false) {//(Done == false)
    Second ++;
    if (Second == 60) {
      Second = 0;
      Minute ++;
    }
    if (Minute == 60) {
      Minute = 0;
      Hour ++;
    }

    //************ Measuring Battery Voltage ***********

    for (int i = 0; i < 100; i++)
    {
      sample = sample + analogRead(BAT_Pin); //read the Battery voltage
      delay (2);
    }
    sample = sample / 100;
    BAT_Voltage = sample * Vcc / 1024.0;
    Serial.print("BAT_Pin = ");
    Serial.print(BAT_Pin, 3);
    Serial.print(", Vref_Voltage = ");
    Serial.print(Vref_Voltage, 3);
    Serial.print(",  sample = ");
    Serial.print(sample, 3);
    Serial.print(",  Vcc = ");
    Serial.print(Vcc, 3);
    Serial.print(",  BAT_Voltage = ");
    Serial.println(BAT_Voltage, 3);
    //  Vcc = Vref_Voltage * 1024.0 / fTemp;

    //*********************************************

    display.clearDisplay();
    display.setTextSize(2);
    display.setCursor(20, 5);
    // display.print(String(Hour) + ":" + String(Minute) + ":" + String(Second));
    display.print(Hour);
    display.print(":");
    display.print(Minute);
    display.print(":");
    display.print(Second);

    display.setTextSize(1);
    display.setCursor(0, 25);
    display.print("Disch Curr: ");
    // display.print(String(Current[PWM_Index])+"mA");
    display.print(Current_Value);
    display.print("mA");

    display.setCursor(2, 40);
    // display.print("Bat Volt:" + String(BAT_Voltage)+"V" );
    display.print("Bat Volt:");
    display.print(BAT_Voltage, 3);
    display.print("V");

    // When total seconds is greater than 32767 the statement below did not work until the byte values
    // Hour, Minute and Second were cast to an unsigned long. Apparently the compiler cast the byte
    // values to an "int" first which cannot represent 32768 correctly
    Capacity = ((unsigned long)Hour * 3600) + ((unsigned long)Minute * 60) + (unsigned long)Second;
    Capacity_f = ((float)Capacity * Current_Value) / 3600.0;

    display.setCursor(2, 55);
    // display.print("Capacity:" + String(Capacity) + "mAh");
    display.print("Capacity:");
    display.print(Capacity_f, 0);
    display.print("mAh");
    display.display();

#if (DEBUG == 4 || DEBUG == 2)
    Print_DEBUG_4();
#endif

    if (BAT_Voltage < Low_BAT_level)
    { //BAT_Voltage < Low_BAT_level

#if (DEBUG == 4 || DEBUG == 5)
      Serial.println("\nCurrent_Value PWM_Value");
      Serial.print(Current_Value);
      Serial.print(" ");
      Serial.println(PWM_Value);
      Serial.println("\nHour Minute Second PWM_Index");
      Serial.print(Hour);
      Serial.print(" ");
      Serial.print(Minute);
      Serial.print(" ");
      Serial.print(Second);
      Serial.print(" ");
      Serial.println(PWM_Index);
#endif

      // When total seconds is greater than 32767 the statement below did not work until the byte values
      // Hour, Minute and Second were cast to an unsigned long. Apparently the compiler cast the byte
      // values to an "int" first which cannot represent 32768 correctly
      Capacity = ((unsigned long)Hour * 3600) + ((unsigned long)Minute * 60) + (unsigned long)Second;

#if (DEBUG == 4 || DEBUG == 5)
      Serial.println("Capacity HMS");
      Serial.println(Capacity);
#endif

      Capacity_f = ((float)Capacity * Current_Value) / 3600.0;

#if (DEBUG == 4 || DEBUG == 5)
      Serial.println("Capacity HMS*PWM");
      Serial.println(Capacity_f, 1);
#endif

      display.clearDisplay();
      display.setTextSize(2);
      display.setCursor(2, 15);
      display.print("Capacity:");
      display.setCursor(2, 40);
      // display.print(String(Capacity) + "mAh");
      display.print(Capacity_f, 1);
      display.print("mAh");
      display.display();
      Done = true;
      PWM_Value = 0;
      analogWrite(PWM_Pin, PWM_Value);
      digitalWrite(Buzzer, HIGH);
      delay(200);
      digitalWrite(Buzzer, LOW);
      delay(100);
      digitalWrite(Buzzer, HIGH);
      delay(200);
      digitalWrite(Buzzer, LOW);
      delay(100);
      digitalWrite(Buzzer, HIGH);
      delay(200);
      digitalWrite(Buzzer, LOW);
      delay(100);
      digitalWrite(Buzzer, HIGH);
      delay(200);
      digitalWrite(Buzzer, LOW);
      delay(100);
      digitalWrite(Buzzer, HIGH);
      delay(200);
      digitalWrite(Buzzer, LOW);
      delay(100);
    }//BAT_Voltage < Low_BAT_level
    delay(1000);
  }//(Done == false)

}// timerInterrupt

void Display_UP_DOWN()
{ //Display_UP_DOWN()
  Current_Value = Current[PWM_Index];

  display.clearDisplay();
  display.setCursor(2, 25);
  display.print("Curr:");
  display.print(Current_Value);
  display.print("mA ");
  display.setCursor(2, 40);
  display.print("PWM=");
  display.print(PWM_Value);
  display.display();
}//Display_UP_DOWN()

void Print_DEBUG_4()
{ //Print_DEBUG_4()
  Serial.print(Hour);
  Serial.print(":");
  Serial.print(Minute);
  Serial.print(":");
  Serial.print(Second);
  Serial.print(" ");
  Serial.print(BAT_Voltage, 3);
  Serial.print("v ");
  Serial.print(Capacity_f, 1);
  Serial.println("mAh");
}//Print_DEBUG_4()

Made one once, years ago. Simple enough, ran constant current and timed the discharge down to a constant 0.8v per cell.
Didn't have Arduino back in those days so more than likely simple enough without one still these days..

Have a look at the LM358 Datasheet.

It can be programmed with 2 resistors to give voltages between 1.2V and 5.3V.

For 1.2V, no resistors are required but the Feedback pin should be connected to GND.

Gilshultz,
I placed a 10K from D10 to ground. Thanks for the suggestion for startup. There was occasionally an issued in it starting up. That part is fixed.

As for the diode across A0 and 5V for a 24V battery, I don't really get it. I'm only going to run it with a 5V supply.

Also, when you get a chance, can look through my post#12. Ta.

Wawa, thanks for this reply an the link, but it's a little over my head.
Are you recommending with my circuit that I add say a 150 ohm resister in line between the gate pin (pin 1) of the mosfet and pin 1 of the LM358 op amp?

You mean LM385 (voltage reference), not the LM358 (opamp).

A Schottky diode between A0 and 5volt can protect the Nano pin in case battery voltage becomes higher than Arduino supply. That protection must also include a 10k resistor between battery and A0 (in series). When that resistor is used, the diode is sort-off not needed anymore.

More replying to gilshultz, but yes,
commonly done if the mosfet is driven from an Arduino pin (see link in previous post).
Not really needed when the mosfet is driven from an LM358, because the output of that opamp is over-current protected.
Leo..

Hi Leo.
Can you check the following changes are what you were suggesting (R7, R8 and D1) - where D1 is a schottky diode BAT48 (as it's the only type I have) :


I've also added a 10K between pin 10 of the arduino and ground.

Ignore the 150 ohm resister in my case - :+1:

Move C1 (220uF) to the other side of R7, where it was before.
C2 (100n) can stay where it is.
Can't hurt to use two 100n caps, one on each side of R7.
BAT48 is fine.
Leo..

Done.