Site icon Homemade Circuit Projects

Real MPPT Solar Charger Circuit Using Arduino, LCD, and Manual/Auto Switch

So in this article we are trying to make a true MPPT solar charger project using Arduino which will charge a 12V battery from a solar panel and will use MPPT logic to always extract maximum power from the solar panel. That means that even when sunlight changes, we try to adjust PWM duty cycle smartly so that the panel gives out optimum wattage all the time, not wastefully.

What we will need:

We are going to use these things:

How it works:

We know that solar panel has one sweet spot where it gives max wattage. That spot changes if sunlight goes up or down. So we need to track that spot using code. That method is called Perturb and Observe (P&O). It means that we change duty cycle slightly and observe if power increased or decreased. If it increased then we go more in that direction. If it reduced then we go back. Very simple.

Manual and Auto switch:

We also want a manual override. That means user can stop MPPT and use fixed duty cycle if needed. So we use a switch connected to digital pin, if it is LOW = auto mode (MPPT running), if HIGH = manual mode (fixed PWM).

LCD display:

We show all info on LCD: solar volts, current, power, PWM duty, mode, etc. So we know what is going on live.

How we sense things:

Solar voltage is read via voltage divider (scaled down to 0-5V)

Current is read either by ACS712 or INA219 (user selects in code)

PWM control:

We use analogWrite (fast PWM pin) to generate switching signal to buck MOSFET. We can also use Timer1 library if more accuracy is needed later.

Basic Tracking Type MPPT Circuit Diagram

simple Arduino MPPT circuit

Circuit Connections

Solar panel positive goes to input of buck inductor.

Solar panel negative goes to Arduino GND.

Inductor connects to diode (cathode to output).

Output side goes to battery +ve.

Battery -ve goes to common GND.

MOSFET drain to solar panel positive (input), source to inductor input, inductor output to battery +ve.

For calculating the inductor value, you can take the help of this buck converter calculator.

Arduino PWM output (D3) goes to MOSFET gate through 100 ohm.

Pull-down 10k from gate to source.

Flyback diode across inductor input to GND.

Voltage divider: 100k and 10k from panel +ve to A0.

Current sensor:

LCD Pins and Their Connection Explanation:

LCD Pin No.LCD Pin NameConnects ToDescription (crude and simple)
1GNDArduino GNDThis is LCD negative supply. Connect to GND of Arduino.
2VCCArduino 5VThis is LCD positive. Connect to 5V from Arduino.
3V0Center of 10k potThis controls screen contrast. Pot ends go to 5V and GND, center goes here. Adjust for sharp text.
4RSArduino D7Register Select. Tells LCD if we are sending command or data. Connect to D7 of Arduino.
5RWGNDRead/Write pin. Tie to GND for always write mode (we never read from LCD).
6EN (E)Arduino D6Enable pin. Triggers the LCD to latch in the data. Connect to D6 of Arduino.
7 to 10D0 to D3Not UsedThese are only used in 8-bit mode. In 4-bit mode, we leave them unconnected.
11D4Arduino D5Data line 4. Connect to D5 of Arduino.
12D5Arduino D4Data line 5. Connect to D4 of Arduino.
13D6Arduino D3Data line 6. Connect to D3 of Arduino.
14D7Arduino D2Data line 7. Connect to D2 of Arduino.
15A (LED +)220 ohm to 5VLED backlight +. You can put 220 ohm resistor from here to 5V, or direct 5V if too dim.
16K (LED -)GNDLED backlight -ve. Connect to GND.

Buck Converter Connection Details

In the MOSFET buck converter stage, we do the connections in the following manner:

We take the solar panel positive, give it to the drain of the MOSFET. Then the source of MOSFET goes to the inductor input. After the inductor we connect to battery +ve. The MOSFET source side also connects with one side of flyback diode and its other side goes to battery -ve. That way when MOSFET turns OFF then diode gives path for inductor to dump energy into battery.

Full Program Code

//==================== MPPT Solar Charger Code by homemade-circuits.com ====================//
//== Dual Current Sensor Options: ACS712 or INA219
//== Manual/Auto Switch Control
//== LCD Display for Parameters

#include <LiquidCrystal.h>
#include <Wire.h>
#include <Adafruit_INA219.h>

//================ LCD Setup ===================//
LiquidCrystal lcd(9, 8, 7, 6, 5, 4);

//================ Constants ===================//
const int pwmPin = 3;           // PWM output to buck converter
const int potPin = A0;          // For manual duty cycle control
const int autoManualSwitch = 2; // Switch for manual/auto
const int voltagePin = A1;      // Panel voltage divider input (0 to 5V)
const int acsPin = A2;          // ACS712 analog output

