/*
CHARGER for 2S Lipo battery
by Marco Zonca, 2022
This sketch works as 2S LiPo Charger, originally made for Autopilot2 for small sailing boats
Arduino Nano as MCU, 3 relais, LM317, ua7812, 3 Thermistors TMP36, DAC module, 2 fuses, 4 BC337 NPN, 5W ceramic resistor, 2 RGB LED,
resistors and capacitors, Buzzer, JST connectors, Cooling Fan, Bluetooth HC-05, etc.;
/*
WARNING: before switching Relais2 ON or OFF,
switch OFF Relais1 first, then Relais2, then Relais1 ON again if necessary;
This circuit KEEPS SEPARATED the battery ground from any other ground because during balanced charging
the pins Cells, (-) and (+), are necessarily switched from one CELL to another, and inverted polarity at common wire!
LETS CONNECT the load only by the way of X1-LOAD connector; the X1-LOAD power is automatically full disconnected when charging (both wires (-) and (+))
*/
#include <Wire.h>
#include <Adafruit_MCP4725.h>
Adafruit_MCP4725 DAC;
//--------------------------------------------------Charging constant Values
const float CBatt = 2.600; // put here the battery power A/h
const float VCmin = 3.20; // absolute minimum cell Voltage
const float VCMax = 4.22; // absolute max cell voltage
const float VCfinalize = 4.18; // finalize charging cell voltage (after this it will charge at fixed voltage and limited current)
const float VCchgd = 4.18; // already charged cell voltage (skip charging)
const float ETAdd = 60; // additionally time in minutes for charging (finalize)
const float ETFact = 1.20; // coefficent estimated charging time (plus additionally ETAdd)
const float ETFactAlarm = 2.00; // coefficent estimated charging time sets Alarm too (plus additionally ETAdd)
const float CellChgCurrent = CBatt/5; // charging current 1/5 of battery (cell) A/h i.e. 2.600 / 5 = 0.520 A
const float CellFinalizeCurrent = CellChgCurrent / 100 * 20; // % of charging current in finalizing mode, if below then stop charging (see VCfinalize)
const float CellSlowDownCurrent = CellChgCurrent / 100 * 50; // % of charging current in slow down mode (LM317 or uA7812 or Battery high temperature)
const float VPower = 5.0; // max DAC voltage
const byte HighTRegH = 60; // LM317 or uA7812 high (threshold H) temperature C
const byte HighTRegL = 50; // LM317 or uA7812 high (threshold L) temperature C
const byte HighTBatH = 40; // battery high (threshold H) temperature C
const byte HighTBatL = 30; // battery high (threshold L) temperature C
const byte FanTRHigh = 55; // Fan (threshold H) LM317 or uA7812 temperature C
const byte FanTRLow = 45; // Fan (threshold L) LM317 or uA7812 temperature C
const byte FanTBHigh = 36; // Fan (threshold H) battery temperature C
const byte FanTBLow = 32; // Fan (threshold L) battery temperature C
const byte RegulatorTAlarm = 70; // regulators TC alarm (STOP charging)
const byte BatteryTAlarm = 45; // battery TC alarm (STOP charging)
//--------------------------------------------------Charging constant Values
const byte Relais1ConnectCellsPin = 2;
const byte Relais2SwitchCellsPin = 3;
const byte RGBledBluePin[3] = {0,4,6};
const byte RGBledRedPin[3] = {0,5,7};
const byte FanPWMPin = 9;
const byte VcellPin = 14;
const byte VoutPin = 15;
const byte BuzzerPin = 16;
const byte TMP36_BatteryPin = 17;
const byte TMP36_7812Pin = 20;
const byte TMP36_317Pin = 21;
const byte Set_OFF = LOW;
const byte Set_ON = HIGH;
const int PrintDebugInterval = 4000;
const int CheckChargeInterval = 10000;
const byte DAC_Address = 0x60;
const float DAC_InitialV = 3.0; // charger Volt to cell (it is an initial/parking value, should not charge at this value!)
const boolean IsDEBUG = true; // set this as TRUE for Serial Monitor debug data output
const float Rload = 0.47; // shunt resistor
boolean IsCharging = false;
boolean IsOverTime = false;
boolean IsAlreadyCharged = false;
boolean IsSlowDown = false;
boolean IsALARM = false;
byte PhaseNr = 0;
byte WhichCellIsOn = 0;
byte WhichFanSpeedIsOn = 0;
int FanSpeed[3] = {255*0/100, 255*90/100, 255*100/100}; // % of max speed, 0% normal TC, 90% high TC, 100% ALARM
float TempBattery = 0;
float Temp7812 = 0;
float Temp317 = 0;
float Vcell = 0;
float Voutput = 0;
float Vload = 0;
float Aload = 0;
float SetVOutput = 0;
float SetDAC = 0;
float TFull = 0; // estimated charge time in minutes
float TRemain[3] = {0,0,0}; // estimated remaining time of charging in minutes
float TScale = 0; // time ETAdd reduction factor
float C_OverTime[3] = {0,0,0}; // estimated time of charging in minutes
float C_AlarmTime[3] = {0,0,0}; // estimated time of charging in minutes sets Alarm
float SoC[3] = {0,0,0}; // state of charge in %
float VInitCell[3] = {0,0,0}; // initial charging cell voltage
float VFinalCell[3] = {0,0,0}; // final charging cell voltage
unsigned long lastPrintDebugMillis = 0;
unsigned long lastCheckChargeMillis = 0;
unsigned long ChTimeStart[3] = {0,0,0}; // charging start time, time elapsed as minutes from power-up
unsigned long ChTimeEnd[3] = {0,0,0}; // charging start time, time elapsed as minutes from power-up
unsigned long ChTimeNow = 0; // now time, time elapsed as minutes from power-up
void setup() {
if (IsDEBUG) Serial.begin(38400); // output both serial monitor & bluetooth HC-05
DAC.begin(DAC_Address);
pinMode(RGBledBluePin[1], OUTPUT);
pinMode(RGBledRedPin[1], OUTPUT);
pinMode(RGBledBluePin[2], OUTPUT);
pinMode(RGBledRedPin[2], OUTPUT);
pinMode(TMP36_BatteryPin, INPUT);
pinMode(TMP36_7812Pin, INPUT);
pinMode(TMP36_317Pin, INPUT);
pinMode(VcellPin, INPUT);
pinMode(VoutPin, INPUT);
pinMode(Relais1ConnectCellsPin,OUTPUT);
pinMode(Relais2SwitchCellsPin,OUTPUT);
pinMode(BuzzerPin,OUTPUT);
pinMode(FanPWMPin,OUTPUT);
DisconnectAllCells();
WriteDACVOutput(DAC_InitialV);
buzzerBips(1);
ledShow();
}//setup()
void loop() {
readTemperatures();
readVAvalues();
if ((IsDEBUG) && (lastPrintDebugMillis + PrintDebugInterval) < millis()) serialPrintDebug();
if (IsALARM==false) {
if ((lastCheckChargeMillis + CheckChargeInterval) < millis()) checkCharge();
if (WhichCellIsOn) display();
} else { // ALARM
if (WhichCellIsOn) DisconnectAllCells();
display();
buzzerBips(5);
}//IsALARM
}//loop()
void checkCharge() { // ----------------------------------------------------------------------------------- start, charge or skip, finish
float ri = 0;
float current = 0;
float c = 0;
TFull = roundZeroDec(CBatt / CellChgCurrent) * 60;
current=CellChgCurrent;
if (IsSlowDown == true) { // limiting current during high TC
TFull = roundZeroDec(CBatt / CellSlowDownCurrent) * 60;
current=CellSlowDownCurrent;
}
if (Vcell > VCfinalize) {
TFull = roundZeroDec(CBatt / CellFinalizeCurrent) * 60;
TScale=(((Aload - CellFinalizeCurrent) * 100) / (current - CellFinalizeCurrent)) / 100;
} else {
TScale=1;
}
if (IsCharging == true) { // ----------------------------------------------------- charging
if (Vcell > VCMax) { // ======== stop charging, over VCMax...
ChTimeEnd[WhichCellIsOn]=roundZeroDec(((millis()/1000)/60)+1);
VFinalCell[WhichCellIsOn]=Vcell; // final cell voltage
DisconnectAllCells();
WriteDACVOutput(DAC_InitialV);
IsCharging=false;
if (PhaseNr==1) buzzerBips(2);
if (PhaseNr==2) buzzerBips(3);
if (IsDEBUG) Serial.println("STOP, over VCMax...");
} else {
if (Vcell <= VCfinalize) { // ========== tuning, fixed current
for (ri=(SetVOutput - 0.06);ri=ri+0.02;ri<VPower) { // increment DAC voltage till reaching "current"
WriteDACVOutput(ri);
readVAvalues();
if (IsDEBUG) serialPrintChg("TUNE");
if ((Aload >= current) || (Vcell>=(VCMax - 0.02))) break;
}
}//IfVcell<=Finalize
if (Vcell > VCfinalize) { // ============ finalize, fixed voltage and limited current
for ((ri=SetVOutput - 0.03);ri=ri+0.01;ri<=VCMax) { // increment DAC voltage till reaching "VCMax-0.02"
WriteDACVOutput(ri);
readVAvalues();
if (IsDEBUG) serialPrintChg("FINAL");
if ((Aload >= current) || (Vcell>=(VCMax - 0.02))) break;
}
if (Aload < CellFinalizeCurrent) { // === stop charging, below finalizing current, perfect
ChTimeEnd[WhichCellIsOn]=roundZeroDec(((millis()/1000)/60)+1);
VFinalCell[WhichCellIsOn]=Vcell; // final cell voltage
DisconnectAllCells();
WriteDACVOutput(DAC_InitialV);
IsCharging=false;
if (PhaseNr==1) buzzerBips(2);
if (PhaseNr==2) buzzerBips(3);
if (IsDEBUG) Serial.println("END, current finalized");
}
}//IfVcell>=Finalize
}//ifVCell>=VCMax
}//IfIsCharging==true
if (IsCharging == false) { // ----------------------------------------------------- phase and start
if (PhaseNr < 2) { // =============== switch Cell -> 1 -> 2
PhaseNr++;
ConnectCell_N(PhaseNr);
readVAvalues();
if (Vcell >= VCchgd) {
IsAlreadyCharged=true;
} else {
IsAlreadyCharged=false;
}
IsOverTime=false;
if (IsAlreadyCharged == false) { // ================ start charging, fixed current
ChTimeStart[WhichCellIsOn]=roundZeroDec(((millis()/1000)/60)+1);
VInitCell[WhichCellIsOn]=Vcell; // initial cell voltage
C_OverTime[WhichCellIsOn] = roundZeroDec(((((CBatt / CellChgCurrent) * 60) * (VCMax - 0.02 - VInitCell[WhichCellIsOn])) * ETFact) + ETAdd); // estimated maximum time of charging
C_AlarmTime[WhichCellIsOn] = roundZeroDec(((((CBatt / CellChgCurrent) * 60) * (VCMax - 0.02 - VInitCell[WhichCellIsOn])) * ETFactAlarm) + ETAdd); // estimated maximum time of charging then setes Alarm
for (ri=Vcell;ri=ri+0.02;ri<VPower) { // increment DAC voltage till reaching "current"
WriteDACVOutput(ri);
readVAvalues();
if (IsDEBUG) serialPrintChg("START");
if ((Aload >= current) || (Vcell>=(VCMax-0.02))) break;
}
IsCharging=true;
} else {
ChTimeStart[WhichCellIsOn]=roundZeroDec(((millis()/1000)/60)+1); // ======== charging not necessary, already charged...
VInitCell[WhichCellIsOn]=Vcell; // initial cell voltage
C_OverTime[WhichCellIsOn] = roundZeroDec(((((CBatt / CellChgCurrent) * 60) * (VCMax - 0.02 - VInitCell[WhichCellIsOn])) * ETFact) + ETAdd); // estimated maximum time of charging
C_AlarmTime[WhichCellIsOn] = roundZeroDec(((((CBatt / CellChgCurrent) * 60) * (VCMax - 0.02 - VInitCell[WhichCellIsOn])) * ETFactAlarm) + ETAdd); // estimated maximum time of charging then sets Alarm
ChTimeEnd[WhichCellIsOn]=roundZeroDec(((millis()/1000)/60)+1);
VFinalCell[WhichCellIsOn]=Vcell; // final cell voltage
display();
DisconnectAllCells();
WriteDACVOutput(DAC_InitialV);
if (PhaseNr==1) buzzerBips(2);
if (PhaseNr==2) buzzerBips(3);
if (IsDEBUG) Serial.println("END, already charged");
}//IsAlreadyCharged==false
}//IfPhase<2
}//IsCharging==false
if (WhichCellIsOn) {
SoC[WhichCellIsOn] = roundZeroDec(100 - ((VCMax - 0.02 - Vcell) * 100)); // state of charge in %
ChTimeNow=roundZeroDec(((millis()/1000)/60)+1); // now time as minutes from power-up +1
if ((ChTimeNow-ChTimeStart[WhichCellIsOn]) > C_OverTime[WhichCellIsOn]) IsOverTime=true;
if ((ChTimeNow-ChTimeStart[WhichCellIsOn]) > C_AlarmTime[WhichCellIsOn]) IsALARM=true;
TRemain[WhichCellIsOn] = roundZeroDec(((TFull * (VCMax - 0.02 - Vcell)) * ETFact) + (ETAdd * TScale)); // estimated remaining time of charging in minutes
}
lastCheckChargeMillis=millis();
}//checkCharge()
void buzzerBips(byte n) {
byte q=0;
for (q=1;q<=n;q++) {
digitalWrite(BuzzerPin, HIGH);
delay(100);
digitalWrite(BuzzerPin, LOW);
delay(100);
}
}//buzzerBips()
/*
WARNING: before switching Relais2 ON or OFF,
switch OFF Relais1 first, then Relais2, then Relais1 ON again if necessary;
This circuit KEEPS SEPARATED the battery ground from any other ground because during balanced charging
the pins Cells, (-) and (+), are necessarely switched from one CELL to another, and inverted polarity at common wire!
*/
void DisconnectAllCells() { // ------------------------------ disconnect Cells by Relais
digitalWrite(Relais1ConnectCellsPin, Set_OFF);
delay(1000);
digitalWrite(Relais2SwitchCellsPin, Set_OFF);
delay(1000);
WhichCellIsOn = 0;
}//DisconnectAllCells()
void ConnectCell_N(byte c) { // ----------------------------- connect Cell by Relais
switch (c) {
case 1:
digitalWrite(Relais1ConnectCellsPin, Set_OFF);
delay(1000);
digitalWrite(Relais2SwitchCellsPin, Set_OFF);
delay(1000);
digitalWrite(Relais1ConnectCellsPin, Set_ON);
delay(1000);
break;
case 2:
digitalWrite(Relais1ConnectCellsPin, Set_OFF);
delay(1000);
digitalWrite(Relais2SwitchCellsPin, Set_ON);
delay(1000);
digitalWrite(Relais1ConnectCellsPin, Set_ON);
delay(1000);
break;
}
WhichCellIsOn = c;
}//ConnectCell_N()
void WriteDACVOutput(float v) { // ------------------------- write DAC
SetVOutput = v;
SetDAC = ((SetVOutput - 1.25 + 0.75) * (4095.0 / 5.0)); // (Vdac - VdacADD + Vdiod) * (Res / Vref)
DAC.setVoltage(SetDAC, false);
delay(1000);
}//WriteDACVOutput()
void display() { // ---------------------------------------- display LED status
digitalWrite(RGBledBluePin[WhichCellIsOn],LOW);
digitalWrite(RGBledRedPin[WhichCellIsOn],LOW);
if (IsALARM==true) {
blink_redALARM();
} else {
if (IsAlreadyCharged==false) {
if ((IsCharging==true)) {
if (IsOverTime==false) {
if (SoC[WhichCellIsOn] <= 20) blink_red();
if (SoC[WhichCellIsOn] > 20 && SoC[WhichCellIsOn] <=40) blink_red_purple();
if (SoC[WhichCellIsOn] > 40 && SoC[WhichCellIsOn] <=60) blink_purple();
if (SoC[WhichCellIsOn] > 60 && SoC[WhichCellIsOn] <=80) blink_purple_blue();
if (SoC[WhichCellIsOn] > 80 && SoC[WhichCellIsOn] <=90) blink_blue();
if (SoC[WhichCellIsOn] > 90) blink_slowblue();
} else {
blink_quickblue(); //overtime warning
}//over
} else {
steady_red(); //deciding what to do
}//charging
} else {
steady_blue(); //charged
}//already
}//IsALARM
}//display()
void readVAvalues() { // ---------------------------------- read V, A, values
float n=0;
float s=0;
float VCmem=0;
float VOmem=0;
int x=0;
for (x=1;x<=100;x++) { // x nr. of readings as average filter
n = analogRead(VcellPin);
s = ((5.0 * n) / 1023); // from cell
VCmem=VCmem+s;
n = analogRead(VoutPin);
s = ((5.0 * n) / 1023); // from LM317
VOmem=VOmem+s;
}
s=(VCmem/(x-1));
Vcell = (s + ((s * 1.40) /100)); // +- % arbitrary correction (not active if = 0.00)
Vcell = roundThreeDec(Vcell);
s=(VOmem/(x-1));
Voutput = (s + ((s * 1.40) /100)); // +- % arbitrary correction (not active if = 0.00)
Voutput = roundThreeDec(Voutput);
s=(Voutput-Vcell);
Vload = roundThreeDec(s);
n=(Vload/Rload);
Aload = roundThreeDec(n);
}//readVAvalues()
void readTemperatures() { // --------------------------------- read temperatures
int n=0;
n = analogRead(TMP36_BatteryPin);
TempBattery = (((5.0 * n) / 1023) - 0.500 ) * 100; // (-500mV=offset) 0 to 500 = below zero values
TempBattery = roundZeroDec(TempBattery);
n = analogRead(TMP36_7812Pin);
Temp7812 = (((5.0 * n) / 1023) - 0.500 ) * 100;
Temp7812 = roundZeroDec(Temp7812);
n = analogRead(TMP36_317Pin);
Temp317 = (((5.0 * n) / 1023) - 0.500 ) * 100;
Temp317 = roundZeroDec(Temp317);
if ((Temp7812 < HighTRegL) && (Temp317 < HighTRegL) && (TempBattery < HighTBatL)) { // current
IsSlowDown = false; // will normal chg current
}
if ((Temp7812 > HighTRegH) || (Temp317 > HighTRegH) || (TempBattery > HighTBatH)) {
IsSlowDown = true; // will decrease chg current
}
if (IsALARM==false) {
if ((Temp7812 < FanTRLow) && (Temp317 < FanTRLow) && (TempBattery < FanTBLow)) { // fan
analogWrite(FanPWMPin, FanSpeed[0]); // Fan normal temperatures
WhichFanSpeedIsOn=FanSpeed[0];
}
if ((Temp7812 > FanTRHigh) || (Temp317 > FanTRHigh) || (TempBattery > FanTBHigh)) {
analogWrite(FanPWMPin, FanSpeed[1]); // Fan high temperatures
WhichFanSpeedIsOn=FanSpeed[1];
}
if ((Temp7812 > RegulatorTAlarm) || (Temp317 > RegulatorTAlarm) || (TempBattery > BatteryTAlarm)) { // ALARM
IsALARM = true; // will STOP charging etc.
analogWrite(FanPWMPin, FanSpeed[2]); // Fan ALARM temperatures
WhichFanSpeedIsOn=FanSpeed[2];
}
} else {
analogWrite(FanPWMPin, FanSpeed[2]); // Fan ALARM
WhichFanSpeedIsOn=FanSpeed[2];
}
}//readTemperatures()
void blink_red() { // ----------------------------------------- led
delay(500);
digitalWrite(RGBledRedPin[WhichCellIsOn], HIGH);
}
void blink_redALARM() {
digitalWrite(RGBledRedPin[1], LOW);
digitalWrite(RGBledRedPin[2], LOW);
digitalWrite(RGBledBluePin[1], LOW);
digitalWrite(RGBledBluePin[2], LOW);
delay(100);
digitalWrite(RGBledRedPin[1], HIGH);
delay(100);
digitalWrite(RGBledRedPin[1], LOW);
digitalWrite(RGBledRedPin[2], HIGH);
delay(100);
}
void blink_blue() {
delay(500);
digitalWrite(RGBledBluePin[WhichCellIsOn], HIGH);
delay(500);
}
void blink_purple() {
delay(500);
digitalWrite(RGBledRedPin[WhichCellIsOn], HIGH);
digitalWrite(RGBledBluePin[WhichCellIsOn], HIGH);
delay(500);
}
void blink_red_purple() {
delay(500);
digitalWrite(RGBledRedPin[WhichCellIsOn], HIGH);
delay(1000);
digitalWrite(RGBledBluePin[WhichCellIsOn], HIGH);
delay(500);
}
void blink_purple_blue() {
delay(500);
digitalWrite(RGBledRedPin[WhichCellIsOn], HIGH);
digitalWrite(RGBledBluePin[WhichCellIsOn], HIGH);
delay(1000);
digitalWrite(RGBledRedPin[WhichCellIsOn], LOW);
digitalWrite(RGBledBluePin[WhichCellIsOn], HIGH);
delay(500);
}
void blink_slowblue() {
delay(1000);
digitalWrite(RGBledBluePin[WhichCellIsOn], HIGH);
delay(2000);
}
void blink_quickblue() {
delay(100);
digitalWrite(RGBledBluePin[WhichCellIsOn], HIGH);
delay(100);
}
void steady_blue() {
digitalWrite(RGBledBluePin[WhichCellIsOn], HIGH);
}
void steady_red() {
digitalWrite(RGBledRedPin[WhichCellIsOn], HIGH);
}
void ledShow() { // -------------------------------------------- initial show & Fan
digitalWrite(RGBledBluePin[1], HIGH);
digitalWrite(RGBledRedPin[1], LOW);
digitalWrite(RGBledBluePin[2], LOW);
digitalWrite(RGBledRedPin[2], LOW);
delay(500);
digitalWrite(RGBledBluePin[1], HIGH);
digitalWrite(RGBledRedPin[1], HIGH);
digitalWrite(RGBledBluePin[2], LOW);
digitalWrite(RGBledRedPin[2], LOW);
delay(500);
digitalWrite(RGBledBluePin[1], LOW);
digitalWrite(RGBledRedPin[1], HIGH);
digitalWrite(RGBledBluePin[2], LOW);
digitalWrite(RGBledRedPin[2], LOW);
delay(500);
digitalWrite(RGBledBluePin[1], LOW);
digitalWrite(RGBledRedPin[1], LOW);
digitalWrite(RGBledBluePin[2], HIGH);
digitalWrite(RGBledRedPin[2], LOW);
delay(500);
digitalWrite(RGBledBluePin[1], LOW);
digitalWrite(RGBledRedPin[1], LOW);
digitalWrite(RGBledBluePin[2], HIGH);
digitalWrite(RGBledRedPin[2], HIGH);
delay(500);
digitalWrite(RGBledBluePin[1], LOW);
digitalWrite(RGBledRedPin[1], LOW);
digitalWrite(RGBledBluePin[2], LOW);
digitalWrite(RGBledRedPin[2], HIGH);
delay(500);
digitalWrite(RGBledBluePin[1], LOW);
digitalWrite(RGBledRedPin[1], HIGH);
digitalWrite(RGBledBluePin[2], LOW);
digitalWrite(RGBledRedPin[2], HIGH);
analogWrite(FanPWMPin, FanSpeed[1]); // Fan high temperatures test
delay(5000);
analogWrite(FanPWMPin, FanSpeed[0]);
}//ledShow()
void serialPrintChg(const char msg[]) { // -------------------------------- print charging
Serial.print(msg);
Serial.print(":");
Serial.print(" Cell=");
Serial.print(WhichCellIsOn);
Serial.print(" Vdac=");
Serial.print(SetVOutput,3);
Serial.print(" Vcel=");
Serial.print(Vcell,3);
Serial.print(" Acel=");
Serial.println(Aload,3);
}
void serialPrintDebug() { // ----------------------------------------------- print debug serial & bluetooth
Serial.print("TBatt="); // temperatures
Serial.print(TempBattery,0);
Serial.print(" T7812=");
Serial.print(Temp7812,0);
Serial.print(" T317=");
Serial.print(Temp317,0);
Serial.print(" Fan=");
Serial.print(WhichFanSpeedIsOn);
Serial.println("/255");
Serial.print("Cell="); // VA values
Serial.print(WhichCellIsOn);
Serial.print(" VCel=");
Serial.print(Vcell,3);
Serial.print(" Vdac=");
Serial.print(Voutput,3);
Serial.print(" ACel=");
Serial.println(Aload,3);
Serial.print("IsAlrdy="); // status
Serial.print(IsAlreadyCharged);
Serial.print(" IsCharg=");
Serial.print(IsCharging);
Serial.print(" IsOver=");
Serial.print(IsOverTime);
Serial.print(" IsALRM=");
Serial.print(IsALARM);
Serial.print(" IsSlow=");
Serial.println(IsSlowDown);
Serial.print("Start[1]="); // charging times [1]
Serial.print(ChTimeStart[1]);
Serial.print(" End[1]=");
if (ChTimeEnd[1] > 0) {
Serial.print(ChTimeEnd[1]);
} else {
Serial.print("?");
}
Serial.print(" Time[1]=");
if (ChTimeEnd[1] > 0) {
Serial.print(long(ChTimeEnd[1] - ChTimeStart[1]));
} else {
Serial.print("?");
}
Serial.print(" VInit[1]=");
Serial.print(VInitCell[1],3);
Serial.print(" VFinal[1]=");
Serial.print(VFinalCell[1],3);
Serial.print(" Over[1]=");
Serial.print(C_OverTime[1]);
Serial.print(" Alarm[1]=");
Serial.print(C_AlarmTime[1]);
Serial.print(" Remain[1]=");
Serial.print(TRemain[1]);
Serial.print(" SoC%[1]=");
Serial.println(SoC[1]);
Serial.print("Start[2]="); // charging times [2]
Serial.print(ChTimeStart[2]);
Serial.print(" End[2]=");
if (ChTimeEnd[2] > 0) {
Serial.print(ChTimeEnd[2]);
} else {
Serial.print("?");
}
Serial.print(" Time[2]=");
if (ChTimeEnd[2] > 0) {
Serial.print(long(ChTimeEnd[2] - ChTimeStart[2]));
} else {
Serial.print("?");
}
Serial.print(" VInit[2]=");
Serial.print(VInitCell[2],3);
Serial.print(" VFinal[2]=");
Serial.print(VFinalCell[2],3);
Serial.print(" Over[2]=");
Serial.print(C_OverTime[2]);
Serial.print(" Alarm[2]=");
Serial.print(C_AlarmTime[2]);
Serial.print(" Remain[2]=");
Serial.print(TRemain[2]);
Serial.print(" SoC%[2]=");
Serial.println(SoC[2]);
Serial.print("TimeNow=");
Serial.println(ChTimeNow);
lastPrintDebugMillis=millis();
}//serialPrintDebug()
// round zero decimal // ----------------------------------------------- rounds
float roundZeroDec(float f) {
float y, d;
y = f*1;
d = y - (int)y;
y = (float)(int)(f*1)/1;
if (d >= 0.5) {
y += 1;
} else {
if (d < -0.5) {
y -= 1;
}
}
return y;
}
// round three decimals
float roundThreeDec(float f) {
float y, d;
y = f*1000;
d = y - (int)y;
y = (float)(int)(f*1000)/1000;
if (d >= 0.5) {
y += 0.001;
} else {
if (d < -0.5) {
y -= 0.001;
}
}
return y;
}
Comments