#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,20,4); //LCD i2c adress sometimes 0x3f or 0x27
//Icons
uint8_t Battery[8] = {0x0E, 0x1B, 0x11, 0x11, 0x1F, 0x1F, 0x1F, 0x1F};
uint8_t Panel[8] = {0x1F, 0x15, 0x1F, 0x15, 0x1F, 0x15, 0x1F, 0x00};
uint8_t Pwm[8] = {0x1D, 0x15, 0x15, 0x15, 0x15,0x15, 0x15, 0x17};
uint8_t Flash[8] = {0x01, 0x02, 0x04, 0x1F, 0x1F, 0x02, 0x04, 0x08};
//Constants
#define bulk_voltage_max 14.5
#define bulk_voltage_min 13
#define absorption_voltage 14.7
#define float_voltage_max 13
#define battery_min_voltage 10
#define solar_min_voltage 19
#define charging_current 2.0
#define absorption_max_current 2.0
#define absorption_min_current 0.1
#define float_voltage_min 13.2
#define float_voltage 13.4
#define float_max_current 0.12
#define LCD_refresh_rate 1000
byte BULK = 0; //Give values to each mode
byte ABSORPTION = 1;
byte FLOAT = 2;
byte mode = 0; //We start with mode 0 BULK
//Inputs
//Outputs
//Variables
float bat_voltage = 0;
int e = 0;
float solar_current = 0;
float t = 0.185; //Value defined by manufacturer ACS712 5A
float o = 0;
float solar_power = 0;
String load_status = "OFF";
int p = 0;
unsigned int before_millis = 0;
unsigned int now_millis = 0;
String mode_str = "BULK";
void setup(){
pinMode(A1,INPUT); //Set pins as inputs
pinMode(A0,INPUT);
pinMode(A2,INPUT);
pinMode(10,OUTPUT); //Set pins as OUTPUTS
digitalWrite(10,0); //Set PWM to LOW so MSOFET is off
pinMode(2,OUTPUT);
digitalWrite(2,0); //Start with the relay turned off
TCCR1B = TCCR1B & B11111000 | B00000001; //timer 1 PWM frequency of 31372.55 Hz
Serial.begin(9600);
lcd.init(); //Init the LCD
lcd.backlight(); //Activate backlight
lcd.createChar(0, Battery);
lcd.createChar(1, Panel);
lcd.createChar(2, Pwm);
lcd.createChar(3, Flash);
before_millis = millis; //Used for LCD refresh rate
}
void loop(){
o = x(15);
bat_voltage = z(15);
solar_current = w(15);
solar_power = bat_voltage * solar_current;
p = map(e,0,255,0,100);
now_millis = millis();
if(now_millis - before_millis > LCD_refresh_rate)
{
before_millis = now_millis;
lcd.clear();
lcd.setCursor(0,0); //Column 0 row 0
lcd.write(1); //Panel icon
lcd.print(" "); //Empty space
lcd.print(o,2); //Soalr voltage
lcd.print("V"); //Volts
lcd.print(" "); //Empty spaces
lcd.write(0); //Battery icon
lcd.print(" "); //Empty space
lcd.print(bat_voltage,2); //Battery voltsge
lcd.print("V"); //Volts
lcd.setCursor(0,1); //Column 0 row 1
lcd.print(" "); //Empty spaces
lcd.print(solar_current,2); //Solar current
lcd.print("A"); //Ampers
lcd.print(" LOAD "); //Print LOAD
lcd.print(load_status); //LOAD status
lcd.setCursor(0,2); //Column 0 row 2
lcd.print(" "); //Empty spaces
lcd.print(solar_power,2); //Solar power
lcd.print("W"); //Watts
lcd.print(" PWM "); //Print PWM
lcd.print(p); //PWM value
lcd.print("%"); //Percentage
lcd.setCursor(0,3); //Column 0 row 3
lcd.print(mode_str); //Print the mode
}
if(bat_voltage < battery_min_voltage){
digitalWrite(2,0); //We DISABLE the load if battery is undervoltage
load_status = "OFF";
}
else{
digitalWrite(2,1); //We ENABLE the load if battery charged
load_status = "ON";
}
///////////////////////////FLOAT///////////////////////////
///////////////////////////////////////////////////////////
if(mode == FLOAT){
if(bat_voltage < float_voltage_min){
mode = BULK;
mode_str = "BULK";
}
else{
if(solar_current > float_max_current){ //If we exceed max current value, we change mode
mode = BULK;
mode_str = "BULK";
}//End if >
else{
if(bat_voltage > float_voltage){
e--;
e = constrain(e,0,254);
}
else {
e++;
e = constrain(e,0,254);
}
}//End else > float_max_current
analogWrite(10,e);
}
}//END of mode == FLOAT
//Bulk/Absorption
else{
if(bat_voltage < bulk_voltage_min){
mode = BULK;
mode_str = "BULK";
}
else if(bat_voltage > bulk_voltage_max){
mode_str = "ABSORPTION";
mode = ABSORPTION;
}
////////////////////////////BULK///////////////////////////
///////////////////////////////////////////////////////////
if(mode == BULK){
if(solar_current > charging_current){
e--;
e = constrain(e,0,254);
}
else {
e++;
e = constrain(e,0,254);
}
analogWrite(10,e);
}//End of mode == BULK
/////////////////////////ABSORPTION/////////////////////////
///////////////////////////////////////////////////////////
if(mode == ABSORPTION){
if(solar_current > absorption_max_current){ //If we exceed max current value, we reduce duty cycle
e--;
e = constrain(e,0,254);
}//End if > absorption_max_current
else{
if(bat_voltage > absorption_voltage){
e++;
e = constrain(e,0,254);
}
else {
e--;
e = constrain(e,0,254);
}
if(solar_current < absorption_min_current){
mode = FLOAT;
mode_str = "FLOAT";
}
}//End else > absorption_max_current
analogWrite(10,e);
}// End of mode == absorption_max_current
}//END of else mode == FLOAT
//Serial.println(bat_voltage);
}//End void loop
/////////////////////////FUNCTIONS/////////////////////////
///////////////////////////////////////////////////////////
float x(int n)
{
float v = 0;
for(int i=0; i < n; i++)
{
v += (analogRead(A1) * (5.0 / 1023.0) * 8.0);
}
v = v/n;
if(v < 0){v = 0;}
return(v);
}
float z(int n)
{
float v = 0;
for(int i=0; i < n; i++)
{
v += (analogRead(A2) * (5.0 / 1023.0) * 7.85);
}
v = v/n;
if(v < 0){v = 0;}
return(v);
}
float w(int n)
{
float v;
float c =0;
for(int i=0; i < n; i++)
{
v = analogRead(A0) * (5.0 / 1023.0);
c = c + (v-2.5)/t;
}
c = c/n;
if(c < 0){c = 0;}
return(c);
}
uno:A5.2
uno:A4.2
uno:AREF
uno:GND.1
uno:13
uno:12
uno:11
uno:10
uno:9
uno:8
uno:7
uno:6
uno:5
uno:4
uno:3
uno:2
uno:1
uno:0
uno:IOREF
uno:RESET
uno:3.3V
uno:5V
uno:GND.2
uno:GND.3
uno:VIN
uno:A0
uno:A1
uno:A2
uno:A3
uno:A4
uno:A5
lcd1:GND
lcd1:VCC
lcd1:SDA
lcd1:SCL
pot1:GND
pot1:SIG
pot1:VCC
pot2:GND
pot2:SIG
pot2:VCC
led1:A
led1:C
r1:1
r1:2
pot3:GND
pot3:SIG
pot3:VCC
led2:A
led2:C
r2:1
r2:2