Arduino Solar Power System

I have featured several articles on solar power charging circuits, now I am actually making one for my home use. I am currently on works to develop this system, although I know the theories behind it, I still learned a lot in this process. This system will be used for cellphone charging and a small light.

About the CIrcuit

The main controller is the arduino nano. This was my choice because it is the easiest solution I know and there are many resources online. The charging circuit used the popular LM317 voltage regulator. This voltage regulator is linear and not recommended for solar charger simple because of big power lost of linear regulators. When you are working with solar chargers, you want to make use most of the available power so linear regulators are not ideal for this kind of application.

Charging current measurement

I have used simple resistor for sensing and measuring the charging current. This circuit is posted on my previous article here. This is to make sure that the charging current will not exceed the normal level.

 

Code

This code is not yet final, with some bugs but working. Feel free to edit it and distribute. I will post the final code when I finish it. Unfortunately I only have time during weekends and not all weekends I have time for this so it may take some time to finish this project.

// include the library code:
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(2, 4, 7, 8, 12, 13);
int batt = 7; //
int solarcell = 2; //
int iin = 6; //
int sw1_pin = 0;
double cal_batt = 1.00400641;// 12.53/12.48
double cal_solar = 1;
double cal_iin = 1.01689461; // 12.64/12.43

/****** LCD Custom *******/
byte bat[8] = {
  B01110,
  B10001,
  B10001,
  B10001,
  B10001,
  B10001,
  B11111,
};

byte bat1[8] = {
  B01110,
  B10001,
  B10001,
  B10001,
  B10001,
  B11111,
  B11111,
};

byte bat2[8] = {
  B01110,
  B10001,
  B10001,
  B10001,
  B11111,
  B11111,
  B11111,
};

byte bat3[8] = {
  B01110,
  B10001,
  B10001,
  B11111,
  B11111,
  B11111,
  B11111,
};

byte bat4[8] = {
  B01110,
  B10001,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
};

byte bat5[8] = {
  B01110,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
};

byte sun[8] = {
  B01010,
  B01010,
  B11111,
  B11111,
  B01110,
  B00100,
  B11000,
};
#define LED1 3
#define LED2 5
#define LED3 6
#define LED4 9
//#define CHARGE_ON 3

int batt_val = 0;
double batt_voltage = 0;
int solarcell_val = 0;
double solarcell_voltage = 0;
int icharge_val = 0;
double icharge = 0;
double solar_minus_batt = 0;
int update_ctr = 0;
bool charge = false;
double v_offset = 0;
int icharge_int = 0;
bool light1 = false;
int light1_level = 0;
int sw1 = 0;
int sw_ctr = 0;
bool batt_full = false;
bool charge_fault = false;

void setup() {
  pinMode(LED1, OUTPUT); //LED1
  pinMode(LED2, OUTPUT); //LED2
  pinMode(LED3, OUTPUT); //LED3
  pinMode(LED4, OUTPUT); //LED4

  pinMode(A3, OUTPUT);
  //pinMode(A6, INPUT);
  //digitalWrite(A3, HIGH);

  // LCD Custom Chars
  lcd.createChar(0, bat);
  lcd.createChar(1, bat1);
  lcd.createChar(2, bat2);
  lcd.createChar(3, bat3);
  lcd.createChar(4, bat4);
  lcd.createChar(5, bat5);
  lcd.createChar(6, sun);
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  // Print a message to the LCD.
  //
  lcd.setCursor(0, 0);
  lcd.write(byte(0));
  lcd.setCursor(0, 1);
  lcd.write(byte(6));
  //
  digitalWrite(LED1, LOW);
  digitalWrite(LED2, HIGH); // inverted
  digitalWrite(LED3, LOW);
  digitalWrite(LED4, LOW);
  digitalWrite(LED4, LOW);
  iin_calibrate();
  update_analog();
}

void loop() {
  update_ctr++;
  if(update_ctr >= 100) // update analog readings
  {
    update_analog();
    update_ctr = 0;
    if(charge)
    {
      charging_icon();
    } else
    {
      battery_icon();
    }
  }

  lcd.setCursor(1, 0);
  //lcd.print(":");
  lcd.print(batt_voltage);

  if(solarcell_voltage > 17 && batt_full == false && charge_fault == false)
  {
    digitalWrite(A3, HIGH);
    lcd.setCursor(6, 0);
    lcd.print("V Charging");
    //lcd.print("V Chg:On ");
    charge = true;
  } else
  {
    if(solarcell_voltage < batt_voltage && icharge_int < 100) // disable
    {
      digitalWrite(A3, LOW); //disable charge
      //lcd.print("V Chg:OFF");
      charge = false;
    }
    if(batt_full == true || charge_fault == true)
    {
      digitalWrite(A3, LOW); //disable charge
      lcd.setCursor(5, 0);
      lcd.print("V Batt Full");
      charge = false;
    }

  }

  //lcd.print("V");
  lcd.setCursor(1, 1);
  //lcd.print("Sun:");
  lcd.print(solarcell_voltage);
  lcd.print("V ");
  if(!charge)
  {
    lcd.print("Chg:Off ");
  } else
  {
    lcd.print(icharge_int);
    lcd.print("mA ");
  }
  read_sw();
  batt_protect();
}

