mirror of
https://github.com/adafruit/Adafruit_TSL2561.git
synced 2025-08-01 01:44:27 +02:00
First commit
This commit is contained in:
541
Adafruit_TSL2561.cpp
Normal file
541
Adafruit_TSL2561.cpp
Normal file
@@ -0,0 +1,541 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file Adafruit_TSL2561.cpp
|
||||
@author K.Townsend (Adafruit Industries)
|
||||
@license BSD (see license.txt)
|
||||
|
||||
Driver for the TSL2561 digital luminosity (light) sensors.
|
||||
|
||||
Pick one up at http://www.adafruit.com/products/439
|
||||
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
@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)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
#include <avr/pgmspace.h>
|
||||
#include <util/delay.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Adafruit_TSL2561.h"
|
||||
|
||||
/*========================================================================*/
|
||||
/* PRIVATE FUNCTIONS */
|
||||
/*========================================================================*/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Sends a single command byte over I2C
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_TSL2561::writeCmd (uint8_t cmd)
|
||||
{
|
||||
Wire.beginTransmission(_addr);
|
||||
#if ARDUINO >= 100
|
||||
Wire.write(cmd);
|
||||
#else
|
||||
Wire.send(cmd);
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Writes a register and an 8 bit value over I2C
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_TSL2561::write8 (uint8_t reg, uint32_t value)
|
||||
{
|
||||
Wire.beginTransmission(_addr);
|
||||
#if ARDUINO >= 100
|
||||
Wire.write(reg);
|
||||
Wire.write(value & 0xFF);
|
||||
#else
|
||||
Wire.send(reg);
|
||||
Wire.send(value & 0xFF);
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads an 8 bit value over I2C
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t Adafruit_TSL2561::read8(uint8_t reg)
|
||||
{
|
||||
Wire.beginTransmission(_addr);
|
||||
#if ARDUINO >= 100
|
||||
Wire.write(reg);
|
||||
#else
|
||||
Wire.send(reg);
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
|
||||
Wire.requestFrom(_addr, 1);
|
||||
#if ARDUINO >= 100
|
||||
return Wire.read();
|
||||
#else
|
||||
return Wire.receive();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads a 16 bit values over I2C
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint16_t Adafruit_TSL2561::read16(uint8_t reg)
|
||||
{
|
||||
uint16_t x; uint16_t t;
|
||||
|
||||
Wire.beginTransmission(_addr);
|
||||
#if ARDUINO >= 100
|
||||
Wire.write(reg);
|
||||
#else
|
||||
Wire.send(reg);
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
|
||||
Wire.requestFrom(_addr, 2);
|
||||
#if ARDUINO >= 100
|
||||
t = Wire.read();
|
||||
x = Wire.read();
|
||||
#else
|
||||
t = Wire.receive();
|
||||
x = Wire.receive();
|
||||
#endif
|
||||
x <<= 8;
|
||||
x |= t;
|
||||
return x;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Enables the device
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_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 Adafruit_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 Adafruit_TSL2561::getData (uint16_t *broadband, uint16_t *ir)
|
||||
{
|
||||
/* Enable the device by setting the control bit to 0x03 */
|
||||
enable();
|
||||
|
||||
/* Wait x ms for ADC to complete */
|
||||
switch (_tsl2561IntegrationTime)
|
||||
{
|
||||
case TSL2561_INTEGRATIONTIME_13MS:
|
||||
delay(14);
|
||||
break;
|
||||
case TSL2561_INTEGRATIONTIME_101MS:
|
||||
delay(102);
|
||||
break;
|
||||
default:
|
||||
delay(403);
|
||||
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();
|
||||
}
|
||||
|
||||
/*========================================================================*/
|
||||
/* CONSTRUCTORS */
|
||||
/*========================================================================*/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Constructor
|
||||
*/
|
||||
/**************************************************************************/
|
||||
Adafruit_TSL2561::Adafruit_TSL2561(uint8_t addr)
|
||||
{
|
||||
_addr = addr;
|
||||
_tsl2561Initialised = false;
|
||||
_tsl2561AutoGain = false;
|
||||
_tsl2561IntegrationTime = TSL2561_INTEGRATIONTIME_13MS;
|
||||
_tsl2561Gain = TSL2561_GAIN_1X;
|
||||
_tsl2561SensorID = -1;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Constructor
|
||||
*/
|
||||
/**************************************************************************/
|
||||
Adafruit_TSL2561::Adafruit_TSL2561(uint8_t addr, int32_t sensorID)
|
||||
{
|
||||
_addr = addr;
|
||||
_tsl2561Initialised = false;
|
||||
_tsl2561AutoGain = false;
|
||||
_tsl2561IntegrationTime = TSL2561_INTEGRATIONTIME_13MS;
|
||||
_tsl2561Gain = TSL2561_GAIN_1X;
|
||||
_tsl2561SensorID = sensorID;
|
||||
}
|
||||
|
||||
/*========================================================================*/
|
||||
/* PUBLIC FUNCTIONS */
|
||||
/*========================================================================*/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Initializes I2C and configures the sensor (call this function before
|
||||
doing anything else)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
boolean Adafruit_TSL2561::begin(void)
|
||||
{
|
||||
Wire.begin();
|
||||
|
||||
/* Make sure we're actually connected */
|
||||
uint8_t x = read8(TSL2561_REGISTER_ID);
|
||||
if (!(x & 0x0A))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_tsl2561Initialised = true;
|
||||
|
||||
/* Set default integration time and gain */
|
||||
setIntegrationTime(_tsl2561IntegrationTime);
|
||||
setGain(_tsl2561Gain);
|
||||
|
||||
/* Note: by default, the device is in power down mode on bootup */
|
||||
disable();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Enables or disables the auto-gain settings when reading
|
||||
data from the sensor
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_TSL2561::enableAutoGain(bool enable)
|
||||
{
|
||||
_tsl2561AutoGain = enable ? true : false;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Sets the integration time for the TSL2561
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_TSL2561::setIntegrationTime(tsl2561IntegrationTime_t time)
|
||||
{
|
||||
if (!_tsl2561Initialised) begin();
|
||||
|
||||
/* 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();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Adjusts the gain on the TSL2561 (adjusts the sensitivity to light)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_TSL2561::setGain(tsl2561Gain_t gain)
|
||||
{
|
||||
if (!_tsl2561Initialised) begin();
|
||||
|
||||
/* 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
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_TSL2561::getLuminosity (uint16_t *broadband, uint16_t *ir)
|
||||
{
|
||||
bool valid = false;
|
||||
|
||||
if (!_tsl2561Initialised) begin();
|
||||
|
||||
/* If Auto gain disabled get a single reading and continue */
|
||||
if(!_tsl2561AutoGain)
|
||||
{
|
||||
getData (broadband, ir);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Converts the raw sensor values to the standard SI lux equivalent.
|
||||
Returns 0 if the sensor is saturated and the values are unreliable.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint32_t Adafruit_TSL2561::calculateLux(uint16_t broadband, uint16_t ir)
|
||||
{
|
||||
unsigned long chScale;
|
||||
unsigned long channel1;
|
||||
unsigned long channel0;
|
||||
|
||||
/* Make sure the sensor isn't saturated! */
|
||||
uint16_t clipThreshold;
|
||||
switch (_tsl2561IntegrationTime)
|
||||
{
|
||||
case TSL2561_INTEGRATIONTIME_13MS:
|
||||
clipThreshold = TSL2561_CLIPPING_13MS;
|
||||
break;
|
||||
case TSL2561_INTEGRATIONTIME_101MS:
|
||||
clipThreshold = TSL2561_CLIPPING_101MS;
|
||||
break;
|
||||
default:
|
||||
clipThreshold = TSL2561_CLIPPING_402MS;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Return 0 lux if the sensor is saturated */
|
||||
if ((broadband > clipThreshold) || (ir > clipThreshold))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the correct scale depending on the intergration time */
|
||||
switch (_tsl2561IntegrationTime)
|
||||
{
|
||||
case TSL2561_INTEGRATIONTIME_13MS:
|
||||
chScale = TSL2561_LUX_CHSCALE_TINT0;
|
||||
break;
|
||||
case TSL2561_INTEGRATIONTIME_101MS:
|
||||
chScale = TSL2561_LUX_CHSCALE_TINT1;
|
||||
break;
|
||||
default: /* No scaling ... integration time = 402ms */
|
||||
chScale = (1 << TSL2561_LUX_CHSCALE);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Scale for gain (1x or 16x) */
|
||||
if (!_tsl2561Gain) chScale = chScale << 4;
|
||||
|
||||
/* Scale the channel values */
|
||||
channel0 = (broadband * chScale) >> TSL2561_LUX_CHSCALE;
|
||||
channel1 = (ir * chScale) >> TSL2561_LUX_CHSCALE;
|
||||
|
||||
/* 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 */
|
||||
unsigned long ratio = (ratio1 + 1) >> 1;
|
||||
|
||||
unsigned int b, m;
|
||||
|
||||
#ifdef TSL2561_PACKAGE_CS
|
||||
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
|
||||
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
|
||||
|
||||
unsigned long temp;
|
||||
temp = ((channel0 * b) - (channel1 * m));
|
||||
|
||||
/* Do not allow negative lux value */
|
||||
if (temp < 0) temp = 0;
|
||||
|
||||
/* 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 */
|
||||
return lux;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Gets the most recent sensor event
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_TSL2561::getEvent(sensors_event_t *event)
|
||||
{
|
||||
uint16_t broadband, ir;
|
||||
|
||||
/* Clear the event */
|
||||
memset(event, 0, sizeof(sensors_event_t));
|
||||
|
||||
event->version = sizeof(sensors_event_t);
|
||||
event->sensor_id = _tsl2561SensorID;
|
||||
event->type = SENSOR_TYPE_LIGHT;
|
||||
event->timestamp = 0;
|
||||
|
||||
/* Calculate the actual lux value */
|
||||
getLuminosity(&broadband, &ir);
|
||||
event->light = calculateLux(broadband, ir);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Gets the sensor_t data
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_TSL2561::getSensor(sensor_t *sensor)
|
||||
{
|
||||
/* Clear the sensor_t object */
|
||||
memset(sensor, 0, sizeof(sensor_t));
|
||||
|
||||
/* Insert the sensor name in the fixed length char array */
|
||||
strncpy (sensor->name, "TSL2561", sizeof(sensor->name) - 1);
|
||||
sensor->name[sizeof(sensor->name)- 1] = 0;
|
||||
sensor->version = 1;
|
||||
sensor->sensor_id = _tsl2561SensorID;
|
||||
sensor->type = SENSOR_TYPE_LIGHT;
|
||||
sensor->min_delay = 0;
|
||||
sensor->max_value = 17000.0; /* Based on trial and error ... confirm! */
|
||||
sensor->min_value = 0.0;
|
||||
sensor->resolution = 1.0;
|
||||
}
|
204
Adafruit_TSL2561.h
Normal file
204
Adafruit_TSL2561.h
Normal file
@@ -0,0 +1,204 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file Adafruit_TSL2561.h
|
||||
@author K. Townsend (Adafruit Industries)
|
||||
|
||||
@section LICENSE
|
||||
|
||||
Software License Agreement (BSD License)
|
||||
|
||||
Copyright (c) 2013, Adafruit Industries
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holders nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
#ifndef _TSL2561_H_
|
||||
#define _TSL2561_H_
|
||||
|
||||
#if ARDUINO >= 100
|
||||
#include <Arduino.h>
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#endif
|
||||
#include <Adafruit_Sensor.h>
|
||||
#include <Wire.h>
|
||||
|
||||
#define TSL2561_VISIBLE 2 // channel 0 - channel 1
|
||||
#define TSL2561_INFRARED 1 // channel 1
|
||||
#define TSL2561_FULLSPECTRUM 0 // channel 0
|
||||
|
||||
// I2C address options
|
||||
#define TSL2561_ADDR_LOW (0x29)
|
||||
#define TSL2561_ADDR_FLOAT (0x39) // Default address (pin left floating)
|
||||
#define TSL2561_ADDR_HIGH (0x49)
|
||||
|
||||
// Lux calculations differ slightly for CS package
|
||||
//#define TSL2561_PACKAGE_CS
|
||||
#define TSL2561_PACKAGE_T_FN_CL
|
||||
|
||||
#define TSL2561_COMMAND_BIT (0x80) // Must be 1
|
||||
#define TSL2561_CLEAR_BIT (0x40) // Clears any pending interrupt (write 1 to clear)
|
||||
#define TSL2561_WORD_BIT (0x20) // 1 = read/write word (rather than byte)
|
||||
#define TSL2561_BLOCK_BIT (0x10) // 1 = using block read/write
|
||||
|
||||
#define TSL2561_CONTROL_POWERON (0x03)
|
||||
#define TSL2561_CONTROL_POWEROFF (0x00)
|
||||
|
||||
#define TSL2561_LUX_LUXSCALE (14) // Scale by 2^14
|
||||
#define TSL2561_LUX_RATIOSCALE (9) // Scale ratio by 2^9
|
||||
#define TSL2561_LUX_CHSCALE (10) // Scale channel values by 2^10
|
||||
#define TSL2561_LUX_CHSCALE_TINT0 (0x7517) // 322/11 * 2^TSL2561_LUX_CHSCALE
|
||||
#define TSL2561_LUX_CHSCALE_TINT1 (0x0FE7) // 322/81 * 2^TSL2561_LUX_CHSCALE
|
||||
|
||||
// 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)
|
||||
#define TSL2561_AGC_THI_101MS (36000) // Max value at Ti 101ms = 37177
|
||||
#define TSL2561_AGC_TLO_101MS (200)
|
||||
#define TSL2561_AGC_THI_402MS (63000) // Max value at Ti 402ms = 65535
|
||||
#define TSL2561_AGC_TLO_402MS (500)
|
||||
|
||||
// Clipping thresholds
|
||||
#define TSL2561_CLIPPING_13MS (4900)
|
||||
#define TSL2561_CLIPPING_101MS (37000)
|
||||
#define TSL2561_CLIPPING_402MS (65000)
|
||||
|
||||
enum
|
||||
{
|
||||
TSL2561_REGISTER_CONTROL = 0x00,
|
||||
TSL2561_REGISTER_TIMING = 0x01,
|
||||
TSL2561_REGISTER_THRESHHOLDL_LOW = 0x02,
|
||||
TSL2561_REGISTER_THRESHHOLDL_HIGH = 0x03,
|
||||
TSL2561_REGISTER_THRESHHOLDH_LOW = 0x04,
|
||||
TSL2561_REGISTER_THRESHHOLDH_HIGH = 0x05,
|
||||
TSL2561_REGISTER_INTERRUPT = 0x06,
|
||||
TSL2561_REGISTER_CRC = 0x08,
|
||||
TSL2561_REGISTER_ID = 0x0A,
|
||||
TSL2561_REGISTER_CHAN0_LOW = 0x0C,
|
||||
TSL2561_REGISTER_CHAN0_HIGH = 0x0D,
|
||||
TSL2561_REGISTER_CHAN1_LOW = 0x0E,
|
||||
TSL2561_REGISTER_CHAN1_HIGH = 0x0F
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TSL2561_INTEGRATIONTIME_13MS = 0x00, // 13.7ms
|
||||
TSL2561_INTEGRATIONTIME_101MS = 0x01, // 101ms
|
||||
TSL2561_INTEGRATIONTIME_402MS = 0x02 // 402ms
|
||||
}
|
||||
tsl2561IntegrationTime_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TSL2561_GAIN_1X = 0x00, // No gain
|
||||
TSL2561_GAIN_16X = 0x10, // 16x gain
|
||||
}
|
||||
tsl2561Gain_t;
|
||||
|
||||
class Adafruit_TSL2561 : public Adafruit_Sensor {
|
||||
public:
|
||||
Adafruit_TSL2561(uint8_t addr);
|
||||
Adafruit_TSL2561(uint8_t addr, int32_t sensorID);
|
||||
boolean begin(void);
|
||||
|
||||
/* TSL2561 Functions */
|
||||
void enableAutoGain(bool enable);
|
||||
void setIntegrationTime(tsl2561IntegrationTime_t time);
|
||||
void setGain(tsl2561Gain_t gain);
|
||||
void getLuminosity (uint16_t *broadband, uint16_t *ir);
|
||||
uint32_t calculateLux(uint16_t broadband, uint16_t ir);
|
||||
|
||||
/* Unified Sensor API Functions */
|
||||
void getEvent(sensors_event_t*);
|
||||
void getSensor(sensor_t*);
|
||||
|
||||
private:
|
||||
int8_t _addr;
|
||||
boolean _tsl2561Initialised;
|
||||
boolean _tsl2561AutoGain;
|
||||
tsl2561IntegrationTime_t _tsl2561IntegrationTime;
|
||||
tsl2561Gain_t _tsl2561Gain;
|
||||
int32_t _tsl2561SensorID;
|
||||
|
||||
void enable (void);
|
||||
void disable (void);
|
||||
void writeCmd (uint8_t cmd);
|
||||
void write8 (uint8_t reg, uint32_t value);
|
||||
uint8_t read8 (uint8_t reg);
|
||||
uint16_t read16 (uint8_t reg);
|
||||
void getData (uint16_t *broadband, uint16_t *ir);
|
||||
};
|
||||
#endif
|
35
README.md
35
README.md
@@ -1,4 +1,33 @@
|
||||
Adafruit_TSL2561
|
||||
================
|
||||
#Adafruit TSL2561 Light Sensor Driver #
|
||||
|
||||
Unified sensor driver for Adafruit's TSL2561 breakouts
|
||||
This driver is for the Adafruit TSL2561 Breakout, and is based on Adafruit's Unified Sensor Library (Adafruit_Sensor).
|
||||
|
||||
## About the TSL2561 ##
|
||||
|
||||
The TSL2561 is a 16-bit digital (I2C) light sensor, with adjustable gain and 'integration time'.
|
||||
|
||||
Adjusting the gain allows you to make the sensor more or less 'sensitive' to light (depending on if you are indoors or outdoors, for example). Adjusting the 'integration time' essentially increases the resolution of the device, since the analog converter inside the chip has time to take more samples.
|
||||
|
||||
One of the big advantages of the TSL2561 is that it is capable of measuring both broadband (visible plus infrared) and infrared light thanks to two distinct sensing units on the device. This is important in certain lighting environments to be able to read the light level reliably.
|
||||
|
||||
Mor information on the TSL2561 can be found in the datasheet: http://www.adafruit.com/datasheets/TSL2561.pdf
|
||||
|
||||
## What is the Adafruit Unified Sensor Library? ##
|
||||
|
||||
The Adafruit Unified Sensor Library (Adafruit_Sensor) provides a common interface and data type for any supported sensor. It defines some basic information about the sensor (sensor limits, etc.), and returns standard SI units of a specific type and scale for each supported sensor type.
|
||||
|
||||
It provides a simple abstraction layer between your application and the actual sensor HW, allowing you to drop in any comparable sensor with only one or two lines of code to change in your project (essentially the constructor since the functions to read sensor data and get information about the sensor are defined in the base Adafruit_Sensor class).
|
||||
|
||||
This is imporant useful for two reasons:
|
||||
|
||||
1.) You can use the data right away because it's already converted to SI units that you understand and can compare, rather than meaningless values like 0..1023.
|
||||
|
||||
2.) Because SI units are standardised in the sensor library, you can also do quick sanity checks working with new sensors, or drop in any comparable sensor if you need better sensitivity or if a lower cost unit becomes available, etc.
|
||||
|
||||
Light sensors will always report units in lux, gyroscopes will always report units in rad/s, etc. ... freeing you up to focus on the data, rather than digging through the datasheet to understand what the sensor's raw numbers really mean.
|
||||
|
||||
## About this Driver ##
|
||||
|
||||
Adafruit invests time and resources providing this open source code. Please support Adafruit and open-source hardware by purchasing products from Adafruit!
|
||||
|
||||
Written by Kevin (KTOWN) Townsend for Adafruit Industries.
|
138
sensorapi/sensorapi.pde
Normal file
138
sensorapi/sensorapi.pde
Normal file
@@ -0,0 +1,138 @@
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_Sensor.h>
|
||||
#include <Adafruit_TSL2561.h>
|
||||
|
||||
/* This driver uses the Adafruit unified sensor library (Adafruit_Sensor),
|
||||
which provides a common 'type' for sensor data and some helper functions.
|
||||
|
||||
To use this driver you will also need to download the Adafruit_Sensor
|
||||
library and include it in your libraries folder.
|
||||
|
||||
You should also assign a unique ID to this sensor for use with
|
||||
the Adafruit Sensor API so that you can identify this particular
|
||||
sensor in any data logs, etc. To assign a unique ID, simply
|
||||
provide an appropriate value in the constructor below (12345
|
||||
is used by default in this example).
|
||||
|
||||
Connections
|
||||
===========
|
||||
Connect SCL to analog 5
|
||||
Connect SDA to analog 4
|
||||
Connect VDD to 3.3V DC
|
||||
Connect GROUND to common ground
|
||||
|
||||
I2C Address
|
||||
===========
|
||||
The address will be different depending on whether you leave
|
||||
the ADDR pin floating (addr 0x39), or tie it to ground or vcc.
|
||||
The default addess is 0x39, which assumes the ADDR pin is floating
|
||||
(not connected to anything). If you set the ADDR pin high
|
||||
or low, use TSL2561_ADDR_HIGH (0x49) or TSL2561_ADDR_LOW
|
||||
(0x29) respectively.
|
||||
|
||||
History
|
||||
=======
|
||||
2013/JAN/31 - First version (KTOWN)
|
||||
*/
|
||||
|
||||
Adafruit_TSL2561 tsl = Adafruit_TSL2561(TSL2561_ADDR_FLOAT, 12345);
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
Displays some basic information on this sensor from the unified
|
||||
sensor API sensor_t type (see Adafruit_Sensor for more information)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void displaySensorDetails(void)
|
||||
{
|
||||
sensor_t sensor;
|
||||
tsl.getSensor(&sensor);
|
||||
Serial.println("------------------------------------");
|
||||
Serial.print ("Sensor: "); Serial.println(sensor.name);
|
||||
Serial.print ("Driver Ver: "); Serial.println(sensor.version);
|
||||
Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id);
|
||||
Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println(" lux");
|
||||
Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" lux");
|
||||
Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" lux");
|
||||
Serial.println("------------------------------------");
|
||||
Serial.println("");
|
||||
delay(500);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
Configures the gain and integration time for the TSL2561
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void configureSensor(void)
|
||||
{
|
||||
/* You can also manually set the gain or enable auto-gain support */
|
||||
// tsl.setGain(TSL2561_GAIN_1X); /* No gain ... use in bright light to avoid sensor saturation */
|
||||
// tsl.setGain(TSL2561_GAIN_16X); /* 16x gain ... use in low light to boost sensitivity */
|
||||
tsl.enableAutoGain(true); /* Auto-gain ... switches automatically between 1x and 16x */
|
||||
|
||||
/* Changing the integration time gives you better sensor resolution (402ms = 16-bit data) */
|
||||
tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_13MS); /* shortest integration time (bright light) */
|
||||
// tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_101MS); /* medium integration time (medium light) */
|
||||
// tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_402MS); /* longest integration time (dim light) */
|
||||
|
||||
/* Update these values depending on what you've set above! */
|
||||
Serial.println("------------------------------------");
|
||||
Serial.print ("Gain: "); Serial.println("Auto");
|
||||
Serial.print ("Timing: "); Serial.println("13 ms");
|
||||
Serial.println("------------------------------------");
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
Arduino setup function (automatically called at startup)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void setup(void)
|
||||
{
|
||||
Serial.begin(9600);
|
||||
Serial.println("Light Sensor Test"); Serial.println("");
|
||||
|
||||
/* Initialise the sensor */
|
||||
if(!tsl.begin())
|
||||
{
|
||||
/* There was a problem detecting the ADXL345 ... check your connections */
|
||||
Serial.print("Ooops, no TSL2561 detected ... Check your wiring or I2C ADDR!");
|
||||
while(1);
|
||||
}
|
||||
|
||||
/* Display some basic information on this sensor */
|
||||
displaySensorDetails();
|
||||
|
||||
/* Setup the sensor gain and integration time */
|
||||
configureSensor();
|
||||
|
||||
/* We're ready to go! */
|
||||
Serial.println("");
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
Arduino loop function, called once 'setup' is complete (your own code
|
||||
should go here)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void loop(void)
|
||||
{
|
||||
/* Get a new sensor event */
|
||||
sensors_event_t event;
|
||||
tsl.getEvent(&event);
|
||||
|
||||
/* Display the results (light is measured in lux) */
|
||||
if (event.light)
|
||||
{
|
||||
Serial.print(event.light); Serial.println(" lux");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If event.light = 0 lux the sensor is probably saturated
|
||||
and no reliable data could be generated! */
|
||||
Serial.println("Sensor overload");
|
||||
}
|
||||
delay(250);
|
||||
}
|
Reference in New Issue
Block a user