APDS9960 Proximity, Gesture and Ambient Light Sensor Interfacing with Arduino

APDS9960 is a sensor that detects six different gestures, detects proximity, senses ambient Light and provides information about the presence of Colors Red, Green, Blue or Clear. It consists of a built-in UV, IR blocking filters, an I2C compatible interface, and four separate photodiodes. Furthermore, it detects gestures by sensing IR light waves reflected from an object and convert this information about distance, velocity, and direction of an object to a digital value. The same reflected IR rays measure the distance between the device and the user. The ALS feature measures red, green, and blue content of light. This article explains in detail about the working, uses, and applications of APDS9960.

APDS9960 Proximity, Gesture and Ambient Light Sensor

APDS9960 Pinout Diagram

This multipurpose APDS9960 sensor breakout board consists of 6 pins. The pin configuration details are given in the next section.

APDS9960 Proximity, Gesture and Ambient Light Sensor Pinout

Pin Description

This section contain details and working of each pin of APDS9960.

  • Pin1 and pin7 are the pins for the I2C interface. SDA is a serial data address terminal and the Serial clock terminal provides clock pulse for transmission of this data.
  • Pin2 is an active low interrupt pin.
  • LDR is an LED driver input pin for APDS9960 proximity LED. Connect a constant power source at this pin for LED drivers.
  • LEDK is the cathode pin of the LED. Connect this pin to LDR if you are using an internal circuit of the led driver.
  • LEDA is the anode pin of the LED.
  • Pin6 and 8 are power supply pins. Connect pin 6 to ground. Apply voltage supply in a range of 2.4V to 3.6V at pin 8.

APDS9960 breakout Features


It is a multifunction sensor that provides features of gesture detection, ambient light, and RGB Color Sensing and proximity sensing. Most importantly, it senses ambient Light and red, green, blue colors through UV and IR blocking filters and its gain is adjustable from 1x to 64x.

The proximity sensing provides trimmed IR intensity due to which you don’t need extra components for calibration. The proximity detection system contains adjustment resistors that provide offset compensation, an ambient light rejection which gives accurate and improved results, and a saturation indicator bit.

The circuit for gesture detection includes 32 dataset storage FIFO, Interrupt driven I2C communication, and a programmable driver which provides current to IR LED.
It has a fast mode 7-bit I2C compatible interface which provides data rates of up to 400kHz.

  • Maximum voltage supply required for LED is 4.5V.
  • Voltage supply range = 2.4 to 3.6V.
  • Temperature range = -40°C to 85°C

Where to use APDS9960?


APDS9960 is a multifunctional sensor that supports color detection, proximity measurement, and gesture detection through a single module. It can detect up to six gestures which include left, right, up, down, far and near. The range of detection is about 4 to 8 inches.

It has a very high sensitivity which makes it well-suited for operations behind dark glass. You can interface this sensor with Arduino, microcontrollers, etc to perform a variety of functions. You can use this sensor in remote controls for controlling robots and other devices.

APDS9960 Interfacing with Arduino

The hardware is simple and easy to use. The APDS9960 breakout board of the sensor operates on 3.3V due to the presence of an onboard voltage regulator.

APDS9960 consists of four photodiodes that are sensitive to different directions. Whenever an object within a detection range performs any gesture, the object reflects back the IR signal transmitted by the LED. The photodiodes detect that signal and that is how it obtains the information regarding velocity and distance of an object.

Using this information, the sensor detects the type of gesture. The sensor has different channels which detect light red, blue, green, and clear colors through IR and UV blocking filters and a data converter. The configurable interrupt controls the detect function and triggers the sensor to release the Infrared light or detect it.

This circuit diagram shows Interfacing of APDS9960 with Arduino Nano.

APDS9960 Proximity, Gesture and Ambient Light Sensor Interfacing with Arduino

To write Program for Arduino with APDS9960 sensor, fortunately, library of this breakout board is available. First of all, go to this link and download Arduino library:

After that make connection of APDS9960 with Arduin, according to this table:

Arduino PinAPDS-9960 BoardFunction
3.3VVCCPower
GNDGNDGround
A4SDAI2C Data
A5SCLI2C Clock
2INTInterrupt

This Arduino library provide example codes to measure light, color, gesture detection and proximity sensor output.

Arduino Ambient Light Code

#include <Wire.h>
#include <SparkFun_APDS9960.h>

// Pins
#define APDS9960_INT    2  // Needs to be an interrupt pin
#define LED_PIN         13 // LED for showing interrupt

// Constants
#define LIGHT_INT_HIGH  1000 // High light level for interrupt
#define LIGHT_INT_LOW   10   // Low light level for interrupt

// Global variables
SparkFun_APDS9960 apds = SparkFun_APDS9960();
uint16_t ambient_light = 0;
uint16_t red_light = 0;
uint16_t green_light = 0;
uint16_t blue_light = 0;
int isr_flag = 0;
uint16_t threshold = 0;

