Constantin PowerWall

M

mrconstantin

Guest
Hi,


I am Constantin from Romania, and i will start the first PowerWall project.

I wish to make an modular PowerWall system for easy upgrading.

I will use 18650 Li-Ion Recycled battery buy-it from dismantling company.

For the frame i will use BOSH x shapealuminiu modular frame.

The electronics i will try to use as much i can the DIY circuits.


FIRST STEP - Battery

I bought 1000 Li-Ion 18650 RecycledBattery!!! the price was less then 0.4 usd/cell


image_pwwsqe.jpg


Also some 100 pcs5x4 support from China


image_keixkm.jpg


Imax B6 Charger - chose that one becouse i can charge also some 6s pacs during the constraction, and also have a lot of function for charge and discharge!


image_mmidha.jpg


Let's START Building!!

FIRST PROBLEM - Testing the cells

If u use recycled cells u need to test the capacity of each one! For that u need only a charger with tester function!

BUT

Every cell will need about 4hours to charge and also will need about 6hours to discharge if u charge it with 0.5Ah, and also discharge with low discharge function.
For me my first1000 cels will take at minimum 10000 hours that meens416 days if i work 24 hours on day with 1 charger!!!
The solution is to work with many chargers usuly i see is used the 4 cels version, so if u do the math if i have 16chargers i will make 64cels / day that will take about 15daysfor 1000 cels.

On ebay the option are:

3.25$ - only the discharge function and 1 battery for 64 pcs = 208$ + tax
40$ - Charger + discharger C3100 - with analyzer function 4 cels, for 64 i need 16 pcs =640$ - is more expensive then the cells!

This option was not ok for me!

Next QUEST - Build an DIY Multi Battery Tester - Charger Discharge

After some documentation i make this solution:

This is my first Modular 16 Cell Smart Battery Tester


image_cvaiei.jpg


Specification:

Max 8 module - 128 cell
Charging module - TP4056 with discharge protection at 2.5V
Charging Curent 520mA -1A Fix
Discharge Curent: 420mA - 250mA by Rezistor Load
Simultan Charge max 64 cells
Display LCD 128x64
Keypad 16 keys
Smart Option
Lan/Internet Server
Online Raport / Email
SD card Data Storage



Charging Board:


image_lqxyra.jpg


Discharge Board


image_tnqkto.jpg


Battery Holders 3D Printed
image_bqlbci.jpg


That is it for the moment!

Best regards
 
jesusangel said:
I lke the DIY way, but how do you calculate the capacity?, with costant resistor the amperage decreases as the voltage decreases, and when you know that one cell is discharged? you need something else to control the time of discharge at least.

Regards

I use 2 analog read from arduino to read voltage before and after the load rezistor. After that I make the difference and I know the voltage droped on rezistor.
After that I can calculate the curent true rezisor Ir=Ur/R the capacity will be Ir*Dt the curent true rezistor multiplay by the time.

The voltage readed before the rezistor is the battery voltage so I can stop the discharge at 2.7 or other settings from microcontroller. Also I use Tp4056 with discharge protection so even the discharge moafet remain open the protection.will cutt of at 2.5V

For the end of charge I read the status of the full charging led from TP4056 after that I disconect the power from charger and connect the discharger, then I repetly check the voltage of battery and the rezistor to calculate the real capacity of battery.

Best regards
 
Watched your vids and posted in the video section as you linked your videos there (btw, you can post videos here, too ;) ):
That's practically exactly what I was wanting to do Smile I really like this work! Nicely explained and laid out Smile Nice walk-through. And your english was just fine!

However, why don't you use an A2D (I think this is what it is) with I2C interface for the analog reading. Wouldn't that allow you to read all the values somewhat at the same time?
Though, I do like the CD4052B variant, as it looks to me like it has 2 leads that switch from pairs of pins at a time (pin 1&2, then 3&4, then 5&6, ...). This would effectively isolate the grounds, yes?

Now, could we use a digital mux for the fets? Reason I ask is cuz I have nano's and would like to use what I already have.

I did notice that you didn't post the code anywhere. I think I can follow the schematic based on what you showed in the video, though.
 
Hi

U can use Nano with i2c digital mux like PCF8574T and also with analogic mux, but i dont chose this one because nano have only 2k of RAM, and i need to use a lote of longs variabile 4 bytes) for the time how is in milisecs and also floats variabile (4 bytes) for the capacity storage. In my case each module will handle 32 cells so i will need a lot of ram and also procesor time to read and calculate the capacity.
The other reason i dont chose nano is because nano have 12 digital pin (0 and is for serial) and mega have 52 , so if i need same amount of digital i/0 i need to use nano with 5 PCF8574T and the price will be same as a mega.

For analogic i chose to multiplex the exits because the mega is not multithred procesor, i read one serial each time, so i can use an cd 405x series for that.

In my design i can connect 4 module of 32 cells with the control module - i use an mega as control module, i conect to this the keyboard the display and the w5100 network module, the mega have 4 hardware serials and true serial i send and receive status from each charging/discharging module so even i will enter in menu setting or i try to make an sever command true network the charge and tester will continue to operate independent and will calculate the real battery capacity.

Also in this design u can make 1 module and upgrade if u need more slots.

About the 16 slots for 32 battery.
I calculate the charge / discharge /charge cycle for 1 battery is more then 8-10 hours, becaouse i dont want to let the battery empty after the test is done i nned to recharge the battery for storage.
So if i am not home on the cycle is complete or i am sleeping the charger will stay doing nothing, so from my point of view i add an 16 channel relay how change the battery on slots, so my charging slots will have 2 battery each, so for this relay i also need some digital pins, but i used from the control mega how have used less (display, keyboard w5100). In this whay my charging discharging slots will work minimum 20 hours/ day, and i can change the complete charged battery without stop the process.

i dont upload the source code because is not full completed, i implement the relay option now. I will add more video and data for this project.

best regards
 
Kewls!
I hadn't thought of the memory limitation before. We get so used to being able to just use any memory type when programming on our computers, that we forget about the small devices with limited storage.
Here's a thought:
Use several variables to do the calculations.
Code:
int mTime;
int leftTime;
int rightTime[];
long calcTime;

mTime = millis();
leftTime = mTime / 1000; //basically move the decimal left 4 places and store that in the leftTime. Being put in an int removes the trailing decimal numbers, right?
rightTime[i] = mTime - (leftTime * 1000); //now subtract to acquire just right portion of mTime

//then in the loops, we just use this to get the proper time again
calcTime = (leftTime * 1000) + rightTime[i];

Not sure if that would work or not. But, since an int is 1/2 the size of a long, it would save memory in the long run. Though, it would add a little processor load to do the calculations when doing the math portions in the loops.

Buuuut, I could be completely bogusly wrong here :p
 
Korishan said:
Kewls!
I hadn't thought of the memory limitation before. We get so used to being able to just use any memory type when programming on our computers, that we forget about the small devices with limited storage.
Here's a thought:
Use several variables to do the calculations.
Code:
int mTime;
int leftTime;
int rightTime[];
long calcTime;

mTime = millis();
leftTime = mTime / 1000; //basically move the decimal left 4 places and store that in the leftTime. Being put in an int removes the trailing decimal numbers, right?
rightTime[i] = mTime - (leftTime * 1000); //now subtract to acquire just right portion of mTime

//then in the loops, we just use this to get the proper time again
calcTime = (leftTime * 1000) + rightTime[i];

