Here is the Arduino code (sorry, the indentation was lost):
Revised 4-8-2014
const int LowCellV = 3200, HiCellV = 4210, LowBatV = 24000; // millivolts
const byte ChargePin = 2, LoadPin = 8, LEDpin = 7;
byte i = 0, j = 0, BalPwm [7];
byte BalOut [7] = {12, 11, 10, 9, 6, 5, 3}; // balance drive pins
int BatV = 0, BotCell = 4300;
long Cal [7] = {4828, 4840, 4828, 4834, 4817, 4834, 4831}; // cell voltage calibration
unsigned int CellV [7];
unsigned long PwmMicros = 0, ReadMillis = 0, Timeout = 0, LedMinis = 0;
boolean Charge = false, Vlimit = false, LED = false;
boolean Warn = false, Balancing = false, Charging = false, Discharge = false;
void setup() {
for (i=0; i < 7; i++) pinMode (BalOut, OUTPUT);
pinMode (2, OUTPUT);
pinMode (4, INPUT);
pinMode (7, OUTPUT);
pinMode (8, OUTPUT);
Serial.begin(9600);
}
void loop() {
if ((millis() - ReadMillis) > 500) { // check cell voltages twice a second
ReadMillis = millis(); // reset 2X per sec timer
if (digitalRead(4) == HIGH) Charge = true; // check for charger voltage
if (digitalRead(4) == LOW) Charge = false;
if (Vlimit == true) {
if (Charge == false) return;
if (LED == false) { // blink LED
LED = true;
digitalWrite(LEDpin, HIGH);
}
else {
LED = false;
digitalWrite(LEDpin, LOW);
}
return;
}
if (Balancing == true) {
for (i=1; i < 7; i++) digitalWrite (BalOut, LOW); // stop balancing
delay(50); // settle down
}
for (i=0; i < 7; i++) CellV = 0; // clear old values
for (j=0; j < 5; j++) { // read cell V 5 times
for (i=0; i < 7; i++) CellV = CellV + analogRead(i) * Cal / 1000;
}
for (i=0; i < 7; i++) CellV = CellV / 5; // average of 5
if (Balancing == true) {
for (i=1; i < 7; i++) analogWrite(BalOut, BalPwm); // resume balancing
}
BatV = CellV[6] * 7; // overall bat voltage
for (i=6; i > 0; i--) CellV = (CellV * (i+1)) - (CellV[i-1] * i); // individual cells
if (Charge == false) { // discharge protection
if (Discharge == false) Discharge = true;
for (i=0; i < 7; i++) { // low cell cutoff
if (CellV < LowCellV) {
Vlimit = true;
digitalWrite(LoadPin, LOW);
return;
}
}
if (BatV < LowBatV) { // LV cutoff
Vlimit = true;
digitalWrite(LoadPin, LOW);
return;
}
if (BatV < (LowBatV + 500)) Warn = true; // LV warning
if (Warn == true) {
if (LED == false) { // blink LED
LED = true;
digitalWrite(LEDpin, HIGH);
}
else {
LED = false;
digitalWrite(LEDpin, LOW);
}
}
digitalWrite(LoadPin, HIGH); // turn on load
return;
} // end of discharge protection
BotCell = 4300;
digitalWrite(LoadPin, LOW); // turn off output for short charge
for (i=0; i < 7; i++) { // check cell voltages
Serial.print(CellV);
Serial.print(" ");
if ((CellV < (LowCellV - 200)) || (CellV > HiCellV) || (((millis() - Timeout) > 12000000UL) && (Balancing == true)) || ((CellV > 4100) && (Discharge == true))) {
// cell V limits, short charge or timeout
Vlimit = true;
for (j=1; j < 7; j++) digitalWrite (BalOut[j], LOW); // stop balancing
BalPwm[0] = 0;
digitalWrite(ChargePin, LOW); // stop charging
digitalWrite(LEDpin, LOW);
LED = false;
return;
}
if (CellV < BotCell) BotCell = CellV; // find lowest cell
if ((CellV > 4100) && (Balancing == false)) { // enable balancing
Balancing = true;
Timeout = millis();
digitalWrite(LEDpin, LOW);
LED = false;
}
}
Serial.println("");
Serial.println(BatV);
if (Charging == false) {
digitalWrite(ChargePin, HIGH); // turn on charge
digitalWrite(LEDpin, HIGH);
LED = true;
Charging = true;
}
if (Balancing == false) return;
for (i=0; i < 7; i++) { // adjust balance currents
if ((BalPwm < 250) && ((CellV - BotCell) > 20)) BalPwm = BalPwm + 10; // turn up high cell balance
if ((BalPwm > 9) && ((CellV - BotCell) < 20)) BalPwm = BalPwm - 10; // turn down low cell balance
if (i > 0) analogWrite(BalOut, BalPwm);
Serial.print(BalPwm);
Serial.print(" ");
}
Serial.println("");
}
if ((BalPwm[0] != 0) && (Vlimit == false)) { // last PWM channel
if ((micros() - PwmMicros) > 4000) { // 4ms cycle time
PwmMicros = micros(); // reset cycle
digitalWrite(12, HIGH);
delayMicroseconds(BalPwm[0] * 15);
digitalWrite(12, LOW);
digitalWrite(LEDpin, HIGH); // dim ON light
delayMicroseconds(800);
digitalWrite(LEDpin, LOW);
}
}
if (((Balancing == true) || (Charge == false)) && (Warn == false) && (BalPwm[0] == 0) && (Vlimit == false)) { // dim ON light
if ((millis() - LedMinis) > 5) { // 5ms cycle time
LedMinis = millis(); // reset cycle
digitalWrite(LEDpin, HIGH);
delay(1);
digitalWrite(LEDpin, LOW);
}
}
}