Lithium batteries are high-performance but fragile. This DIY BMS project walks you through building a cell-level monitoring and balancing system. You'll learn to monitor individual cell voltages (in a 3S or 4S pack) and activate balancing resistors to prevent overcharging.
A BMS serves three primary functions: Protection (disconnecting if a cell is too high/low), Monitoring (reporting state of charge), and Balancing (ensuring all cells stay at the same voltage). This project implements all three for a 3S (11.1V/12.6V) Lithium-Ion pack.
The code detects if Cell A is higher than Cell B. If the difference exceeds 50mV, it activates a transistor that bleeds energy from the higher cell through a power resistor until they are equalized.
Measuring multiple cells in series requires careful common-ground consideration. We use an external 16-bit ADC (ADS1115) for high precision.
| Peripheral | Device Pin | Arduino Pin | Notes |
|---|---|---|---|
| ADS1115 ADC | SDA / SCL | A4 / A5 | I2C Data Bus |
| Cell 1 Balancer | Base | Digital 3 | Triggers Shunt 1 |
| Cell 2 Balancer | Base | Digital 4 | Triggers Shunt 2 |
| Cell 3 Balancer | Base | Digital 5 | Triggers Shunt 3 |
| Master Relay | IN | Digital 7 | Pack Cut-off |
Lithium cells can catch fire if shorted or overcharged. Always perform initial testing with a power-limited supply, keep a sand bucket or fire extinguisher nearby, and never leave your DIY BMS unattended during the first few charge cycles.
#include <Adafruit_ADS1X15.h>
Adafruit_ADS1115 ads;
float cell1, cell2, cell3;
void setup() {
ads.begin();
pinMode(3, OUTPUT); // Balancer 1
pinMode(4, OUTPUT); // Balancer 2
pinMode(5, OUTPUT); // Balancer 3
pinMode(7, OUTPUT); // Main Cut-off
digitalWrite(7, HIGH); // Enable Load
}
void loop() {
cell1 = ads.readADC_SingleEnded(0) * 0.1875 / 1000.0 * 2.0;
cell2 = (ads.readADC_SingleEnded(1) * 0.1875 / 1000.0 * 3.0) - cell1;
cell3 = (ads.readADC_SingleEnded(2) * 0.1875 / 1000.0 * 4.0) - (cell1 + cell2);
// Safety Cut-off
if (cell1 < 3.0 || cell2 < 3.0 || cell3 < 3.0) digitalWrite(7, LOW);
if (cell1 > 4.25 || cell2 > 4.25 || cell3 > 4.25) digitalWrite(7, LOW);
// Simple Passive Balancing
if (cell1 > cell2 + 0.05) digitalWrite(3, HIGH); else digitalWrite(3, LOW);
if (cell2 > cell3 + 0.05) digitalWrite(4, HIGH); else digitalWrite(4, LOW);
delay(1000);
}