Not sure if that would work or not. But, since an int is 1/2 the size of a long, it would save memory in the long run. Though, it would add a little processor load to do the calculations when doing the math portions in the loops.

Buuuut, I could be completely bogusly wrong here :p

float getVoltage(uint8_t pin){ //read voltage from analog pins
float sample=0.0;
for(uint8_t i=0;i<readSample;i++){
sample+=analogRead(pin);
delay(2);
}
sample=sample/readSample;
return (float)sample*Vcc*2/1024; //Vcc =5V i use an 10k rezistor diverer to pull down the analog pin and better reading
}

The code for the capacity:

float _batVoltage=readBatVoltage(i); //read the battery voltage
float _mosfetVoltge=readMosVoltage(i); //red the mosfet voltage
long _now=millis(); //time in millisecs
long _timePassed=_now-lastRead;
lastRead=_now;
float current=(_batVoltage-_mosfetVoltage)/RES_VALUE *1000; //in mA // RES_VALUE was 10ohm in my case
batteryCapacity+= current * (_timePassed / 3600000.0); // inHours


From IRLZ44N Specs the RDSon is only 0.022 ohm, so the voltage dropped on mosfet is less then 0.01V can be ignored. I make few tests and its a fact.
If u use N MOSFETS with big RDSon on 5V like the non logic mosfetsu will need to measure the voltage dropped on the MOSFET.

OnIRLZ44N u dont need to do that, so u can use only 1 Analog pin to measure the voltage true the resistor.

Best regards
 
Hi

Today was testing day for my Multi Charger / Tester Unit!!

I make some modification on design i use an 8 channel relay for each 16 charger pack to handle 32 battery. every cycle will takke about 8 hours to charge - discharge - recharge so usuly in 24 hours i will be able to test 2 battery for each charger soket.


image_wscymr.jpg


This is my firs complete test unit, with 16 sokets and 16 cell hoked up.


image_zjaopb.jpg



image_ftasbc.jpg


I make some test with 8 cells, and all the data was send it by serial connection because the central control unit is not finished yes.
From my test i discover the IRLZ have an internal RDSon ot only 0.022ohm so the dropped voltage on mosfet is less then 0.01V, so u can read only the rezistorvoltage on discharging u dont need 2 analog Pins to make the math.
Also if u dont want to have strange voltage reader u need to use an resistor divider to pull down the arduino analogic pin.

I compare my result with the Imax B6 and will be a difference about 100mA in readings. I think is because Imax make CC discharge and my will make an VC discharge because i use an static resistor load.
For me will no be a problem i can see what cels are broken and also can pair them by the capacity.


image_qtdlno.jpg


Best regards
 
Hi,

I like to DIY but when there are so much options already made by our friends from PRC why bother?
I useThis testerand made a plate with 6 of them and alo charge with standard TP4056.


image_nyuftw.jpg


image_uxotgc.jpg


P.S. Greetings from Romania :rolleyes:
 
KaminoReal said:
I like to DIY but when there are so much options already made by our friends from PRC why bother?

Flexibility, super logging ability, semi-automation, easy expandability, space conservation, and the DIY factor ;) Plus you get to learn things.
 
Constantin,

Great work on this - I want to build something similar.I've enjoyed your videos as well. I do have 2 questions for you:

1. Since I have an abundance of thermistors from opening packs. Could we tie those into the cell holders and monitor cell temps individually during the cycling process and shutdown the charging process and email us if we hit some predefined threshold?

2. If I were inclined to increase the accuracy of capacity monitoring so it's on par with what a foxnovo F-4s or Opus would provide, would that greatly increase complexity?

Thanks.
 
srk said:
Constantin,

Great work on this - I want to build something similar.I've enjoyed your videos as well. I do have 2 questions for you:

1. Since I have an abundance of thermistors from opening packs. Could we tie those into the cell holders and monitor cell temps individually during the cycling process and shutdown the charging process and email us if we hit some predefined threshold?

2. If I were inclined to increase the accuracy of capacity monitoring so it's on par with what a foxnovo F-4s or Opus would provide, would that greatly increase complexity?

Thanks.

Hi,

1. - Yes ucan add temperature reading - i use CD74HC4067 16 Chanel Multiplexer, u can control it with 4 digital pins + 1 analog pin for reading, i have 2 of that instaled on the discharge board, u can see it on picture. One is reading battery VCC and the other read the VCC after the load resistor.
U can add one more multiplexer with an other analog pin and read 16 termistor to check the battery temperature. After the data is collected will be no problem to send it.


image_qlaahh.jpg


2. If u use 2 voltage reading, before and after resistor the final results are ok. if u use only one before of the resistor u can have a little difference because u can have an 0.1V drop on the mosfet RDSon Value.
The results haveaccuracy, the difference is fromhow u discharge the battery if u will discharge with 1A or 0.5A or less, Li-Ion Cell make power from an chimical reaction if the battery is old and his life is finish u will see the voltage will drop very fast if u tray to discharge with 1A or more, that why u need an balance BMS board.
From my test same cell have an difference of mA if i discharged with my Imax b6 with 1A or 0.5A.
Also if u check the specification of the battery on pdf fileu will see the cell will charge about 100% if u charged with 400-500mA and at95% on 1A and less of 95%on fast charge.
From this facts the same battery will have some difference in total capacity from the charging and also discharging parameters.The difference will be about 5%. So for an 2000mA will be less or more then 100mA

I think if u want to make an PowerWall the discharge will be with less ma then an EV bike cell. If u want to make an EV bike or other aplication with high demand of instant poweru will need to discharge with 1A or more for that use 3.7 or 5 ohm resistor as Load, for slow dischargeuse 10 ohm load.

best regards


I think foxnovo F-4s or Opus like the Imax will discharge with an constant current. But in ral life the LI-Ion will not be discharged with same current will be discharge as the power is demanded.

If u want to make an constant discharge u need to use an variabile resistor because the Ohm Low u=I*r, in our case the U will decrease from 4.2 to 2.7V so u need an resistor to change from 4.2ohm to 2.7 ohm if u discharge with 1A.
In theory an mosfet is a variabile Resistor, and RDSon will be changed by the gate Vgs, so if u mach an MOSFET with a good RDSon graph and can dissipate the heat generated by the RDSon u can make an Constant Current Discharge circuit by change the U from the gate of the MOSFET.

Is only a theory, i dont try it!
 
Hi

i finish the first 32 cells module and also the main controller.
I use an aluminium x 2020 profile.Size is L 500 mm l190 mm h120 mm. The space is ok the H can be less but my alu profile was all ready cut. I can put inside also the power supply, i use 5V 40A power supply.


image_gcdnex.jpg


I use an 128x64 Graphic Display, i display 8 cells status and capacity and i change with next 8 at 10 sec. if i need more data i need to select a cell from keypad.


image_hbnkjo.jpg


Also i add the W5100 for network communication and internet server. The soft is not ready but in few days i will make online data with some graph.


image_fhtbwf.jpg


The software for the charger unit:

Code:
/*###########################################
SMART CHARGER MULTI BATTERY TESTER
Version 0.1 Beta
Project: Constantin PowerWall
by 81ROI, ROMANIA

Slave UNIT - This software will automatic charge, discharge and mesure capacity of 16 cells 18650 Li-Ion Battery 

 This is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This software is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY!
 See the GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with Grbl. If not, see <http://www.gnu.org/licenses/>.

###########################################*/

