Arduino Solar Current Sink


Solar panel current sink.

Characterization of a solar panel, for the purposes of this project, means to graph the voltage vs. current for a range of currents, with an approximately even illumination. It may seem a little simple to expect that to tell us anything standard about the panels, but I don't want to know anything standard. All I want to know how this particular panel behaves in this particular backyard. How much load can I give it before the voltage drops to a point that it can't be used?

You probably won't find that information on any smallish solar panel. They rate them at max voltage x max current. The problem is these two things are at opposite ends of the operating range. The maximum voltage point is exactly the minimum current point, and vice versa. Somewhere in between there is a point where the panel makes the maximum power.

And it's called (oddly enough) the maximum power point (MPP). On the graphs below, the yellow line is the total power being generated by the panel. Power increases, but then falls off. It is not exactly coincident with the sharp voltage falloff, but is somewhere just above that point. In order to harvest the maximum power, you need to find that point. For the top panel, it is 7.061V @ 76mA.

Solar panel output graph
8V 0.5W Solar panel output graph


This panel was used in the Solar Powered Arduino Pro Mini experiment. It cost $4 a couple of years back, and turned out to be perfect for the job.

Solar panel output graph
9V 1W Solar panel output graph


This Radio Shack 9V 1W Solar Panel I picked up at Amazon for $8. It doesn't quite do the 115mA it is rated for, but does 75mA at the maximum power point. It is intended to power a remote radio in an upcoming project.

Solar panel output graph
12V 3W Solar panel output graph


This honker panel I also got from Amazon, a 12 Volt 3 Watt solar panel. I used two of them in the Solar Arduino Uno experiment. They deliver a combined 400mA in full sunlight at the maximum power point. This is the highest performer of the panels I tested, in that it comes closest to the rated specs.

Solar panel output graph
9V 3W Solar panel output graph (fake)


Here is the main reason for this project. This panel was marketed as 9V 3W on, when it actually is a 5V @ 0.75W panel. I looked recently and the panel is still being sold as a 9V 3W panel, even after they had to refund my money. I just sent them this graph and asked for a refund.

A high-power rheostat could be used, but it isn't going to be nearly as easy to the control the current. With this circuit the Arduino just ramps the set point linearly, and measures the values of voltage and current. The accuracy is based on the precision of the current sensing resistor, R1. In my application, the total power generated by a single panel was about 2.25W, but a larger panel could be tested, with an output up to 450mA. A resistor with less resistance could be used for larger panels. A 1Ω resistor would be good for up to 5A. These values are more than the 2W rating of this resistor, so if you are going to measure more than 450mA, you need to decrease the resistance and increase the power rating of the resistor.

Solar panel current sink
Solar panel current sink

The Arduino sketch puts the setpoint on PWM pin D9, waits 50mS for things to settle, then reads the voltage and current on A0 and A1. That data gets written to the uSD card, for use later. The panel voltage is (5/1024)*ADU*3. (5/1024) is the voltage per ADU, and times 3 because the voltage divider made up of R2/(R3||R4)cuts the voltage to one third. The current in amps is (5/1024)*ADU/10. (5/1024) for the same reason, and divided by 10 because the load resistor R1 is 10 ohms. The Arduino increments the PWM duty cycle from 0 to 100% in 256 intervals, causing the current to increase from 0mA to a maximum of 500mA in 1.95mA increments. There is a point at which the panel gives up, and its output voltage drops to nearly zero. The Arduino does not care - it goes on about its business of increasing the current flow, which of course it can't do, so the data is no good after the voltage falls, except to indicate the short-circuit current. The short-circuit current remains amazingly constant regardless of load after it decides it is shorted. The minimum load is the value of the resistor (10Ω) plus the Rds(on) of the MOSFET.

The OpAmp works with the MOSFET to keep the voltage generated by the current through R1 equal to the set voltage on C1. It is a voltage controlled current source. The current from the solar panel goes through the MOSFET and resistor R1, with a little bypassing it to go through the resistor divider to measure the panel voltage.


The code just starts the process, then hangs forever when done.

 * Solar Panel Characterization
 * This app uses a voltage controlled current sink circuit to
 * characterize solar panel performance at various loads. It
 * makes a CSV file that can be used in a spreadsheet to make
 * spiffy charts.

#include <SPI.h>
#include <SD.h>

// (4700.0 + 2350.0) / 2350.0 * 0.004883
#define ADU_FACTOR_VOLTS (double)(0.014649)
#define ADU_FACTOR_AMPS (double)(0.0004883)

// An LED to indicate it is finished.
#define LED 7

// CS on the Sparkfun board.
const int chipSelect = 8;

int pwmValue;
int currentPin = A1;
int voltagePin = A0;
int currentSink = 9;

File dataFile;

void setup() 

  pinMode(LED, OUTPUT);
  pinMode(chipSelect, OUTPUT);
  if (!SD.begin(chipSelect)) {
    Serial.println("Card not present.");
    // Halt!
  Serial.println("Card initialized.");

  dataFile ="solar.csv", FILE_WRITE);
  if (!dataFile) {
    Serial.println("Error opening file on SD card.");
    // Halt!
  String output = "PWM,VOLTAGE,CURRENT,POWER";

  pwmValue = 0;

void loop() 
  // Set the current sink to the next level.
  analogWrite(currentSink, pwmValue);

  // Give it 50 milliseconds to stabilize.

  // Read the voltage.
  double voltage = analogRead(voltagePin) * ADU_FACTOR_VOLTS;

  // Read the current.
  double current = analogRead(currentPin) * ADU_FACTOR_AMPS;

  // Make a csv string.
  String output = String(pwmValue) + "," + String(voltage, 3) + "," + String(current, 3) + "," + String(voltage * current, 3);


  // Store the data on the SD card.

  // Adjust to the next level. Halt if > 255.
  if (++pwmValue == 256)
    // Shutdown the current sink (the transistor could get very hot).
    analogWrite(currentSink, 0);

    // Close the file on the SD card.

    // Let the user know it is finished.

    // Loop forever.
    while(1) {
      digitalWrite(LED, HIGH);
      digitalWrite(LED, LOW);

The result is a CSV file containing all 256 pairs of values:


The circuit is built on a Sparkfun Micro SD Shield. The SD card is because when I was going to be using this it would be outside and the sunniest part of the day. A laptop would be useless. I have added an LED on pin D7 which flashes when the scan is done. The scan starts when you power it up. If you reset it, it appends the next scan to the existing file.

  Serial.println("Card initialized.");
  if (SD.exists("solar.csv")) {

The last three lines above, placed right after that println, would delete the file if it exists. I left that out because I sometimes want to run it against several panels in one run, and swapping out the SD card is a bother.

I use Numbers to post process the data into a graph, but Excel works, too.

Arduino Board Logo


Arduino-Board is the go-to source for information on many available Arduino and Arduino-like boards, tutorials and projects.

Help and Support


Stay updated

Sign up if you would like to receive our once monthly newsletter.