Solarbox Powerbank Firmware V0.24
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
}