0% found this document useful (0 votes)
3 views10 pages

MPPT Code

The document is an Arduino sketch for a solar charge controller that uses an LCD to display solar panel and battery voltage and current. It implements calibration, PWM control for charging stages, and maintains various states for efficient battery charging. The code includes functions for reading voltage and current, calibrating sensors, and updating the LCD display based on the charging status.

Uploaded by

artemisgamer2200
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views10 pages

MPPT Code

The document is an Arduino sketch for a solar charge controller that uses an LCD to display solar panel and battery voltage and current. It implements calibration, PWM control for charging stages, and maintains various states for efficient battery charging. The code includes functions for reading voltage and current, calibrating sensors, and updating the LCD display based on the charging status.

Uploaded by

artemisgamer2200
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

#include <Wire.

h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27,16,2);

#define PV_VOLT_PIN A0
#define PV_CURR_PIN A1
#define BAT_VOLT_PIN A2
#define BAT_CURR_PIN A3
#define PWM_PIN 10

#define AVG_SAMPLES 16

float pvCurrentOffset = 2.5;


float batCurrentOffset = 2.5;

float Vout = 14.6;


float CC_LIMIT = 10.0;

float D = 0.6;
float step = 0.003;

float Dmin = 0.25;


float Dmax_lim = 0.95;

int state = 0;
int counter = 0;

float V[3];
float I[3];

float Iph = 1;
float Rseries = 0;
float A = 1;
float B = 1;

float Vmax = 18;


float Pmax = 1;
float Dmax;

unsigned long last_reset = 0;


unsigned long reset_period = 1000;

unsigned long lcd_timer = 0;


int lcd_page = 0;

float readVoltage(int pin)


{
long sum = 0;

for(int i=0;i<AVG_SAMPLES;i++)
sum += analogRead(pin);

float adc = sum/(float)AVG_SAMPLES;


float V = adc * 5.0 / 1023.0;

return V * 5.0;
}

float readCurrent(int pin, float offset)


{
long sum = 0;

for(int i=0;i<AVG_SAMPLES;i++)
sum += analogRead(pin);

float adc = sum/(float)AVG_SAMPLES;


float V = adc * 5.0 / 1023.0;
float current = (V - offset) / 0.1;

if(abs(current) < 0.05) current = 0;

return current;
}

float calibrateSensor(int pin)


{
long sum = 0;

for(int i=0;i<200;i++)
{
sum += analogRead(pin);
delay(5);
}

float adc = sum / 200.0;


float V = adc * 5.0 / 1023.0;

return V;
}

void setPWM(float duty)


{
duty = constrain(duty,0,0.95);
OCR1B = duty * ICR1;
}

void setup()
{
pinMode(PWM_PIN,OUTPUT);

[Link]();
[Link]();

[Link](0,0);
[Link]("Calibrating...");

pvCurrentOffset = calibrateSensor(PV_CURR_PIN);
batCurrentOffset = calibrateSensor(BAT_CURR_PIN);

[Link]();
[Link]("Calibration OK");
delay(1000);

TCCR1A = 0;
TCCR1B = 0;

TCCR1A |= (1<<COM1B1);
TCCR1A |= (1<<WGM11);

TCCR1B |= (1<<WGM12);
TCCR1B |= (1<<WGM13);
TCCR1B |= (1<<CS10);

ICR1 = 800;

Dmax = Vout / Vmax;

setPWM(D);
}

void loop()
{
float Vpv = readVoltage(PV_VOLT_PIN);
float Ipv = readCurrent(PV_CURR_PIN, pvCurrentOffset);

float Vbat = readVoltage(BAT_VOLT_PIN);


float Ibat = readCurrent(BAT_CURR_PIN, batCurrentOffset);

float Ppv = Vpv * Ipv;

String chargeStage;

if(Vbat < 14.4)


chargeStage = "BULK";
else if(Vbat <= 14.6)
chargeStage = "ABSORB";
else if(Ibat < 1.0)
chargeStage = "FLOAT";
else
chargeStage = "ABSORB";

if(state==0)
{
D = 0.8;

if(counter==1)
Iph = max(Ipv,0.001);

counter++;

if(counter>=2)
{
state = 1;
counter = 0;
}
}

else if(state>=1 && state<=3)


{
float Dsample[3] = {0.9,0.85,0.8};
D = Dsample[state-1];

if(counter==1)
{
V[state-1] = Vpv;
I[state-1] = Ipv;
}

counter++;

if(counter>=2)
{
state++;
counter = 0;
}
}

else if(state==4)
{
float dI1 = max(Iph-I[0],0.001);
float dI2 = max(Iph-I[1],0.001);

float K1 = log(dI1);
float K2 = log(dI2);

float V21 = V[1]-V[0];


float I21 = I[1]-I[0];
float K21 = K2-K1;

float dI3 = max(Iph-I[2],0.001);


float K3 = log(dI3);

float V31 = V[2]-V[0];


float I31 = I[2]-I[0];
float K31 = K3-K1;
Rseries = (K31*V21 - K21*V31)/(K21*I31 - K31*I21);

B = K21/(V21 + I21*Rseries);
A = exp(K1 - B*(V[0] + I[0]*Rseries));

float Ptemp = 0;

for(float I_scan = 0.85*Iph; I_scan < 0.95*Iph; I_scan += 0.01)


{
float V_est = (1/B)*log((Iph-I_scan)/A) - Rseries*I_scan;
float P_est = V_est * I_scan;

if(P_est > Ptemp)


{
Ptemp = P_est;
Vmax = V_est;
}
}

Pmax = Ptemp;
Dmax = Vout / Vmax;

D = Dmax;

state = 5;

last_reset = millis();
}

else
{
float P = Vpv * Ipv;

if(P > Pmax)


{
Pmax = P;
Vmax = Vpv;
Dmax = Vout / Vmax;
D = Dmax - step;
}
else
{
step = -step;
D = Dmax - step;
}
}

if(Vbat >= 14.6)


D -= 0.01;

if(Ibat >= CC_LIMIT)


D -= 0.01;

D = constrain(D,Dmin,Dmax_lim);

setPWM(D);

if(millis()-last_reset > reset_period)


{
state = 0;
counter = 0;
}

if(millis() - lcd_timer > 2000)


{
lcd_timer = millis();
lcd_page++;
if(lcd_page > 3) lcd_page = 0;
[Link]();
}

if(lcd_page == 0)
{
[Link](0,0);
[Link]("PV V:");
[Link](Vpv,1);
[Link]("V");

[Link](0,1);
[Link]("PV I:");
[Link](Ipv,2);
[Link]("A");
}

else if(lcd_page == 1)
{
[Link](0,0);
[Link]("PV Power");

[Link](0,1);
[Link](Ppv,1);
[Link]("W");
}

else if(lcd_page == 2)
{
[Link](0,0);
[Link]("Bat V:");
[Link](Vbat,1);
[Link]("V");

[Link](0,1);
[Link]("Bat I:");
[Link](Ibat,2);
[Link]("A");
}

else if(lcd_page == 3)
{
[Link](0,0);
[Link]("Charging:");

[Link](0,1);
[Link](chargeStage);
}

delay(10);
}

You might also like