bobc
10 kW
PCBs ordered 
#define scale 0.005 // scale trim adjusts reading of lowest cell
#define hicorr 0.0004 // diff trim corrects for difference amp errors
#define adcdel 10 // a few milliseconds for relay to clack and amp to stabilise
#define logginginterval 4000 // data logging time interval in milliseconds
#define Ncells 26 // number of cells
#define balthresh 3.0 // balance down to 3.00V on all cells
#define chargelim 3.4 // charge up to 3.40V on highest voltage cell
float Vcell[Ncells];
int celladc[Ncells];
float cellsum;
float mincell;
float maxcell;
int adcmin;
byte cellid;
void scancells() { // assume selectors all at zero to start
digitalWrite(7, HIGH); // 10000
delay(adcdel);
celladc[16] = analogRead(A0);
digitalWrite(5, HIGH); // 10100
delay(adcdel);
celladc[20] = analogRead(A0);
digitalWrite(7, LOW); // 00100
delay(adcdel);
celladc[4] = analogRead(A0);
digitalWrite(3, HIGH); // 00101
delay(adcdel);
celladc[5] = analogRead(A0);
digitalWrite(7, HIGH); // 10101
delay(adcdel);
celladc[21] = analogRead(A0);
digitalWrite(4, HIGH); // 10111
delay(adcdel);
celladc[23] = analogRead(A0);
digitalWrite(5, LOW); // 10011
delay(adcdel);
celladc[19] = analogRead(A0);
digitalWrite(4, LOW); // 10001
delay(adcdel);
celladc[17] = analogRead(A0);
digitalWrite(6, HIGH); // 11001
delay(adcdel);
celladc[25] = analogRead(A0);
digitalWrite(7, LOW);
digitalWrite(4, HIGH); // 01011
delay(adcdel);
celladc[11] = analogRead(A0);
digitalWrite(3, LOW); // 01010
delay(adcdel);
celladc[10] = analogRead(A0);
digitalWrite(6, LOW); // 00010
delay(adcdel);
celladc[2] = analogRead(A0);
digitalWrite(5, HIGH); // 00110
delay(adcdel);
celladc[6] = analogRead(A0);
digitalWrite(7, HIGH); // 10110
delay(adcdel);
celladc[22] = analogRead(A0);
digitalWrite(5, LOW); // 10010
delay(adcdel);
celladc[18] = analogRead(A0);
digitalWrite(6, HIGH); // 11010
delay(adcdel);
celladc[26] = analogRead(A0);
digitalWrite(4, LOW); // 11000
delay(adcdel);
celladc[24] = analogRead(A0);
digitalWrite(6, LOW); // 01000
delay(adcdel);
celladc[8] = analogRead(A0);
digitalWrite(3, HIGH); // 01001
delay(adcdel);
celladc[9] = analogRead(A0);
digitalWrite(5, HIGH); // 01101
delay(adcdel);
celladc[13] = analogRead(A0);
digitalWrite(3, LOW); // 01100
delay(adcdel);
celladc[12] = analogRead(A0);
digitalWrite(4, HIGH); // 01110
delay(adcdel);
celladc[14] = analogRead(A0);
digitalWrite(3, HIGH); // 01111
delay(adcdel);
celladc[15] = analogRead(A0);
digitalWrite(6, LOW); // 00111
delay(adcdel);
celladc[7] = analogRead(A0);
digitalWrite(5, LOW); // 00011
delay(adcdel);
celladc[3] = analogRead(A0);
digitalWrite(4, LOW); // 00001
delay(adcdel);
celladc[1] = analogRead(A0);
digitalWrite(3, LOW); // 00000
Vcell[1] = celladc[1] * scale;
cellsum = Vcell[1];
mincell = Vcell[1];
maxcell = Vcell[1];
for (int x = 2; x <= Ncells; x++) {
Vcell[x] = celladc[x] * scale + cellsum * hicorr;
cellsum += Vcell[x];
if (Vcell[x] < mincell) {
mincell = Vcell[x];
};
if (Vcell[x] > maxcell) {
maxcell = Vcell[x];
};
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////
void setup() {
// put your setup code here, to run once:
// initialize serial:
Serial.begin(9600); // serial control via the usb uart
Serial.setTimeout(10000); // 10s serial timeout
// set up ports
pinMode(2, OUTPUT); // state LED
pinMode(3, OUTPUT); // cell select LS
pinMode(4, OUTPUT); // cell select bit 1
pinMode(5, OUTPUT); // cell select bit 2
pinMode(6, OUTPUT); // cell select bit 3
pinMode(7, OUTPUT); // cell select MS
InitTimersSafe();
pinMode(13, OUTPUT); // ready relay (also lights LED on arduino)
//initiallise
digitalWrite(2, LOW); // state zero
digitalWrite(3, LOW); // select cell 0
digitalWrite(4, LOW); // select cell 0
digitalWrite(5, LOW); // select cell 0
digitalWrite(6, LOW); // select cell 0
digitalWrite(7, LOW); // select cell 0
digitalWrite(13, LOW); // charger off
//measure cells
analogReference(INTERNAL);
delay(adcdel);
Vcell[1] = analogRead(A0) * scale; // dummy read - sort out adc
Serial.println("scan all cells");
scancells();
if (mincell < balthresh) { // only balance when empty
for (int x = Ncells; x > 0; x--) {
digitalWrite(3, bitRead(x, 0));
digitalWrite(4, bitRead(x, 1));
digitalWrite(5, bitRead(x, 2));
digitalWrite(6, bitRead(x, 3));
digitalWrite(7, bitRead(x, 4));
adcmin = int((balthresh - (cellsum * hicorr))/scale);
cellsum -= Vcell[x];
delay(adcdel);
while (analogRead(A0) > adcmin) {
delay(adcdel);
}
}
}
digitalWrite(3, LOW); // just in case it was left on cell 1...
digitalWrite(13, HIGH); // balanced - start charging
while (maxcell < chargelim) {
scancells(); // check cell voltages
delay(4000);
}
digitalWrite(13, LOW); // full - stop charging
Serial.println("ready for input");
}
void loop() {
}
#define scale 0.0048 // scale trim adjusts reading of lowest cell
#define hicorr 0.0006 // diff trim corrects for difference amp errors
#define adcdel 30 // a few milliseconds for relay to clack and amp to stabilise
#define logginginterval 5000 // data logging time interval in milliseconds
#define Nc 6 // number of cells
#define balthresh 3.5 // balance down to 3.00V on all cells
#define chargelim 3.6 // charge up to 4.10V on highest voltage cell
float Vcell[Nc];
int celladc[Nc];
float cellsum;
float mincell;
float maxcell;
int adcmin;
byte cellid;
//byte mincellid;
void scanfiltcells() { // assume selectors all at zero to start
digitalWrite(5, HIGH); // 00100
delay(adcdel);
celladc[3] = analogRead(A0);
digitalWrite(3, HIGH); // 00101
delay(adcdel);
celladc[4] = analogRead(A0);
digitalWrite(5, LOW); // 00001
delay(adcdel);
celladc[0] = analogRead(A0);
digitalWrite(4, HIGH); // 00011
delay(adcdel);
celladc[2] = analogRead(A0);
digitalWrite(3, LOW); // 00010
delay(adcdel);
celladc[1] = analogRead(A0);
digitalWrite(5, HIGH); // 00110
delay(adcdel);
celladc[5] = analogRead(A0);
digitalWrite(5, LOW); // 00010
digitalWrite(4, LOW); // 00000
Vcell[0] = 0.900 * Vcell[0] + celladc[0] * scale * 0.100;
cellsum = Vcell[0];
mincell = Vcell[0];
maxcell = Vcell[0];
for (int x = 1; x < Nc; x++) {
Vcell[x] = 0.900 * Vcell[x] + celladc[x] * scale * 0.100 + cellsum * hicorr;
cellsum += Vcell[x];
if (Vcell[x] < mincell) {
mincell = Vcell[x];
};
if (Vcell[x] > maxcell) {
maxcell = Vcell[x];
};
}
}
void scancells() { // assume selectors all at zero to start
digitalWrite(5, HIGH); // 00100
delay(adcdel);
celladc[3] = analogRead(A0);
digitalWrite(3, HIGH); // 00101
delay(adcdel);
celladc[4] = analogRead(A0);
digitalWrite(5, LOW); // 00001
delay(adcdel);
celladc[0] = analogRead(A0);
digitalWrite(4, HIGH); // 00011
delay(adcdel);
celladc[2] = analogRead(A0);
digitalWrite(3, LOW); // 00010
delay(adcdel);
celladc[1] = analogRead(A0);
digitalWrite(5, HIGH); // 00110
delay(adcdel);
celladc[5] = analogRead(A0);
digitalWrite(5, LOW); // 00010
digitalWrite(4, LOW); // 00000
Vcell[0] = celladc[0] * scale;
cellsum = Vcell[0];
mincell = Vcell[0];
maxcell = Vcell[0];
for (int x = 1; x < Nc; x++) {
Vcell[x] = celladc[x] * scale + cellsum * hicorr;
cellsum += Vcell[x];
if (Vcell[x] < mincell) {
mincell = Vcell[x];
};
if (Vcell[x] > maxcell) {
maxcell = Vcell[x];
};
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////
void setup() {
// put your setup code here, to run once:
// initialize serial:
Serial.begin(9600); // serial control via the usb uart
Serial.setTimeout(10000); // 10s serial timeout
// set up ports
//pinMode(2, OUTPUT); // state LED
pinMode(3, OUTPUT); // cell select LS
pinMode(4, OUTPUT); // cell select bit 1
pinMode(5, OUTPUT); // cell select bit 2
pinMode(6, OUTPUT); // cell select bit 3
pinMode(7, OUTPUT); // cell select MS
pinMode(11, INPUT); // '0' means enable balance
pinMode(12, OUTPUT); // beef up 12V supply from battery tap b4
pinMode(13, OUTPUT); // charge enable relay (also lights LED on arduino)
//initiallise
//digitalWrite(2, LOW); // state zero
digitalWrite(3, LOW); // select cell 0
digitalWrite(4, LOW); // select cell 0
digitalWrite(5, LOW); // select cell 0
digitalWrite(6, LOW); // select cell 0
digitalWrite(7, LOW); // select cell 0
digitalWrite(12, LOW); // main battery psu backup disabled
digitalWrite(13, LOW); // charger off
//measure cells
analogReference(INTERNAL);
delay(adcdel);
Vcell[0] = analogRead(A0) * scale; // dummy read - sort out adc
// for (int x = 0; x < Nc; x++) {
// Vcell[x] = 3.5;
// }
Serial.println("scan all cells");
scancells();
if (mincell < 3.0) {
mincell = 3.0;
Serial.print("Minimum cell ");
Serial.print(mincell);
Serial.println("V");
}
if ((mincell < balthresh) && (digitalRead(11) == 0)) { // only balance when empty
Serial.println("Do a bottom balance");
digitalWrite(12, HIGH); // 12V supply may need backup
for (int x = Nc-1; x >= 0; x--) {
digitalWrite(3, bitRead(x+1, 0));
digitalWrite(4, bitRead(x+1, 1));
digitalWrite(5, bitRead(x+1, 2));
digitalWrite(6, bitRead(x+1, 3));
digitalWrite(7, bitRead(x+1, 4));
adcmin = int((mincell - (cellsum * hicorr))/scale);
cellsum -= Vcell[x];
delay(adcdel);
Serial.print("cell ");
Serial.print(x+1);
Serial.print(" voltage ");
Serial.print(Vcell[x]);
Serial.print("V ; discharge to ADC value ");
Serial.println(adcmin);
while (analogRead(A0) > adcmin) {
delay(adcdel);
}
}
digitalWrite(12, LOW); // 12V backup off
}
digitalWrite(3, LOW); // just in case it was left on cell 1...
digitalWrite(13, HIGH); // balanced - start charging
Serial.println("Charging started");
while (maxcell < chargelim) {
delay(logginginterval);
scanfiltcells(); // check cell voltages
for (int x = 0; x < Nc; x++) {
Serial.print("cell ");
Serial.print(x+1);
Serial.print(" voltage ");
Serial.print(Vcell[x]);
Serial.print("V ");
Serial.println(celladc[x]);
}
Serial.print("cell sum ");
Serial.print(cellsum);
Serial.print(" min cell ");
Serial.print(mincell);
Serial.print(" max cell ");
Serial.println(maxcell);
}
digitalWrite(13, LOW); // full - stop charging
for (int x = 0; x < Nc; x++) {
Serial.print("cell ");
Serial.print(x+1);
Serial.print(" voltage ");
Serial.print(Vcell[x]);
Serial.println("V");
}
Serial.println("Charging terminated");
}
void loop() {
while (Serial.available() > 0) {
int cellid = Serial.parseInt();
// look for the newline. then use the number to select a cell
if (Serial.read() == '\n') {
scancells();
if (cellid <= Nc) {
for (int x = 0; x < Nc; x++) {
Serial.print("cell ");
Serial.print(x+1);
Serial.print(" voltage ");
Serial.print(Vcell[x]);
Serial.print("V adc reading ");
Serial.println(celladc[x]);
}
Serial.println(" ");
Serial.print("Discharging cell ");
Serial.println(cellid);
digitalWrite(3, bitRead(cellid, 0));
digitalWrite(4, bitRead(cellid, 1));
digitalWrite(5, bitRead(cellid, 2));
digitalWrite(6, bitRead(cellid, 3));
digitalWrite(7, bitRead(cellid, 4));
}
}
}
}