#define SENSOR_ACS712 0
#define SENSOR_INA219 1
int currentSensorOption = SENSOR_INA219;  // Change to SENSOR_ACS712 if required

//================ INA219 Setup ===================//
Adafruit_INA219 ina219;

//================ Variables ===================//
float panelVoltage = 0;
float panelCurrent = 0;
float panelPower = 0;
float prevPower = 0;
float dutyCycle = 0.5; // Initial duty cycle
float delta = 0.01;     // Step size for perturb & observe

unsigned long lastMPPT = 0;
const unsigned long mpptInterval = 500; // in ms

void setup() {
  pinMode(pwmPin, OUTPUT);
  pinMode(autoManualSwitch, INPUT_PULLUP);
  lcd.begin(16, 2);
  analogWrite(pwmPin, (int)(dutyCycle * 255));

  if (currentSensorOption == SENSOR_INA219) {
    ina219.begin();
  }

  lcd.print("MPPT Solar Ready");
  delay(2000);
  lcd.clear();
}

void loop() {
  bool isManual = digitalRead(autoManualSwitch) == LOW;
  if (isManual) {
    manualControl();
  } else {
    autoMPPT();
  }
  showLCD();
  delay(200);
}

void manualControl() {
  int potValue = analogRead(potPin);
  dutyCycle = map(potValue, 0, 1023, 10, 95) / 100.0;
  analogWrite(pwmPin, dutyCycle * 255);
  readPanelParameters();
}

void autoMPPT() {
  if (millis() - lastMPPT >= mpptInterval) {
    lastMPPT = millis();
    readPanelParameters();

    if (panelPower > prevPower) {
      dutyCycle += delta;
    } else {
      dutyCycle -= delta;
      delta = -delta; // Reverse direction
    }

    if (dutyCycle > 0.95) dutyCycle = 0.95;
    if (dutyCycle < 0.1) dutyCycle = 0.1;

    analogWrite(pwmPin, dutyCycle * 255);
    prevPower = panelPower;
  }
}

void readPanelParameters() {
  panelVoltage = analogRead(voltagePin) * (25.0 / 1023.0); // Assuming 100k:10k divider for 25V max

  if (currentSensorOption == SENSOR_ACS712) {
    int sensorValue = analogRead(acsPin);
    float voltage = sensorValue * (5.0 / 1023.0);
    panelCurrent = (voltage - 2.5) / 0.1; // For ACS712 20A
  } else if (currentSensorOption == SENSOR_INA219) {
    panelCurrent = ina219.getCurrent_mA() / 1000.0; // mA to A
  }

  panelPower = panelVoltage * panelCurrent;
}

void showLCD() {
  lcd.setCursor(0, 0);
  lcd.print("V:"); lcd.print(panelVoltage, 1);
  lcd.print(" I:"); lcd.print(panelCurrent, 1);

  lcd.setCursor(0, 1);
  lcd.print("P:"); lcd.print(panelPower, 1);
  lcd.print(" D:"); lcd.print((int)(dutyCycle * 100));
}

Real MPPT Circuit Diagram with Current Sensor

Arduino true MPPT circuit

Step-by-Step Real MPPT Charger Wiring and Connection Explanation:

Basic Arduino Power Setup

2) LCD 16x2 Wiring (with LiquidCrystal Library)

LCD PinConnect to Arduino
VSSGND
VDD+5V
VOMiddle pin of 10k pot for contrast
RSD9
END8
D4D7
D5D6
D6D5
D7D4
RWGND
A (LED+)220 ohm to +5V
K (LED-)GND

We use pins D4 to D9 for LCD. A 10k preset is needed between +5V, GND, and LCD pin 3 to adjust contrast.

3) Solar Panel Input to Buck Converter

4) Current Sensor Options (ACS712 or INA219)

Option 1: Using ACS712 (e.g., 5A version)

Option 2: Using INA219

In the code, you can switch between ACS712 or INA219 by changing the flag useINA219 = true; or false;.

5) Manual / Auto Switch

In manual mode you can manually adjust duty cycle using the pot.

6) Manual Mode Potentiometer (10k)

7) Battery Output

Table showing the main Arduino Pins:

Arduino PinFunction
D3PWM to MOSFET Gate
A0ACS712 output
A4SDA for INA219
A5SCL for INA219
A1Potentiometer for manual
D10Manual/Auto switch input
D4-D9LCD Display

How It All Works:

Exit mobile version