//Program: RGB Led Spectrophotometer
//Author: João Pedro da Silva
#include "U8glib.h"
#include "math.h"
// IMPORTANT NOTE: The following list is incomplete. The complete list of supported
// devices with all constructor calls is here: http://code.google.com/p/u8glib/wiki/device
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NO_ACK); // Display which does not send AC
//constants
const int incrementLambdaBtnPin = 2;
const int decrementLambdaBtnPin = 3;
const int calibrationBtnPin = 4;
const int deltaLambda = 5; //nm
const int initLambda = 380; //nm
const int finLambda = 780; //nm
const int ledBluePin = 9;
const int ledGreenPin = 10;
const int ledRedPin = 11;
const int ldrPin = A0;
//global variables
float absorbance = 0.000;
int lambda = initLambda; //380 - 780 nm
bool calibration = false;
int rgb[3] = {0,0,0}; //{red, green, blue}
float ldrVoltage = 5.0; //5.0 V is related to the minimum of light intensity
float calibratedLdrVoltage = 5;
void draw()
{
//writing info on oled display
u8g.setFont(u8g_font_fur11);
//wavelength
u8g.setPrintPos(5,15);
String strLambda = String(lambda) + " nm";
u8g.print(strLambda);
//calibration indication
if(calibration == 1) u8g.drawStr( 100, 15, "cal");
//absorbance
u8g.setFont(u8g_font_fub17);
u8g.setPrintPos(6,52);
String strAbsorbance = "A = " + String(absorbance, 3);
u8g.print(strAbsorbance);
//oled screen frame
u8g.drawRFrame(0,0, 128, 64, 4);
}
void ledRGBControl(int redValue, int greenValue, int blueValue) {
analogWrite(ledRedPin, redValue);
analogWrite(ledGreenPin, greenValue);
analogWrite(ledBluePin, blueValue);
}
void incrementLambda() {
calibration = false;
if(lambda >= initLambda && lambda < finLambda) lambda += deltaLambda;
}
void decrementLambda() {
calibration = false;
if(lambda > initLambda && lambda <= finLambda) lambda -= deltaLambda;
}
//code adapted from https://academo.org/demos/wavelength-to-colour-relationship/
void lambdaToRgb(int wavelength) {
float gamma = 0.80;
int intensityMax = 255;
float factor, red, blue, green;
if((wavelength >= 380) && (wavelength < 440)){
red = (- 1.0) * (wavelength - 440) / (440 - 380);
green = 0.0;
blue = 1.0;
}else if((wavelength >= 440) && (wavelength < 490)){
red = 0.0;
green = 1.0 * (wavelength - 440) / (490 - 440);
blue = 1.0;
}else if((wavelength >= 490) && (wavelength < 510)){
red = 0.0;
green = 1.0;
blue = (- 1.0) * (wavelength - 510) / (510 - 490);
}else if((wavelength >= 510) && (wavelength < 580)){
red = 1.0 * (wavelength - 510) / (580 - 510);
green = 1.0;
blue = 0.0;
}else if((wavelength >= 580) && (wavelength < 645)){
red = 1.0;
green = (-1.0) * (wavelength - 645) / (645 - 580);
blue = 0.0;
}else if((wavelength >= 645) && (wavelength < 781)){
red = 1.0;
green = 0.0;
blue = 0.0;
}else{
red = 0.0;
green = 0.0;
blue = 0.0;
}
// Let the intensity fall off near the vision limits
if((wavelength >= 380) && (wavelength < 420)){
factor = 0.3 + 0.7*(wavelength - 380) / (420 - 380);
}else if((wavelength >= 420) && (wavelength < 701)){
factor = 1.0;
}else if((wavelength >= 701) && (wavelength < 781)){
factor = 0.3 + 0.7*(780 - wavelength) / (780 - 700);
}else{
factor = 0.0;
}
if (red != 0){
red = round(intensityMax * pow(red * factor, gamma));
}
if (green != 0){
green = round(intensityMax * pow(green * factor, gamma));
}
if (blue != 0){
blue = round(intensityMax * pow(blue * factor, gamma));
}
rgb[0] = (int) red;
rgb[1] = (int) green;
rgb[2] = (int) blue;
}
float ldrOutput() {
return (analogRead(ldrPin) / 1024.0) * 5.0;
}
void calibrate() {
calibration = true;
calibratedLdrVoltage = ldrOutput();
}
void calcAbsorbance() {
absorbance = log(ldrOutput()/calibratedLdrVoltage);
}
void setup()
{
Serial.begin(9600);
u8g.disableCursor();
pinMode(incrementLambdaBtnPin, INPUT_PULLUP); //increment lambda btn
pinMode(decrementLambdaBtnPin, INPUT_PULLUP); //decrement lambda btn
pinMode(calibrationBtnPin, INPUT_PULLUP); //calibration btn
pinMode(ledRedPin, OUTPUT); //led rgb red
pinMode(ledGreenPin, OUTPUT); //led rgb green
pinMode(ledBluePin, OUTPUT); //led rgb blue
}
void loop()
{
int btnIncrementLambdaState = digitalRead(incrementLambdaBtnPin);
int btnDecrementLambdaState = digitalRead(decrementLambdaBtnPin);
int btnCalibrationState = digitalRead(calibrationBtnPin);
if(btnIncrementLambdaState == LOW) incrementLambda();
if(btnDecrementLambdaState == LOW) decrementLambda();
if(btnCalibrationState == LOW) calibrate();
lambdaToRgb(lambda);
ledRGBControl(rgb[0], rgb[1], rgb[2]);
calcAbsorbance();
u8g.firstPage();
do
{
draw();
} while( u8g.nextPage() );
delay(10);
}