/*###########pinout#########################
Arduino MEGA

Charge MOSFET      D22-D37
Discharge Mosfet    D2-D17
Complet Charge LED   D38-D53

MUX1 is used to read Vbat and Vres for 1-8 cells is connected C0 = Vbat1 C1 = Vres1 , C2 = Vbat2 C3 = Vres2, ... , C14 = Vbat8 C15 = Vres8
MUX1 S0-S3       A0-A3
MUX1 Enable       A4
MUX1 Sig        A14

MUX1 is used to read Vbat and Vres for 9-16 cells is connected C0 = Vbat9 C1 = Vres9 , C2 = Vbat10 C3 = Vres10, ... , C14 = Vbat16 C15 = Vres16
MUX2 S0-S3       A5-A8
MUX2 Enable       A9
MUX2 Sig        A15

Serial Output:
[Battery]Status|Capacity|Voltage
[Battery]Status|Capacity|Voltage|chargeTime|dischargeTime|rechargeTime

Times are in milisec
##########################################*/


#define statusEmpty           0
#define statusReady           1
#define statusCharge           2
#define statusHigh            3
#define statusDischarge         4
#define statusLow            5
#define statusRecharge          6
#define statusIdle            7

#define chargeON             0  //mosfet control signal nedit to open 0=GND 1=5V
#define chargeOFF            1
#define dischargeON           1
#define dischargeOFF           0

#define BATTERY_NUMBER         16  //number of charge/discharge battery
#define MOSFET_CHARGE_PIN        22  //pin of the first charge MOSFET 
#define MOSFET_DISCHARGE_PIN      2  //pin of the first discharge MOSFET
#define CHARGING_COMPLETE_PIN      38  //pin of the first charging complete LED
#define BATTERY8_VOLTAGE_PIN      A4  //pin of the first battery voltage sensor
#define BATTERY16_VOLTAGE_PIN      A9  //pin of the first resistor voltage sensor
#define MUX1_S0             A0  //mux1 s0 pin
#define MUX2_S0             A5  //mux2 s0 pin
#define MUX1_EN             A14 //mux1 enable pin
#define MUX2_EN             A15 //mux2 enable pin

#define RES_VALUE            10 //value of resistor in ohm

bool mosfetChargeMode[BATTERY_NUMBER];    //store the mosfet working status 0 - off 1 - on
bool mosfetDischargeMode[BATTERY_NUMBER];  //store the mosfet working status 0 - off 1 - on
bool relayMode[BATTERY_NUMBER];       //store relay pozition 0 or 1
uint8_t chargerStatus[BATTERY_NUMBER];   //store status of the slots

float batteryCapacity[BATTERY_NUMBER];      //store the batterys capacity


long lastRead[BATTERY_NUMBER];    //store the last time when the voltage sensor was readed
long chargeTime[BATTERY_NUMBER];   //time of charging
long dischargeTime[BATTERY_NUMBER]; //time to discharge
long rechargeTime[BATTERY_NUMBER];  //time to reacharge - this is the full recharge from 2.7 to full

float batteryHigh=4.2;        //battery high when is charged
float batteryLow=2.7;         //battery cut of discharge
float Vcc=5;             //voltage of the 5v pin from arduino tested with multimeter
uint8_t readSample=100;        //number of samples to read from an analog pin

bool stringAvailable=false;      //used to see when we have an command on serial
String stringRx="";          //serial data

#define raportDelay      30000 //raport once at 30 sec
long lastTimeRaport=0;         //time of last raport;
bool autoRaport=true;        //autoraport

void setup() {
  Serial.begin(9600); //used for usb serial
  Serial1.begin(9600); //used for inter module communication

 // put your setup code here, to run once:

 // Set pin INPUT / OUTPUT
 for (uint8_t i=0;i<BATTERY_NUMBER;i++){
  pinMode(MOSFET_CHARGE_PIN+i,OUTPUT);
  digitalWrite(MOSFET_CHARGE_PIN+i,chargeOFF);
  mosfetChargeMode[i]=false;
  
  pinMode(MOSFET_DISCHARGE_PIN+i,OUTPUT);
  digitalWrite(MOSFET_DISCHARGE_PIN+i,dischargeOFF);
  mosfetDischargeMode[i]=false;
  
  pinMode(CHARGING_COMPLETE_PIN+i,INPUT);
  digitalWrite(CHARGING_COMPLETE_PIN+i,HIGH);

 }
 //set analog inputs
  for(uint8_t i=0;i<4;i++){
    pinMode(MUX1_S0+i,OUTPUT);
    digitalWrite(MUX1_S0+i,LOW);
   
    pinMode(MUX2_S0+i,OUTPUT);
    digitalWrite(MUX2_S0+i,LOW);
  }
  //disable mux
   pinMode(MUX1_EN,OUTPUT);
   pinMode(MUX2_EN,OUTPUT);
   digitalWrite(MUX1_EN,HIGH);
   digitalWrite(MUX2_EN,HIGH);
  //init charge
  initCharger();
}

void loop() {   
// put your main code here, to run repeatedly:
  checkStatus();    //check status of charges
  raport();       //send raport if is needit
 

}
void rx_empty(void)
{
 while (Serial1.available() > 0) {
  Serial1.read();
 }
}
void serial1Event()                      
{
 while (Serial1.available())
 {
  char MinChar = (char)Serial1.read();          // Char received from Serial1
  if (MinChar == '\n')
  {
   stringAvailable = true;
  }
  else
  {
   if (MinChar >= ' ') {stringRx += MinChar;}   // >= ' ' to avoid not wanted ctrl char.
  }
 }
}

void initCharger(){
 for(uint8_t i=0;i<BATTERY_NUMBER;i++){       //set all charger sokets as empty for be ready to take new battery.
   chargerStatus[i]=statusEmpty;  
 }
 Serial.println("Multi Charger Ready!");
}

void setMux(uint8_t mux,uint8_t channel){
 int controlPin[] = {mux, mux+1, mux+2, mux+3};
 int muxChannel[16][4]={ {0,0,0,0}, //channel 0
             {1,0,0,0}, //channel 1
             {0,1,0,0}, //channel 2
             {1,1,0,0}, //channel 3
             {0,0,1,0}, //channel 4
             {1,0,1,0}, //channel 5
             {0,1,1,0}, //channel 6
             {1,1,1,0}, //channel 7
             {0,0,0,1}, //channel 8
             {1,0,0,1}, //channel 9
             {0,1,0,1}, //channel 10
             {1,1,0,1}, //channel 11
             {0,0,1,1}, //channel 12
             {1,0,1,1}, //channel 13
             {0,1,1,1}, //channel 14
             {1,1,1,1} //channel 15
             };
 for(uint8_t i = 0; i < 4; i ++){
  digitalWrite(controlPin[i], muxChannel[channel][i]);
 }
 delay(100);
}

void enableMux(uint8_t n){
 if(n<8)
   digitalWrite(MUX1_EN,LOW);
 else
   digitalWrite(MUX2_EN,LOW);
 delay(50);
}

void disableMux(uint8_t n){
 if(n<8)
   digitalWrite(MUX1_EN,HIGH);
 else
   digitalWrite(MUX2_EN,HIGH);
 delay(50);
}

float getVoltage(uint8_t pin){           //read voltage from analog pins
 float sample=0.0;
 for(uint8_t i=0;i<readSample;i++){
   sample+=analogRead(pin);
   delay(1);     
 }
 sample=sample/readSample;
 return (float)sample*Vcc*2/1024;
}

