Solarbox Powerbank Firmware V0.24

Aus Open Source Ecology - Germany
Zur Navigation springen Zur Suche springen

This is still under development and acts as a kind of working horse, so please ignore all the redundant comments

* created on 08/04/2014
   by Debasish Dutta/deba168
   
   extended on 04.09.2014 by OS/case
      
   This code is in the public domain.
   If you modify please inform me
   send a modified copy which will be helpfull for me
 */

#include <LiquidCrystal.h>
/*
 The LCD-Display circuit:
 * LCD RS pin to digital pin 12
 * LCD Enable pin to digital pin 11
 * LCD D4 pin to digital pin 5
 * LCD D5 pin to digital pin 4
 * LCD D6 pin to digital pin 3
 * LCD D7 pin to digital pin 2
 * LCD R/W pin to ground
 * 10K resistor:
 * ends to +5V and ground
 * wiper to LCD VO pin (pin 3)
 */
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);


// LEDs
int RED=8;           // To indicate discharged condition of battery
int GREEN=7;         // Solar or Grid-Power on
int redflag = 0;       // make red LED blink
int greenflag = 0;       // make green LED blink


// Sampling
float solar_volt =0; // variable for solar panel voltage
float bat_volt=0;    // variable for battery voltage
float bat_amp=0;    // variable for battery voltage
float old_bat_amp;
float sample1=0;     // reading from Arduino pin A0
float sample2=0;     // reading from Arduino pin A1
float sample3=0;     // reading from Arduino pin A2
int fenster = 100;     // Fensterbreite f. gleitenden Durchschnitt
float gleiwin[100];      // gleitender Durchschnitt
//gleiwin = new float[fenster];


// Kalibrierwerte
float vsys = 0.0;    // gemessene Systemspannung
float r1 = 0.0;      // gemessener 1. Widerstand von Spannungsteiler VBat
float r2 = 0.0;      // gemessener 2. Widerstand von Spannungsteiuler VBat
float rel = 0.0;
float onebit;
float rfaktor = 0;  // Realitätsfaktor zum Abgleich mit meinem Multimeter


// Charging Values
//float vladeschluss = 6.4; // Max-Voltage per cell 3.2
//float vladeschluss = 6.6; // Max-Voltage per cell 3.3
//float vladeschluss = 7.2; // Max-Voltage per cell 3.6 ==> this defines the upper level if 100% use of cell capacity is wanted
float vladeschluss = 7.1; // Max-Voltage per cell 3.55 ==> this defines the upper level if about 95% use of cell capacity is wanted - its healthier

// float vladeschluss = 7.2; // Max-Voltage per cell 3.55 ==> this defines the upper level if about 95% use of cell capacity is wanted - its healthier

//float cc = 0.5;   // constant current , current clamp for CC/CV-charging

float cc = 0.9;   // constant current , current clamp for CC/CV-charging


int pwm=6;           // pwm out put to mosfet
// float duty = 0.0;    // duty cycle prozente
int duty = 0;    // duty cycle prozente
int chargingflag = 0;


// Discharging Values
float ventladeschluss = 5.6; // Min-Voltage per cell 2.8 ==> Depth of Discharge (DOD) about 80%
int load=9;          //load is connected to pin-9

// Floating Values
// float vfloating_min = 6.8;  // In floating-mode discharge until 3.45V per cell then start charging again ==> Hysteresis
float vfloating_min = 6.9;  // In floating-mode discharge until 3.45V per cell then start charging again ==> Hysteresis
float cv = vladeschluss;    // default value for charging, choose a smaller value for more battery-health
int floatingflag = 0;  




// Evaluation
unsigned long timestamp;
int charged_percent =0; 
int i = 0;