void setup() {
  
  // Set LED as output
  pinMode(LED_PIN, OUTPUT);
  pinMode(APDS9960_INT, INPUT);
  
  // Initialize Serial port
  Serial.begin(9600);
  Serial.println();
  Serial.println(F("-------------------------------------"));
  Serial.println(F("SparkFun APDS-9960 - Light Interrupts"));
  Serial.println(F("-------------------------------------"));
  
  // Initialize interrupt service routine
  attachInterrupt(0, interruptRoutine, FALLING);
  
  // Initialize APDS-9960 (configure I2C and initial values)
  if ( apds.init() ) {
    Serial.println(F("APDS-9960 initialization complete"));
  } else {
    Serial.println(F("Something went wrong during APDS-9960 init!"));
  }
  
  // Set high and low interrupt thresholds
  if ( !apds.setLightIntLowThreshold(LIGHT_INT_LOW) ) {
    Serial.println(F("Error writing low threshold"));
  }
  if ( !apds.setLightIntHighThreshold(LIGHT_INT_HIGH) ) {
    Serial.println(F("Error writing high threshold"));
  }
  
  // Start running the APDS-9960 light sensor (no interrupts)
  if ( apds.enableLightSensor(false) ) {
    Serial.println(F("Light sensor is now running"));
  } else {
    Serial.println(F("Something went wrong during light sensor init!"));
  }
  
  // Read high and low interrupt thresholds
  if ( !apds.getLightIntLowThreshold(threshold) ) {
    Serial.println(F("Error reading low threshold"));
  } else {
    Serial.print(F("Low Threshold: "));
    Serial.println(threshold);
  }
  if ( !apds.getLightIntHighThreshold(threshold) ) {
    Serial.println(F("Error reading high threshold"));
  } else {
    Serial.print(F("High Threshold: "));
    Serial.println(threshold);
  }
  
  // Enable interrupts
  if ( !apds.setAmbientLightIntEnable(1) ) {
    Serial.println(F("Error enabling interrupts"));
  }
  
  // Wait for initialization and calibration to finish
  delay(500);
}

void loop() {
  
  // If interrupt occurs, print out the light levels
  if ( isr_flag == 1 ) {
    
    // Read the light levels (ambient, red, green, blue) and print
    if (  !apds.readAmbientLight(ambient_light) ||
          !apds.readRedLight(red_light) ||
          !apds.readGreenLight(green_light) ||
          !apds.readBlueLight(blue_light) ) {
      Serial.println("Error reading light values");
    } else {
      Serial.print("Interrupt! Ambient: ");
      Serial.print(ambient_light);
      Serial.print(" R: ");
      Serial.print(red_light);
      Serial.print(" G: ");
      Serial.print(green_light);
      Serial.print(" B: ");
      Serial.println(blue_light);
    }
    
    // Turn on LED for a half a second
    digitalWrite(LED_PIN, HIGH);
    delay(500);
    digitalWrite(LED_PIN, LOW);
    
    // Reset flag and clear APDS-9960 interrupt (IMPORTANT!)
    isr_flag = 0;
    if ( !apds.clearAmbientLightInt() ) {
      Serial.println("Error clearing interrupt");
    }
    
  }
}

void interruptRoutine() {
  isr_flag = 1;
}

Arduino Color Detection Code

#include <Wire.h>
#include <SparkFun_APDS9960.h>

// Global Variables
SparkFun_APDS9960 apds = SparkFun_APDS9960();
uint16_t ambient_light = 0;
uint16_t red_light = 0;
uint16_t green_light = 0;
uint16_t blue_light = 0;

void setup() {
  
  // Initialize Serial port
  Serial.begin(9600);
  Serial.println();
  Serial.println(F("--------------------------------"));
  Serial.println(F("SparkFun APDS-9960 - ColorSensor"));
  Serial.println(F("--------------------------------"));
  
  // Initialize APDS-9960 (configure I2C and initial values)
  if ( apds.init() ) {
    Serial.println(F("APDS-9960 initialization complete"));
  } else {
    Serial.println(F("Something went wrong during APDS-9960 init!"));
  }
  
  // Start running the APDS-9960 light sensor (no interrupts)
  if ( apds.enableLightSensor(false) ) {
    Serial.println(F("Light sensor is now running"));
  } else {
    Serial.println(F("Something went wrong during light sensor init!"));
  }
  
  // Wait for initialization and calibration to finish
  delay(500);
}

void loop() {
  
  // Read the light levels (ambient, red, green, blue)
  if (  !apds.readAmbientLight(ambient_light) ||
        !apds.readRedLight(red_light) ||
        !apds.readGreenLight(green_light) ||
        !apds.readBlueLight(blue_light) ) {
    Serial.println("Error reading light values");
  } else {
    Serial.print("Ambient: ");
    Serial.print(ambient_light);
    Serial.print(" Red: ");
    Serial.print(red_light);
    Serial.print(" Green: ");
    Serial.print(green_light);
    Serial.print(" Blue: ");
    Serial.println(blue_light);
  }
  
  // Wait 1 second before next reading
  delay(1000);
}

APDS9960 Gesture Detection Sketch

#include <Wire.h>
#include <SparkFun_APDS9960.h>

// Pins
#define APDS9960_INT    2 // Needs to be an interrupt pin

// Constants