float readBatVoltage(uint8_t bat){
 uint8_t voltagePin;
 uint8_t muxPin;
 uint8_t muxChannel;
 if(bat<8){
    voltagePin=BATTERY8_VOLTAGE_PIN;
    muxPin=MUX1_S0;
 }
 else{
    voltagePin=BATTERY16_VOLTAGE_PIN;
    muxPin=MUX2_S0;
 }
 enableMux(bat);
 muxChannel=bat%8*2;
 setMux(muxPin,muxChannel);
 float v= getVoltage(voltagePin);
 disableMux(bat);
 return v;
 
}

float readResVoltage(uint8_t bat){
 uint8_t voltagePin;
 uint8_t muxPin;
 uint8_t muxChannel;
 if(bat<8){
    voltagePin=BATTERY8_VOLTAGE_PIN;
    muxPin=MUX1_S0;
 }
 else{
    voltagePin=BATTERY16_VOLTAGE_PIN;
    muxPin=MUX2_S0;
 }
 enableMux(bat);
 muxChannel=bat%8*2+1;
 setMux(muxPin,muxChannel);
 float v= getVoltage(voltagePin);
 disableMux(bat);
 return v;
}

void setCharge(uint8_t n, bool mode){             //change mosfet workning mode
  if(mode){
   digitalWrite(MOSFET_CHARGE_PIN+n,chargeON); 
  }
  else{
   digitalWrite(MOSFET_CHARGE_PIN+n,chargeOFF);
  }
  mosfetChargeMode[n]=mode;
  delay(10);
}

void setDischarge(uint8_t n, bool mode){             //change mosfet workning mode
  if(mode){
   digitalWrite(MOSFET_DISCHARGE_PIN+n,dischargeON);
  }
  else{
   digitalWrite(MOSFET_DISCHARGE_PIN+n,dischargeOFF);
  }
  mosfetDischargeMode[n]=mode;
  delay(10);
}

bool isChargeingComplete(uint8_t n){               //check if battery is charging
 if(digitalRead(CHARGING_COMPLETE_PIN+n)==LOW)
  return true;
 return false;
}

void checkStatus(){
 for(uint8_t i=0;i<BATTERY_NUMBER;i++){
   if(chargerStatus[i]==statusEmpty){
     batteryCapacity[i]=0;
     float _batVoltage=readBatVoltage(i);
     if(_batVoltage>0.3){
      chargerStatus[i]=statusReady;
      Serial.println("["+String(i)+"]"+String(chargerStatus[i])+"|"+String(batteryCapacity[i])+"|"+String(_batVoltage));
     }
   }
   if(chargerStatus[i]==statusReady){
     setDischarge(i,false);
     setCharge(i,true);
     chargeTime[i]=millis();
     chargerStatus[i]=statusCharge;
     Serial.println("["+String(i)+"]"+String(chargerStatus[i])+"|"+String(batteryCapacity[i])+"|");
   }
   if(chargerStatus[i]==statusCharge){
     if(isChargeingComplete(i)){
      setCharge(i,false);
      setDischarge(i,false);
      float _batVoltage=readBatVoltage(i);
      chargeTime[i]=millis()-chargeTime[i];
      chargerStatus[i]=statusHigh;
      Serial.println("["+String(i)+"]"+String(chargerStatus[i])+"|"+String(batteryCapacity[i])+"|"+String(_batVoltage)+"|"+String(chargeTime[i]));
     }
   }
   if(chargerStatus[i]==statusHigh){
      batteryCapacity[i]=0.0;
      lastRead[i]=millis();
      dischargeTime[i]=millis();
      chargerStatus[i]=statusDischarge;
      setCharge(i,false);
      setDischarge(i,true);
      Serial.println("["+String(i)+"]"+String(chargerStatus[i])+"|"+String(batteryCapacity[i])+"|");
   }
   if(chargerStatus[i]==statusDischarge){
      float _batVoltage=readBatVoltage(i);
      float _resVoltage=readResVoltage(i);
      long _now=millis();
      long _timePassed=_now-lastRead[i];
      lastRead[i]=_now;
      float current=(_batVoltage-_resVoltage)/RES_VALUE *1000; //in mA
      batteryCapacity[i]+= current * (_timePassed / 3600000.0); // one Hour = 3600000ms
      if(_batVoltage<batteryLow){
       setDischarge(i,false);
       setCharge(i,false);
       dischargeTime[i]=_now-dischargeTime[i];
       chargerStatus[i]=statusLow;
       Serial.println("["+String(i)+"]"+String(chargerStatus[i])+"|"+String(batteryCapacity[i])+"|"+String(_batVoltage)+"|"+String(dischargeTime[i]));
      }
     
   }
   if(chargerStatus[i]==statusLow){
     setDischarge(i,false);
     setCharge(i,true);
     rechargeTime[i]=millis();
     chargerStatus[i]=statusRecharge;
     Serial.println("["+String(i)+"]"+String(chargerStatus[i])+"|"+String(batteryCapacity[i])+"|");
   }
   if(chargerStatus[i]==statusRecharge){
     if(isChargeingComplete(i)){
      setDischarge(i,false);
      setCharge(i,false);
      float _batVoltage=readBatVoltage(i);
      rechargeTime[i]=millis()-rechargeTime[i];
      chargerStatus[i]=statusIdle;
      Serial.println("["+String(i)+"]"+String(chargerStatus[i])+"|"+String(batteryCapacity[i])+"|"+String(_batVoltage)+"|"+String(rechargeTime[i]));
     }
    }
    if(chargerStatus[i]==statusIdle){
      float _batVoltage=readBatVoltage(i);
      if(_batVoltage<2){
        chargerStatus[i]=statusEmpty;
        Serial.println("["+String(i)+"]"+String(chargerStatus[i])+"|"+String(batteryCapacity[i])+"|");
     }
    }
 }
}
void raport(){
 if(millis()-lastTimeRaport<raportDelay || autoRaport==false) return;
 raportAll();
}
void raportAll(){
 Serial.println();

  for(uint8_t i=0;i<BATTERY_NUMBER;i++){
   raportCharger(i);
  }
 lastTimeRaport=millis();
 Serial.println();
}
void raportCharger(uint8_t i){
 float _batVoltage;
 switch(chargerStatus[i]){
   case statusEmpty: case statusCharge:
     Serial.println("["+String(i)+"]"+String(chargerStatus[i])+"|"+String(batteryCapacity[i])+"|");
   break;
   case statusHigh: case statusReady:
     _batVoltage=readBatVoltage(i);
     Serial.println("["+String(i)+"]"+String(chargerStatus[i])+"|"+String(batteryCapacity[i])+"|"+String(_batVoltage));
   break;
   case statusDischarge: case statusLow:
     _batVoltage=readBatVoltage(i);
     Serial.println("["+String(i)+"]"+String(chargerStatus[i])+"|"+String(batteryCapacity[i])+"|"+String(_batVoltage)+"|"+String(millis()-dischargeTime[i]));  
   break;
   case statusRecharge:
     Serial.println("["+String(i)+"]"+String(chargerStatus[i])+"|"+String(batteryCapacity[i])+"|");
   break;
   case statusIdle:
     _batVoltage=readBatVoltage(i);
     Serial.println("["+String(i)+"]"+String(chargerStatus[i])+"|"+String(batteryCapacity[i])+"|"+String(_batVoltage)+"|"+String(chargeTime[i])+"|"+String(dischargeTime[i])+"|"+String(rechargeTime[i]));
   break;
  }
}
 
