November, so soon! I kind of had to put this one down for awhile and work on things that were not laptop-centric, I just was spending too much time in front of a computer screen. Luckily, Tiuri De Jong was on the case, and he has developed the proof-of-concept code I posted earlier into a fully-working demonstration.
I uploaded it to my Arduino, and I’m getting stable results with an apparently linear response, although the specific numerical values themselves aren’t particularly meaningful. For example, under my workbench lamp that I metered at about 40fc and has a CCT of 5000K, it measured 290fc at 3500K. I get that the part would require calibration before it would be useful, but it’s strange to me that it would be off by 1500K color temperature and a factor of 5 for illuminance, out of the box? I’d be interested to know if anyone else has a similar experience.
What I’m working on now is measuring the values given by the TCS3414 vs. a known accurate illuminance and color temperature meter, to tell if the deviation from true value is a constant, or a linear function, or what. I’ve verified that the calculations are done correctly in the code per the datasheet.
But in the meantime, it seems like a shame to deprive everyone else of Tiuri De Jong’s complete and, might I add, lucidly written code, so it may be downloaded here:
2012-11-18 Light Meter Code Rev5
I’ve also posted the code in full after the jump.
Some helpful hints on hardware: It turns out that as long as you have only one 3.3V device on the i2c bus, you don’t have to have the level shifter circuit I was using, you can connect it directly to the i2c pins (but power it via 3.3V supply, not 5V). So that’s simpler. Also, Taos recommends a .1μF decoupling capacitor between the 3.3V supply and ground, located adjacent to the unit, to reduce fluctuations due to logic level shifting:
The interrupt functionality is not implemented in the current code, so you can leave that pin unconnected, and omit RPI.
And, the code. As always, I recommend downloading the zip file rather than copying-and-pasting, sometimes the WordPress monster eats semicolons.
// TCS3414 receiver code rev 5
// Developed by Tiuri de Jong, with contributions by Max Pierson
// This software is released under WTFPL, although credit and share-alike are appreciated.
// 18 November 2012
//include the library for i2c
#include
unsigned int TCS3414values[4]; // [Clear,Red,Green,Blue]
float TCS3414medium[4]; // [Clear,Red,Green,Blue]
float TCS3414mediate[4]; // [Clear,Red,Green,Blue]
float ColorTemperature = 0;
// SET the integration time here. Higher times allow for higher values with better precicion.
int integrationtime = 400; //12 == 12ms, 100 = 100ms, 400 = 400ms. Other values are note accepted
int loopdelay = integrationtime; //loop delay depends on the integration time
boolean debug = false; //change to true if you want to see the various debug serial output bits
boolean percentageEnabled = false; //enable/disable the percentage mode
boolean compensateEnabled = false; //enable/disable color compensation of the sensor sensitivity per color
void setup(){
Wire.begin();// join i2c bus (address optional for master)
Serial.begin(9600);//115200
while (!Serial) {
; // wait for serial port to connect. This while loop is needed for the Arduino Leonardo only
}
CMD(0);
TCS3414Start(14,2000);
}
//The main function.. This repeats itself forever!
void loop() {
getSerialCommands(); //to be able to receive commands
//gets the raw values from the sensors and writes it to TCS3414values[]
TSC3414All(TCS3414values);
//compensate based on the filter characteristics of the TCS3414
if(compensateEnabled)
colorCompensator(TCS3414values);
//keeps a running average from the last 4 values per color.
calculateMedium(TCS3414mediate,TCS3414values,4.0);
//calculates the color temperature, using the algorithm in the TCS3414 datasheet
ColorTemperature = CCTCalc(TCS3414values);
//displays percentage values, if enabled.
if(percentageEnabled){
makePercentage(TCS3414values, TCS3414medium);
}
Serial.print(“Clear: “);
Serial.print(TCS3414values[0]);
if(percentageEnabled)
Serial.print(“%”);
Serial.print(“\tRed: “);
Serial.print(TCS3414values[1]);
if(percentageEnabled)
Serial.print(“%”);
Serial.print(” \tGreen: “);
Serial.print(TCS3414values[2]);
if(percentageEnabled)
Serial.print(“%”);
Serial.print(“\tBlue: “);
if(percentageEnabled){
Serial.print(TCS3414values[3]);
Serial.println(“%”);
}else{
Serial.println(TCS3414values[3]);
}
delay(loopdelay); //delays by the integration time between measurements
}//end loop()
/*
* ======================================================
* Calculation functions
* ======================================================
*/
/*** takes the raw values from the sensors and converts them to
Correlated Color Temperature. Returns a float with CCT ***/
float CCTCalc(unsigned int allcolors[]){
float TCS3414tristimulus[3]; // [tri X, tri Y, tri Z]
float TCS3414chromaticityCoordinates[2]; //chromaticity coordinates // [x, y]
//calculate tristimulus values (chromaticity coordinates)
//The tristimulus Y value represents the illuminance of our source
TCS3414tristimulus[0] = (-0.14282 * allcolors[1]) + (1.54924 * allcolors[2]) + (-0.95641 * allcolors[3]); //X
TCS3414tristimulus[1] = (-0.32466 * allcolors[1]) + (1.57837 * allcolors[2]) + (-0.73191 * allcolors[3]); //Y // = Illuminance
TCS3414tristimulus[2] = (-0.68202 * allcolors[1]) + (0.77073 * allcolors[2]) + (0.56332 * allcolors[3]); //Z
float XYZ = TCS3414tristimulus[0] + TCS3414tristimulus[1] + TCS3414tristimulus[2];
//calculate the chromaticiy coordinates
TCS3414chromaticityCoordinates[0] = TCS3414tristimulus[0] / XYZ; //x
TCS3414chromaticityCoordinates[1] = TCS3414tristimulus[1] / XYZ; //y
float n = (TCS3414chromaticityCoordinates[0] – 0.3320) / (0.1858 – TCS3414chromaticityCoordinates[1]);
float CCT = ( (449*pow(n,3)) + (3525*pow(n,2)) + (6823.3 * n) + 5520.33 );
Serial.print(“Illuminance: “);
Serial.print(TCS3414tristimulus[1]);
Serial.print(“\tx: “);
Serial.print(TCS3414chromaticityCoordinates[0]);
Serial.print(” \ty: “);
Serial.print(TCS3414chromaticityCoordinates[1]);
Serial.print(” \tCCT: “);
Serial.print(CCT);
Serial.print(“K\t — \t”);
return CCT;
}
/*** Keeps a running average of 4 values per color. ***/
void calculateMedium(float med[], unsigned int value[], float divider){
for(int i = 0; i < 4; i++){
med[i] = ( (med[i]*(divider-1.0)) + value[i] ) / divider;
}
}
/*** calculates percentages for R,G,B channels, if enabled. ***/
void makePercentage(unsigned int allcolors[], float allmedium[]){ //makes every color a percentage, 100% is the average of the previous 4 values before this is entered.
for(int i=0; i 0){
int receive_command = Serial.read();
if(receive_command == 49){//49 == 1
Serial.println(“Percentage enabled, max value (100%) set to current medium”);
percentageEnabled = true;//enables/disables percentage mode.
for(int o = 0; o < 4; o++){
TCS3414medium[o] = TCS3414mediate[o];
}
}else if(receive_command == 48){//48 == 0
Serial.println(“Percentage disabled”);
percentageEnabled = false;//enables/disables percentage mode.
}else if(receive_command == 63){//63 == ?
CMD(2000);
}else if(receive_command == 112){//112 == p
Serial.println(“pausing for 5 seconds (stackable)…”);
delay(5000);
getSerialCommands();
}else if(receive_command == 99){//99 == c
Serial.println(“Color compensation enabled”);
compensateEnabled = true;
}else if(receive_command == 110){//110 == n
Serial.println(“Color compensation disabled”);
compensateEnabled = false;
}else{
Serial.print(“The command entered ( “);
Serial.print(receive_command);
Serial.println(” ) was NOT found in the command list”);
}
}
}
void CMD(int delayTime){
Serial.println(“=========== Command list ===========”);
Serial.println(“\’ \'”);
Serial.println(” ? == Show this command list”);
Serial.println(“”);
Serial.println(” p == pause for 5 seconds (stackable)”);
Serial.println(“”);
Serial.println(” 1 == Enable Percentage mode”);
Serial.println(” 0 == Disable Percentage mode”);
Serial.print(” Percentage mode is currently: “);
if(percentageEnabled){
Serial.println(“ON”);
}else{
Serial.println(“OFF”);
}
Serial.println(“”);
Serial.println(” c == Enable Color compensation mode”);
Serial.println(” n == Disable Color compensation mode”);
Serial.print(” Color compensation mode is currently: “);
if(compensateEnabled){
Serial.println(“ON”);
}else{
Serial.println(“OFF”);
}
Serial.println(“\’ \'”);
Serial.println(“====================================”);
delay(delayTime);
}