// Global Variables
SparkFun_APDS9960 apds = SparkFun_APDS9960();
int isr_flag = 0;

void setup() {

  // Set interrupt pin as input
  pinMode(APDS9960_INT, INPUT);

  // Initialize Serial port
  Serial.begin(9600);
  Serial.println();
  Serial.println(F("--------------------------------"));
  Serial.println(F("SparkFun APDS-9960 - GestureTest"));
  Serial.println(F("--------------------------------"));
  
  // Initialize interrupt service routine
  attachInterrupt(0, interruptRoutine, FALLING);

  // Initialize APDS-9960 (configure I2C and initial values)
  if ( apds.init() ) {
    Serial.println(F("APDS-9960 initialization complete"));
  } else {
    Serial.println(F("Something went wrong during APDS-9960 init!"));
  }
  
  // Start running the APDS-9960 gesture sensor engine
  if ( apds.enableGestureSensor(true) ) {
    Serial.println(F("Gesture sensor is now running"));
  } else {
    Serial.println(F("Something went wrong during gesture sensor init!"));
  }
}

void loop() {
  if( isr_flag == 1 ) {
    detachInterrupt(0);
    handleGesture();
    isr_flag = 0;
    attachInterrupt(0, interruptRoutine, FALLING);
  }
}

void interruptRoutine() {
  isr_flag = 1;
}

void handleGesture() {
    if ( apds.isGestureAvailable() ) {
    switch ( apds.readGesture() ) {
      case DIR_UP:
        Serial.println("UP");
        break;
      case DIR_DOWN:
        Serial.println("DOWN");
        break;
      case DIR_LEFT:
        Serial.println("LEFT");
        break;
      case DIR_RIGHT:
        Serial.println("RIGHT");
        break;
      case DIR_NEAR:
        Serial.println("NEAR");
        break;
      case DIR_FAR:
        Serial.println("FAR");
        break;
      default:
        Serial.println("NONE");
    }
  }
}

Proximity Interrupt Sketch

#include <Wire.h>
#include <SparkFun_APDS9960.h>

// Pins
#define APDS9960_INT    2  // Needs to be an interrupt pin
#define LED_PIN         13 // LED for showing interrupt

// Constants
#define PROX_INT_HIGH   50 // Proximity level for interrupt
#define PROX_INT_LOW    0  // No far interrupt

// Global variables
SparkFun_APDS9960 apds = SparkFun_APDS9960();
uint8_t proximity_data = 0;
int isr_flag = 0;

void setup() {
  
  // Set LED as output
  pinMode(LED_PIN, OUTPUT);
  pinMode(APDS9960_INT, INPUT);
  
  // Initialize Serial port
  Serial.begin(9600);
  Serial.println();
  Serial.println(F("---------------------------------------"));
  Serial.println(F("SparkFun APDS-9960 - ProximityInterrupt"));
  Serial.println(F("---------------------------------------"));
  
  // Initialize interrupt service routine
  attachInterrupt(0, interruptRoutine, FALLING);
  
  // Initialize APDS-9960 (configure I2C and initial values)
  if ( apds.init() ) {
    Serial.println(F("APDS-9960 initialization complete"));
  } else {
    Serial.println(F("Something went wrong during APDS-9960 init!"));
  }
  
  // Adjust the Proximity sensor gain
  if ( !apds.setProximityGain(PGAIN_2X) ) {
    Serial.println(F("Something went wrong trying to set PGAIN"));
  }
  
  // Set proximity interrupt thresholds
  if ( !apds.setProximityIntLowThreshold(PROX_INT_LOW) ) {
    Serial.println(F("Error writing low threshold"));
  }
  if ( !apds.setProximityIntHighThreshold(PROX_INT_HIGH) ) {
    Serial.println(F("Error writing high threshold"));
  }
  
  // Start running the APDS-9960 proximity sensor (interrupts)
  if ( apds.enableProximitySensor(true) ) {
    Serial.println(F("Proximity sensor is now running"));
  } else {
    Serial.println(F("Something went wrong during sensor init!"));
  }
}

void loop() {
  
  // If interrupt occurs, print out the proximity level
  if ( isr_flag == 1 ) {
  
    // Read proximity level and print it out
    if ( !apds.readProximity(proximity_data) ) {
      Serial.println("Error reading proximity value");
    } else {
      Serial.print("Proximity detected! Level: ");
      Serial.println(proximity_data);
    }
    
    // Turn on LED for a half a second
    digitalWrite(LED_PIN, HIGH);
    delay(500);
    digitalWrite(LED_PIN, LOW);
    
    // Reset flag and clear APDS-9960 interrupt (IMPORTANT!)
    isr_flag = 0;
    if ( !apds.clearProximityInt() ) {
      Serial.println("Error clearing interrupt");
    }
    
  }
}

void interruptRoutine() {
  isr_flag = 1;
}

APDS9960 Applications

  • Smartphones, TV, Touch Screens of cell phones, etc.
  • Measuring color temperature
  • Backlight adjustment in devices, LCD displays, and RGB monitors
  • Robotics
  • Medical Equipment

Datasheet

Related Projects:

Leave a Comment