Awesome!! I will have to look at this later as I don't have the time atm. And, I will definitely have to start building my own version :)

Best teacher is through application, not just a book ;)
 
hi

I make some progress, i make my 32 cells module unit work and finish the structure.


image_lmsnmx.jpg



image_yyufux.jpg



image_cliimo.jpg



image_czexnz.jpg


I notice i only use about 15% of the mega memory on charging control unit, so for the next 32 module i will usePCF8574T i2c port expander and will be controlled by the same board.
Also i notice when the power is down a little power will flow fromTP4056 to the arduino so the LCD will backlight will still glow a little, i will make some test and if will be need it i will add some diodes to prevent this thing.
So form my point of view u can use nano with some i2cPCF8574T will do the job.

I add the video on youtube section.

Now i can test about 48batterys on a dayif i change the completed one when are finished. for me is ok i can start to build the power wall cells now and when i will have more time i will add the other 32 module to speed up the testing.

What u need for 32 Module:

Mosfets
16 x IRLZ44N
16 x IRF5305

Resistors
36 x 10k Resistors
16 x 10ohm 5W Resistors

Diodes
16 x 1n4001 //used to stop tp4056 to power the arduino

Module
2 x CD4HC4067
6 xPCF8574T //if u chose to use nano or 2 if u chose to use mega
2 x 8 channel relay

32 x battery holder // or print ur own battery holder

1 x Power Supply 5V 40A

1 x nano or mega

Bosh Aluminium 20x20mm 2 x 500mm 4 x 100mm

3D printed Parts.

All the data can be read it on serial without eny other thing

Extra:
LCD Control Unit with internet connection:

1 x1288x64 LCD Display
1 x Mega 2560
1 x 16 Key Keyboard

Upgrade andTo Do List:

Battery temperature reading:
16 x 100k termistor
1 xCD4HC4067



Best regards
 
A lote of people ask me if i will make an constant discharge circuit!

YES i will make it Tommorow!

tomorrow i will make an other movie with the constant current version.
In theory Ohm Low is :
I=U/R
So u know the U will be changing from 4.2 to 2.5V on discharge of the cell.
For I to be constant u have tow option:

1 - to change the R value : this can be done like that use an fixed R + RDSon of MOSFET so if u want to discharge with max 1A at 2.5V u will need an 2.5Ohm resistor at the end of the cycle. So u will need an 2.5ohm 5W at end and 2.5ohm + RDSon of MOSFET 4.2ohm on start. So will need to control the mosfet to have a resistor of 1.7 ohm.
Because IRLZ44n is an logic mosfet u will need few mV to have that resistance because if u look to data sheet u will have less then 0.8 ohm on 2V and at 5V u have 0.028 ohm.
Also the RDSon will depend of the temperature of the MOSFET, so from my point of view cant be done with an logic mosfet!!!

2 - the second option is to control the voltage to make that U/R constant. so if u will have same 2.5ohm 5W resistor and can make an voltage regulator controlled by the microcontroler u can also have an constant current discharge.

I will try the second version an i will make the presentation video tomorrow.
All the parts u brought for this project cant be used but on constant discharge will discharge with only 250mA. if u want to reach 500mW put 2 resistors 10 ohm in parallel to reach 5ohm and if u want 1A u need 2.5ohm resistor or 4 10 ohm in parallel.

Also form other test is better to use different MUX one for Vbat reading and one of Vres reading, in my presentation i use the odd inputs (0,2,4,6,8,10,12,14) of mux for Vbat and even inputs (1,3,5,7,9,11,13,15) for Vres. I use also 2 mux but was easy to wiring with odd and even but better is to be separate one mux all 16 inputs for Vres and one mux for Vbat. Because I see the circuit need few millisec after the mux change the input to drop the voltage from 4V (battery voltage) to 0.018V (voltage droped on mosfet), for that i need to ad an 50milisec delay on each reading. when u have 32 batttery will and some sec of delay.

Constant Current Schematics:


image_xtfsfe.jpg


best regards
 
Hi all,

I chose to make an Constant Current Discharger controlled by arduino.
I will use for that the OA LM358 to drive my IRLZ44N MOFETS, i need to change some power resistors. i think best option will be 2.2ohm 5W i will make some tests.
Also one of the problems i need for each discharge one PWM Pin to control the voltage dropped on resistor, arduino mega have only 15 PWM and nano have only 6 so for this update i can drive only 15 battery direct with the mega, but i think i will use TLC5940NT as 16 pwm signals circuit.
The good part is i will not need only 1 mux for reading voltage of battery and one i can used to read the temperature of them.

So extra part list for each 32 cells dscharger will be:

8 x lm358 (lm3588 have dual channel)
1 x TLC5940
16 x 1ohm or 2.2 ohm resistor (on constant load i use 10ohm 5w)


best regards
 
Code:
/*###########################################
SMART CHARGER MULTI BATTERY TESTER
Version 0.2 Beta
Project: Constantin PowerWall
by 81ROI, ROMANIA

Slave UNIT - This software will automatic charge, discharge and mesure capacity of 16 cells 18650 Li-Ion Battery 

 This is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This software is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY!
 See the GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with Grbl. If not, see <http://www.gnu.org/licenses/>.

###########################################*/

/*###########pinout#########################
Arduino MEGA

Charge MOSFET      D22-D37
Discharge Mosfet    D2-D17
Complet Charge LED   D38-D53

MUX1 is used to read Vbat and Vres for 1-8 cells is connected C0 = Vbat1 C1 = Vres1 , C2 = Vbat2 C3 = Vres2, ... , C14 = Vbat8 C15 = Vres8
MUX1 S0-S3       A0-A3
MUX1 Enable       A4
MUX1 Sig        A14

MUX1 is used to read Vbat and Vres for 9-16 cells is connected C0 = Vbat9 C1 = Vres9 , C2 = Vbat10 C3 = Vres10, ... , C14 = Vbat16 C15 = Vres16
MUX2 S0-S3       A5-A8
MUX2 Enable       A9
MUX2 Sig        A15

SDA SCL
RELAY1         D20 21
RELAY2         D20 21

Serial Output:
<Battery]Status|Capacity|Voltage>
<Battery]Status|Capacity|Voltage|chargeTime|dischargeTime|rechargeTime>

Times are in minutes
##########################################*/

#include <Wire.h>

#define STATUS_EMPTY           0
#define STATUS_READY           1
#define STATUS_CHARGE           2
#define STATUS_HIGH            3
#define STATUS_DISCHARGE         4
#define STATUS_LOW            5
#define STATUS_RECHARGE          6
#define STATUS_IDLE            7
#define STATUS_WAIT            8

#define CHARGE_ON             0  //mosfet control signal nedit to open 0=GND 1=5V
#define CHARGE_OFF            1
#define DISCHARGE_ON           1
#define DISCHARGE_OFF           0
#define RELAY_P0             1
#define RELAY_P1             0


#define MOSFET_CHARGE_PIN        22  //pin of the first charge MOSFET 
#define MOSFET_DISCHARGE_PIN      2  //pin of the first discharge MOSFET
#define CHARGING_COMPLETE_PIN      38  //pin of the first charging complete LED
#define BATTERY8_VOLTAGE_PIN      A4  //pin of the first battery voltage sensor
#define BATTERY16_VOLTAGE_PIN      A9  //pin of the first resistor voltage sensor
#define MUX1_S0             A0  //mux1 s0 pin
#define MUX2_S0             A5  //mux2 s0 pin
#define MUX1_EN             A14 //mux1 enable pin
#define MUX2_EN             A15 //mux2 enable pin