void read_sw()
{
  sw1 = analogRead(sw1_pin);

  if(sw_ctr > 50)
  {
    if(sw1 > 500)
    {
      if(light1 == true)
      {
        light1_level = light1_level - 51;
        if(light1_level < 0)
        {
          light1_level = 255;
          light1 = false;
          digitalWrite(LED2, HIGH); // inverted
        }
        analogWrite(LED2, light1_level);
        if(light1 == true)
        {
          lcd.setCursor(9, 0);
          lcd.print(" "); // clear
          lcd.setCursor(9, 0);
          lcd.print("L1:");
          lcd.print(255 - light1_level);
        } else
        {
          lcd.setCursor(9, 0);
          lcd.print("L1:off ");
        }
     } else
    {
      light1 = true;
      light1_level = 204;
      //digitalWrite(LED2, LOW); // inverted
      analogWrite(LED2, light1_level);
      if(light1 == true)
      {
        lcd.setCursor(9, 0);
        lcd.print(" "); // clear
        lcd.setCursor(9, 0);
        lcd.print("L1:");
        lcd.print(255 - light1_level);
      } else
      {
        lcd.setCursor(9, 0);
        lcd.print("L1:off ");
      }
    }
   sw_ctr = 0;
  }
  } else
  {
    sw_ctr++;
   }
}

void batt_protect()
{
if(batt_voltage >= 14)
{
batt_full = true;
} else
{
if(batt_voltage <= 13)
{
batt_full = false;
}
}

if(icharge_int > 1500)
{
charge_fault = true;
} else
{
charge_fault = false;
}

}

void iin_calibrate()
{
batt_val = analogRead(batt);
icharge_val = analogRead(iin);

//resistor = 10k, 47k//47k
batt_voltage = batt_val + (batt_val*2.35);
batt_voltage = (batt_voltage/1023) * 5;
//12.39 actual vs 12.12 read
// Calibration
batt_voltage = batt_voltage * cal_batt;

icharge = icharge_val + (icharge_val*2.35);
icharge = (icharge/1023) * 5;
icharge = icharge * cal_iin;
v_offset = icharge - batt_voltage;
}
void update_analog()
{
  batt_val = analogRead(batt); // read the input pin
  //resistor = 10k, 47k//47k
  batt_voltage = batt_val + (batt_val*2.35);
  batt_voltage = (batt_voltage/1023) * 5;
  //12.39 actual vs 12.12 read
  // Calibration
  batt_voltage = batt_voltage * cal_batt;

  icharge_val = analogRead(iin); // read the input pin
  //resistor = 1 ohm
  icharge = icharge_val + (icharge_val*2.35);
  icharge = (icharge/1023) * 5;

  icharge = icharge * cal_iin;

  icharge = (icharge - batt_voltage - v_offset) * 1000;// - v_offset;
  icharge_int = (int)(icharge);
  //icharge = icharge_val - batt_val - v_offset;
  //icharge = v_offset;

  solarcell_val = analogRead(solarcell); // read the input pin
  //resistor = 10k, 100k
  solarcell_voltage = solarcell_val + (solarcell_val*10);
  solarcell_voltage = (solarcell_voltage/1023) * 5;
  //12.39 actual vs 12.12 read
  // Calibration
  solarcell_voltage = solarcell_voltage * cal_solar;

  solar_minus_batt = solarcell_voltage - batt_voltage;
}

void charging_icon()
{
static int chg_ctr = 0;
chg_ctr++;
if(chg_ctr >= 6)
{
chg_ctr = 0;
}
lcd.setCursor(0, 0);
lcd.write(byte(chg_ctr));
}

void battery_icon()
{
static int bat_ctr = 0;
if (batt_voltage > 14.2)
{
bat_ctr = 5;
} else if (batt_voltage > 13.7)
{
bat_ctr = 4;
} else if (batt_voltage > 13.1)
{
bat_ctr = 3;
} else if (batt_voltage > 12.5)
{
bat_ctr = 2;
} else if (batt_voltage > 12.1)
{
bat_ctr = 1;
} else if (batt_voltage > 11.7)
{
bat_ctr = 0;
}
lcd.setCursor(0, 0);
lcd.write(byte(bat_ctr));
}