Luminosity sensor by Texas Advanced Optoelectronic Solutions Inc.. Device combines one broadband photodiode (visible plus infrared) and one infrared-responding photodiode. Sets Gain x1 and 402mS as default.
Dependents: MusicBoxForFathersDay FTHR_SensorHub Affich_Lum_Moist Projetv0 ... more
Diff: TSL2561.cpp
- Revision:
- 5:5b1b625fda6f
- Parent:
- 4:05d322353720
--- a/TSL2561.cpp Tue Feb 20 10:52:41 2018 +0000 +++ b/TSL2561.cpp Fri Sep 21 22:57:07 2018 +0000 @@ -1,47 +1,169 @@ -/* - * mbed library program - * Luminosity sensor -- LIGHT-TO-DIGITAL CONVERTER (light intensity to a digital signal output) - * TSL2561 by Texas Advanced Optoelectronic Solutions Inc. +/*! + * @file Adafruit_TSL2561_U.cpp + * + * @mainpage Adafruit TSL2561 Light/Lux sensor driver + * + * @section intro_sec Introduction + * + * This is the documentation for Adafruit's TSL2561 driver for the + * Arduino platform. It is designed specifically to work with the + * Adafruit TSL2561 breakout: http://www.adafruit.com/products/439 + * + * These sensors use I2C to communicate, 2 pins (SCL+SDA) are required + * to interface with the breakout. + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * @section dependencies Dependencies + * + * This library depends on + * <a href="https://github.com/adafruit/Adafruit_Sensor"> + * Adafruit_Sensor</a> being present on your system. Please make sure you have + * installed the latest version before using this library. + * + * @section author Author + * + * Written by Kevin "KTOWN" Townsend for Adafruit Industries. * - * Copyright (c) 2015,'17,'18 Kenji Arai / JH1PJL - * http://www.page.sannet.ne.jp/kenjia/index.html - * http://mbed.org/users/kenjiArai/ - * Created: Feburary 21st, 2015 - * Revised: August 23rd, 2017 - * Revised: Feburary 20th, 2018 bug fix -> read_ID() & who_am_i() - * Thanks PARK JAICHANG - */ + * @section license License + * + * BSD license, all text here must be included in any redistribution. + * + * @section HISTORY + * + * v2.0 - Rewrote driver for Adafruit_Sensor and Auto-Gain support, and + * added lux clipping check (returns 0 lux on sensor saturation) + * v1.0 - First release (previously TSL2561) +*/ +/**************************************************************************/ + +//------- Modified by ---------------------------------------------------------- +// Kenji Arai / JH1PJL +// http://www.page.sannet.ne.jp/kenjia/index.html +// http://mbed.org/users/kenjiArai/ +// Created: Feburary 21st, 2015 +// Revised: August 23rd, 2017 +// Revised: Feburary 20th, 2018 bug fix -> read_ID() & who_am_i() +// Thanks PARK JAICHANG +// Revised: March 31st, 2018 Added "Auto Range mode" +// Use Adafruit library +// +// Original information https://www.adafruit.com/product/439 +// Original source files https://github.com/adafruit/TSL2561-Arduino-Library +// https://github.com/adafruit/Adafruit_TSL2561 +// Change for Mbed platform +// modified -> all related files +//------------------------------------------------------------------------------ #include "TSL2561.h" +// T, FN and CL package values +#define TSL2561_LUX_K1T (0x0040) ///< 0.125 * 2^RATIO_SCALE +#define TSL2561_LUX_B1T (0x01f2) ///< 0.0304 * 2^LUX_SCALE +#define TSL2561_LUX_M1T (0x01be) ///< 0.0272 * 2^LUX_SCALE +#define TSL2561_LUX_K2T (0x0080) ///< 0.250 * 2^RATIO_SCALE +#define TSL2561_LUX_B2T (0x0214) ///< 0.0325 * 2^LUX_SCALE +#define TSL2561_LUX_M2T (0x02d1) ///< 0.0440 * 2^LUX_SCALE +#define TSL2561_LUX_K3T (0x00c0) ///< 0.375 * 2^RATIO_SCALE +#define TSL2561_LUX_B3T (0x023f) ///< 0.0351 * 2^LUX_SCALE +#define TSL2561_LUX_M3T (0x037b) ///< 0.0544 * 2^LUX_SCALE +#define TSL2561_LUX_K4T (0x0100) ///< 0.50 * 2^RATIO_SCALE +#define TSL2561_LUX_B4T (0x0270) ///< 0.0381 * 2^LUX_SCALE +#define TSL2561_LUX_M4T (0x03fe) ///< 0.0624 * 2^LUX_SCALE +#define TSL2561_LUX_K5T (0x0138) ///< 0.61 * 2^RATIO_SCALE +#define TSL2561_LUX_B5T (0x016f) ///< 0.0224 * 2^LUX_SCALE +#define TSL2561_LUX_M5T (0x01fc) ///< 0.0310 * 2^LUX_SCALE +#define TSL2561_LUX_K6T (0x019a) ///< 0.80 * 2^RATIO_SCALE +#define TSL2561_LUX_B6T (0x00d2) ///< 0.0128 * 2^LUX_SCALE +#define TSL2561_LUX_M6T (0x00fb) ///< 0.0153 * 2^LUX_SCALE +#define TSL2561_LUX_K7T (0x029a) ///< 1.3 * 2^RATIO_SCALE +#define TSL2561_LUX_B7T (0x0018) ///< 0.00146 * 2^LUX_SCALE +#define TSL2561_LUX_M7T (0x0012) ///< 0.00112 * 2^LUX_SCALE +#define TSL2561_LUX_K8T (0x029a) ///< 1.3 * 2^RATIO_SCALE +#define TSL2561_LUX_B8T (0x0000) ///< 0.000 * 2^LUX_SCALE +#define TSL2561_LUX_M8T (0x0000) ///< 0.000 * 2^LUX_SCALE + +// CS package values +#define TSL2561_LUX_K1C (0x0043) ///< 0.130 * 2^RATIO_SCALE +#define TSL2561_LUX_B1C (0x0204) ///< 0.0315 * 2^LUX_SCALE +#define TSL2561_LUX_M1C (0x01ad) ///< 0.0262 * 2^LUX_SCALE +#define TSL2561_LUX_K2C (0x0085) ///< 0.260 * 2^RATIO_SCALE +#define TSL2561_LUX_B2C (0x0228) ///< 0.0337 * 2^LUX_SCALE +#define TSL2561_LUX_M2C (0x02c1) ///< 0.0430 * 2^LUX_SCALE +#define TSL2561_LUX_K3C (0x00c8) ///< 0.390 * 2^RATIO_SCALE +#define TSL2561_LUX_B3C (0x0253) ///< 0.0363 * 2^LUX_SCALE +#define TSL2561_LUX_M3C (0x0363) ///< 0.0529 * 2^LUX_SCALE +#define TSL2561_LUX_K4C (0x010a) ///< 0.520 * 2^RATIO_SCALE +#define TSL2561_LUX_B4C (0x0282) ///< 0.0392 * 2^LUX_SCALE +#define TSL2561_LUX_M4C (0x03df) ///< 0.0605 * 2^LUX_SCALE +#define TSL2561_LUX_K5C (0x014d) ///< 0.65 * 2^RATIO_SCALE +#define TSL2561_LUX_B5C (0x0177) ///< 0.0229 * 2^LUX_SCALE +#define TSL2561_LUX_M5C (0x01dd) ///< 0.0291 * 2^LUX_SCALE +#define TSL2561_LUX_K6C (0x019a) ///< 0.80 * 2^RATIO_SCALE +#define TSL2561_LUX_B6C (0x0101) ///< 0.0157 * 2^LUX_SCALE +#define TSL2561_LUX_M6C (0x0127) ///< 0.0180 * 2^LUX_SCALE +#define TSL2561_LUX_K7C (0x029a) ///< 1.3 * 2^RATIO_SCALE +#define TSL2561_LUX_B7C (0x0037) ///< 0.00338 * 2^LUX_SCALE +#define TSL2561_LUX_M7C (0x002b) ///< 0.00260 * 2^LUX_SCALE +#define TSL2561_LUX_K8C (0x029a) ///< 1.3 * 2^RATIO_SCALE +#define TSL2561_LUX_B8C (0x0000) ///< 0.000 * 2^LUX_SCALE +#define TSL2561_LUX_M8C (0x0000) ///< 0.000 * 2^LUX_SCALE + +// Auto-gain thresholds +#define TSL2561_AGC_THI_13MS (4850) ///< Max value at Ti 13ms = 5047 +#define TSL2561_AGC_TLO_13MS (100) ///< Min value at Ti 13ms = 100 +#define TSL2561_AGC_THI_101MS (36000) ///< Max value at Ti 101ms = 37177 +#define TSL2561_AGC_TLO_101MS (200) ///< Min value at Ti 101ms = 200 +#define TSL2561_AGC_THI_402MS (63000) ///< Max value at Ti 402ms = 65535 +#define TSL2561_AGC_TLO_402MS (500) ///< Min value at Ti 402ms = 500 + +// Clipping thresholds ///< # Counts that trigger a change in gain/integration +#define TSL2561_CLIPPING_13MS (4900) +#define TSL2561_CLIPPING_101MS (37000) +#define TSL2561_CLIPPING_402MS (65000) + +// Delay for integration times +#define TSL2561_DELAY_INTTIME_13MS (15) ///< Wait 15ms for 13ms integration +#define TSL2561_DELAY_INTTIME_101MS (120) ///< Wait 120ms for 101ms integration +#define TSL2561_DELAY_INTTIME_402MS (450) ///< Wait 450ms for 402ms integration + +/*========================================================================*/ +/* CONSTRUCTORS */ +/*========================================================================*/ + TSL2561::TSL2561 (PinName p_sda, PinName p_scl) - : _i2c_p(new I2C(p_sda, p_scl)), _i2c(*_i2c_p) + : _i2c_p(new I2C(p_sda, p_scl)), _i2c(*_i2c_p) { - TSL2561_addr = TSL2561_ADDRESS_GND; + _addr = TSL2561_ADDR_LOW; init(); } TSL2561::TSL2561 (PinName p_sda, PinName p_scl, uint8_t addr) - : _i2c_p(new I2C(p_sda, p_scl)), _i2c(*_i2c_p) + : _i2c_p(new I2C(p_sda, p_scl)), _i2c(*_i2c_p) { - TSL2561_addr = addr; + _addr = addr; init(); } TSL2561::TSL2561 (I2C& p_i2c) - : _i2c(p_i2c) + : _i2c(p_i2c) { - TSL2561_addr = TSL2561_ADDRESS_GND; + _addr = TSL2561_ADDR_LOW; init(); } TSL2561::TSL2561 (I2C& p_i2c, uint8_t addr) - : _i2c(p_i2c) + : _i2c(p_i2c) { - TSL2561_addr = addr; + _addr = addr; init(); } +/*========================================================================*/ +/* PUBLIC FUNCTIONS */ +/*========================================================================*/ /////////////// Read Lux from sensor ////////////////////// /* For 0 < CH1/CH0 < 0.50 Lux = 0.0304 x CH0-0.062 x CH0 x ((CH1/CH0)1.4) @@ -56,25 +178,28 @@ double ratio; double dlux; - dt[0] = CMD_MULTI + TSL2561_DATA0LOW; - _i2c.write((int)TSL2561_addr, (char *)dt, 1, true); - _i2c.read(TSL2561_addr, (char *)dt, 2, false); - ch0 = dt[1] << 8 | dt[0]; - dt[0] = CMD_MULTI + TSL2561_DATA1LOW; - _i2c.write((int)TSL2561_addr, (char *)dt, 1, true); - _i2c.read(TSL2561_addr, (char *)dt, 2, false); - ch1 = dt[1] << 8 | dt[0]; - if (ch0 == 0xFFFF) { - return 2500.0; - } + _TSL2561AutoGain = false; + _TSL2561IntegrationTime = TSL2561_INTEGRATIONTIME_13MS; + _TSL2561Gain = TSL2561_GAIN_1X; + /* Set default integration time and gain */ + setIntegrationTime(_TSL2561IntegrationTime); + setGain(_TSL2561Gain); + uint16_t x0, x1; + getLuminosity(&x0, &x1); + ch0 = x0; + ch1 = x1; + //printf("ch0 = %d, ch1 = %d\r\n", ch0, ch1); + //printf("Integ. Time = %d, Gain %d\r\n", + // _TSL2561IntegrationTime, _TSL2561Gain); lux0 = (double)ch0; lux1 = (double)ch1; ratio = lux1 / lux0; read_timing_reg(); - lux0 *= (402.0/integ_time); - lux1 *= (402.0/integ_time); + lux0 *= (402.0/(double)integ_time); + lux1 *= (402.0/(double)integ_time); lux0 /= gain; lux1 /= gain; + //printf("Integ. Time = %f, Gain %d\r\n", integ_time, gain); if (ratio <= 0.5) { dlux = 0.03040 * lux0 - 0.06200 * lux0 * pow(ratio,1.4); } else if (ratio <= 0.61) { @@ -86,54 +211,528 @@ } else { dlux = 0; } + disable(); return (float)dlux; } -/////////////// Initialize //////////////////////////////// -void TSL2561::init() +float TSL2561::lux_auto(void) +{ + uint32_t data; + + enableAutoRange(true); + getEvent(&data); + //printf("line:%d\r\n", __LINE__); + return (float)data; +} + +/**************************************************************************/ +/*! + @brief Initializes I2C connection and settings. + Attempts to determine if the sensor is contactable, then sets up a default + integration time and gain. Then powers down the chip. + @returns True if sensor is found and initialized, false otherwise. +*/ +/**************************************************************************/ +bool TSL2561::init() +{ + _TSL2561Initialised = false; + _TSL2561AutoGain = false; + _TSL2561IntegrationTime = TSL2561_INTEGRATIONTIME_13MS; + _TSL2561Gain = TSL2561_GAIN_1X; + + /* Make sure we're actually connected */ + uint8_t x = read8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_ID); + if (x & 0xF0 != 0x50) { // ID code for TSL2561 + //printf("initialize error!\r\n"); + return false; + } + //printf("ID=0x%02x\r\n", x); + _TSL2561Initialised = true; + + /* Set default integration time and gain */ + setIntegrationTime(_TSL2561IntegrationTime); + setGain(_TSL2561Gain); + read_timing_reg(); + + /* Note: by default, the device is in power down mode on bootup */ + disable(); + + t.reset(); + t.start(); + //printf("Integ. Time = %d, Gain %d\r\n", + // _TSL2561IntegrationTime, _TSL2561Gain); + //printf("initialize finished!\r\n"); + x = read8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING); + //printf("TIMING REG=0x%02x\r\n", x); + return true; +} + +/**************************************************************************/ +/*! + @brief Enables or disables the auto-gain settings when reading + data from the sensor + @param enable Set to true to enable, False to disable +*/ +/**************************************************************************/ +void TSL2561::enableAutoRange(bool enable) +{ + _TSL2561AutoGain = enable ? true : false; +} + +/**************************************************************************/ +/*! + @brief Sets the integration time for the TSL2561. Higher time means + more light captured (better for low light conditions) but will + take longer to run readings. + @param time The amount of time we'd like to add up values +*/ +/**************************************************************************/ +void TSL2561::setIntegrationTime(TSL2561IntegrationTime_t time) +{ + /* Enable the device by setting the control bit to 0x03 */ + enable(); + /* Update the timing register */ + write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, time | _TSL2561Gain); + /* Update value placeholders */ + _TSL2561IntegrationTime = time; + /* Turn the device off to save power */ + disable(); +} + +/**************************************************************************/ +/*! + @brief Adjusts the gain on the TSL2561 (adjusts the sensitivity to light) + @param gain The value we'd like to set the gain to +*/ +/**************************************************************************/ +void TSL2561::setGain(TSL2561Gain_t gain) +{ + /* Enable the device by setting the control bit to 0x03 */ + enable(); + /* Update the timing register */ + write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, _TSL2561IntegrationTime | gain); + /* Update value placeholders */ + _TSL2561Gain = gain; + /* Turn the device off to save power */ + disable(); +} + +/**************************************************************************/ +/*! + @brief Gets the broadband (mixed lighting) and IR only values from + the TSL2561, adjusting gain if auto-gain is enabled + @param broadband Pointer to a uint16_t we will fill with a sensor + reading from the IR+visible light diode. + @param ir Pointer to a uint16_t we will fill with a sensor the + IR-only light diode. +*/ +/**************************************************************************/ +void TSL2561::getLuminosity (uint16_t *broadband, uint16_t *ir) +{ + bool valid = false; + + /* If Auto gain disabled get a single reading and continue */ + if(!_TSL2561AutoGain) { + //printf("Get data without Auto gain\r\n"); + getData (broadband, ir); + return; + } + //printf("Get data with Auto gain\r\n"); + /* Read data until we find a valid range */ + bool _agcCheck = false; + do { + uint16_t _b, _ir; + uint16_t _hi, _lo; + TSL2561IntegrationTime_t _it = _TSL2561IntegrationTime; + + /* Get the hi/low threshold for the current integration time */ + switch(_it) { + case TSL2561_INTEGRATIONTIME_13MS: + _hi = TSL2561_AGC_THI_13MS; + _lo = TSL2561_AGC_TLO_13MS; + break; + case TSL2561_INTEGRATIONTIME_101MS: + _hi = TSL2561_AGC_THI_101MS; + _lo = TSL2561_AGC_TLO_101MS; + break; + default: + _hi = TSL2561_AGC_THI_402MS; + _lo = TSL2561_AGC_TLO_402MS; + break; + } + + getData(&_b, &_ir); + + /* Run an auto-gain check if we haven't already done so ... */ + if (!_agcCheck) { + if ((_b < _lo) && (_TSL2561Gain == TSL2561_GAIN_1X)) { + /* Increase the gain and try again */ + setGain(TSL2561_GAIN_16X); + /* Drop the previous conversion results */ + getData(&_b, &_ir); + /* Set a flag to indicate we've adjusted the gain */ + _agcCheck = true; + } else if ((_b > _hi) && (_TSL2561Gain == TSL2561_GAIN_16X)) { + /* Drop gain to 1x and try again */ + setGain(TSL2561_GAIN_1X); + /* Drop the previous conversion results */ + getData(&_b, &_ir); + /* Set a flag to indicate we've adjusted the gain */ + _agcCheck = true; + } else { + /* Nothing to look at here, keep moving .... + Reading is either valid, or we're already at the chips limits */ + *broadband = _b; + *ir = _ir; + valid = true; + } + } else { + /* If we've already adjusted the gain once, just return the new results. + This avoids endless loops where a value is at one extreme pre-gain, + and the the other extreme post-gain */ + *broadband = _b; + *ir = _ir; + valid = true; + } + } while (!valid); +} + +/**************************************************************************/ +/*! + Enables the device +*/ +/**************************************************************************/ +void TSL2561::enable(void) +{ + /* Enable the device by setting the control bit to 0x03 */ + write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, TSL2561_CONTROL_POWERON); +} + +/**************************************************************************/ +/*! + Disables the device (putting it in lower power sleep mode) +*/ +/**************************************************************************/ +void TSL2561::disable(void) +{ + /* Turn the device off to save power */ + write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, TSL2561_CONTROL_POWEROFF); +} + +/**************************************************************************/ +/*! + Private function to read luminosity on both channels +*/ +/**************************************************************************/ +void TSL2561::getData (uint16_t *broadband, uint16_t *ir) { - _i2c.frequency(100000); - power_up(); - set_timing_reg(TIMING_DEFAULT); + /* Enable the device by setting the control bit to 0x03 */ + enable(); + + /* Wait x ms for ADC to complete */ + switch (_TSL2561IntegrationTime) { + case TSL2561_INTEGRATIONTIME_13MS: + wait_ms(TSL2561_DELAY_INTTIME_13MS); + break; + case TSL2561_INTEGRATIONTIME_101MS: + wait_ms(TSL2561_DELAY_INTTIME_101MS); + break; + default: + wait_ms(TSL2561_DELAY_INTTIME_402MS); + break; + } + + /* Reads a two byte value from channel 0 (visible + infrared) */ + *broadband = read16(TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN0_LOW); + + /* Reads a two byte value from channel 1 (infrared) */ + *ir = read16(TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN1_LOW); + + /* Turn the device off to save power */ + disable(); } +/**************************************************************************/ +/*! + @brief Converts the raw sensor values to the standard SI lux equivalent. + @param broadband The 16-bit sensor reading from the IR+visible light diode. + @param ir The 16-bit sensor reading from the IR-only light diode. + @returns The integer Lux value we calcuated. + Returns 0 if the sensor is saturated and the values are + unreliable, or 65536 if the sensor is saturated. +*/ +/**************************************************************************/ +/**************************************************************************/ +/*! + + Returns +*/ +/**************************************************************************/ +uint32_t TSL2561::calculateLux(uint16_t broadband, uint16_t ir) +{ + unsigned long chScale; + unsigned long channel1; + unsigned long channel0; + + //printf("line:%d\r\n", __LINE__); + /* Make sure the sensor isn't saturated! */ + uint16_t clipThreshold; + //printf("_TSL2561IntegrationTime=%d\r\n", _TSL2561IntegrationTime); + switch (_TSL2561IntegrationTime) { + case TSL2561_INTEGRATIONTIME_13MS: + clipThreshold = TSL2561_CLIPPING_13MS; + chScale = TSL2561_LUX_CHSCALE_TINT0; + //printf("line:%d\r\n", __LINE__); + break; + case TSL2561_INTEGRATIONTIME_101MS: + clipThreshold = TSL2561_CLIPPING_101MS; + chScale = TSL2561_LUX_CHSCALE_TINT1; + break; + default: + clipThreshold = TSL2561_CLIPPING_402MS; + chScale = (1 << TSL2561_LUX_CHSCALE); + break; + } + //printf("clipThreshold=%d\r\n", clipThreshold); + /* Return 65536 lux if the sensor is saturated */ + if ((broadband > clipThreshold) || (ir > clipThreshold)) { + //printf("line:%d\r\n", __LINE__); + return 65536; + } + + //printf("line:%d\r\n", __LINE__); + //printf("chScale=%d\r\n", chScale); + /* Scale for gain (1x or 16x) */ + if (!_TSL2561Gain) { + chScale = chScale << 4; + } + //printf("chScale=%d\r\n", chScale); + /* Scale the channel values */ + channel0 = (broadband * chScale) >> TSL2561_LUX_CHSCALE; + channel1 = (ir * chScale) >> TSL2561_LUX_CHSCALE; + //printf("channel0=%d, channel1=%d\r\n", channel0, channel1); + + /* Find the ratio of the channel values (Channel1/Channel0) */ + unsigned long ratio1 = 0; + if (channel0 != 0) { + ratio1 = (channel1 << (TSL2561_LUX_RATIOSCALE+1)) / channel0; + } + + /* round the ratio value */ + long ratio = (ratio1 + 1) >> 1; + //printf("ratio1=%d, ratio=%d\r\n", ratio1, ratio); + unsigned int b, m; + +#ifdef TSL2561_PACKAGE_CS + //printf("line:%d\r\n", __LINE__); + if ((ratio >= 0) && (ratio <= TSL2561_LUX_K1C)) { + b=TSL2561_LUX_B1C; + m=TSL2561_LUX_M1C; + } else if (ratio <= TSL2561_LUX_K2C) { + b=TSL2561_LUX_B2C; + m=TSL2561_LUX_M2C; + } else if (ratio <= TSL2561_LUX_K3C) { + b=TSL2561_LUX_B3C; + m=TSL2561_LUX_M3C; + } else if (ratio <= TSL2561_LUX_K4C) { + b=TSL2561_LUX_B4C; + m=TSL2561_LUX_M4C; + } else if (ratio <= TSL2561_LUX_K5C) { + b=TSL2561_LUX_B5C; + m=TSL2561_LUX_M5C; + } else if (ratio <= TSL2561_LUX_K6C) { + b=TSL2561_LUX_B6C; + m=TSL2561_LUX_M6C; + } else if (ratio <= TSL2561_LUX_K7C) { + b=TSL2561_LUX_B7C; + m=TSL2561_LUX_M7C; + } else if (ratio > TSL2561_LUX_K8C) { + b=TSL2561_LUX_B8C; + m=TSL2561_LUX_M8C; + } +#else + //printf("line:%d\r\n", __LINE__); + if ((ratio >= 0) && (ratio <= TSL2561_LUX_K1T)) { + b=TSL2561_LUX_B1T; + m=TSL2561_LUX_M1T; + } else if (ratio <= TSL2561_LUX_K2T) { + b=TSL2561_LUX_B2T; + m=TSL2561_LUX_M2T; + } else if (ratio <= TSL2561_LUX_K3T) { + b=TSL2561_LUX_B3T; + m=TSL2561_LUX_M3T; + } else if (ratio <= TSL2561_LUX_K4T) { + b=TSL2561_LUX_B4T; + m=TSL2561_LUX_M4T; + } else if (ratio <= TSL2561_LUX_K5T) { + b=TSL2561_LUX_B5T; + m=TSL2561_LUX_M5T; + } else if (ratio <= TSL2561_LUX_K6T) { + b=TSL2561_LUX_B6T; + m=TSL2561_LUX_M6T; + } else if (ratio <= TSL2561_LUX_K7T) { + b=TSL2561_LUX_B7T; + m=TSL2561_LUX_M7T; + } else if (ratio > TSL2561_LUX_K8T) { + b=TSL2561_LUX_B8T; + m=TSL2561_LUX_M8T; + } +#endif + + long temp; + temp = ((channel0 * b) - (channel1 * m)); + + /* Do not allow negative lux value */ + if (temp < 0L) { + temp = 0; + } + //printf("line:%d\r\n", __LINE__); + /* Round lsb (2^(LUX_SCALE-1)) */ + temp += (1 << (TSL2561_LUX_LUXSCALE-1)); + + /* Strip off fractional portion */ + uint32_t lux = temp >> TSL2561_LUX_LUXSCALE; + + /* Signal I2C had no errors */ + //printf("Lux=%d\r\n", lux); + return lux; +} + +/**************************************************************************/ +/*! + @brief Gets the most recent sensor event + @param event Pointer to a sensor_event_t type that will be filled + with the lux value, timestamp, data type and sensor ID. + @returns True if sensor reading is between 0 and 65535 lux, + false if sensor is saturated +*/ +/**************************************************************************/ +bool TSL2561::getEvent(uint32_t *event) +{ + uint16_t broadband, ir; + + /* Calculate the actual lux value */ + getLuminosity(&broadband, &ir); + //printf("broadband=%d, ir=%d\r\n", broadband, ir); + *event = calculateLux(broadband, ir); + //printf("LUX=%f\r\n", event->light); + //printf("LUX=%d\r\n", *event); + //printf("line:%d\r\n", __LINE__); + if (*event == 65536) { + //printf("line:%d\r\n", __LINE__); + return false; + } + //printf("line:%d\r\n", __LINE__); + return true; +} + +/**************************************************************************/ +/*! + @brief Gets the sensor_t data + @param sensor A pointer to a sensor_t structure that we will fill with + details about the TSL2561 and its capabilities +*/ +/**************************************************************************/ +void TSL2561::getSensor(sensor_t *sensor) +{ + /* Insert the sensor name in the fixed length char array */ + //sensor->version = 1; + sensor->min_delay = 0; + sensor->max_value = 17000.0; /* Based on trial and error ... confirm! */ + sensor->min_value = 1.0; + sensor->resolution = 1.0; +} + +/*========================================================================*/ +/* PRIVATE FUNCTIONS */ +/*========================================================================*/ + +/**************************************************************************/ +/*! + @brief Writes a register and an 8 bit value over I2C + @param reg I2C register to write the value to + @param value The 8-bit value we're writing to the register +*/ +/**************************************************************************/ +void TSL2561::write8 (uint8_t reg, uint8_t value) +{ + dt[0] = reg; + dt[1] = value; + _i2c.write((int)_addr, (char *)dt, 2, false); +} + +/**************************************************************************/ +/*! + @brief Reads an 8 bit value over I2C + @param reg I2C register to read from + @returns 8-bit value containing single byte data read +*/ +/**************************************************************************/ +uint8_t TSL2561::read8(uint8_t reg) +{ + dt[0] = reg; + _i2c.write((int)_addr, (char *)dt, 1, true); + _i2c.read(_addr, (char *)dt, 1, false); + return dt[0]; +} + +/**************************************************************************/ +/*! + @brief Reads a 16 bit values over I2C + @param reg I2C register to read from + @returns 16-bit value containing 2-byte data read +*/ +/**************************************************************************/ +uint16_t TSL2561::read16(uint8_t reg) +{ + dt[0] = reg; + _i2c.write((int)_addr, (char *)dt, 1, true); + _i2c.read(_addr, (char *)dt, 2, false); + uint16_t data = ((uint16_t)dt[1] << 8) + dt[0]; + return data; +} + +/*========================================================================*/ +/* JH1PJL Original Functions -> Keep compacibility for older revision */ +/*========================================================================*/ + /////////////// Timing Register /////////////////////////// uint8_t TSL2561::set_timing_reg(uint8_t parameter) { - dt[0] = CMD_SINGLE + TSL2561_TIMING; - dt[1] = parameter; - _i2c.write((int)TSL2561_addr, (char *)dt, 2, false); - dt[0] = CMD_SINGLE + TSL2561_TIMING; - _i2c.write((int)TSL2561_addr, (char *)dt, 1, true); - _i2c.read(TSL2561_addr, (char *)dt, 1, false); - return dt[0]; + enable(); + write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, parameter); + return read8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING); } uint8_t TSL2561::read_timing_reg(void) { - uint8_t i; + uint8_t i, data; - dt[0] = CMD_SINGLE + TSL2561_TIMING; - _i2c.write((int)TSL2561_addr, (char *)dt, 1, true); - _i2c.read(TSL2561_addr, (char *)dt, 1, false); - if (dt[0] & TIMING_GAIN_16){ + data = read8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING); + if (data & TSL2561_GAIN_16X) { gain = 16; + _TSL2561Gain = TSL2561_GAIN_16X; } else { gain = 1; + _TSL2561Gain = TSL2561_GAIN_1X; } - i = dt[0] & 0x3; + i = data & 0x3; switch (i) { case 0: integ_time = 13.7; + _TSL2561IntegrationTime = TSL2561_INTEGRATIONTIME_13MS; break; case 1: integ_time = 101.0; + _TSL2561IntegrationTime = TSL2561_INTEGRATIONTIME_101MS; break; case 2: integ_time = 402.0; + _TSL2561IntegrationTime = TSL2561_INTEGRATIONTIME_402MS; break; default: integ_time = 0; + _TSL2561IntegrationTime = TSL2561_INTEGRATIONTIME_13MS; break; } return dt[0]; @@ -142,10 +741,7 @@ /////////////// ID //////////////////////////////////////// uint8_t TSL2561::read_ID() { - dt[0] = CMD_SINGLE + TSL2561_ID; - _i2c.write((int)TSL2561_addr, (char *)dt, 1, true); - _i2c.read(TSL2561_addr, (char *)dt, 2, false); - id_number = dt[0]; + id_number = read8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_ID); return id_number; } @@ -164,16 +760,12 @@ /////////////// Power ON/OFF ////////////////////////////// void TSL2561::power_up() { - dt[0] = CMD_SINGLE + TSL2561_CONTROL; - dt[1] = 3; - _i2c.write((int)TSL2561_addr, (char *)dt, 2, false); + enable(); } void TSL2561::power_down() { - dt[0] = CMD_SINGLE + TSL2561_CONTROL; - dt[1] = 0; - _i2c.write((int)TSL2561_addr, (char *)dt, 2, false); + disable(); } /////////////// I2C Freq. ///////////////////////////////// @@ -181,4 +773,3 @@ { _i2c.frequency(hz); } -