#define RES_VALUE            10 //value of resistor in ohm
#define BATTERY_NUMBER         16  //number of charge/discharge battery
#define BATTERY_ROWS           2

bool mosfetChargeMode[BATTERY_NUMBER];    //store the mosfet working status 0 - off 1 - on
bool mosfetDischargeMode[BATTERY_NUMBER];  //store the mosfet working status 0 - off 1 - on
bool relayMode[BATTERY_NUMBER];       //store relay pozition 0 or 1
uint8_t chargerStatus[BATTERY_NUMBER];   //store status of the slots
long lastRead[BATTERY_NUMBER];    //store the last time when the voltage sensor was readed
bool autoMode[BATTERY_NUMBER];    //used for charger auto start CYCLE: Charge - Discharge - Recharge

uint8_t batteryStatus[BATTERY_NUMBER*BATTERY_ROWS];
bool batteryComplete[BATTERY_NUMBER*BATTERY_ROWS];
float batteryVoltage[BATTERY_NUMBER*BATTERY_ROWS];
float batteryCapacity[BATTERY_NUMBER*BATTERY_ROWS];      //store the batterys capacity
long chargeTimeStart[BATTERY_NUMBER*BATTERY_ROWS];   //time of charging
long chargeTimeStop[BATTERY_NUMBER*BATTERY_ROWS];   //time of charging
long dischargeTimeStart[BATTERY_NUMBER*BATTERY_ROWS]; //time to discharge
long dischargeTimeStop[BATTERY_NUMBER*BATTERY_ROWS]; //time to discharge
long rechargeTimeStart[BATTERY_NUMBER*BATTERY_ROWS];  //time to reacharge - this is the full recharge from 2.7 to full
long rechargeTimeStop[BATTERY_NUMBER*BATTERY_ROWS];  //time to reacharge - this is the full recharge from 2.7 to full

float batteryHigh=4.2;        //battery high when is charged
float batteryLow=2.7;         //battery cut of discharge
float Vcc=5;             //voltage of the 5v pin from arduino tested with multimeter
uint8_t readSample=100;        //number of samples to read from an analog pin

#define RAPORT_TIME      10000 //raport once at 30 sec
long lastTimeRaport=0;        //time of last raport;
bool autoRaport=true;        //autoraport
bool Serial1Raport=true;

#define STATUS_TIME      5000  //check status one at 3 sec     
long lastTimeStatus;

#define SERIAL_BUFFER      63 //max data to send
bool string1Available=false;     //used to see when we have an command on serial
String string1Rx="";         //serial data
String string1Tx="";         //serial1 string need it to send
uint8_t serial1Sendit=0;       //serial1 sendit
bool serial1Confirmed=true;     //serial1 confirmed
bool serial1Connected=true;     //if serial 1 is connected to controller

#define RELAY_1 0x20         //address of first i2c relay
#define RELAY_2 0x39         //address of second 12c relay

void setup() {
  Serial.begin(9600); //used for usb serial
  Serial1.begin(9600); //used for inter module communication
  Wire.begin();

 // put your setup code here, to run once:

 // Set pin INPUT / OUTPUT
 for (uint8_t i=0;i<BATTERY_NUMBER;i++){
  pinMode(MOSFET_CHARGE_PIN+i,OUTPUT);
  digitalWrite(MOSFET_CHARGE_PIN+i,CHARGE_OFF);
  mosfetChargeMode[i]=false;
  
  pinMode(MOSFET_DISCHARGE_PIN+i,OUTPUT);
  digitalWrite(MOSFET_DISCHARGE_PIN+i,DISCHARGE_OFF);
  mosfetDischargeMode[i]=false;
  
  pinMode(CHARGING_COMPLETE_PIN+i,INPUT);
  digitalWrite(CHARGING_COMPLETE_PIN+i,HIGH);

 }
 //set analog inputs
  for(uint8_t i=0;i<4;i++){
    pinMode(MUX1_S0+i,OUTPUT);
    digitalWrite(MUX1_S0+i,LOW);
   
    pinMode(MUX2_S0+i,OUTPUT);
    digitalWrite(MUX2_S0+i,LOW);
  }
  //disable mux
   pinMode(MUX1_EN,OUTPUT);
   pinMode(MUX2_EN,OUTPUT);
   digitalWrite(MUX1_EN,HIGH);
   digitalWrite(MUX2_EN,HIGH);

 //all relay in position 0
 IOexpanderWrite(RELAY_1,255 );
 IOexpanderWrite(RELAY_2,255 );
  //init charge
  initCharger();
}




void loop() {   
// put your main code here, to run repeatedly:
  checkStatus();    //check status of charges
  raport();       //send raport if is needit
 
  serial1Event();     //check data from buffer
  Serial1Tx();      //senddata from serial buffer
}

void IOexpanderWrite(byte address, byte data )
{
Wire.beginTransmission(address);
Wire.write(data);
Wire.endTransmission();
delay(10);
}
void setRelay(uint8_t n, bool mode){
 uint8_t relayAddress;
 uint8_t r;
 int data=0;
 
 if(mode)
  relayMode[n]=RELAY_P1;
 else
  relayMode[n]=RELAY_P0;
  
 if(n<8){
   relayAddress=RELAY_1;
   r=0;
 }
 else{
  relayAddress=RELAY_2;
  r=8;
 }
 
 for(uint8_t i=0;i<8;i++){
   if(relayMode[r+i]){
     data+=0.5+pow(2,i);
   }
 }
 IOexpanderWrite(relayAddress,data); 
 delay(10);
}
void initCharger(){
 for(uint8_t i=0;i<BATTERY_NUMBER;i++){       //set all charger sokets as empty for be ready to take new battery.
   chargerStatus[i]=STATUS_EMPTY;  
   autoMode[i]=true;
   relayMode[i]=RELAY_P0;
 }
 Serial.println("Multi Charger Ready!");
}

void setMux(uint8_t mux,uint8_t channel){
 int controlPin[] = {mux, mux+1, mux+2, mux+3};
 int muxChannel[16][4]={ {0,0,0,0}, //channel 0
             {1,0,0,0}, //channel 1
             {0,1,0,0}, //channel 2
             {1,1,0,0}, //channel 3
             {0,0,1,0}, //channel 4
             {1,0,1,0}, //channel 5
             {0,1,1,0}, //channel 6
             {1,1,1,0}, //channel 7
             {0,0,0,1}, //channel 8
             {1,0,0,1}, //channel 9
             {0,1,0,1}, //channel 10
             {1,1,0,1}, //channel 11
             {0,0,1,1}, //channel 12
             {1,0,1,1}, //channel 13
             {0,1,1,1}, //channel 14
             {1,1,1,1} //channel 15
             };
 for(uint8_t i = 0; i < 4; i ++){
  digitalWrite(controlPin[i], muxChannel[channel][i]);
 }
 delay(10);
}

void enableMux(uint8_t n){
 if(n<8)
   digitalWrite(MUX1_EN,LOW);
 else
   digitalWrite(MUX2_EN,LOW);
 delay(10);
}

void disableMux(uint8_t n){
 if(n<8)
   digitalWrite(MUX1_EN,HIGH);
 else
   digitalWrite(MUX2_EN,HIGH);

 delay(10);
}

