Ultraviolet Intensity Measurement Experiment: Unterschied zwischen den Versionen
Dl8rds (Diskussion | Beiträge) (→Component List) |
Dl8rds (Diskussion | Beiträge) |
||
| Zeile 273: | Zeile 273: | ||
[[Image:2017-07-31-UV-Sensor5.jpg|400px]] | [[Image:2017-07-31-UV-Sensor5.jpg|400px]] | ||
[[Image:2017-07-31-UV-Sensor6.jpg|400px]] | [[Image:2017-07-31-UV-Sensor6.jpg|400px]] | ||
| + | |||
| + | [[Image:2017-07-31-UV-Sensor7.jpg|600px]] | ||
Aktuelle Version vom 8. August 2017, 23:03 Uhr
Inhaltsverzeichnis
1 Project Scope
When my daughter (my first child) was still a baby, my father bought a UV sensor so he could measure the UV intensity. Babys are very sensitive to UV light and the worst thing he could image was a baby sunburn.
So I thought, what about creating an alarm sensor that would measure UV intensity continuously. The result is this experiment, years later but no less outdated.
2 Solution Concept
I decided to build up the entire solution on the basis of a PoE 803.af Arduino Ethernet, including measurement of environment data and ambient light, including a solar cell based voltage verification.
There are pairs of ML8511 sensors, one pair simply behind the SiO (Silicium Oxide / Quarz glass), and another pair behind a lowpass UVB filter so that these two can measure exclusively UV-A. The UVB intensity is then the difference between the tutal power in this spectral region minus the UVA.
Here is a nice overview of sunburn effects:
The sensor will display all measured values including a normalization on a web page. I am also interested in other environmental data (is the sensor doing fine?), so I decided to use a BME280 sensor also.
The ADS1115 has a programmable sensitivity feature, and the ML8511 runs on 3,3V. So I decided to use this 16 bit ADC on a Vmax basis of 4,096V, since the signal will not exceed 3,3V anyway. 3,28V is Vmax according to the sensor's spec and it will correlate with a brutal amount of 15mW/cm².
Here is the rough output scale of the sensor:
3 Component List
- Hammond 1550E aluminium diecast case: 50 €
- 2sided base PCB: 2 €
- Arduino Ethernet: 65 €
- Programmer: 3 €
- Watterott BME280: 14 €
- 4x Sparkfun ML8511: 4x 15€ = 60 €
- 1x Sparkfun TEMT6000: 5 €
- https://www.sparkfun.com/products/8688
- https://learn.sparkfun.com/tutorials/temt6000-ambient-light-sensor-hookup-guide
- Adafruit ADS1115: 15 €
- 2 solar cells: 5 €
- screws, mounts: 10 €
- Edmund Optics UVB lowpass: 80 €
- Cut-Off Position λc (nm): 309±6
- https://www.edmundoptics.com/optics/optical-filters/longpass-edge-filters/n-wg-305-50.8mm-sq.-longpass-filter/
- Quarz glass to pass all wavelengths: 65 €
- Silicon glue: 10 €
- TP-Link PoE injector: 25
Total: ~400 €
4 Code
#include <SPI.h>
#include <Ethernet.h>
#include <Wire.h>
#include <Adafruit_ADS1015.h>
#include "cactus_io_BME280_I2C.h"
Adafruit_ADS1115 ads; /* Use this for the 16-bit version */
// Create the BME280 object
BME280_I2C bme; // I2C using default 0x77
// or BME280_I2C bme(0x76); // I2C using address 0x76
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
IPAddress ip(192, 168, 178, 177);
// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
// start the Ethernet connection and the server:
Ethernet.begin(mac, ip);
server.begin();
Serial.print("server is at ");
Serial.println(Ethernet.localIP());
// The ADC input range (or gain) can be changed via the following
// functions, but be careful never to exceed VDD +0.3V max, or to
// exceed the upper and lower limits if you adjust the input range!
// Setting these values incorrectly may destroy your ADC!
// ADS1015 ADS1115
// ------- -------
// ads.setGain(GAIN_TWOTHIRDS); // 2/3x gain +/- 6.144V 1 bit = 3mV 0.1875mV (default)
ads.setGain(GAIN_ONE); // 1x gain +/- 4.096V 1 bit = 2mV 0.125mV
// ads.setGain(GAIN_TWO); // 2x gain +/- 2.048V 1 bit = 1mV 0.0625mV
// ads.setGain(GAIN_FOUR); // 4x gain +/- 1.024V 1 bit = 0.5mV 0.03125mV
// ads.setGain(GAIN_EIGHT); // 8x gain +/- 0.512V 1 bit = 0.25mV 0.015625mV
// ads.setGain(GAIN_SIXTEEN); // 16x gain +/- 0.256V 1 bit = 0.125mV 0.0078125mV
ads.begin();
if (!bme.begin()) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
while (1);
}
bme.setTempCal(-1);
}
//The Arduino Map function but for floats
//From: http://forum.arduino.cc/index.php?topic=3922.0
float mapfloat(float x, float in_min, float in_max, float out_min, float out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
void loop() {
// listen for incoming clients
EthernetClient client = server.available();
if (client) {
Serial.println("new client");
// an http request ends with a blank line
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
Serial.write(c);
// if you've gotten to the end of the line (received a newline
// character) and the line is blank, the http request has ended,
// so you can send a reply
if (c == '\n' && currentLineIsBlank) {
// send a standard http response header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close"); // the connection will be closed after completion of the response
client.println("Refresh: 5"); // refresh the page automatically every 5 sec
client.println();
client.println("<!DOCTYPE HTML>");
client.println("<html>");
client.println("<table>");
client.print("<tr><td>");
client.print("Light Intensity:");
client.print("</td><td>");
int sensorReading = analogRead(0);
Serial.print("Light Intensity: "); Serial.println(sensorReading);
client.print(sensorReading);
client.println("</td></tr>");
int16_t adc0, adc1, adc2, adc3;
float adc0_1, adc1_1, adc2_1, adc3_1;
float uvIntensity_0, uvIntensity_1, uvIntensity_2, uvIntensity_3;
client.print("<tr><td>");
client.print("UVB1 (mW/cm2):");
client.print("</td><td>");
adc0 = ads.readADC_SingleEnded(0);
adc0_1 = (float)adc0 / 8000;
uvIntensity_0 = mapfloat(adc0_1, 0.987, 2.8, 0.0, 15.0);
Serial.print("UVB1: "); Serial.println(uvIntensity_0);
client.print(uvIntensity_0);
client.println("</td></tr>");
client.print("<tr><td>");
client.print("UVB2 (mW/cm2):");
client.print("</td><td>");
adc1 = ads.readADC_SingleEnded(1);
adc1_1 = (float)adc1 / 8000;
uvIntensity_1 = mapfloat(adc1_1, 0.999, 2.8, 0.0, 15.0);
Serial.print("UVB2: "); Serial.println(uvIntensity_1);
client.print(uvIntensity_1);
client.println("</td></tr>");
client.print("<tr><td>");
client.print("UV1 (mW/cm2):");
client.print("</td><td>");
adc2 = ads.readADC_SingleEnded(2);
adc2_1 = (float)adc2 / 8000;
uvIntensity_2 = mapfloat(adc2_1, 0.989, 2.8, 0.0, 15.0);
Serial.print("UV1: "); Serial.println(uvIntensity_2);
client.print(uvIntensity_2);
client.println("</td></tr>");
client.print("<tr><td>");
client.print("UV2 (mW/cm2):");
client.print("</td><td>");
adc3 = ads.readADC_SingleEnded(3);
adc3_1 = (float)adc3 / 8000;
uvIntensity_3 = mapfloat(adc3_1, 0.999, 2.8, 0.0, 15.0);
Serial.print("UV2: "); Serial.println(uvIntensity_3);
client.print(uvIntensity_3);
client.println("</td></tr>");
bme.readSensor();
client.print("<tr><td>");
client.print("Pressure (millibar)");
client.print("</td><td>");
Serial.print("Pressure (millibar): "); Serial.println(bme.getPressure_MB());
client.print(bme.getPressure_MB());
client.println("</td></tr>");
client.print("<tr><td>");
client.print("Humidity (%rel)");
client.print("</td><td>");
Serial.print("Humidity (%rel): "); Serial.println(bme.getHumidity());
client.print(bme.getHumidity());
client.println("</td></tr>");
client.print("<tr><td>");
client.print("Temperature (C)");
client.print("</td><td>");
Serial.print("Temperature (C): "); Serial.println(bme.getTemperature_C());
client.print(bme.getTemperature_C());
client.println("</td></tr>");
client.println("</table>");
client.println("</html>");
break;
}
if (c == '\n') {
// you're starting a new line
currentLineIsBlank = true;
} else if (c != '\r') {
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
// give the web browser time to receive the data
delay(1);
// close the connection:
client.stop();
Serial.println("client disconnected");
}
}
5 Sample Output
Here is a sample output from this evening, notably with no UV rays at all. The next days will be very sunny, so I'm looking forward to read the measurements.
Light Intensity: 285 UVB1 (mW/cm2): 0.02 UVB2 (mW/cm2): 0.02 UV1 (mW/cm2): 0.02 UV2 (mW/cm2): 0.02 Pressure (millibar) 957.97 Humidity (%rel) 58.39 Temperature (C) 27.26