element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
DIY Test Instrumentation
  • Challenges & Projects
  • Project14
  • DIY Test Instrumentation
  • More
  • Cancel
DIY Test Instrumentation
Blog SCDVM : Solar Cell Characteristic Measurement
  • Blog
  • Forum
  • Documents
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join DIY Test Instrumentation to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: dubbie
  • Date Created: 13 Aug 2021 1:56 PM Date Created
  • Views 2390 views
  • Likes 13 likes
  • Comments 9 comments
  • nano
  • diytestinstrumentationch
  • curve fitting
  • solar cell
  • oled graphic display
Related
Recommended

SCDVM : Solar Cell Characteristic Measurement

dubbie
dubbie
13 Aug 2021

For the DIY Test Instrument Project14 Challenge I decided that I wanted to make something using a graphic display and something I have been playing with this summer (when the sun actually shines!) are solar cells. Solar cells are interesting things as the power they produce is very dependent on the sunshine 'power', naturally, which affects the maximum power transfer point. The maximum power transfer load occurs when the load resistance across the solar cell is the same as the internal resistance of the solar cell and the internal resistance varies depending on the intensity of the sunshine falling on the solar cell. So it seemed to me that a meter that would measure and display the maximum power transfer and the maximum power transfer load resistance would be a good thing. So here it is.

 

Circuit Diagram

 

The circuit consists of a Nano connected to a 128x64 OLED white display which is used to show text and graphics. Ten of the Nano digital outputs are used to control analogue switches (ULN2003A) capable of a maximum current of 500 mA, used to apply resistive loads from 44 Ohms upto 220 Ohms. I didn't have all the specific resistor values I wanted so I made them up out of the values I did have. (Note : Buying lower value pin-thro-hole resistors is quite difficult if you only want a few). The values I managed were:

 

44 Ohms  (22 + 22)

57 Ohms  (10 + 47)

69 Ohms  (22 + 47)

79 Ohms  (10 + 22 + 47)

91 Ohms  (22 + 22 + 47)

100 Ohms

122 Ohms (22 + 100)

150 Ohms

200 Ohms

220 Ohms

 

image

 

I used Veroboard to construct the circuit, aiming for as few additional wires as possible, which is why the circuit is a bit 'odd' in places. In the end I think I only used four wires, plus the components, which seemed pretty good to me.

 

The circuit works by applying one of the resistive loads across the connected solar cell for a short period of 20 mA. I only had 250 mW resistors so a short applied load period was sensible, in order to avoid overheating the resistors, and I choose 20 ms. Solar cells are essentially semiconductors so should have short rise times and 20 ms seemed a good amount. I didn't have time to experiment with alternative delay values and the resistors did not seem to warm up. The solar cell voltage, Vsolar, is then measured using A0 on the Nano. In order to calculate the current through the load resistor I needed to subtract the Vbe voltage of the ULN2003AULN2003A transistors switches from Vsolar and then divide by the resistor value. Rather than try and measure the Vbe one each resistor load I took a sequence of manual measurement's using a DVM at various loads and decided that a value of 0.65V would be sufficiently accurate. The current can then be calculated as:

 

     I solar = (Vsolar - Vbe)/R

 

and the power becomes

 

    Psolar = Vsolar x Isolar

 

for each value of resistor.

 

To make a nice display on the OLED display it would be preferable to have more than 10 values (one for each different resistive load). Additional values can be obtained by fitting a polynomial curve to the power values. A library exists to do this in Arduino called CurveFitting which is easy to install via the Library Manager.

 

Sadly, it transpires that the Nano does not seem to have enough data memory to be able to implement both the OLED display and the curve fitting process as when both are implemented the same programme became unstable, resetting and just producing rubbish. There was insufficient time to rework the hardware circuit using  an Arduino with a larger memory (I did try the programme using a Maker WAN1310 and it seemed to work but it was not a pin for pin replacement for the Nano) so I ended up with two separate programmes. One obtains the power values, the other determines the polynomial coefficients. So I manually typed the power values into the curve fitting programme, obtained the coefficients and then manually entered them back into the first programme. I managed to get a working result although not in 'real-time'.  It would only take a bit more time and effort to rework the hardware to use the Maker WAN1310 (or some other Arduino with more memory) to create a fully working real-time measurement system.

 

The programme listing for the power collection part (with the graphic display part as well), is listed below. It is a bit long as the output bits controlling the resistor loads are handled explicitly rather than using a for loop, as the outputs used are not all sequential - due to the hardware construction. But, it works. It is also possible that not all of this programme is actually needed - there were many iterations.

 