float getVoltage(uint8_t pin){           //read voltage from analog pins
 float sample=0.0;
 for(uint8_t i=0;i<readSample;i++){
   sample+=analogRead(pin);  
   delay(1);  
 }
 sample=sample/readSample;
 return (float)sample*Vcc*2/1024;
}

float readBatVoltage(uint8_t bat){
 uint8_t voltagePin;
 uint8_t muxPin;
 uint8_t muxChannel;
 if(bat<8){
    voltagePin=BATTERY8_VOLTAGE_PIN;
    muxPin=MUX1_S0;
 }
 else{
    voltagePin=BATTERY16_VOLTAGE_PIN;
    muxPin=MUX2_S0;
 }
 enableMux(bat);
 muxChannel=bat%8*2;
 setMux(muxPin,muxChannel);
 float v= getVoltage(voltagePin);
 disableMux(bat);
 return v;
 
}

float readResVoltage(uint8_t bat){
 uint8_t voltagePin;
 uint8_t muxPin;
 uint8_t muxChannel;
 if(bat<8){
    voltagePin=BATTERY8_VOLTAGE_PIN;
    muxPin=MUX1_S0;
 }
 else{
    voltagePin=BATTERY16_VOLTAGE_PIN;
    muxPin=MUX2_S0;
 }
 enableMux(bat);
 muxChannel=bat%8*2+1;
 setMux(muxPin,muxChannel);
 float v= getVoltage(voltagePin);
 disableMux(bat);
 return v;
}

void setCharge(uint8_t n, bool mode){             //change mosfet workning mode
  if(mode){
   digitalWrite(MOSFET_CHARGE_PIN+n,CHARGE_ON); 
  }
  else{
   digitalWrite(MOSFET_CHARGE_PIN+n,CHARGE_OFF);
  }
  mosfetChargeMode[n]=mode;
  delay(10);
}

void setDischarge(uint8_t n, bool mode){             //change mosfet workning mode
  if(mode){
   digitalWrite(MOSFET_DISCHARGE_PIN+n,DISCHARGE_ON);
  }
  else{
   digitalWrite(MOSFET_DISCHARGE_PIN+n,DISCHARGE_OFF);
  }
  mosfetDischargeMode[n]=mode;
  delay(10);
}

bool isChargeingComplete(uint8_t n){               //check if battery is charging
 if(digitalRead(CHARGING_COMPLETE_PIN+n)==LOW)
  return true;
 return false;
}

void checkStatus(){

 if(millis()-lastTimeStatus<STATUS_TIME) return;
 lastTimeStatus=millis();

 for(uint8_t i=0;i<BATTERY_NUMBER;i++){
   uint8_t bat;
   
   if(relayMode[i]==RELAY_P0){
     bat=i;
   }
   else{
     bat=16+i;
   }
   
   if(chargerStatus[i]==STATUS_EMPTY){
     setCharge(i,true);
     setCharge(i,false);
     float bat_Voltage=readBatVoltage(i);
     if(bat_Voltage>2){
      chargerStatus[i]=STATUS_READY;
      batteryStatus[bat]=chargerStatus[i];
     }
   }
   
   if(chargerStatus[i]==STATUS_READY){
     float bat_Voltage=readBatVoltage(i);
     batteryVoltage[bat]=bat_Voltage;
     batteryCapacity[bat]=0;
     chargeTimeStart[bat]=0;
     chargeTimeStop[bat]=0;
     dischargeTimeStart[bat]=0;
     dischargeTimeStop[bat]=0;
     rechargeTimeStart[bat]=0;
     rechargeTimeStop[bat]=0;
       if(Serial1Raport)
        Serial1Send("<"+String(bat)+"|"+String(chargerStatus[i])+"|"+String(batteryCapacity[bat])+"|"+String(batteryVoltage[bat])+">");
       //Serial.println("<"+String(bat)+"|"+String(chargerStatus[i])+"|"+String(batteryCapacity[bat])+"|"+String(batteryVoltage[bat])+">");
      
       if(autoMode[i]){
        setCharge(i,true);
        chargeTimeStart[bat]=millis();
        chargerStatus[i]=STATUS_CHARGE;
        batteryStatus[bat]=chargerStatus[i];
       }
       else{
         if(bat_Voltage<0.3){
           chargerStatus[i]=STATUS_EMPTY;
           batteryStatus[bat]=chargerStatus[i];
          if(Serial1Raport)
            Serial1Send("<"+String(bat)+"|"+String(chargerStatus[i])+"|"+String(batteryCapacity[bat])+"|"+String(bat_Voltage)+">");
         //  Serial.println("<"+String(bat)+"|"+String(chargerStatus[i])+"|"+String(batteryCapacity[bat])+"|"+String(bat_Voltage)+">");
          }
       }
   }
    
   if(chargerStatus[i]==STATUS_CHARGE){
     chargeTimeStop[bat]=millis();
     if(isChargeingComplete(i)){
      setCharge(i,false);
      float bat_Voltage=readBatVoltage(i);
      batteryVoltage[bat]=bat_Voltage;
      chargerStatus[i]=STATUS_HIGH;
      batteryStatus[bat]=chargerStatus[i];
     }
   }
   if(chargerStatus[i]==STATUS_HIGH){
     if(autoMode){
      batteryCapacity[bat]=0.0;
      lastRead[i]=millis();
      dischargeTimeStart[bat]=millis();
      chargerStatus[i]=STATUS_DISCHARGE;
      batteryStatus[bat]=chargerStatus[i];
      setDischarge(i,true);
    }
     else{
       float bat_Voltage=readBatVoltage(i);
       if(bat_Voltage<1){
         chargerStatus[i]=STATUS_EMPTY;
         batteryStatus[bat]=chargerStatus[i];
        if(Serial1Raport)
         Serial1Send("<"+String(bat)+"|"+String(chargerStatus[i])+"|"+String(batteryCapacity[bat])+"|"+String(bat_Voltage)+">");
        //Serial.println("<"+String(bat)+"|"+String(chargerStatus[i])+"|"+String(batteryCapacity[bat])+"|"+String(bat_Voltage)+">");
        }
     }
   }
   if(chargerStatus[i]==STATUS_DISCHARGE){
      float bat_Voltage=readBatVoltage(i);
      float res_Voltage=readResVoltage(i);
      long now=millis();
      long time_Passed=now-lastRead[i];
      lastRead[i]=now;
      dischargeTimeStop[bat]=now;
      float current=(bat_Voltage-res_Voltage)/RES_VALUE *1000; //in mA
      batteryCapacity[bat]+= current * (time_Passed / 3600000.0); // one Hour = 3600000ms
      batteryVoltage[bat]=bat_Voltage;
      if(bat_Voltage<batteryLow){
       setDischarge(i,false);
       chargerStatus[i]=STATUS_LOW;
       batteryStatus[bat]=chargerStatus[i];
      }
     
   }
   if(chargerStatus[i]==STATUS_LOW){
     if(autoMode){
       setCharge(i,true);
       rechargeTimeStart[bat]=millis();
       chargerStatus[i]=STATUS_RECHARGE;
       batteryStatus[bat]=chargerStatus[i];
     }
     else{
       float bat_Voltage=readBatVoltage(i);
       if(bat_Voltage<1){
         chargerStatus[i]=STATUS_EMPTY;
         batteryStatus[bat]=chargerStatus[i];
        if(Serial1Raport)
         Serial1Send("<"+String(bat)+"|"+String(chargerStatus[i])+"|"+String(batteryCapacity[bat])+"|"+String(bat_Voltage)+">");
        //Serial.println("<"+String(bat)+"|"+String(chargerStatus[i])+"|"+String(batteryCapacity[bat])+"|"+String(bat_Voltage)+">");
        }
     }
    
   }
   if(chargerStatus[i]==STATUS_RECHARGE){
     rechargeTimeStop[bat]=millis();
     if(isChargeingComplete(i)){
      setCharge(i,false);
      float bat_Voltage=readBatVoltage(i);
      batteryVoltage[bat]=bat_Voltage;
      batteryComplete[bat]=true;
      chargerStatus[i]=STATUS_IDLE;
      batteryStatus[bat]=chargerStatus[i];
      if(Serial1Raport)
        Serial1Send("<"+String(bat)+"|"+String(chargerStatus[i])+"|"+String(batteryCapacity[bat])+"|"+String(batteryVoltage[bat])+"|"+String((chargeTimeStop[bat]-chargeTimeStart[bat])/60000)+"|"+String((dischargeTimeStop[bat]-dischargeTimeStart[bat])/60000)+"|"+String((rechargeTimeStop[bat]-rechargeTimeStart[bat])/60000)+">");
       //Serial.println("<"+String(bat)+"|"+String(chargerStatus[i])+"|"+String(batteryCapacity[bat])+"|"+String(batteryVoltage[bat])+"|"+String((chargeTimeStop[bat]-chargeTimeStart[bat])/60000)+"|"+String((dischargeTimeStop[bat]-dischargeTimeStart[bat])/60000)+"|"+String((rechargeTimeStop[bat]-rechargeTimeStart[bat])/60000)+">");
     }
    }
    if(chargerStatus[i]==STATUS_IDLE){
     
      float bat_Voltage=readBatVoltage(i);     
      if(bat_Voltage<1){
        chargerStatus[i]=STATUS_EMPTY;
        batteryStatus[bat]=chargerStatus[i];
        batteryComplete[bat]=false;   
        if(Serial1Raport)
         Serial1Send("<"+String(bat)+"|"+String(chargerStatus[i])+"|"+String(batteryCapacity[bat])+"|"+String(bat_Voltage)+">");
        //Serial.println("<"+String(bat)+"|"+String(chargerStatus[i])+"|"+String(batteryCapacity[bat])+"|"+String(bat_Voltage)+">");
      }
      else{
         if(relayMode[i]==RELAY_P0 && batteryComplete[i+BATTERY_NUMBER]==false){
           setRelay(i,true);
           chargerStatus[i]=STATUS_EMPTY;
         } 
         if(relayMode[i]==RELAY_P1 && batteryComplete[i+BATTERY_NUMBER]){
           setRelay(i,false);
         }
      }
    }
    //raport
   
   
 }
}
//###########Serial#################
void rx_empty(void)
{
 while(Serial1.available() > 0) {
  Serial1.read();
 }
}


