A lux sensor library
TSL2561.cpp
- Committer:
- joshuasmth04
- Date:
- 2015-08-13
- Revision:
- 3:5b5911bfc644
- Parent:
- 2:c45d34e9c3f0
File content as of revision 3:5b5911bfc644:
// date 7/6/2015 // author E wendt //TSL2561 light sensor library // lux equation approximation without floating point calculations ////////////////////////////////////////////////////////////////////////////// // Routine: unsigned int CalculateLux(unsigned int ch0, unsigned int ch0, int iType) // // Description: Calculate the approximate illuminance (lux) given the raw // channel values of the TSL2560. The equation if implemented // as a piece−wise linear approximation. // // Arguments: unsigned int iGain − gain, where 0:1X, 1:16X // unsigned int tInt − integration time, where 0:13.7mS, 1:100mS, 2:402mS, // 3:Manual // unsigned int ch0 − raw channel value from channel 0 of TSL2560 // unsigned int ch1 − raw channel value from channel 1 of TSL2560 // unsigned int iType − package type (T or CS) // // Return: unsigned int − the approximate illuminance (lux) // ////////////////////////////////////////////////////////////////////////////// #include "mbed.h" #include "TSL2561.h" TSL2561::TSL2561(PinName sda, PinName scl, char slave_address) : i2c_p(new I2C(sda, scl)), i2c(*i2c_p), address(slave_address), _integration(TSL2561_INTEGRATIONTIME_402MS), _gain(TSL2561_GAIN_0X) { initialize(); } TSL2561::TSL2561(I2C &i2c_obj, char slave_address) : i2c_p(NULL), i2c(i2c_obj), address(slave_address), _integration(TSL2561_INTEGRATIONTIME_402MS), _gain(TSL2561_GAIN_0X) { initialize(); } TSL2561::~TSL2561() { if (NULL != i2c_p) { delete i2c_p; } } //The register addresses are all passed to i2c write via the bottum 4 bits of the command register //check and see if it is reading the correct id register (should read (0x10) for register value bool TSL2561::initialize(void) { float idf; //debug uint16_t idu; char ID_REGISTER[1] = {TSL2561_REGISTER_ID}; i2c.write(address, ID_REGISTER, 1, true); char DATA[1] = {0}; i2c.read(address, DATA, 1, false); idu = DATA[0]; idf = (float)idu; //debug if (idu & 0x0A) { pc.printf("FOUND TSL2561\r\n"); //debug } else { pc.printf("NOT FOUND TSL2561\r\n"); //debug pc.printf("%4.0f ID\n",idf); //debug return false; } //set default integration time and gain setTimingGain(_integration, _gain); disable(); return true; } void TSL2561::enable(void) { //power on device by writing 0x03 to the control register char CONTROL_ON[2] = {TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, TSL2561_CONTROL_POWERON}; i2c.write(address, CONTROL_ON, 2); //***//Comment this wait out and the disable function to reduce read time, at the cost of power consumption. //wait_ms(400); //It takes a sec for the TSL to start up. //***// //This sets everything to default values. (402ms integration time, interupts disabled etc.) } void TSL2561::disable(void) { //power off device by writing 0x00 in control register //***// //char CONTROL_OFF[2] = {TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, TSL2561_CONTROL_POWEROFF}; //i2c.write(address, CONTROL_OFF, 2); //***// } void TSL2561::setTimingGain(tsl2561IntegrationTime_t integration, tsl2561Gain_t gain) { enable(); _integration = integration; _gain = gain; char TIME_SETTING[2] = {TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, _integration | _gain}; i2c.write(address, TIME_SETTING, 2); disable(); } uint32_t TSL2561::calculateLux(uint16_t ch0, uint16_t ch1) { unsigned long chScale; unsigned long channel1; unsigned long channel0; //scale the measurment if the integration time is not 402 ms switch (_integration) { case TSL2561_INTEGRATIONTIME_13MS: chScale = CHSCALE_TINT0; break; case TSL2561_INTEGRATIONTIME_101MS: chScale = CHSCALE_TINT1; break; default: //No scaling when integration time is set to 402 ms chScale = (1 << CH_SCALE); break; } //scale the measurment if gain is NOT x16 if(!_gain) { chScale = chScale << 4; } //scale the channel values channel0 = (ch0 * chScale) >> CH_SCALE; channel1 = (ch1 * chScale) >> CH_SCALE; //Find the ratio of the channel values (Channel 11/Channel 10) to set coeficients unsigned long ratio1 = 0; if (channel0 != 0) { ratio1 = (channel1 << (RATIO_SCALE+1))/channel0; } //round the ratio value unsigned long ratio = (ratio1 + 1) >> 1; unsigned int b=0, m=0; //check which coefficients the ratio dictates #ifdef TSL2561_PACKAGE_CS //Adafruit sells the T package but these coefficients are for the CS package if ((ratio >= 0) && (ratio <= K1C)) { b = B1C; m = M1C; } else if (ratio <= K2C) { b = B2C; m = M2C; } else if (ratio <= K3C) { b = B3C; m = M3C; } else if (ratio <= K4C) { b = B4C; m = M4C; } else if (ratio <= K5C) { b = B5C; m = M5C; } else if (ratio <= K6C) { b = B6C; m = M6C; } else if (ratio <= K7C) { b = B7C; m = M7C; } else if (ratio <= K8C) { b = B8C; m = M8C; } #else if ((ratio >= 0) && (ratio <= K1T)) { //Coefficients for all other packages, will probably use these b = B1T; m = M1T; } else if (ratio <= K2T) { b = B2T; m = M2T; } else if (ratio <= K3T) { b = B3T; m = M3T; } else if (ratio <= K4T) { b = B4T; m = M4T; } else if (ratio <= K5T) { b = B5T; m = M5T; } else if (ratio <= K6T) { b = B6T; m = M6T; } else if (ratio <= K7T) { b = B7T; m = M7T; } else if (ratio <= K8T) { b = B8T; m = M8T; } #endif unsigned long temp_val; temp_val = ((channel0*b) - (channel1*m)); //do not allow negative lux value if (temp_val < 0) { temp_val = 0; } //round lsb (2^(LUX_SCALE-1)) temp_val += (1 << (LUX_SCALE-1)); //strip off fractional portion uint32_t lux = temp_val >> LUX_SCALE; //signal I2C had no errors return lux; } uint32_t TSL2561::getFullLuminosity (void) { // Enable the device by setting the control bit to 0x03 enable(); // Wait x ms for ADC to complete switch (_integration) { case TSL2561_INTEGRATIONTIME_13MS: wait(14/1000); break; case TSL2561_INTEGRATIONTIME_101MS: wait(102/1000); break; default: wait(403/1000); break; } uint32_t x; //will store data for luminosity //uint16_t x1; //will store data from channel 1 (optional to store data in steps) //uint16_t x0; //will store data from channel 0 (I just modified x) //Address the Ch1 lower data register and configure for Read Word char ch1_reg[1] = {TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN1_LOW}; //Create array to store data char ch1_data[2] = {0,0}; i2c.write(address, ch1_reg, 1); i2c.read(address, ch1_data, 2); // Merge bytes x = ch1_data[0] | (ch1_data[1] << 8); // int x <<= 16; //Address the Ch1 lower data register and configure for Read Word char ch0_reg[1] = {TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN0_LOW}; //Create array to store data char ch0_data[2] = {0,0}; i2c.write(address, ch0_reg, 1); i2c.read(address, ch0_data, 2); // Merge bytes of channel 0 and channel 1 x |= ch0_data[0] | (ch0_data[1] << 8); // int disable(); return x; } uint16_t TSL2561::getLuminosity (uint8_t channel) { uint32_t x = getFullLuminosity(); if (channel == 0) { // Reads two byte value from channel 0 (visible + infrared) return (x & 0xFFFF); } else if (channel == 1) { // Reads two byte value from channel 1 (infrared) return (x >> 16); } else if (channel == 2) { // Reads all and subtracts out just the visible return ( (x & 0xFFFF) - (x >> 16)); } // unknown channel return 0; } void TSL2561::read_lux(void) { uint32_t full_lums; //set to default gain (Note: going high gain to low is slower but more reliable, low gain to high gain is faster but less reliable) setTimingGain(TSL2561_INTEGRATIONTIME_13MS, TSL2561_GAIN_16X); // start at high gain and long readings wait(0.1);// give the TSL time to adjust, more time is more reliable but slower, less time lessreliable but faster //decreas gain/time if reading is to high (diable this block and change that^ line for fixed gain) //take reading read_again: full_lums = getFullLuminosity(); channal0 = (full_lums & 0xFFFF); channal1 = (full_lums >> 16); //If ir, or vis and ir, are within 5% of max then decreas the gain/time and repeat //Pick the corect time to match ^ if(((channal0 > 4794) | (channal1 > 4792)) & (_gain != TSL2561_GAIN_0X)){ //13ms //if(((channal0 > 35318) | (channal1 > 35318)) & (_gain != TSL2561_GAIN_0X)){ //101ms //if(((channal0 > 62258) | (channal1 > 62258)) & (_gain != TSL2561_GAIN_0X)){ //402ms setTimingGain(_integration, TSL2561_GAIN_0X); wait(0.1); // give the TSL time to adjust, more time is more reliable but slower, less time lessreliable but faster goto read_again; } //calculate lux from reading lux = calculateLux(channal0, channal1); //pc.printf("gain: %d time: %d, lux:%d\r\n", _gain, _integration, lux); //pc.printf("ch0:%d, ch1: %d\r\n", channal0, channal1); }