APDS-9301 Sensor Hookup Guide
Introduction
The APDS-9301 is an I2C compatible luminosity sensor which returns readings in lux. It is non-instantaneous, requiring some integration time to take a measurement. SparkFun provides a library making use of the part very simple.
Required Materials
Please check the wish list below for items required to follow this tutorial.
Tools
No special tools are required to follow this tutorial. You will need a soldering iron, solder, and general soldering accessories.
Suggested Reading
We suggest reviewing the tutorials below to ensure that you're up-to-date with all of the skills necessary to follow this hookup guide.
How to Solder: Through-Hole Soldering
Installing an Arduino Library
Hardware Overview
The APDS-9301 breakout board is fairly simple, with only a few ancillary passive components in addition to the ADPS-9301 sensor IC itself.
APDS-9301 sensor - This is the sensor IC. Its operating voltage only extends up to 3.6V, so to use it with a 5V Arduino or Arduino clone, you'll need some kind of voltage translation!
I2C pullup resistors - The board includes pullup resistor so you don't need to add them externally.
INT pin - The APDS-9301 can be programmed to generate an interrupt under certain conditions. This pin will be asserted low (i.e., pulled to ground) when those conditions are met. Note that this is an open collector pin, so you'll need to enable the pullup resistor on the processor for it to work.
SparkFun standard I2C header - Most boards which can be communicated to via I2C use this pinout, making it easy to stack them or connect them in a daisy chain.
Address Select Jumpers - On the back of the board, the only item of interest is the address select jumper. By default, this jumper is open, resulting in an I2C address of 0x39. If the HIGH side of the jumper is closed, the address will be** 0x29**. If the LOW side of the jumper is closed, the address will be 0x49. If a big old blob of solder closes both sides of the jumper, it will still work, and the address will be 0x49.
Library Overview
Here's a list of the most critical functions supported by the library.
begin(address)
- enables the IC, sets the gain and integration times to minimum (i.e., lowest sensitivity), and disables the interrupt.setGain(gainLevel)
- there are two possible parameters to pass to this function:APDS9301::LOW_GAIN
andAPDS9301::HIGH_GAIN
. High gain is 16x more sensitive than low gain.gain getGain()
- returns one of the two values specified insetGain()
above. This function actually reads the gain from the sensor and returns the true value currently being used.setIntegrationTime(integrationTime)
- there are three possible parameters to pass to this function:APDS9301::INT_TIME_13_7_MS
,APDS9301::INT_TIME_101_MS
, andAPDS9301::INT_TIME_402_MS
. Sensitivity to light increases with integration time, and the rate at which new data is generated by the sensor is also determined by integration time. By default, the integration time is set to the lowest value (13.7ms).intTime getIntegrationTime()
- returns one of the three values specfied insetIntegrationTime()
above. This function actually reads the gain from the sensor and returns the true value currently being used.enableInterrupt(intMode)
- pass eitherAPDS9301::INT_ON
orAPDS9301::INT_OFF
to this function to enable or disable the interrupt functionality. By default, the interrupt is disabled. If enabled, the following three functions will determine the circumstances under which an interrupt will be issued and the INT pin will be set high.setCyclesForInterrupt(cycles)
- sets number of ADC cycles values must be in interrupt range for an interrupt to occur. Pass0
to interrupt on every ADC cycle (ADC cycle time is defined by integration time as discussed above). Pass1
to interrupt if the reading is ever above the high threshold or below the low threshold (see next two functions for information regarding threshold settings). Pass2
through15
to require that many cycles above or below the respective threshold before issuing an interrupt.setLowThreshold(threshold)
- pass anunsigned int
to this function between0
and65535
. Readings on CH0 of the sensor (which detects both visible and IR light) below this threshold for the time set by thesetCyclesForInterrupt()
will trigger an interrupt on the INT pin. To disable the low threshold, simply write0
to this function.unsigned int getLowThreshold()
- returns the current low threshold setting, read from the sensor directly.setHighThreshold(threshold)
- pass anunsigned int
to this function between0
and65535
. Readings on CH0 of the sensor (which detects both visible and IR light) above this threshold for the time set by thesetCyclesForInterrupt()
will trigger an interrupt on the INT pin. To disable the high threshold, simply write65535
to this function.unsigned int getHighThreshold()
- returns the current low threshold setting, read from the sensor directly.float readLuxLevel()
- returns a floating point number representing the current light level in lux. Note that due to inherent inaccuracy in the sensor, this value is only accurate to within 35%-40% of the actual absolute lux value.
Example
Hardware Hookup
We use a hookup as pictured below for our example project. However, this basic Arduino code should work for any number of different Arduino compatible boards. In this case, we show it on an Arduino Pro 3.3V, to allow the setup to work without any level translation between the Arduino and the APDS-9301.
Note that this setup requires some soldering. New to soldering? Check out our through hole soldering guide!
Notes on Operation
The APDS-9301 has two internal light sensing elements: CH0, which responds to infrared and visible light, and CH1, which responds to only visible light. By combining these two channels, the sensor is able to compensate for local infrared light and provide a more accurate estimate of the current lux value.
The calculation of lux reading from CHO and CH1 sensor output readings is not straightforward. The function is piecewise, with different coefficients depending on the ratio CH1/CH0. This function is automatically implemented in the readLuxLevel()
library function, but can be found in the datasheet if you're curious.
The APDS-9301 sensor works by multiplying the light input signal by a gain (either 1x or 16x) and then using an integrating ADC to measure the light input over some integration time. As such, the integration time imposes an inherent limit on the maximum reading of the ADC. For the 13.7ms integration time, this limit is 5047. For the 101ms integration time, this limit is 37177. For the full 402ms integration time, the maximum is actually defined by the size of the output variable, an 16-bit unsigned integer, at 65535. This fact should be taken into account when selecting a value for the interrupt high and low threshold values. For instance, if the integration time is 13.7ms and a high threshold of 6000 is set, that threshold will never be reached.
Example Code
Note: This example assumes you are using the latest version of the Arduino IDE on your desktop. If this is your first time using Arduino, please review our tutorial on installing the Arduino IDE. If you have not previously installed an Arduino library, please check out our installation guide.
Make sure to install the APDS-9301 Arduino library before using the example code. You can obtain the library through the Arduino Library Manager by serarching for "SparkFun APDS-9301 Lux Sensor" in order to install the latest version. The library can also be found in the SparkFun APDS-9301 Library GitHub repository to manually install:
Below is a simple example code for Arduino that uses the APDS-9301 library. First, the example code sets the gain and integration time. Then enables and sets thresholds for the interrupt. Finally, the code reads the current lux level and prints it to the serial port. It also prints a message when the light level exceeds a certain threshold. It should get you up and running in no time!
language:c
#include "Wire.h"
#include <Sparkfun_APDS9301_Library.h>
APDS9301 apds;
#define INT_PIN 2 // We'll connect the INT pin from our sensor to the
// INT0 interrupt pin on the Arduino.
bool lightIntHappened = false; // flag set in the interrupt to let the
// mainline code know that an interrupt occurred.
void setup()
{
SerialUSB.begin(115200);
Wire.begin();
// APDS9301 sensor setup.
apds.begin(0x39); // We're assuming you haven't changed the I2C
// address from the default by soldering the
// jumper on the back of the board.
apds.setGain(APDS9301::LOW_GAIN); // Set the gain to low. Strictly
// speaking, this isn't necessary, as the gain
// defaults to low.
apds.setIntegrationTime(APDS9301::INT_TIME_13_7_MS); // Set the
// integration time to the shortest interval.
// Again, not strictly necessary, as this is
// the default.
apds.setLowThreshold(0); // Sets the low threshold to 0, effectively
// disabling the low side interrupt.
apds.setHighThreshold(50); // Sets the high threshold to 500. This
// is an arbitrary number I pulled out of thin
// air for purposes of the example. When the CH0
// reading exceeds this level, an interrupt will
// be issued on the INT pin.
apds.setCyclesForInterrupt(1); // A single reading in the threshold
// range will cause an interrupt to trigger.
apds.enableInterrupt(APDS9301::INT_ON); // Enable the interrupt.
apds.clearIntFlag();
// Interrupt setup
pinMode(INT_PIN, INPUT_PULLUP); // This pin must be a pullup or have
// a pullup resistor on it as the interrupt is a
// negative going open-collector type output.
attachInterrupt(digitalPinToInterrupt(2), lightInt, FALLING);
}
void loop()
{
static unsigned long outLoopTimer = 0;
apds.clearIntFlag();
// This is a once-per-second timer that calculates and prints off
// the current lux reading.
if (millis() - outLoopTimer >= 1000)
{
outLoopTimer = millis();
SerialUSB.print("Luminous flux: ");
SerialUSB.println(apds.readLuxLevel(),6);
if (lightIntHappened)
{
SerialUSB.println("Interrupt");
lightIntHappened = false;
}
}
}
void lightInt()
{
lightIntHappened = true;
}
After uploading code, try opening the Arduino serial monitor at 115200 baud and observe the sensor's output.
As you can see, once per second, the sketch will print the luminous flux and whether or not the level selected for an interrupt has been exceeded.
Resources and Going Further
Now that you've successfully got your APDS-9301 sensor up and running, it's time to incorporate it into your own project!
For more information on the APDS-9301 sensor, check out the resources below:
- Wikipedia: Lux - To help you better understand what it is you're measuring, exactly.
- APDS-9301 Breakout Schematic (PDF)
- APDS-9301 Breakout Eagle Files (ZIP)
- APDS-9301 Datasheet (AV02-2315EN0.PDF) - If you want to move beyond the limits of the library and explore the base features of the chip itself.
- APDS-9301 Sensor GitHub Repository - Eagle files and example code for the APDS-9301 Sensor.
Need some inspiration for your next project? Check out some of these related tutorials: