Interrupts with TSL2561 Sensor

Hi, this is my first post and I hope I picked the right place to post it.

I’m trying to build a light sensor that will sleep when there is 0 light (lux = 0), wake up when there is light, and record its readings onto an SD card. I’ve modified code from EKMallon’s Data Logger project:

Data Logger Project

The problem I’m having is figuring out where and how to integrate an interrupt into the code to do what I want. Any help would be greatly appreciated. Ideally the RTC interrupt would also be disabled so only the light sensor wakes it up.

My code exceeds the 9000 character limit but this is where I think I need to add/remove lines. I’ve uploaded the rest as an attachment.

RTC.setAlarm1Simple(Alarmhour, Alarmminute);
RTC.turnOnAlarm(1);
if (RTC.checkAlarmEnabled(1)) {
                                                //you would comment out most of this message printing
                                                //if your logger was actually being deployed in the field
  Serial.print(F("RTC Alarm Enabled!"));
  Serial.print(F(" Going to sleep for : "));
  Serial.print(SampleIntervalMinutes);
  Serial.println(F(" minutes"));
  Serial.println();Serial.flush();    //adds a carriage return & waits for buffer to empty 
} 

  delay(25);                              //this optional delay is only here so we can see the LED’s otherwise the entire loop executes so fast you might not see it.
  digitalWrite(GREEN_PIN, LOW);
                                                // Note: Normally you would NOT leave a red indicator LED on during sleep! This is just so you can see when your logger is sleeping, & when it's awake
  digitalWrite(RED_PIN, HIGH);  // Turn on red led as our indicator that the Arduino is sleeping. Remove this before deployment.
                                              //——– sleep and wait for next RTC alarm ————–
                                              // Enable interrupt on pin2 & attach it to rtcISR function:
  attachInterrupt(0, rtcISR, LOW); //D2
  attachInterrupt(1, lightISR, LOW); //D3

                                              // Enter power down state with ADC module disabled to save power:
  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_ON);
                                              //processor starts HERE AFTER THE RTC ALARM WAKES IT UP
  detachInterrupt(0); // immediately disable the interrupt on waking
  detachInterrupt(1);
  digitalWrite(RED_PIN, LOW);
  digitalWrite(GREEN_PIN, HIGH); //Interupt woke processor, turn on green led
}

One note, I’m using Sparkfun’s library for the sensor as it seems to give more precise readings than Adafruit’s.

KNOWN_GOOD.ino (12.9 KB)

I don't think the TSL2561 has any output other than its I2C interface. You can't have it provide a signal to wake up at brightness.

What you can do instead is use an LDR and OpAmp.

LDR + resistor on one input of the OpAmp, voltage divider on the other side. That gives you a high/low output (depending on the light level, and how you wire it: high can be both at dark and at light), and that signal in turn you can connect to an Arduino pin as wake up signal.

Actually the tsl2561 has an interrupt pin, I'm just confused as to what I need to add to the code to use it. I've only ever used time-based alarms before

https://gammon.com.au/interrupts

Indeed, the TSL2561 has level interrupts. See datasheet/pp 15-17 for description on how they work. Interesting stuff.

Thanks for the help, I scrapped together a code that runs a very basic interrupt that activates after reaching a value outside an arbitrary threshold.

If you’re interested:

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_TSL2561_U.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)
*/
//MUST add false tag or else sensor will default to sleep mode between readings
//Interrupts won't work without false being declared

Adafruit_TSL2561_Unified tsl = Adafruit_TSL2561_Unified(TSL2561_ADDR_FLOAT, 12345, false); 

// We assume the Adafruit TSL2561's "int" pin is attached to this digital pin
#define INTERRUPT_PIN 3

/**************************************************************************/
/*
    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.enableAutoRange(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);      /* fast but low resolution */
  // tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_101MS);  /* medium resolution and speed   */
   tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_402MS);  /* 16-bit data but slowest conversions */

  /* Configure interrupt thresholds */
  // First: convert lux value to raw sensor value, using "sunlight" approximation.
  // Other approximations, see Adafruit_TSL2561_U.h
  uint32_t threshold = tsl.calculateRawCH0(3000, TSL2561_APPROXCHRATIO_SUN);
  Serial.println("threshold: "); Serial.println(threshold);
  tsl.setInterruptThreshold(0,100); //High value is channel 0 data

  /* Enable level interrupt, trigger interrupt after 5 integration times
     -> Because integration time is 13ms by default, this means the threshold
        needs to be exceeded for more than 65ms before the interrupt is triggered.
        Maximum value is 15; put to 1 for immediate triggering; put to 0 to have
        the interrupt triggered after every integration time (regardless of whether
        the thresholds were exceeded or not)
  */
  tsl.setInterruptControl(TSL2561_INTERRUPTCTL_LEVEL, 1);
  tsl.clearLevelInterrupt();

  /* Update these values depending on what you've set above! */
  Serial.println("------------------------------------");
  Serial.print  ("Gain:         "); Serial.println("1x");
  Serial.print  ("Timing:       "); Serial.println("101 ms");
  Serial.println("------------------------------------");
}

/**************************************************************************/
/*
    Arduino setup function (automatically called at startup)
*/
/**************************************************************************/
void setup(void)
{
  Serial.begin(9600);
  Serial.println("Light Sensor Test"); Serial.println("");

  /* Configure the interrupt pin as input pin */
  pinMode(INTERRUPT_PIN, INPUT_PULLUP);

  /* Initialise the sensor */
  //use tsl.begin() to default to Wire,
  //tsl.begin(&Wire2) directs api to use Wire2, etc.
  if(!tsl.begin())
  {
    /* There was a problem detecting the TSL2561 ... 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)
{
  /* Interrupt triggered? */
  if(digitalRead(INTERRUPT_PIN) == LOW) {
    // We have an interrupt!
    Serial.println("TSL2561 reported interrupt thresholds exceeded!");
    sensors_event_t event;
    tsl.getEvent (&event);
    if (event.light) {
      Serial.print(event.light); Serial.println (" lux");
    }
    // Clear interrupt on sensor
    tsl.clearLevelInterrupt();
  }
//  /* 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);
}