void setup()
{
  
  TCCR0B = TCCR0B & 0b11111000 | 0x05; // setting prescaar for 61.03Hz pwm
  Serial.begin(9600);
  pinMode(pwm,OUTPUT);
  //pinMode(load,OUTPUT);
  pinMode(RED,OUTPUT);
  pinMode(GREEN,OUTPUT);

  digitalWrite(pwm,LOW);
  //digitalWrite(load,LOW);
  digitalWrite(RED,LOW);
  digitalWrite(GREEN,LOW);
  
  lcd.begin(16, 2);                     // columns, rows. size of display
  lcd.clear();                         // clear the screen
  /*
  lcd.print("Solar-Charger");
  lcd.setCursor(0, 1);
  lcd.print("V.0.24, by OS 2014");
  delay(10);
  lcd.clear();
  */
  
     
  // duty = 50;
  
  
}









// void loop_disabled()
void loop()
{
  lcd.setCursor(16,1); // set the cursor outside the display count
  lcd.print(" ");      // print empty character
  timestamp = millis();
  
  ///////////////////////////  VOLTAGE SENSING ////////////////////////////////////////////
  int zaehler = 10;
  
  for(int i=0;i<zaehler;i++)
  {
    sample1+=analogRead(A1);  //read the input voltage from solar panel
    sample2+=analogRead(A2);  //read the battery voltage 
    sample3+=analogRead(A0);  //read the battery amperage 
    delay(4);
  }
  sample1=sample1/zaehler; 
  sample2=sample2/zaehler; 
  sample3=sample3/zaehler; 
  
  delay(1);
   
   // Kalibrierung
   // vsys = 4.200;         // gemessene Spannung am Arduino, versorgt durch PC
   // rfaktor = 1.1122;      // rfaktor bei PC-Versorgung
   vsys = 5.003;         // gemessene Spannung am BuckBoost-Converter ==> Arduino-5V-Pin (Achtung nicht Vin nehmen, da linearregler >= 7V verlangt !!!)
   rfaktor = 1;
   // rfaktor = 0.98;         // Anpassung an zweites Multimeter
   // vsys = 3.95;         // gemessene Spannung am Arduino, versorgt durch Batterie mit BuckBoost-Converter
   //// rfaktor = 1.10396;    // rfaktor bei buckbooster-Betrieb
   // rfaktor = 1.106;    // rfaktor gemittelt aus PC- und Buckbooster-Betrieb
   
   r1 = 9.96;            // gemessener R1 von Spannungsteiler Batterie
   r2 = 4.67;            // gemessener R2 von Spannungsteiler Batterie
    
   rel = (r1+r2)/r2;          // Verhältniss R2 zu R1
   onebit = vsys/1023;   // 1 Bit entspricht rund 4.89mV (=5.02V / 1024 Bit)
   
   // Spannungsteiler Batterie
   bat_volt = sample2*onebit;  // tatsächlich durch ADC gemessene VBat - uninterpretiert
   bat_volt = bat_volt/rfaktor;  // Realitätsfaktor gegenüber Multimetermessung: 1.1122
   bat_volt = bat_volt * rel; // umgerechnet in Gesamtvolt

   // Spnnungsteiler ExternalInput (z.B. Solar, oder Netzteil)
   solar_volt = sample1*onebit;  // tatsächlich durch ADC gemessene VBat - uninterpretiert
   solar_volt = solar_volt/rfaktor;  // Realitätsfaktor gegenüber Multimetermessung: 1.1122
   solar_volt = solar_volt * rel; // umgerechnet in Gesamtvolt


  ///////////////////////////  AMPERAGE SENSING ////////////////////////////////////////////
   // Amperemessung Batterie, mittels ACS714
   //// sample3 = sample3+36;
   //sample3 = sample3+30;
   bat_amp = map(sample3, 102, 921, -300, 300)/10.00;
   //bat_amp = bat_amp * 0.5; // Anpassung an mein Multimeter  Alternative: Amp-Wert ca 1000 mal messen und mitteln, nähert sich dadurch meinem Multimeter an
   // bat_amp = bat_amp * 0.76; // Anpassung an mein Multimeter  Alternative: Amp-Wert ca 1000 mal messen und mitteln, nähert sich dadurch meinem Multimeter an

   double Current = currentSensor(analogRead(0));  // Read  analog value
   // printDouble(Current, 2);                  
    bat_amp = (float) Current;

// Glättung  
/*
   old_bat_amp = 0;
   for(i=1; i<(fenster-1); i++)
   {
     gleiwin[i-1] = gleiwin[i];
     old_bat_amp = old_bat_amp + gleiwin[i];
   }
   gleiwin[fenster-1] = bat_amp;
   old_bat_amp = old_bat_amp + bat_amp;
   bat_amp = old_bat_amp / fenster;
*/   
//bat_amp = bat_amp -0.9;
 bat_amp = bat_amp +2.9;
 bat_amp = bat_amp / 3;

//   bat_amp = bat_amp +0.03;
   // bat_amp = bat_amp * fenster;
   
// old_bat_amp = bat_amp + old_bat_amp;
// old_bat_amp = old_bat_amp / 2;


  ///////////////////////////  DATA OUTPUT ////////////////////////////////////////////
  lcd.setCursor(0,0); // set the cursor at 1st col and 1st row
  lcd.print("Vs:");
  lcd.print(solar_volt);
  
  lcd.setCursor(8,0); // set the cursor at 8st col and 1st row
  lcd.print("Vb:");
  lcd.print(bat_volt);
  //lcd.print(rel);
  //lcd.print(sample2);

  lcd.setCursor(8,1); // set the cursor at 8st col and 2nd row
  lcd.print("Ab:             ");
  lcd.setCursor(11,1); // set the cursor at 8st col and 2nd row
  lcd.print(bat_amp);
  
  lcd.setCursor(0,1); // set the cursor at 8st col and 2nd row
  lcd.print("Du:     ");
  lcd.setCursor(3,1); // set the cursor at 8st col and 2nd row
  // lcd.print(duty);
  lcd.print(sample3);


   Serial.print(bat_volt);
   Serial.print(",");   
   Serial.print(bat_amp);
   Serial.print(",");   
   Serial.print(solar_volt);
   Serial.print(",");   
   Serial.print(chargingflag);
   Serial.print(",");   
   Serial.println(duty);
   // Serial.print(",");   
   // Serial.println(timestamp);
  
    
/////////////////////////// State machine ////////////////////////////////////////////////

/*
if((solar_volt > bat_volt) && (bat_volt > 0))    // external voltage input and battery are connected
{
 duty = cc / 0.0172;    // empirisch gemessen
 
 analogWrite(pwm,2.55 * duty);  // float charging 

}
else duty = 0;
*/


if((solar_volt > bat_volt) && (bat_volt > 0))    // external voltage input and battery are connected
{
  //********* Charge ************************
  // duty = 30;
  
  // duty = 25;

  if(bat_volt < vladeschluss)  // Charging in CurrentClamp-mode (CC)
  {
    if(chargingflag == 0)  // OFF mode
    {
      if(bat_volt > vfloating_min) chargingflag = 0; // between 3.55 and 3.45 stay off, in floating-mode
      else chargingflag = 1;                         // below 3.45 restart charging, in floating-mode
    }
    else  // chargingflag != 0
    {
      if(chargingflag == 1)
      {
        //Serial.print("CC-Charging: ");
         duty = cc / 0.0172;    // 0.0172 empirisch gemessene charging-rate pro 1% duty
        // if(bat_amp > cc && duty > 0) duty = duty-1;
        // if(bat_amp == cc) duty = duty;  // do nothing
        // if(bat_amp < cc && duty < 100) duty = duty+1;
        analogWrite(pwm,2.55 * duty);  // float charging 
      }
    }
  }


  if(bat_volt >= vladeschluss) // Charging in VoltageClamp-mode (CV)
  {
    if(bat_amp > cc/10) // Charging in VoltageClamp-mode (CV)
    {
      //Serial.print("CV-Charging: ");
      if(bat_volt > cv && duty > 0) duty = duty-1;
      if(bat_volt == cv) duty = duty;  // do nothing
      if(bat_volt < cv && duty < 100) duty = duty+1;
      analogWrite(pwm,2.55 * duty);  // float charging 
      chargingflag = 2;
    }
    else // (bat_amp <= cc/10)) // shut down when battery is fully charged
    {
      // Serial.println("Discharging: ");
      duty = 0;
      analogWrite(pwm,duty);  // stop charging
      chargingflag = 0;  
    }
  }

} // endif solar_volt > bat_volt
else // solar_volt <= bat_volt // No external voltage input or no battery is connected
{
  // Stop charging anyway
  duty = 0;
  analogWrite(pwm,0); 
  chargingflag = 0;
  
  //********************* Discharge **********************
  //Serial.print("DisCharging: ");
  // Low voltage protection for the Battery
  if( bat_volt <= ventladeschluss )
  {
    chargingflag = 1;
    
    // Verbraucher abklemmen
    
    // Arduino shutdown (or go sleep ?)
  }  
  
} // end else



delay(4);

//////////////////////////////LED INDICATION ////////////////////////////////////////


//Red LED will glow when any Solar-Power comes in
if(solar_volt > 0) {
  digitalWrite(RED,HIGH);
}
else
{
  digitalWrite(RED,LOW);
}

//Green LED will glow when a battery is connected
if(bat_volt > 0) {
  digitalWrite(GREEN,HIGH);
}
else
{
  digitalWrite(GREEN,LOW);
}


/*
// external voltage is there, but to weak for charging.
if(solar_volt <= bat_volt) 
{

  digitalWrite(RED,HIGH);
}
*/


if (chargingflag == 1)
{
 // Red LED will blink continiously indicating charging is going on
 if(redflag == 0) 
 {
   digitalWrite(RED,HIGH);
   redflag = 1;
 }
 else
 {
   digitalWrite(RED,LOW);
   redflag = 0;
 }
 delay(5);
}

if (chargingflag == 2)
{
 // Green LED will blink continiously indicating charging is going on
 if(greenflag == 0) 
 {
   digitalWrite(GREEN,HIGH);
   greenflag = 1;
 }
 else
 {
   digitalWrite(GREEN,LOW);
   greenflag = 0;
 }
 delay(5);
}



 
} // end loop()

