I have retrieved some old laptop batteries to use in my projects. But it is going so difficult to identify the right one in the battery pack. Earlier in one of my previous battery testers instructable, I discussed how you can identify good cells by measuring their voltages. But this method is not at all reliable. So I wanted to find a way where we can measure each cell’s exact capacity instead of their voltages. In a previous article, we have already built an IoT-based Battery Monitoring System. Also, check out this.
This project is so simple, that it relies on Ohms Law. None of that DIY projects can be 100% accurate, so this Battery Capacity Tester is also not perfect. But it gives reasonable outputs that can be used and compared with other batteries, so you can easily identify good cells in an old battery pack.
While building this project, I realized that there are a lot of things that can be improved. In the future, I will try to implement those things. But for the time being, I am happy with it. I hope this little tester will be useful, so I am sharing it with you all.
Please be aware of working with a Li-ion battery that is highly explosive and dangerous. I am not responsible for any loss of property damage, or life risk. This project was demonstrated for those who have a bit of knowledge of rechargeable lithium-ion technology. Please do not attempt this if you are an unknown.
Circuit Diagram

Components Required
- Arduino Nano
- 128*64 OLED I2C Display
- IRLZ44N MOSFET (Please note that the IRFZ44N mentioned above is wrong in the schematic)
- 10KΩ Resistor (x4)
- Lithium-Ion Battery Holder
- Lithium-Ion Battery (Which will be tested)
- Buzzer
- Breadboard
- 9 Volt Battery
About Parts of Battery Capacity Tester
IRLZ44N MOSFET
Here MOSFET acts like a switch. The digital output from the Arduino pin D2 controls the switch. When a 5V (Digital HIGH) signal is fed to the gate of the MOSFET, it allows the current to flow from the positive terminal of the battery, through the resistor, and the MOSFET then completes the path back to the negative terminal. It discharges the battery over a period of time. So the MOSFET should be chosen in such a way that it can handle maximum discharge current without overheating.
I used an n-channel logic level power MOSFET, IRLZ44. The L shows that it is a logic-level MOSFET. A logic-level MOSFET means that it is designed to turn on fully from the logic level of a microcontroller. The standard MOSFET (IRF series etc) is designed to run from 10V.
If you use an IRF series MOSFET, then it will not fully turn ON by applying 5V from Arduino. I mean the MOSFET will not carry the rated current. To turn ON these MOSFETs you need an additional circuit to boost the gate voltage.
So I will recommend using a logic-level MOSFET, not necessarily IRLZ44. You can use any other MOSFET also.
PCB Design
After designing the schematic diagram of the Battery Capacity Tester, the assembled components and wiring are too clumsy and looked very unprofessional. In fact, the wiring also has a chance of loose connection. To give it a clean and professional look and also to compress the size, I decided to build its PCB prototype using EasyEDA software as it is so simple to use. Now come to the main part, where we need to order our PCB prototype. I always prefer PCBWay for their quality assurance, fastest delivery and also for 24/7 customer support.
PCB View


I’ve done several runs with PCBWay and am happy with the results, it’s good quality. It is one of the most experienced PCB manufacturing companies based in China with an experience of more than a decade in the field of PCB prototype and fabrication. PCBWay has always been committed to technological innovation and meeting the needs of their customers from different industries in terms of quality, delivery, cost-effectiveness and any other demanding requests. The etching, solder mask, and hole sizes are all done well and that is what matters to me. It takes a few hours for a design to get approved and then a couple of days to finish and ship.
With more than a decade in the field of PCB prototypes and fabrication, PCBWay has proved its assurance from time to time. They always look at the customer’s needs from different regions in terms of quality, on-time delivery, cost-effectiveness and any other demanding requests.


