Its been awhile since i've done any sensor projects so i figured i would take a crack at a pyranometer. The concept is relatively simple, essentially its a device that measures the radiative flux density of the sun.
The basic concepts simple, there are rather expensive scientific worldwide standards maintained that are designed to be very accurate and reproducible. Commercially produced models are calibrated against these under various classification standards. Not having access to one, the next best thing would be publicly available data recorded as geographically close as possible. Luckily the weather station at the airport in my city does take solar readings and provides live daily totals and monthly hourly totals.
The design:
There are 3 common types of pyranometers: photovoltaic, photodiode and thermopile. To start I went with a PIN type photodiode the BPW34 configured in a reverse bias mode. Since photodiodes performance is affected by temperature i threw in a TMP36 temperature sensor giving me -40 to 125c readings at +- 2 degrees of accuracy.
The short circuit amperage is roughly 1.86 milliamperes, with a bias voltage of 5 volts requires a resistor value of 2688.2 ohms. I used a 250 ohm 0.01% resistor along with a 5k screw turn potentiometer in series to provide an adjustable value.
This will provide a decent voltage response rate that will be easily measurable by an adc. The remainder of the electronics is an old arduino and a data logger shield i dusted off out from a drawer somewhere. 5 bolts reference with a 10 bit adc is about 0.005 volts resolution. Using an rtc for timing i figure making an averaged sampling once a second should do nicely.
The code:
#include <Wire.h>
#include "RTClib.h"
#include <SPI.h>
#include <SD.h>
SdFile root;
File dataFile;
const int chipSelect = 10;
RTC_DS1307 rtc;
const int analogInPin = A0;
const int analogOutPin = 9;
unsigned int lightSum = 0;
unsigned int tempSum = 0;
byte count = 0;
float lightAverage = 0.0;
float tempAverage = 0.0;
DateTime now;
byte currentSecond = 0;
char filename[13];
void setup() {
// initialize serial communications at 9600 bps:
Serial.begin(9600);
rtc.begin();
SD.begin(10);
now = rtc.now();
sprintf(filename,"%4d%2d%2d.csv",now.year(),now.month(),now.day());
Serial.println(filename);
dataFile = SD.open(filename, FILE_WRITE);
if (!dataFile) {
Serial.println("cannot create file");
return;
}
else {
Serial.println("create file");
}
}
void loop() {
if (count > 63){
lightAverage = (float) lightSum;
lightAverage /= 64.0;
tempAverage = (float) tempSum;
tempAverage /= 64.0;
tempAverage = ((tempAverage * (5000.0/1024.0)) - 500.0 ) / 10.0;
dataFile.print(lightAverage);
dataFile.print(',');
dataFile.print(tempAverage);
dataFile.print(',');
now = rtc.now();
currentSecond = now.second();
dataFile.print(now.year(), DEC);
dataFile.print('/');
dataFile.print(now.month(), DEC);
dataFile.print('/');
dataFile.print(now.day(), DEC);
dataFile.print('T');
dataFile.print(now.hour(), DEC);
dataFile.print(':');
dataFile.print(now.minute(), DEC);
dataFile.print(':');
dataFile.print(now.second(), DEC);
dataFile.println();
dataFile.flush();
while (currentSecond == now.second()){
now = rtc.now();
delay(10);
}
count = 0;
lightSum = 0;
tempSum = 0;
}
else {
count++;
lightSum += analogRead(A0);
tempSum += analogRead(A1);
delay(10);
}
}
Nothing special to look at here, 10 bit sampling means a 0 to 1023 value, the atmega 32 has 16 bit unsigned integers so that is 64 samples cast into a float for the division to prevent rounding errors during accumulation. I could do some weighted averages or something to get around the limitations but this is fine. Samples are performed once every 10 milliseconds for both light and temperature readings. There probably should be a delay between the two readings but as a rough evaluation this is fine to start with. The output is simply written to a csv date stamped to the start of acquisition.