/* Solar Cell DVM

   Displays the Characteristic of a small solar cell

   Dubbie Dubbie     13th Aug'21

   Just for Fun

   Uses an OLED 128x64 (clone of Adafruit display) with I2C with SSD1306

   driver and the Adafruit library. (or is it SPI?)

 

   GND = GND

   VCC = 5V

   SCL = A5

   SDA = A4

 

   10 kOhm resistors between A4-5V and A5-5V remove some problems with the I2C bus.

   It doesn't seem to work without these (sometimes!)

*/

 

#include <Adafruit_GFX.h>      // Include core graphics library for the display

#include <Adafruit_SSD1306.h>  // Include Adafruit_SSD1306 library to drive the display

 

Adafruit_SSD1306 display(128, 64);  // Create display 128x64

 

#define displaywidth 128

#define displayheight 64

#define text_delay 500

#define LED 13

#define SCinput 0  // Analogue input bit for solar cell voltage

#define VbeVoltage 129  // Digital value of 0.63V (Vbe of ULN2003AULN2003A driver)

#define loadondelay 20  // Time resistive load is powered for measurements

#define in1 2   // 220 Ohm

#define in2 3

#define in3 4

#define in4 5

#define in5 6   // 100 Ohm

#define in6 7

#define in7 9

#define in8 10

#define in9 11

#define in10 12

 

double x[] = {45.5, 54.0, 59.4, 65.2, 71.6, 77.0, 90.3, 101.6, 108.8, 98.9};

// Coefficients obtained from a separate programme

double coeffs[] = {-0.00002328, 0.00639639, 0.01055579, 35.644};

 

void setup()

{

  pinMode(LED_BUILTIN, OUTPUT);

  pinMode(in1, OUTPUT);

  pinMode(in2, OUTPUT);

  pinMode(in3, OUTPUT);

  pinMode(in4, OUTPUT);

  pinMode(in5, OUTPUT);

  pinMode(in6, OUTPUT);

  pinMode(in7, OUTPUT);

  pinMode(in8, OUTPUT);

  pinMode(in9, OUTPUT);

  pinMode(in10, OUTPUT);

  digitalWrite(in1, LOW); // Make sure all resistor loads are off

  digitalWrite(in2, LOW);

  digitalWrite(in3, LOW);

  digitalWrite(in4, LOW);

  digitalWrite(in5, LOW);

  digitalWrite(in6, LOW);

  digitalWrite(in7, LOW);

  digitalWrite(in8, LOW);

  digitalWrite(in9, LOW);

  digitalWrite(in10, LOW);

  delay(100);  // Display initialisation delay

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // Not entirely sure what this does

  display.clearDisplay();       // Clear the buffer

  display.setTextColor(WHITE);  // Set color of the text

  display.setRotation(0);       // Set orientation. Goes from 0, 1, 2 or 3

  pinMode(LED, OUTPUT);

  Serial.begin(9600);

  Serial.println("Solar Cell DVM Awake ");

} /*setup */

 

void loop()

{

  int value;

 

  value = 0;

  Serial.println("Starting SCDVM ");

  Serial.println("Made by Dubbie, Just for Fun " );

  Serial.println();

  delay(text_delay);

  display.clearDisplay();  // Clear the display so we can refresh

  display.setCursor(0, 10); // Bottom left

  display.println("Dubbie Dubbie ");

  display.println("Solar DVM");

  display.println("  ");

  display.display();  // This outputs to the screen

  delay(1000);

  display.clearDisplay();

  display.display();

   measureVIP();     // Measure power curve

   plotpowercurve(); // Display power curve 

while(1)

  {

  } /* while */

} /* loop */

 

double getSCV(int load)

 

{

  int SCvoltage;

 

  SCvoltage = 0;

  digitalWrite(load, HIGH);

  delayMicroseconds(loadondelay);  // Short on delay for voltages to satablise

  SCvoltage = analogRead(SCinput);

  digitalWrite(load, LOW);         // Turn off to avoid over heating

  return ((5.0 * SCvoltage)/1023.0); // Convert to floating point voltage

} /* getSCV */

 

double getSCI(int load)

 

{

  double SCI;

  SCI = 0.0;

  SCI = getSCV(load) - 0.65;  // Get voltage across resistor

                             // Now convert to mA : I = V/R * 1000

  switch(load)

    {

      case in1  : SCI = (SCI/220.0) * 1000.0; break;

      case in2  : SCI = (SCI/200.0) * 1000.0; break;

      case in3  : SCI = (SCI/150.0) * 1000.0; break;

      case in4  : SCI = (SCI/122.0) * 1000.0; break;

      case in5  : SCI = (SCI/100.0) * 1000.0; break;

      case in6  : SCI = (SCI/91.0)  * 1000.0; break;

      case in7  : SCI = (SCI/79.0)  * 1000.0; break;

      case in8  : SCI = (SCI/69.0)  * 1000.0; break;

      case in9  : SCI = (SCI/57.0)  * 1000.0; break;

      case in10 : SCI = (SCI/44.0)  * 1000.0; break;

      default : SCI = -1.0;   // Use negatives as an error           

    } /* switch */

  return (SCI);

} /* getSCI */

 