//======================================================================


void test_loop(){

  double Current = currentSensor(analogRead(0));  // Read  analog value

  Serial.print(", VariationFromNull: "); 
  printDouble(Current, 2);                                     // display Current
  Serial.print(" A");
  Serial.println("");

  delay(1000);

} 


// --------------------------------------------------------------------------------------------------------

// Print decimal numbers

void printDouble(double val, byte precision) {

  Serial.print (int(val));                                     // Print int part

  if( precision > 0) {                                         // Print decimal part
    Serial.print(".");
    unsigned long frac, mult = 1;
    byte padding = precision -1;
    while(precision--) mult *=10;
    if(val >= 0) frac = (val - int(val)) * mult; else frac = (int(val) - val) * mult;
    unsigned long frac1 = frac;
    while(frac1 /= 10) padding--;
    while(padding--) Serial.print("0");
    Serial.print(frac,DEC) ;
  }

}

// Read 1.1V reference against AVcc

long readInternalVcc() {

  long result;
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  delay(2);                                                    // Wait for Vref to settle
  ADCSRA |= _BV(ADSC);                                         // Convert
  while (bit_is_set(ADCSRA,ADSC));
  result = ADCL;
  result |= ADCH<<8;
  result = 1126400L / result;                                  // Back-calculate AVcc in mV
  return result;

}

// Calculate current with Allegro ACS714

double currentSensor(int RawADC) {

  int    Sensitivity    = 66; // mV/A

  long   InternalVcc    = readInternalVcc();
  double ZeroCurrentVcc = InternalVcc / 2;
  double SensedVoltage  = (RawADC * InternalVcc) / 1024;
  double Difference     = SensedVoltage - ZeroCurrentVcc;
  double SensedCurrent  = Difference / Sensitivity;

  //Serial.print("ADC: ");
  //Serial.print(RawADC);
  //Serial.print("/1024");

  //Serial.print(", Sensed Voltage: ");
  //printDouble(SensedVoltage, 1);
  //Serial.print("mV");

  //Serial.print(", 0A at: ");
  // printDouble(ZeroCurrentVcc, 1);
  //Serial.print("mV");

  return SensedCurrent;                                        // Return the Current

}