These PCBs were manufactured by PCBWay and the finish quality really impressive, especially with the gold finish path. If you want to finish your product faster you could also ask PCBWay to make a panelized order where you receive multiple PCBs in a single panel. With this, you will also receive SMT Stencil from PCBWay, saving you time and effort. All the orders are high quality and could select a lot of settings such as thickness, flexible PCB, the colour of the solder masks, the number of layers, material, surface finish and more.
Working Principle of Arduino Battery Capacity Tester
Here we used an Arduino Nano which is the main processing unit of this whole circuit working.
After giving the power, Arduino checks the condition if the battery is good or dead. Then it gives the switch ON command to the MOSFET. It generally allows the current to flow from the positive terminal of the battery, through the resistor, and the MOSFET then completes the circuit back to the negative terminal. This process discharges the battery over a period of time.
The Arduino measures the Analog voltage across the load resistor and then divided it by the resistance to find out the discharge current. Then multiplied the value by the time to obtain the exact milliamp-hour value which is the battery capacity value which we want to know.
How to Measure Voltage, Current and Capacity?
Voltage Measurement
We have to find the voltage across the load resistor. The voltages are measured by using two voltage divider circuits. It consists of two resistors with values of 10KΩ each. The output from the divider is connected to Arduino Analog pins A0 and A1.
Arduino Analog pin can measure voltage up to 5V, in our case the maximum voltage is 4.2V (fully charged). Then you may ask, why I am using two dividers unnecessarily. The reason is that my future plan is to use the same tester for the multi-chemistry battery. So this design can be adapted easily to achieve my goal.
Current Measurement
Current (I) = Voltage ( V ) – Voltage drop across the MOSFET / Resistance (R)
Note: I am assuming the voltage drop across the MOSFET is negligible.
Here, V = Voltage across the load resistor and R = 10 Ohm
The result obtained is in amperes. Multiply 1000 to convert it into milliamperes.
So maximum discharge current = 4.2 / 10 = 0.42A = 420mA
Capacity Measurement
Stored Charge ( Q ) = Current ( I ) x Time ( T ).
We have already calculated the current, the only unknown in the above equation is time. The millis() function in Arduino can be used to measure the elapsed time.
Arduino Code for Battery Capacity Tester
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | #include "U8glib.h" #define MOSFET_Pin 2 #define Bat_Pin A0 #define Res_Pin A1 #define Buzzer_Pin 9 U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_NONE); // I2C / TWI float Capacity = 0.0; // Capacity in mAh float Res_Value = 10.0; // Resistor Value in Ohm float Vcc = 4.64; // Voltage of Arduino 5V pin ( Mesured by Multimeter ) float Current = 0.0; // Current in Amp float mA=0; // Current in mA float Bat_Volt = 0.0; // Battery Voltage float Res_Volt = 0.0; // Voltage at lower end of the Resistor float Bat_High = 4.3; // Battery High Voltage float Bat_Low = 2.9; // Discharge Cut Off Voltage unsigned long previousMillis = 0; // Previous time in ms unsigned long millisPassed = 0; // Current time in ms float sample1 =0; float sample2= 0; int x = 0; int row = 0; //************************ OLED Display Draw Function ******************************************************* void draw(void) { u8g.setFont(u8g_font_fub14r); // select font if ( Bat_Volt < 1){ u8g.setPrintPos(10,40); // set position u8g.println("No Battery!"); } else if ( Bat_Volt > Bat_High){ u8g.setPrintPos(25,40); // set position u8g.println("High-V!"); } else if(Bat_Volt < Bat_Low){ u8g.setPrintPos(25,40); // set position u8g.println("Low-V!"); } else if(Bat_Volt >= Bat_Low && Bat_Volt < Bat_High ){ u8g.drawStr(0, 20, "Volt: "); // put string of display at position X, Y u8g.drawStr(0, 40, "Curr: "); u8g.drawStr(0, 60, "mAh: "); u8g.setPrintPos(58,20); // set position u8g.print( Bat_Volt,2); // display Battery Voltage in Volt u8g.println("V"); u8g.setPrintPos(58,40); // set position u8g.print( mA,0); // display current in mA u8g.println("mA"); u8g.setPrintPos(58, 60); // set position u8g.print( Capacity ,1); // display capacity in mAh } } //******************************Buzzer Beep Function ********************************************************* void beep(unsigned char delay_time){ analogWrite(9, 20); // PWM signal to generate beep tone delay(delay_time); // wait for a delayms ms analogWrite(Buzzer_Pin, 0); // 0 turns it off delay(delay_time); // wait for a delayms ms } //*******************************Setup Function *************************************************************** void setup() { Serial.begin(9600); pinMode(MOSFET_Pin, OUTPUT); pinMode(Buzzer_Pin, OUTPUT); digitalWrite(MOSFET_Pin, LOW); // MOSFET is off during the start Serial.println("CLEARDATA"); Serial.println("LABEL,Time,Bat_Volt,capacity"); //Serial.println("Arduino Battery Capacity Tester v1.0"); //Serial.println("BattVolt Current mAh"); } //********************************Main Loop Function*********************************************************** void loop() { // Vcc = readVcc()/1000.0; // Conevrrt mV to Volt // Voltage devider Out = Bat_Volt * R2/(R1+R2 ) // R1 =10K and R2 =10K //************ Measuring Battery Voltage *********** for(int i=0;i< 100;i++) { sample1=sample1+analogRead(Bat_Pin); //read the voltage from the divider circuit delay (2); } sample1=sample1/100; Bat_Volt = 2* sample1 *Vcc/ 1024.0; // ********* Measuring Resistor Voltage *********** for(int i=0;i< 100;i++) { sample2=sample2+analogRead(Res_Pin); //read the voltage from the divider circuit delay (2); } sample2=sample2/100; Res_Volt = 2* sample2 * Vcc/ 1024.0; //********************* Checking the different conditions ************* if ( Bat_Volt > Bat_High){ digitalWrite(MOSFET_Pin, LOW); // Turned Off the MOSFET // No discharge beep(200); Serial.println( "Warning High-V! "); delay(1000); } else if(Bat_Volt < Bat_Low){ digitalWrite(MOSFET_Pin, LOW); beep(200); Serial.println( "Warning Low-V! "); delay(1000); } else if(Bat_Volt > Bat_Low && Bat_Volt < Bat_High ) { // Check if the battery voltage is within the safe limit digitalWrite(MOSFET_Pin, HIGH); millisPassed = millis() - previousMillis; Current = (Bat_Volt - Res_Volt) / Res_Value; mA = Current * 1000.0 ; Capacity = Capacity + mA * (millisPassed / 3600000.0); // 1 Hour = 3600000ms previousMillis = millis(); Serial.print("DATA,TIME,"); Serial.print(Bat_Volt); Serial.print(","); Serial.println(Capacity); row++; x++; delay(4000); } //************************************************** u8g.firstPage(); do { draw(); } while( u8g.nextPage() ); //************************************************* } |