void measureVIP()

 

{

int index;

index = 0;

 

x[0] = getSCV(in1) * getSCI(in1);

x[1] = getSCV(in2) * getSCI(in2);

x[2] = getSCV(in3) * getSCI(in3);

x[3] = getSCV(in4) * getSCI(in4);

x[4] = getSCV(in5) * getSCI(in5);

x[5] = getSCV(in6) * getSCI(in6);

x[6] = getSCV(in7) * getSCI(in7);

x[7] = getSCV(in8) * getSCI(in8);

x[8] = getSCV(in9) * getSCI(in9);

x[9] = getSCV(in10) * getSCI(in10);

 

// This is a fix to ensure the same results everytime

x[0] = 45.5;

x[1] = 54.0;

x[2] = 59.4;

x[3] = 65.2;

x[4] = 71.6;

x[5] = 77.0;

x[6] = 90.3;

x[7] = 101.6;

x[8] = 108.8;

x[9] = 98.9;

 

for (index = 0; index < 10; index++)

{

  Serial.print("P = ");

  Serial.print(x[index]);

  Serial.println(" mW ");

} /* for */

Serial.println();

// delay(5000);  // Delay to see values

} /* measureVIP */

 

void plotpowercurve(void)

 

{

  int x, y;

  double xval = 0.0;

  int maxyval;

  int yval;   int colour;

 

  x = 0;   y = 0;

  yval = 0;

  colour = 1;

  maxyval = 0;

  display.clearDisplay();   // Clear the display

  display.setCursor(0, 10); // Bottom left

  display.println("Calculating Power Curve ");

  display.println("Please wait .... ");

  display.println("  ");

  display.display();  // This outputs to the screen

  delay(1000);

  display.clearDisplay();   // Clear the display

// Get the maximum y value  - needed for scaling the display

  for (x = 0; x < 123; x++)

    {

      xval = 44.0 + ((x * 176.0)/127.0);

      yval = calcy(xval);

      if (yval > maxyval) // Need the largest value for scaling the display

        {

          maxyval = yval;

        } /* if */

    } /* for */

// Now recalculate the y values and plot

// Needed as there isn't enough RAM in the Nano

  for (x = 0; x < 128; x++)

    {

       xval = 44.0 + ((x * 176.0)/127.0);

       yval = calcy(xval);

       y = ((yval * 63) / maxyval);

       display.drawPixel(x, (63 - y), colour);

    } /* for */

// Show max power transfer load value

  display.setCursor(80, 50); // Bottom right

  display.print("R = ");

  display.print(maxyval);

  display.display(); // Display the curve

} /* plotpowercurve */

 

double calcy(double xval )

 

{

double yval;

 

yval = 0.0;

// Use the curve coefficients to calculate value

yval =         coeffs[0] * xval * xval * xval;

yval = yval + (coeffs[1] * xval * xval);

yval = yval + (coeffs[2] * xval);

yval = yval +  coeffs[3];

return(yval);

} // calcy

 

The programme for performing the curve fitting is listed below and is based on the example programme supplied with the library. Both programmes were 'hacked' about a great deal while I was trying to get them working, so there are probably many poor techniques and inefficiencies, plus some unnecessary code. But, they did produce the desired results, eventually!

 

#include <curveFitting.h>

#include <Adafruit_GFX.h>      // Include core graphics library for the display

#include <Adafruit_SSD1306.h>  // Include Adafruit_SSD1306 library to drive the display

 

Adafruit_SSD1306 display(128, 64);  // Create display 128x64

 

void setup()

{

  delay(100);  // Display initialisation delay

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // Not entirely sure what this does

  display.clearDisplay();  // Clear the buffer

  display.setTextColor(WHITE);  // Set color of the text

  display.setRotation(0);  // Set orientation. Goes from 0, 1, 2 or 3

 

  Serial.begin(9600);

  while(!Serial);

  Serial.println("Starting");

  display.clearDisplay();  // Clear the display so we can refresh

  display.setCursor(0, 10); // Bottom left

  display.println("Dubbie Dubbie ");

  display.display();  // This outputs to the screen

 

  char buf[100];

  int xpower = 3;

  int order = 3;

  snprintf(buf, 100, "Fitting curve of order %i to data of power %i...\n", order, xpower);

  Serial.print(buf);

 

  double x[] = {45.5, 54.0, 59.4, 65.2, 71.6, 77.0, 90.3, 101.6, 108.8, 98.9};

  double t[] = {44.0, 57.0, 69.0, 79.0, 91.0, 100.0, 122.0, 150.0, 200.0, 220.0};

 

  double coeffs[order+1];

  int ret = fitCurve(order, sizeof(x)/sizeof(double), t, x, sizeof(coeffs)/sizeof(double), coeffs);

 

  if (ret == 0){ //Returned value is 0 if no error

    char c = 'a';

    Serial.println("Coefficients are");

    Serial.println();

    for (int i = 0; i < sizeof(coeffs)/sizeof(double); i++)

    {

      Serial.print(c); c++; Serial.print(" = ");

      Serial.print(coeffs[i],8);

      Serial.print('\t');

    } /* for */

    Serial.println();

  }

}/* setup */

 

