Solarbox Powerbank Firmware V0.24
/* 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.17, 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
}