#include <Wire.h>
#include "Adafruit_TCS34725.h"
#include "U8glib.h"
#include "OneButton.h"
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <Adafruit_ADXL345_U.h>
U8GLIB_SSD1306_128X32 u8g(U8G_I2C_OPT_NONE); // I2C / TWI
Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_50MS, TCS34725_GAIN_4X);
Adafruit_BME280 bme; // I2C
OneButton button(A2, true);
//Adafruit_ADXL345_Unified tilt = Adafruit_ADXL345_Unified(0);
byte helligkeit;
int potValue;
int averagewled1;
byte batterystatus;
int altinit = 0;
byte readIndex = 0;
byte ledout = 1;
byte taster = 1;
const byte wled = 9;
const byte rled = 13;
const byte uled = 10;
const byte volt = A1;
long lux;
long maxlux;
long kelvin;
long ledbar1 = 0;
long ledbar2 = 0;
float SEALEVELPRESSURE_HPA = 1000.00;
const float G = 9.80665;
float averagetemp;
float averagepressure;
float averagefeucht;
float averagealti;
float averagetemp1;
float averagepressure1;
float averagefeucht1;
float averagealti1;
float voltadc;
float volt1;
float volt2;
float volt3;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// declare some things...
// some magic numbers for this device from the DN40 application note
#define TCS34725_R_Coef 0.136
#define TCS34725_G_Coef 1.000
#define TCS34725_B_Coef -0.444
#define TCS34725_GA 1.0
#define TCS34725_DF 310.0
#define TCS34725_CT_Coef 3810.0
#define TCS34725_CT_Offset 1391.0
// Autorange class for TCS34725
class tcs34725 {
public:
tcs34725(void);
boolean begin(void);
void getData(void);
boolean isAvailable, isSaturated;
uint16_t againx, atime, atime_ms;
uint16_t r, g, b, c;
uint16_t ir;
uint16_t r_comp, g_comp, b_comp, c_comp;
uint16_t saturation, saturation75;
float cratio, cpl, ct, lux, maxlux;
private:
struct tcs_agc {
tcs34725Gain_t ag;
tcs34725IntegrationTime_t at;
uint16_t mincnt;
uint16_t maxcnt;
};
static const tcs_agc agc_lst[];
uint16_t agc_cur;
void setGainTime(void);
Adafruit_TCS34725 tcs;
};
const tcs34725::tcs_agc tcs34725::agc_lst[] = {
{ TCS34725_GAIN_60X, TCS34725_INTEGRATIONTIME_154MS, 0, 63000 },
{ TCS34725_GAIN_16X, TCS34725_INTEGRATIONTIME_154MS, 16790, 63000 },
{ TCS34725_GAIN_4X, TCS34725_INTEGRATIONTIME_154MS, 15740, 63000 },
{ TCS34725_GAIN_1X, TCS34725_INTEGRATIONTIME_154MS, 15740, 0 }
};
tcs34725::tcs34725() : agc_cur(0), isAvailable(0), isSaturated(0) {
}
// initialize the sensor
boolean tcs34725::begin(void) {
tcs = Adafruit_TCS34725(agc_lst[agc_cur].at, agc_lst[agc_cur].ag);
if ((isAvailable = tcs.begin()))
setGainTime();
return (isAvailable);
}
// Set the gain and integration time
void tcs34725::setGainTime(void) {
tcs.setGain(agc_lst[agc_cur].ag);
tcs.setIntegrationTime(agc_lst[agc_cur].at);
atime = int(agc_lst[agc_cur].at);
atime_ms = ((256 - atime) * 2.4);
switch (agc_lst[agc_cur].ag) {
case TCS34725_GAIN_1X:
againx = 1;
break;
case TCS34725_GAIN_4X:
againx = 4;
break;
case TCS34725_GAIN_16X:
againx = 16;
break;
case TCS34725_GAIN_60X:
againx = 60;
break;
}
}
// Retrieve data from the sensor and do the calculations
void tcs34725::getData(void) {
// read the sensor and autorange if necessary
tcs.getRawData(&r, &g, &b, &c);
while (1) {
if (agc_lst[agc_cur].maxcnt && c > agc_lst[agc_cur].maxcnt)
agc_cur++;
else if (agc_lst[agc_cur].mincnt && c < agc_lst[agc_cur].mincnt)
agc_cur--;
else break;
setGainTime();
delay((256 - atime) * 2.4 * 2); // shock absorber
tcs.getRawData(&r, &g, &b, &c);
break;
}
// DN40 calculations
ir = (r + g + b > c) ? (r + g + b - c) / 2 : 0;
r_comp = r - ir;
g_comp = g - ir;
b_comp = b - ir;
c_comp = c - ir;
cratio = float(ir) / float(c);
saturation = ((256 - atime) > 63) ? 65535 : 1024 * (256 - atime);
saturation75 = (atime_ms < 150) ? (saturation - saturation / 4) : saturation;
isSaturated = (atime_ms < 150 && c > saturation75) ? 1 : 0;
cpl = (atime_ms * againx) / (TCS34725_GA * TCS34725_DF);
maxlux = 65535 / (cpl * 3);
lux = (TCS34725_R_Coef * float(r_comp) + TCS34725_G_Coef * float(g_comp) + TCS34725_B_Coef * float(b_comp)) / cpl;
ct = TCS34725_CT_Coef * float(b_comp) / float(r_comp) + TCS34725_CT_Offset;
}
tcs34725 rgb_sensor;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup(void) {
bme.begin();
rgb_sensor.begin();
button.attachClick(shortclick);
button.attachLongPressStart(longclick);
analogReference(INTERNAL); // set internal ref voltage to 2.56 volt (atmega32u4) other maybe 1.1 volts
pinMode(5, OUTPUT); // start reset procedure for display
digitalWrite(5, HIGH);
delay(10);
digitalWrite(5, LOW);
delay(10);
digitalWrite(5, HIGH); // end of reset procedure for display
u8g.setRot180(); // rotale the display by 180°
u8g.setFont(u8g_font_fixed_v0); // set font for u8glib one time; this reduce memory usage
// tilt.begin();
// tilt.setRange(ADXL345_RANGE_2_G);
// tilt.setDataRate(ADXL345_DATARATE_25_HZ);
}
//draw pages include logo on startup
void draw(void)
{
switch (taster)
{
case 1: page1(); break; // flashlite
case 2: page2(); break; // bosch sensor
case 3: page3(); break; // light sensor
// case 4: logo(); break; // startup screen
}
}
void page1(void) {
u8g.drawFrame(100, 0, 18, 12); //draw battery
u8g.drawFrame(117, 2, 4, 8); //draw battery
u8g.drawBox(101, 0, batterystatus, 12); //draw battery status bar
u8g.drawTriangle(0, 12, ledbar1, 12, ledbar1, ledbar2); // draw brighness status bar
if (ledout == 1) // write "white" in white mode
{ u8g.setPrintPos(60, 12);
u8g.print("Weiss");
}
if (ledout == 2) // write "red" in red mode
{ u8g.setPrintPos(60, 12);
u8g.print("Rot");
}
if (ledout == 3) // write "uv" in uv mode
{ u8g.setPrintPos(60, 12);
u8g.print("UV");
}
u8g.setPrintPos(0, 23);
u8g.print("Helligkeit:");
u8g.setPrintPos(64, 23);
u8g.print(helligkeit);
u8g.setPrintPos(0, 32);
u8g.print("Akku:");
u8g.setPrintPos(27, 32);
u8g.print(volt3);
}
//draw second page for bosch sensor
void page2(void) {
u8g.setPrintPos(0, 7);
u8g.print("Temp:");
u8g.setPrintPos(27, 7);
u8g.print(averagetemp1);
u8g.setPrintPos(0, 15);
u8g.print("Hu:");
u8g.setPrintPos(27, 15);
u8g.print(averagefeucht1);
u8g.setPrintPos(0, 23);
u8g.print("hPa:");
u8g.setPrintPos(27, 23);
u8g.print(averagepressure1);
u8g.setPrintPos(0, 31);
u8g.print("alt");
u8g.setPrintPos(27, 31);
u8g.print(averagealti1);
}
//draw third page for light sensor
void page3(void) {
u8g.setPrintPos(0, 9);
u8g.print("Lux:");
u8g.setPrintPos(64, 9);
u8g.print(lux);
u8g.setPrintPos(0, 21);
u8g.print("Kelvin:");
u8g.setPrintPos(64, 21);
u8g.print(kelvin);
u8g.setPrintPos(0, 32);
u8g.print("max Lux:");
u8g.setPrintPos(64, 32);
u8g.print(maxlux);
}
//define actions for short press
void shortclick() {
taster++;
if (taster > 3)
{
taster = 1;
}
}
//define actions for long press
void longclick()
{
if (taster == 1)
{
ledout = ledout + 1; // switch between white, red and uv
}
if (ledout > 3) //go back to white after uv
{
ledout = 1;
}
if (taster == 3) //reset max lux buffer
{
maxlux = 0;
}
if (taster == 2) //set altitude to 0
{
SEALEVELPRESSURE_HPA = averagepressure1;
}
}
void loop(void) {
//draw startup logo
// if (taster == 4 & millis() > 2000)
// {
// taster = 1;
// }
button.tick();
potValue = analogRead(0); //read pot value
if (potValue > 995)
{
potValue = 995;
}
averagewled1 = map(potValue, 0, 995, 0, 255); //map pot value to pwm out
if (ledout == 1) //set output to white
{ analogWrite(wled, averagewled1);
analogWrite(rled, 0);
analogWrite(uled, 0);
}
if (ledout == 2) //set output to red
{ analogWrite(rled, averagewled1);
analogWrite(wled, 0);
analogWrite(uled, 0);
}
if (ledout == 3) //set output to uv
{ analogWrite(uled, averagewled1);
analogWrite(wled, 0);
analogWrite(rled, 0);
}
sensors_event_t event;
// float x, y, bx, by;
// get the latest event:
// tilt.getEvent(&event);
// get the accel readings from the event:
// x = event.acceleration.x; // m/s^2
// y = event.acceleration.y; // m/s^2
//if menu for flashlite is active do some actions
if (taster == 1)
{
volt1 = (analogRead(volt)) * 2.52 / 1023; //read battery voltage
volt2 = ( volt2 * 19 + volt1 ) / 20; // it requires a few loops for average for smoothing
volt3 = ((volt3 * 9) + (volt2 / (14.93 / (14.93 + 17.93)))) / 10; // voltage divider 2,200937709310114
voltadc = volt3 * 241; // calculation for batterystatus
helligkeit = map(potValue, 0, 995, 0, 100); // map potvalue to % for brightness
ledbar1 = (map(potValue, 0, 995, 0, 48)) + 5; // map values for brightness bar
ledbar2 = (map(potValue, 0, 995, 12, 0)) - 2; // map vlaues for brighness bar2
if (millis() > 3000)
{
batterystatus = map(voltadc, 602, 1024, 0, 17); // map batterystatus for batterybar
}
}
//collect bosch sensor data when page two is active
if (taster == 2)
{
averagetemp1 = ((averagetemp1 * 9) + bme.readTemperature()) / 10;
averagepressure1 = ((averagepressure1 * 19) + (bme.readPressure() / 100.0F)) / 20;
averagefeucht1 = ((averagefeucht1 * 19) + bme.readHumidity()) / 20;
averagealti1 = ((averagealti1 * 19) + (bme.readAltitude(SEALEVELPRESSURE_HPA))) / 20;
}
//collect sensor data and draw page3
if (taster == 3)
{
rgb_sensor.getData();
lux = rgb_sensor.lux;
kelvin = rgb_sensor.ct;
if (lux > maxlux)
{
maxlux = lux;
}
}
//draw Picture loop
u8g.firstPage();
do {
draw();
} while ( u8g.nextPage() );
}