void loop(void)

  {

   

  } /* loop */

 

To get the final results I took the hardware outside in the slightly sunny afternoon and obtained a set of power values. Then returned back inside, typed these power values into the curve fitting programme, obtained the  polynomial coefficients and then typed these back into the original programme. The results for all this effort is illustrated in the video below. A nice curve and the maximum power transfer resistor load.

 

Demonstration Video

 

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

 

Summary.

 

I am satisfied that the concept of the Solar Cell DVM  (should this be DPM) is valid and workable, once the problem of needing more data memory for the floating point calculations and graphic display are sorted, probably with a MakerWAN1310 or similar. It will then be possible to monitor the changing maxim power transfer point of individual solar cell, as the sun varies in intensity.

 

I was planning to make a 3D printed casing but this was not started due to the problems outlined above.

 

Dubbie

  • Sign in to reply

Top Comments

  • genebren
    genebren over 4 years ago +6
    Very cool tester! In thinking about the resistive load, I wonder if you could use a single value resistance and then parallel more and more of them as opposed to having a bunch of different resistors.…
  • Andrew J
    Andrew J over 4 years ago +4
    Nice one. It's really frustrating running out of memory on an Arduino when you've put a lot of effort in getting so far..
  • neilk
    neilk over 4 years ago +3
    Nice project, Dubbie I'm mulling over playing with some solar panels; this, or something similar, would be very useful. Neil
  • dubbie
    dubbie over 4 years ago in reply to mp2100

    Allen,

     

    Sadly I have not been able to reach this high point as I had to use a separate programme to determine the curve coefficients. Additionally, when I take it outside I cannot see the display anyway - something of a fundamental problem! I'm toying with the idea of trying to find an alternative display better suited to use in sunshine as I would really quite like to see this meter finished and working properly. However, so far, I have never come across a display that I can actually see outside in the sunshine. I could try my VR googles but then I would just trip over all the obstacles in the garden.

     

    Dubbie

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • dubbie
    dubbie over 4 years ago in reply to Andrew J

    Andrew,

     

    It was really frustrating and I have never experienced this problem before in any of my Arduino projects (I tend to keep thing simple). I think this might also be one of my first projects making use of double floating point numbers - which I found out Nano's do not even implement anyway!

     

    Dubbie

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • dubbie
    dubbie over 4 years ago in reply to neilk

    Neil,

     

    It would certainly seem to be capable of providing you with additional information on setup and similar. However, it did occur to me that if this type of meter was useful, then why had nobody made one before? So maybe solar characteristics are just too dependent on the sunshine intensity - which in the UK at least, is very variable. Today in the UK - middle of the summer - it is 16C, cloudy and cold with no prediction of even sunny spells for several days.

     

    Dubbie

    • Cancel
    • Vote Up +2 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • dubbie
    dubbie over 4 years ago in reply to genebren

    Gene,

     

    I did spend a long time thinking about what resistors to use and whether to try and create the values I wanted by using switched parallel resistors, and I even tried out a prototype. But eventually, after I identified that I would need many resistor values that I did not have, I went for a workable solution of selected values not operated in parallel, to create something that worked. If I had taken any more time I just wouldn't have finished at all!

     

    I did think of using an electronic load but that then seemed like two projects rolled into one. I wasn't that keen. So I just messed about with the resistor values I had. Getting the curve fitting library to work was much harder because the faults were all down to stack overflows into data arrays (at least I think this was what the problem was) and I didn't really know how to fix it. In the past I would have looked at compiler options to see if I could make more memory space available, but with Arduino I have absolutely no idea how to do this - and no time to find out.

     

    Still, I was really happy wi the system I eventually produced which did everything I had wanted. Apart from not being able to see the display in sunshine which was not very helpful for a sunshine based project and it really annoyed me that I hadn't thought of that problem when I started.

     

    Dubbie

    • Cancel
    • Vote Up +2 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • genebren
    genebren over 4 years ago in reply to mp2100

    Thanks!

     

    That was the real problem with my design, I did not get enough light on my tiny solar panels, due to all the shading (multiple Oak trees in my backyard). I did fully test the design using a current-limited power supply to emulate the solar panels.  The design would allow the charger to shift it's charge point, allowing to operate at the optimal power point.

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
>
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube