Beginners Guide to Processing 18650 Cells | Cell Database


Thread Rating:
  • 2 Vote(s) - 4.5 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Constantin PowerWall
#11
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.
Reply


#12
(09-07-2017, 01:24 PM)srk Wrote: 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 u can 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.



      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 have accuracy, the difference is from how 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 file u will see the cell will charge about 100% if u charged with 400-500mA and at 95% 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 power u will need to discharge with 1A or more for that use 3.7 or 5 ohm resistor as Load, for slow discharge use 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!
goodnowm likes this post
Reply
#13
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  l 190 mm h 120 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.



      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. 

 

      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.   
     
     

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;
    }
}
NZ55, KaminoReal, Korishan like this post
Reply
#14
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 Smile

Best teacher is through application, not just a book Wink
Proceed with caution. Knowledge is Power! Literally! Cool 
Knowledge is Power; Absolute Knowledge is Absolutely Shocking!
Dollar Shave Club. Best Razor I've ever used
Certified 18650 Cell Reclamation Technician
Reply
#15
hi

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









     I notice i only use about 15% of the mega memory on charging control unit, so for the next 32 module i will use PCF8574T i2c port expander and will be controlled by the same board.
     Also i notice when the power is down a little power will flow from TP4056 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 i2c PCF8574T will do the job.

     I add the video on youtube section. 

      Now i can test about 48 batterys on a day if 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 x PCF8574T   //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 x 1288x64 LCD Display
1 x Mega 2560
1 x 16 Key Keyboard

Upgrade and To Do List:

Battery temperature reading:
16 x 100k termistor
1 x CD4HC4067



Best regards
ruby2, Korishan, NZ55 like this post
Reply
#16
Photo 
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:



best regards
goodnowm likes this post
Reply
#17
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
Reply
#18
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;
    }   
     
}
srk likes this post
Reply
#19
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?
Reply
#20
(09-17-2017, 12:06 AM)WildCard_25 Wrote: 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 specific peak efficiency about 93-95%, so the power droped to resistor is less then the power taken from battery. My opinion will not work.
Reply


Who read this thread?
100 User(s) read this thread:
hbpowerwall (09-21-2017, 02:22 AM), Chickey (09-14-2017, 11:27 AM), daromer (10-01-2017, 06:06 AM), mike (09-07-2017, 07:32 PM), goodnowm (10-25-2017, 01:27 PM), AveRageJoe (09-18-2017, 03:56 AM), PaulKennett (09-25-2017, 08:10 AM), NiVa (09-18-2017, 11:01 PM), Lux_Gamer (11-04-2017, 07:02 PM), Andreas Kvernes (10-01-2017, 10:04 AM), owitte (09-29-2017, 10:42 AM), Majorphill (09-14-2017, 10:00 AM), BatteryDIY (09-07-2017, 10:58 PM), ruby2 (09-30-2017, 03:21 AM), JustJim (09-26-2017, 01:27 PM), Korishan (10-24-2017, 10:30 PM), A + A (10-01-2017, 03:28 PM), PAF (10-01-2017, 05:18 PM), FERCSA (09-05-2017, 08:14 PM), whisperbot (09-17-2017, 07:16 PM), JGaspar (10-01-2017, 06:46 AM), Tristan Timmer (09-04-2017, 08:55 PM), Alan Blake (09-25-2017, 01:18 AM), flight4900 (10-02-2017, 05:37 AM), jdeadman (10-01-2017, 03:28 AM), charlie246 (09-23-2017, 10:07 PM), 2146 (11-02-2017, 07:48 PM), wim (10-01-2017, 06:10 AM), wimpie007 (09-17-2017, 09:26 PM), frnandu (10-02-2017, 11:00 AM), typ49 (09-13-2017, 12:59 PM), The-J-Man (09-08-2017, 08:37 AM), Jeremy Choy (09-15-2017, 07:33 PM), Abarth595 (09-29-2017, 05:59 PM), kktuo (09-14-2017, 08:56 PM), Off Grid Power wall (09-27-2017, 09:26 AM), Em Em Silverghost (09-18-2017, 11:22 AM), kaits31 (09-06-2017, 09:42 PM), watts-on (09-30-2017, 10:32 PM), Dan Lim (09-17-2017, 09:53 AM), jesusangel (09-29-2017, 03:50 PM), volvo09 (09-20-2017, 03:57 PM), Hanssing (10-01-2017, 10:59 AM), IronSky (09-30-2017, 10:22 PM), silverse2m6 (09-04-2017, 04:46 PM), ismaildoganw (09-06-2017, 02:42 AM), Stefaan De Ridder (09-25-2017, 12:36 PM), Chiptosser (11-17-2017, 02:52 AM), rainbowwarrior38 (09-22-2017, 09:22 AM), systemtm (09-06-2017, 07:50 AM), Lawcomleo (09-09-2017, 08:55 PM), tremors (09-25-2017, 04:23 AM), piotrek111989 (09-29-2017, 06:33 AM), Johnny Stauersbøl (09-14-2017, 06:44 PM), Dennis Van Hoek (09-20-2017, 07:41 PM), brafi (09-17-2017, 07:32 PM), Nitroghost (09-06-2017, 11:36 PM), Terry (09-14-2017, 02:20 PM), N00bPwr (09-14-2017, 06:56 PM), KaminoReal (10-01-2017, 03:06 PM), Robert Crawley (09-08-2017, 05:12 AM), KtB (09-30-2017, 09:36 PM), sk8boy204 (09-04-2017, 05:40 PM), barthy (09-24-2017, 08:18 AM), Seedser (09-18-2017, 12:37 PM), paraskevas (09-29-2017, 02:28 PM), kiwi (10-30-2017, 02:52 PM), Ben Hekert (09-06-2017, 05:29 PM), ivnz (10-01-2017, 07:29 AM), iceisfun (10-01-2017, 01:07 AM), Geek (10-23-2017, 03:09 AM), TAGG (09-17-2017, 07:57 PM), Dave Tucker II (09-22-2017, 06:41 PM), Rad (09-15-2017, 05:47 AM), SWEwall (09-14-2017, 07:57 PM), Jon (09-30-2017, 10:11 PM), WildCard_25 (09-30-2017, 10:10 PM), Ivo Staelens (10-01-2017, 05:52 AM), jose215 (11-09-2017, 01:29 AM), AirDogU2 (09-21-2017, 07:50 PM), Mrsmith (09-07-2017, 10:45 AM), fabioelsabio (09-20-2017, 02:51 PM), jamesk9 (10-05-2017, 01:28 AM), mr_hypno (09-17-2017, 12:03 PM), NZ55 (09-25-2017, 08:05 PM), floydR (11-12-2017, 02:50 AM), AlexCPU (09-18-2017, 10:42 AM), SimonW (09-25-2017, 09:59 AM), Oshey (09-18-2017, 08:09 PM), brol (10-01-2017, 09:12 PM), ryan.nguyen (09-13-2017, 10:45 AM), sunseeker (09-18-2017, 12:53 PM), grgdgreek (10-01-2017, 07:17 AM), Rahtid27 (10-25-2017, 10:34 PM), DarkRaven (09-05-2017, 12:19 AM), druss56 (09-17-2017, 12:52 PM), mrconstantin (11-14-2017, 07:42 PM), Patrick Moreau (09-05-2017, 12:14 AM), mgiljum (09-05-2017, 01:56 AM), Gerard Achternaam (10-01-2017, 07:13 AM)

Forum Jump:


Users browsing this thread: 1 Guest(s)