void serial1Event()                      
{
 while (Serial1.available())
 {
  char MinChar = (char)Serial1.read();          // Char received from Serial1
  if (MinChar == '\n')
  {
   string1Available = true;
   evaluateRx(string1Rx);
   string1Rx="";
  }
  else
  {
   if (MinChar >= ' ') {string1Rx += MinChar;}   // >= ' ' to avoid not wanted ctrl char.
  }
 }
}
void evaluateRx(String s){
 uint8_t _index1,_index2;
 String buff;
 uint8_t n,i;
 switch(s.charAt(0)){
  case 'R': 
      buff=s.substring(1,s.length());
      n=buff.toInt();
      if(n>=0 && n<BATTERY_NUMBER)
       raportDetails(n);
      //Serial1.println("[R"+String(n)+":OK]");
  break;
  case 'S':
      buff=s.substring(1,s.length());
      n=buff.toInt();
      if(n==0){
         serial1Sendit=0;
         string1Tx="";
         serial1Confirmed=true;
         Serial.println("[S0:OK]");
      }else{
         serial1Sendit-=n;
      }
  break;
  case 'C':
      buff=s.substring(1,s.length());
      n=buff.toInt();
      if(n>=0 && n<BATTERY_NUMBER*BATTERY_ROWS)
       batteryComplete[n]=false;
      else
      if(n==33)
       for(i=0;i<BATTERY_NUMBER*BATTERY_ROWS;i++)
         if(batteryComplete[i]) batteryComplete[i]=false;
     
           
  break;
  default:
     if(s=="[OK]") serial1Confirmed=true;
  break;
 }
}

void raport(){
 if(millis()-lastTimeRaport<RAPORT_TIME || autoRaport==false) return;
 
 Serial.println();
  for(uint8_t i=0;i<BATTERY_NUMBER*BATTERY_ROWS;i++){
    if(i%4==0)
     Serial.println();
    Serial.println("<"+String(i)+"|"+String(batteryStatus[i])+"|"+String(batteryCapacity[i])+"|"+String(batteryVoltage[i])+"|"+String((chargeTimeStop[i]-chargeTimeStart[i])/60000)+"|"+String((dischargeTimeStop[i]-dischargeTimeStart[i])/60000)+"|"+String((rechargeTimeStop[i]-rechargeTimeStart[i])/60000)+">");
    Serial1Send("<"+String(i)+"|"+String(batteryStatus[i])+"|"+String(batteryCapacity[i])+"|"+String(batteryVoltage[i])+"|"+String((chargeTimeStop[i]-chargeTimeStart[i])/60000)+"|"+String((dischargeTimeStop[i]-dischargeTimeStart[i])/60000)+"|"+String((rechargeTimeStop[i]-rechargeTimeStart[i])/60000)+">");

 }
 Serial.println();
 lastTimeRaport=millis();
}


void raportDetails(uint8_t i){
  Serial1.println("<"+String(i)+"|"+String(batteryStatus[i])+"|"+String(batteryCapacity[i])+"|"+String(batteryVoltage[i])+"|"+String((chargeTimeStop[i]-chargeTimeStart[i])/60000)+"|"+String((dischargeTimeStop[i]-dischargeTimeStart[i])/60000)+"|"+String((rechargeTimeStop[i]-rechargeTimeStart[i])/60000)+">");
}


void Serial1Send(String s){
 if(Serial1Raport && serial1Connected){
   string1Tx+=s;
 }
 else
   string1Tx="";
}

void Serial1Tx(){
 uint8_t len=Serial1.availableForWrite()-2;
 String buff;
 
 if(len>0 && string1Tx.length()>0 && serial1Confirmed){
   if(len>string1Tx.length())
    len=string1Tx.length();
   buff=string1Tx.substring(0,len);
   string1Tx.remove(0,len);
   Serial1.print("["+buff+"]");
   serial1Sendit=len;
   Serial1.flush();
   serial1Confirmed=false;
  } 
  
}
 
  • Like
Reactions: srk
Just a quick thought, no actual math or looking at specs done :)

What about a buck converter to 5v and put that across a constant 10ohm or 5ohm load?
 
WildCard_25 said:
Just a quick thought, no actual math or looking at specs done :)

What about a buck converter to 5v and put that across a constant 10ohm or 5ohm load?

I think u need an step up buck, but usuly the have an specificpeak efficiency about 93-95%, so the power droped to resistor is less then the power taken from battery. My opinion will notwork.
 
Back
Top