Introduction: Multiple Li-Ion Battery Capacity Tester

Over the Time I have colected a whole bunch of used Laptop Batteries, which are mostly in usable condition.
Older laptop models have 3S2P 18650 Batteries, some even 4S2P, while newer models often have 3S or 4S. What they all have in common is that they have classic 18650 Batteries, which I carefully removed from the Battery pack.

Used Batteries surely do not have the Capacity as new ones, but they are still not to be discarded, and can be used for some future Projects. It is necessary to know in what condition each Battery is, what Capacity each of them has, so that they can be paired later.

As the vast majority of us already know, Battery Capacity defines the amount of Electric Energy stored while the Battery is charged. With all rechargeable Batteries, the Capacity decreases with age and use.

I will not say much about the Theory, there is enough information on the Internet about it: the Capacity is measured so that the Battery is discharged, and the discharge Current and the Time required to discharge the Battery are measured (Q = I x t)


  • 1x Prototype PCB (I used 9x15 cm)
  • 4x MOSFET IRFZ44N (or similar N-Channel)
  • 4x 2-Pin Screw Terminal
  • 4x Ceramic Resistor 5R6 5W
  • 9x Resistor 10 kOhm
  • 8x Resistor 4.7 kOhm
  • 12x Resistor 1 Ohm
  • 5x Resistor 100 Ohm
  • 1x Resistor 47 Ohm
  • 4x Resistor 1 kOhm
  • 4x Resistor 2.2 kOhm
  • (all used resitors are 1% 1/4W or 1% 1206 SMD 1/8W)
  • Capacitor 100nF - 8 Pcs
  • 1x Jumper - salvaged from an old PC Motherboard
  • 1x Arduino Nano
  • 1x ILI 9341 TFT Display
  • 1x Buzzer - salvaged from an old PC Motherboard
  • 4x 18650 Battery holder
  • Female Headers

Step 1: Heart of the Project: Arduino Nano

The Idea for this project I got on this intructable

Most of the Code comes from this guy, and I adapted it to 18650 Batteries and ILI9341 TFT display. ILI9341 has a Touch screen, but I don't have enough free digital ports left on my Arduino to use the Touch features.

Shunt current measurement

Many DIY Capacity Testers measure Current through a Power Resistor, which heats up. By heating it changes its resistance and the measurement is no longer accurate.

That is why I use Shunt Resistors in this project, and the Voltage Drop is measured on them. I did not have the original Shunt Resistors 0.33 Ohm, so I connected in parallel three Resistors 1 Ohm with a Tolerance of 1%, and so is the desired Resistance of 0.333 Ohm obtained.
The typical Power Rating of 1206 SMD Resistors is 0.125W, so in parallel Connection they can withstand 3 x 0.125W = 0.375W. The Current flowing through them is defined by the Value of the Power Resistor (5.6 Ohm) and the Voltage drop across the MOSFET. Let’s ignore the MOSFET for now, and consider only the Resistance of the Power Resistor:

4.2 V / (5.6 +0.333) = 707 mA (max) flows through the Shunt Resistors.

According to Ohm's law, power = Square of the Current times the Resistance

P = (IxI) x R -> (0.707 x 0.707) x 0.333 = 0.166 W,

which is less than the Resistors can withstand (0.375W), so even ordinary 1206 SMD Resistors can withstand this Currnet without any problems. They heat up a bit, but this is negligible compared to heating the Power Resistors, which reach 70 degrees Celsius.


