[137] | 1 | /**************************************************************************/
|
---|
| 2 | /*!
|
---|
| 3 | @file Adafruit_TSL2591.cpp
|
---|
| 4 | @author KT0WN (adafruit.com)
|
---|
| 5 |
|
---|
| 6 | This is a library for the Adafruit TSL2591 breakout board
|
---|
| 7 | This library works with the Adafruit TSL2591 breakout
|
---|
| 8 | ----> https://www.adafruit.com/products/1980
|
---|
| 9 |
|
---|
| 10 | Check out the links above for our tutorials and wiring diagrams
|
---|
| 11 | These chips use I2C to communicate
|
---|
| 12 |
|
---|
| 13 | Adafruit invests time and resources providing this open source code,
|
---|
| 14 | please support Adafruit and open-source hardware by purchasing
|
---|
| 15 | products from Adafruit!
|
---|
| 16 |
|
---|
| 17 | @section LICENSE
|
---|
| 18 |
|
---|
| 19 | Software License Agreement (BSD License)
|
---|
| 20 |
|
---|
| 21 | Copyright (c) 2014 Adafruit Industries
|
---|
| 22 | All rights reserved.
|
---|
| 23 |
|
---|
| 24 | Redistribution and use in source and binary forms, with or without
|
---|
| 25 | modification, are permitted provided that the following conditions are met:
|
---|
| 26 | 1. Redistributions of source code must retain the above copyright
|
---|
| 27 | notice, this list of conditions and the following disclaimer.
|
---|
| 28 | 2. Redistributions in binary form must reproduce the above copyright
|
---|
| 29 | notice, this list of conditions and the following disclaimer in the
|
---|
| 30 | documentation and/or other materials provided with the distribution.
|
---|
| 31 | 3. Neither the name of the copyright holders nor the
|
---|
| 32 | names of its contributors may be used to endorse or promote products
|
---|
| 33 | derived from this software without specific prior written permission.
|
---|
| 34 |
|
---|
| 35 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
---|
| 36 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
---|
| 37 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
---|
| 38 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
---|
| 39 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
---|
| 40 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
---|
| 41 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
---|
| 42 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
---|
| 43 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
---|
| 44 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
---|
| 45 | */
|
---|
| 46 | /**************************************************************************/
|
---|
| 47 | #if defined(ESP8266)
|
---|
| 48 | #include <pgmspace.h>
|
---|
| 49 | #else
|
---|
| 50 | #include <avr/pgmspace.h>
|
---|
| 51 | #endif
|
---|
| 52 | #if defined(__AVR__)
|
---|
| 53 | #include <util/delay.h>
|
---|
| 54 | #endif
|
---|
| 55 | #include <stdlib.h>
|
---|
| 56 |
|
---|
| 57 | #include "Adafruit_TSL2591.h"
|
---|
| 58 |
|
---|
| 59 | Adafruit_TSL2591::Adafruit_TSL2591(int32_t sensorID)
|
---|
| 60 | {
|
---|
| 61 | _initialized = false;
|
---|
| 62 | _integration = TSL2591_INTEGRATIONTIME_100MS;
|
---|
| 63 | _gain = TSL2591_GAIN_MED;
|
---|
| 64 | _sensorID = sensorID;
|
---|
| 65 |
|
---|
| 66 | // we cant do wire initialization till later, because we havent loaded Wire yet
|
---|
| 67 | }
|
---|
| 68 |
|
---|
| 69 | boolean Adafruit_TSL2591::begin(void)
|
---|
| 70 | {
|
---|
| 71 | Wire.begin();
|
---|
| 72 |
|
---|
| 73 | /*
|
---|
| 74 | for (uint8_t i=0; i<0x20; i++)
|
---|
| 75 | {
|
---|
| 76 | uint8_t id = read8(0x12);
|
---|
| 77 | Serial.print("$"); Serial.print(i, HEX);
|
---|
| 78 | Serial.print(" = 0x"); Serial.println(read8(i), HEX);
|
---|
| 79 | }
|
---|
| 80 | */
|
---|
| 81 |
|
---|
| 82 | uint8_t id = read8(0x12);
|
---|
| 83 | if (id == 0x50 )
|
---|
| 84 | {
|
---|
| 85 | //Serial.println("Found Adafruit_TSL2591");
|
---|
| 86 | }
|
---|
| 87 | else
|
---|
| 88 | {
|
---|
| 89 | return false;
|
---|
| 90 | }
|
---|
| 91 |
|
---|
| 92 | _initialized = true;
|
---|
| 93 |
|
---|
| 94 | // Set default integration time and gain
|
---|
| 95 | setTiming(_integration);
|
---|
| 96 | setGain(_gain);
|
---|
| 97 |
|
---|
| 98 | // Note: by default, the device is in power down mode on bootup
|
---|
| 99 | disable();
|
---|
| 100 |
|
---|
| 101 | return true;
|
---|
| 102 | }
|
---|
| 103 |
|
---|
| 104 | void Adafruit_TSL2591::enable(void)
|
---|
| 105 | {
|
---|
| 106 | if (!_initialized)
|
---|
| 107 | {
|
---|
| 108 | if (!begin())
|
---|
| 109 | {
|
---|
| 110 | return;
|
---|
| 111 | }
|
---|
| 112 | }
|
---|
| 113 |
|
---|
| 114 | // Enable the device by setting the control bit to 0x01
|
---|
| 115 | write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_ENABLE, TSL2591_ENABLE_POWERON | TSL2591_ENABLE_AEN | TSL2591_ENABLE_AIEN);
|
---|
| 116 | }
|
---|
| 117 |
|
---|
| 118 | void Adafruit_TSL2591::disable(void)
|
---|
| 119 | {
|
---|
| 120 | if (!_initialized)
|
---|
| 121 | {
|
---|
| 122 | if (!begin())
|
---|
| 123 | {
|
---|
| 124 | return;
|
---|
| 125 | }
|
---|
| 126 | }
|
---|
| 127 |
|
---|
| 128 | // Disable the device by setting the control bit to 0x00
|
---|
| 129 | write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_ENABLE, TSL2591_ENABLE_POWEROFF);
|
---|
| 130 | }
|
---|
| 131 |
|
---|
| 132 | void Adafruit_TSL2591::setGain(tsl2591Gain_t gain)
|
---|
| 133 | {
|
---|
| 134 | if (!_initialized)
|
---|
| 135 | {
|
---|
| 136 | if (!begin())
|
---|
| 137 | {
|
---|
| 138 | return;
|
---|
| 139 | }
|
---|
| 140 | }
|
---|
| 141 |
|
---|
| 142 | enable();
|
---|
| 143 | _gain = gain;
|
---|
| 144 | write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CONTROL, _integration | _gain);
|
---|
| 145 | disable();
|
---|
| 146 | }
|
---|
| 147 |
|
---|
| 148 | tsl2591Gain_t Adafruit_TSL2591::getGain()
|
---|
| 149 | {
|
---|
| 150 | return _gain;
|
---|
| 151 | }
|
---|
| 152 |
|
---|
| 153 | void Adafruit_TSL2591::setTiming(tsl2591IntegrationTime_t integration)
|
---|
| 154 | {
|
---|
| 155 | if (!_initialized)
|
---|
| 156 | {
|
---|
| 157 | if (!begin())
|
---|
| 158 | {
|
---|
| 159 | return;
|
---|
| 160 | }
|
---|
| 161 | }
|
---|
| 162 |
|
---|
| 163 | enable();
|
---|
| 164 | _integration = integration;
|
---|
| 165 | write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CONTROL, _integration | _gain);
|
---|
| 166 | disable();
|
---|
| 167 | }
|
---|
| 168 |
|
---|
| 169 | tsl2591IntegrationTime_t Adafruit_TSL2591::getTiming()
|
---|
| 170 | {
|
---|
| 171 | return _integration;
|
---|
| 172 | }
|
---|
| 173 |
|
---|
| 174 | uint32_t Adafruit_TSL2591::calculateLux(uint16_t ch0, uint16_t ch1)
|
---|
| 175 | {
|
---|
| 176 | uint16_t atime, again;
|
---|
| 177 | float cpl, lux1, lux2, lux;
|
---|
| 178 | uint32_t chan0, chan1;
|
---|
| 179 |
|
---|
| 180 | // Check for overflow conditions first
|
---|
| 181 | if ((ch0 == 0xFFFF) | (ch1 == 0xFFFF))
|
---|
| 182 | {
|
---|
| 183 | // Signal an overflow
|
---|
| 184 | return 0;
|
---|
| 185 | }
|
---|
| 186 |
|
---|
| 187 | // Note: This algorithm is based on preliminary coefficients
|
---|
| 188 | // provided by AMS and may need to be updated in the future
|
---|
| 189 |
|
---|
| 190 | switch (_integration)
|
---|
| 191 | {
|
---|
| 192 | case TSL2591_INTEGRATIONTIME_100MS :
|
---|
| 193 | atime = 100.0F;
|
---|
| 194 | break;
|
---|
| 195 | case TSL2591_INTEGRATIONTIME_200MS :
|
---|
| 196 | atime = 200.0F;
|
---|
| 197 | break;
|
---|
| 198 | case TSL2591_INTEGRATIONTIME_300MS :
|
---|
| 199 | atime = 300.0F;
|
---|
| 200 | break;
|
---|
| 201 | case TSL2591_INTEGRATIONTIME_400MS :
|
---|
| 202 | atime = 400.0F;
|
---|
| 203 | break;
|
---|
| 204 | case TSL2591_INTEGRATIONTIME_500MS :
|
---|
| 205 | atime = 500.0F;
|
---|
| 206 | break;
|
---|
| 207 | case TSL2591_INTEGRATIONTIME_600MS :
|
---|
| 208 | atime = 600.0F;
|
---|
| 209 | break;
|
---|
| 210 | default: // 100ms
|
---|
| 211 | atime = 100.0F;
|
---|
| 212 | break;
|
---|
| 213 | }
|
---|
| 214 |
|
---|
| 215 | switch (_gain)
|
---|
| 216 | {
|
---|
| 217 | case TSL2591_GAIN_LOW :
|
---|
| 218 | again = 1.0F;
|
---|
| 219 | break;
|
---|
| 220 | case TSL2591_GAIN_MED :
|
---|
| 221 | again = 25.0F;
|
---|
| 222 | break;
|
---|
| 223 | case TSL2591_GAIN_HIGH :
|
---|
| 224 | again = 428.0F;
|
---|
| 225 | break;
|
---|
| 226 | case TSL2591_GAIN_MAX :
|
---|
| 227 | again = 9876.0F;
|
---|
| 228 | break;
|
---|
| 229 | default:
|
---|
| 230 | again = 1.0F;
|
---|
| 231 | break;
|
---|
| 232 | }
|
---|
| 233 |
|
---|
| 234 | // cpl = (ATIME * AGAIN) / DF
|
---|
| 235 | cpl = (atime * again) / TSL2591_LUX_DF;
|
---|
| 236 |
|
---|
| 237 | lux1 = ( (float)ch0 - (TSL2591_LUX_COEFB * (float)ch1) ) / cpl;
|
---|
| 238 | lux2 = ( ( TSL2591_LUX_COEFC * (float)ch0 ) - ( TSL2591_LUX_COEFD * (float)ch1 ) ) / cpl;
|
---|
| 239 |
|
---|
| 240 | // The highest value is the approximate lux equivalent
|
---|
| 241 | lux = lux1 > lux2 ? lux1 : lux2;
|
---|
| 242 |
|
---|
| 243 | // Signal I2C had no errors
|
---|
| 244 | return (uint32_t)lux;
|
---|
| 245 | }
|
---|
| 246 |
|
---|
| 247 | uint32_t Adafruit_TSL2591::getFullLuminosity (void)
|
---|
| 248 | {
|
---|
| 249 | if (!_initialized)
|
---|
| 250 | {
|
---|
| 251 | if (!begin())
|
---|
| 252 | {
|
---|
| 253 | return 0;
|
---|
| 254 | }
|
---|
| 255 | }
|
---|
| 256 |
|
---|
| 257 | // Enable the device
|
---|
| 258 | enable();
|
---|
| 259 |
|
---|
| 260 | // Wait x ms for ADC to complete
|
---|
| 261 | for (uint8_t d=0; d<=_integration; d++)
|
---|
| 262 | {
|
---|
| 263 | delay(120);
|
---|
| 264 | }
|
---|
| 265 |
|
---|
| 266 | uint32_t x;
|
---|
| 267 | x = read16(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CHAN1_LOW);
|
---|
| 268 | x <<= 16;
|
---|
| 269 | x |= read16(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CHAN0_LOW);
|
---|
| 270 |
|
---|
| 271 | disable();
|
---|
| 272 |
|
---|
| 273 | return x;
|
---|
| 274 | }
|
---|
| 275 |
|
---|
| 276 | uint16_t Adafruit_TSL2591::getLuminosity (uint8_t channel)
|
---|
| 277 | {
|
---|
| 278 | uint32_t x = getFullLuminosity();
|
---|
| 279 |
|
---|
| 280 | if (channel == TSL2591_FULLSPECTRUM)
|
---|
| 281 | {
|
---|
| 282 | // Reads two byte value from channel 0 (visible + infrared)
|
---|
| 283 | return (x & 0xFFFF);
|
---|
| 284 | }
|
---|
| 285 | else if (channel == TSL2591_INFRARED)
|
---|
| 286 | {
|
---|
| 287 | // Reads two byte value from channel 1 (infrared)
|
---|
| 288 | return (x >> 16);
|
---|
| 289 | }
|
---|
| 290 | else if (channel == TSL2591_VISIBLE)
|
---|
| 291 | {
|
---|
| 292 | // Reads all and subtracts out just the visible!
|
---|
| 293 | return ( (x & 0xFFFF) - (x >> 16));
|
---|
| 294 | }
|
---|
| 295 |
|
---|
| 296 | // unknown channel!
|
---|
| 297 | return 0;
|
---|
| 298 | }
|
---|
| 299 |
|
---|
| 300 | uint8_t Adafruit_TSL2591::read8(uint8_t reg)
|
---|
| 301 | {
|
---|
| 302 | Wire.beginTransmission(TSL2591_ADDR);
|
---|
| 303 | Wire.write(0x80 | 0x20 | reg); // command bit, normal mode
|
---|
| 304 | Wire.endTransmission();
|
---|
| 305 |
|
---|
| 306 | Wire.requestFrom(TSL2591_ADDR, 1);
|
---|
| 307 | while (! Wire.available());
|
---|
| 308 | return Wire.read();
|
---|
| 309 | }
|
---|
| 310 |
|
---|
| 311 | uint16_t Adafruit_TSL2591::read16(uint8_t reg)
|
---|
| 312 | {
|
---|
| 313 | uint16_t x;
|
---|
| 314 | uint16_t t;
|
---|
| 315 |
|
---|
| 316 | Wire.beginTransmission(TSL2591_ADDR);
|
---|
| 317 | #if ARDUINO >= 100
|
---|
| 318 | Wire.write(reg);
|
---|
| 319 | #else
|
---|
| 320 | Wire.send(reg);
|
---|
| 321 | #endif
|
---|
| 322 | Wire.endTransmission();
|
---|
| 323 |
|
---|
| 324 | Wire.requestFrom(TSL2591_ADDR, 2);
|
---|
| 325 | #if ARDUINO >= 100
|
---|
| 326 | t = Wire.read();
|
---|
| 327 | x = Wire.read();
|
---|
| 328 | #else
|
---|
| 329 | t = Wire.receive();
|
---|
| 330 | x = Wire.receive();
|
---|
| 331 | #endif
|
---|
| 332 | x <<= 8;
|
---|
| 333 | x |= t;
|
---|
| 334 | return x;
|
---|
| 335 | }
|
---|
| 336 |
|
---|
| 337 | void Adafruit_TSL2591::write8 (uint8_t reg, uint8_t value)
|
---|
| 338 | {
|
---|
| 339 | Wire.beginTransmission(TSL2591_ADDR);
|
---|
| 340 | #if ARDUINO >= 100
|
---|
| 341 | Wire.write(reg);
|
---|
| 342 | Wire.write(value);
|
---|
| 343 | #else
|
---|
| 344 | Wire.send(reg);
|
---|
| 345 | Wire.send(value);
|
---|
| 346 | #endif
|
---|
| 347 | Wire.endTransmission();
|
---|
| 348 | }
|
---|
| 349 |
|
---|
| 350 | /**************************************************************************/
|
---|
| 351 | /*!
|
---|
| 352 | @brief Gets the most recent sensor event
|
---|
| 353 | */
|
---|
| 354 | /**************************************************************************/
|
---|
| 355 | bool Adafruit_TSL2591::getEvent(sensors_event_t *event)
|
---|
| 356 | {
|
---|
| 357 | uint16_t ir, full;
|
---|
| 358 | uint32_t lum = getFullLuminosity();
|
---|
| 359 | /* Early silicon seems to have issues when there is a sudden jump in */
|
---|
| 360 | /* light levels. :( To work around this for now sample the sensor 2x */
|
---|
| 361 | lum = getFullLuminosity();
|
---|
| 362 | ir = lum >> 16;
|
---|
| 363 | full = lum & 0xFFFF;
|
---|
| 364 |
|
---|
| 365 | /* Clear the event */
|
---|
| 366 | memset(event, 0, sizeof(sensors_event_t));
|
---|
| 367 |
|
---|
| 368 | event->version = sizeof(sensors_event_t);
|
---|
| 369 | event->sensor_id = _sensorID;
|
---|
| 370 | event->type = SENSOR_TYPE_LIGHT;
|
---|
| 371 | event->timestamp = millis();
|
---|
| 372 |
|
---|
| 373 | /* Calculate the actual lux value */
|
---|
| 374 | /* 0 = sensor overflow (too much light) */
|
---|
| 375 | event->light = calculateLux(full, ir);
|
---|
| 376 |
|
---|
| 377 | return true;
|
---|
| 378 | }
|
---|
| 379 |
|
---|
| 380 | /**************************************************************************/
|
---|
| 381 | /*!
|
---|
| 382 | @brief Gets the sensor_t data
|
---|
| 383 | */
|
---|
| 384 | /**************************************************************************/
|
---|
| 385 | void Adafruit_TSL2591::getSensor(sensor_t *sensor)
|
---|
| 386 | {
|
---|
| 387 | /* Clear the sensor_t object */
|
---|
| 388 | memset(sensor, 0, sizeof(sensor_t));
|
---|
| 389 |
|
---|
| 390 | /* Insert the sensor name in the fixed length char array */
|
---|
| 391 | strncpy (sensor->name, "TSL2591", sizeof(sensor->name) - 1);
|
---|
| 392 | sensor->name[sizeof(sensor->name)- 1] = 0;
|
---|
| 393 | sensor->version = 1;
|
---|
| 394 | sensor->sensor_id = _sensorID;
|
---|
| 395 | sensor->type = SENSOR_TYPE_LIGHT;
|
---|
| 396 | sensor->min_delay = 0;
|
---|
| 397 | sensor->max_value = 88000.0;
|
---|
| 398 | sensor->min_value = 0.0;
|
---|
| 399 | sensor->resolution = 1.0;
|
---|
| 400 | }
|
---|