The measured Current through the Power Resistor is 640mA, instead of the calculated 707. Where does the extra Resistance (0.629 Ohm) come from? The Answer is: MOSFET.
Most of us use cheap and easily available MOSFET's, instead of logic level MOSFET's. Arduino's 5V can't fully open the MOSFET (if it's not logic level), so the MOSFET is in saturation state, and has more resistance than its Datasheet says. It warms up a bit because of that, but it’s nothing critical.

Without a Heatsink, the IRFZ44 heats up to 40 degrees.

I didn't have 4 IRFZ44Ns, just only two, so I combined two IRFZ44 and two IRF840. According to the datashet, the IRF840 has an Rds (on) of 0.85 Ohm, and the IRFZ44 only 0.028 Ohm, so the IRF840 heats up a little bit more (about 50 degrees C) than the IRFZ44.

Step 2: Arduino's Accuracy

Well, Arduino's ADCs are functional, but not very accurate. The reason for this is the stability of the Arduino Power Supply, and its reference Voltage depends on it.
I tried different variants, Default Voltage reference, internal 1.1 and external. I also tried the readVcc () function, but none of the variants were correct - deviations from DMM were up to 100mV, so even the Capacity measurement cannot be accurate.

The method I use (I found somewhere on the internet) is the most accurate, deviations from values measured by DMM values are minimal.

The 3V3 PIN was used as the reference voltage, and I measured the voltage on it with a DMM. It is far below 3.3V. The voltage on the 3V3 PIN was 2,938 V when the Arduino was connected to the PC USB port, and 2,945 when is connected to the 7.5V power adapter.

The 3V3 PIN is connected by Jumper to the REF PIN, and the analogReference is set to EXTERNAL. The Jumper can be removed, so both INTERNAL and DEFAULT aRef can be used.

The next Step is to prevent the MOSFET from turning on, comment out the line in the detectBatteryType () function, connect a charged Battery, and measure the Battery Voltage and Voltages on the analog pins for that Battery. SMD Resistors with a tolerance of 1% (ebay quality) were used for Voltage dividers, but 1% of 10kOhm is 100 Ohm, so deviations can be large. The measured Battery Voltage is divided by the measured Voltage on the analog pin, and the result is written to the Code.

For example. on the first battery (B1) with a Voltage of 4.2V pin A0 had 1342.7mV, and pin A1 (after Shunt) 1342.6mV.
4200 / 1342.7 = 3.1280 we write as batRatio

4200 / 1342.6 = 3.1282 we write under FetResRatio

The same would be obtained by accurately measuring the Resistors in the Voltage divider and calculating by formula
1 / (Rlower / (Rlower + Rupper))

1 / (4700 / (4700 + 10000)) = 3.127

Repeat this Step for all Batteries and write the measured Values in the appropriate variables in the Code.
Once all Values have been entered, we can remove comment from the line that turns on the MOSFET.

This way the Arduino reading was almost identical to my DMM.

Voltage dividers are used for the simple reason that a Battery connected directly to the analog input will power up the Arduino even without external power. In this case (without Voltage dividers), analogReference (DEFAULT) should be used. A 100nF Capacitor is connected in parallel to each 4700 Ohm Resistor in the Voltage divider, so the reading at the analog Inputs is more stable.

The push-button is added and connected on D6 PIN, but has no function yet.

Step 3: Measurement Process

The measurement process is simple. After the intro Screen, the Battery slots will be checked to see if there is a Battery connected, and if yes, it's Voltage will be measured. The check takes a few Seconds, and the Battery discharge Process begins.

Unpopulated Slots will be displayed on the Screen as a cyan Bar. Those Slots where the Battery is located will be displayed in the color scheme you choose (in my case green to red), and on the right side next to the Label of each Battery will be displayed its Voltage and the Capacity measured so far.

As the Battery discharges, it's Voltage drops and when it drops below 2.9V (MIN_VOLTAGE), the measurement process of that Battery is completed, it's MOSFET is turned off, a short Beep sounds and the measured Values will be marked green, showing the Battery Capacity and running Time this Battery was tested, in format (H: min)

As long as the measurement Process of any Batteries in the Slots is running, we can subsequently add another Battery to an empty Slot (if we did not fill all the Slots at the beginning), because the status of empty Slots will be constantly checked.
When the measurement Process of all installed Batteries is completed, the Beeper gives three short signals, and a new measurement can be started only by resetting the Arduino.

Since the Batteries does not discharge with a large Current, the measurement Process takes Hours. For orientation, the Battery with 1660mAh tooks 3:20 Hours, and my "strongest" Battery with a measured Capacity of 2633 mAh tooks over 4:30 Hours.

That would be all ...
If I forgot to describe something or there is something unclear, questions and suggestions are welcome.

I apologize for the "unstable" video, but I don't have a Camera Stand above the Table, so I had to hold the Camera in my Hand

Have Fun ...

Step 4: Update Juni 2023

Some updates are made:

for reference Voltage is used good, old TL431, connected as a 2.5V Zener. In this way, the Ref has stable 2.451V (measured with my DMM) and the Arduino's ADC is much more accurate, because Vref is stable.

Added a function to measure the internal resistance (ISR) of each battery, which helps when pairing batteries for the batterypack.

The ISR measurement is performed when checking the battery. First, the no-load voltage is measured (Voc), after which the MOSFET is turned on for half a second. The voltage of the battery under load is measured (Vload), as well as the current used to discharge the battery (Vload/shunt resistance).

Internal resistance is calculated by formula (Voc - Vload)/I. Displayed values are in miliOhm.

The schematics and measurement procedure remained the same as described before, only TL431 was added