HUM: APDS-9960

Color and gesture sensor APDS-9960 breakout-easyC

You are a beginner with Dasduino. Or electronics? A specific module caught your eye, but you do not know how to use it? Do not worry, HUM is here for you! How to Use Module (HUM) is a blog tutorials series by soldered where you will find all you need in order to begin working with your favorite module. Tutorials include: technical characteristics, work principle, instructions on how to connect module with Dasduino and the basic code. Everything else is left to your imagination.

INTRODUCTION

In this tutorial, we will introduce you to the APDS-9960 digital proximity, ambient light, RGB and gesture sensor. Gesture control allows us to detect hand movement to the left or right, and up or down, as well as some complex gestures such as moving your hand away from the sensor, or moving it towards the sensor. Due to its dimensions, abilities and consumption, it has found its purpose in mobile phones as a proximity detection sensor so to  disable touchscreen (and consequently accidental touchscreen) while user is answering the phone, along with screenshot using hand movement and such. But, for starters, we will observe some characteristics of the sensor as well as its appearance.

Sensor characteristics:

• Power supply voltage: 5 VDC (header) 3.3 VDC (easyC)

• SDA and SCL input voltage: 0.8 VDC – 3.6 VDC

• LED diode’s voltage in the sensor: 3 VDC – 4.5 VDC

• Sensor current: 1 – 10 uA Sleep Mode, 38 uA  Standby mode, 790 uA Proximity and gesture reading

• LED diode’s current in the sensor: 12.5 mA – 100 mA

• Type of communication: I2C (Two Wire)

• Maximum I2C frequency: 400 kHz

• Module dimensions: 36 x 22 mm

 

HOW DOES THE MODULE WORK?

The sensor on the module is composed of two parts: the sensor itself and the LED diode that serves to determine the proximity of an object. In the sensor, there are four photodiodes which serve to detect gestures (they are set up in a way to successfully detect hand motion in different directions) and four photodiodes that serve to detect the color and intensity of light.

Each of these four color photodiodes measures the intensity of light of a specific wavelenght ranges, so that we have a photodiode for red, green and blue color which is done in a way that  there is a certain color filter in front of the photodiode. The last photodiode is clear, it only contains infrared and UV filter, and it detects the entire range of colors that photodiodes for red, green and blue detect together. It serves to determine the intensity of light coming to the sensor. In the image below, it is visible which range of colors does the individual photodiode detect.

Gesture detection is based on the observation of the amount of light intensity, provided by the infrared diode which is embedded in the sensor, that reflects back to photodiodes for gesture detection. In the image below, it is visible how a certain gesture is detected. U, L, D, R represent photodiodes for gesture detection. If the proximity of an object is detected first, on the D photodiode, then on the L and R and with a similar count (intensity), and in the end on U diode, it would mean that the downward movement has occured.

Gesture detection code can be adjusted in a way that the change on the INT pin occurs while detecting gestures, but also the same can be enabled for detecting an obstacle (object), and in that case, the sensor would inform us about it via INT pin. This allows making a quick and important operation in the code using interrupts.

 

 

 

HOW TO CONNECT IT?

The way Dasduino and our sensor will be connected is described below. If you choose to connect through the headers it has, keep in mind that you need to bring 5 VDC to the positive pin. If, however, you want to avoid the possibility of making a mistake during connection (you’ve chosen easyC), you will simply connect the sensor board with a cable to the Dasduino. The voltage of the easyC system is 3.3 VDC.

 

ARDUINO CODE

In order to make programming and using this module easier, we will use a prepared library. The library can be found here. If you do not know how to install the library, read our tutorial.

Here, we will show how to use the gesture sensor.

#include "Wire.h"                   //Adding Wire library
#include "SparkFun_APDS9960.h"      //Adding sensor library
#define APDS9960_INT    2           //Defining Croduino's pin to which the INT pin of the sensor will be connected (has to be an Interrupt pin)
SparkFun_APDS9960 apds = SparkFun_APDS9960();   //A constructor for our library in order to have access to functions that control the sensor
int isr_flag = 0;                               //Variable which serves as a flag so to know that a gesture is detected
void setup() {
  //Setting Croduino's pin as an input. To that pin, we connect the INT pin of the sensor
  pinMode(APDS9960_INT, INPUT);
  Serial.begin(9600);   //Initialization of serial communication and adjusting the communication speed (9600 baud)
  Serial.println();     //Printing the message to know that the connection between the computer and Croduino is ok.
  Serial.println(F("**********Test APDS-99600 Senzora – Senzor geste**********"));
  //Setting the interruption routine. If it happens that on the Croduino's pin number 2
  //a fall from logical one to logical zero is detected, the main program is interrupted and it "jumps" to the function "detekcijaGeste()"
  attachInterrupt(0, detekcijaGeste, FALLING);
  //Initialization of the sensor library and checking if the sensor is connected to Croduino.
  if ( apds.init() ) {
    Serial.println(F("Initialization of the APDS-9960 sensor library is successful!"));
  } else {
    Serial.println(F("Initialization of the library is unsuccessful. Sensor is not found. Check the connections!"));
  }
  //If the initialization was successful, start the sensor
  if ( apds.enableGestureSensor(true) ) {
    Serial.println(F("Gesture sensor is started and activated. Make a gesture. :)"));
  } else {
    Serial.println(F("Not possible to start the gesture sensor... :("));
  }
}
void loop() {
  if ( isr_flag == 1 ) {  //If a gesture is detected, the isr_flag will be set to 1.
    detachInterrupt(0);   //Stop detecting gestures, in order to be able to read the current gesture.
    gesta();              //Read the current gesture
    isr_flag = 0;         //Return the flag to 0, which means that a gesture has not happened yet.
    attachInterrupt(0, detekcijaGeste, FALLING);    //Set the gesture detection again, now that Croduino has read which gesture it was about
  }
}
void detekcijaGeste() {   //If the INT pin has fallen from logical one to logical zero, it means that the sensor has read a gesture, so read it in the main program.
  isr_flag = 1;
}
void gesta() {                    //Here we pick up the gesture from the sensor and print what gesture it was about.
  if ( apds.isGestureAvailable() ) {
    Serial.print("Detektirana gesta: ");
    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("Can not be determined.");
    }
  }
}

Furthermore in the code, we will see how to use the sensor for reading levels of red, green and blue color (RGB).

#include "Wire.h"                 //Adding Wire library.
#include "SparkFun_APDS9960.h"    //Adding sensor library.
SparkFun_APDS9960 apds = SparkFun_APDS9960();
uint16_t kolcinaSvjetlosti = 0;   //Variable for saving the amount of light.
uint16_t crvenaBoja = 0;          //Variable for the amount of red light.
uint16_t zelenaBoja = 0;          //Variable for the amount of green light.
uint16_t plavaBoja = 0;           //Variable for the amount of blue light.
void setup() {
  Serial.begin(9600);   //Initialization of serial communication and adjusting the communication speed (9600 baud).
  Serial.println();     //Printing the message so to know that the communication between the computer and Croduino is ok.
  Serial.println(F("**********Test ADPS-99600 Senzora – Senzor boje**********"));
  //Initialization of the sensor library and checking if the sensor is connected to Croduino.
  if ( apds.init() ) {
    Serial.println(F("Initialization of the APDS-9960 sensor library is successful!"));
  } else {
    Serial.println(F("Initialization of the library is unsuccessful. Sensor not found. Check the connections!"));
  }
  //If the initialization was successful, start the color sensor
  if ( apds.enableLightSensor(false) ) {
    Serial.println(F("Color sensor is successfully activated. :)"));
  } else {
    Serial.println(F("Not possible to start the color sensor... :("));
  }
  //Wait for the sensor to stabilize and calibrate.
  delay(500);
}
void loop() {
  //Read the amount of light in the room, and amounts of red, green and blue color.
  //If something has not been read properly, let us know about the error!
  if (  !apds.readAmbientLight(kolcinaSvjetlosti) ||
        !apds.readRedLight(crvenaBoja) ||
        !apds.readGreenLight(zelenaBoja) ||
        !apds.readBlueLight(plavaBoja) ) {
    Serial.println("Error during reading values from the sensor.");
  } else {
    Serial.print("Brightness of space: ");   //Print the values on Serial monitor.
    Serial.print(kolcinaSvjetlosti);
    Serial.print(" Red color: ");
    Serial.print(crvenaBoja);
    Serial.print(" Green color: ");
    Serial.print(zelenaBoja);
    Serial.print(" Blue color: ");
    Serial.println(plavaBoja);
  }
  //Wait one second before new data readings of the sensor.
  delay(1000);
}

In the following code, we will see how to use the Proximity sensor.

#include "Wire.h"                   //Adding Wire library.
#include "SparkFun_APDS9960.h"      //Adding sensor library.
#define APDS9960_INT    2           //Defining Croduino's pin to which we will connect the INT pin of the sensor (has to be an Interrupt pin, on Croduino Basic pins 2 and 3).
#define LED_PIN         13          //Pin to which we want to connect the LED which will inform us when an object near the sensor is detected. We use the LED which is already installed in Croduino.
#define PROX_INT_HIGH   50          //Defining levels on which the sensor will activate.
#define PROX_INT_LOW    0
// Global variables
SparkFun_APDS9960 apds = SparkFun_APDS9960();     //Constructor of the library we use.
uint8_t blizina = 0;                              //Variable to which we save the values of the proximity of an object which is being detected.
int isr_flag = 0;                                 //Variable which serves as a flag so to know that an object near the sensor is detected
void setup() {
  
  // Set LED as output
  pinMode(LED_PIN, OUTPUT);           //Setting the pin to which the LED is connected as an output.
  pinMode(APDS9960_INT, INPUT);       //Setting the pin to which the INT pin of the sensor is connected as an input on the Croduino.
  //Initialization of serial communication with the computer and adjusting the default communication speed (9600 baud).
  Serial.begin(9600);
  Serial.println();     //Printing the message to know that the communication between the computer and Croduino is ok.
  Serial.println(F("**********Test APDS-99600 Senzora – Senzor blizine predmeta**********"));
  
  //Setting the interruption routine. If it happens that on the Croduino's pin number 2
  //a fall from logical one to logical zero is detected, the main program is interrupted and it "jumps" to the function "detekcijaBlizine()".
  attachInterrupt(0, detekcijaBlizine, FALLING);
  
  //Initialization of the sensor library and checking if the sensor is connected to Croduino.
  if ( apds.init() ) {
    Serial.println(F("Initialization of the APDS-9960 sensor library is successful!"));
  } else {
    Serial.println(F("Initialization of the library is unsuccessful. Sensor not found. Check the connections!"));
  }
  
  //Set the gain on the sensor
  if ( !apds.setProximityGain(PGAIN_2X) ) {
    Serial.println(F("Unsuccessful adjusting of the gain on the sensor."));
  }
  
  //Set the detection levels on the sensor (for the interruption routine).
  if ( !apds.setProximityIntLowThreshold(PROX_INT_LOW) ) {
    Serial.println(F("Unsuccessful adjusting of the low detection level."));
  }
  if ( !apds.setProximityIntHighThreshold(PROX_INT_HIGH) ) {
    Serial.println(F("Unsuccessful adjusting of the high detection level."));
  }
  
  //Let the sensor start working, with the interruption mode. When an object near the sensor is detected, the main program is interrupted (main loop) and it "jumps" to the detekcijaBlizine.
  if ( apds.enableProximitySensor(true) ) {
    Serial.println(F("Proximitiy sensor is started and activated. Set the object near the sensor in order to activate it."));
  } else {
    Serial.println(F("Not possible to start the proximity sensor... :("));
  }
}
void loop() {
  
  //If the detection of an object near the sensor occured, it informs the user.
  if ( isr_flag == 1 ) {
  
    //Read the values of the object proximity and print that via serial communication.
    if ( !apds.readProximity(blizina) ) {
      Serial.println("Unsuccessful reading of the object proximity.");
    } else {
      Serial.print("An object near the sensor is detected: ");
      Serial.println(blizina);
    }
    
    //Besides on the serial port, inform us via LED on the Croduino. Let the LED blink.
    digitalWrite(LED_PIN, HIGH);
    delay(500);
    digitalWrite(LED_PIN, LOW);
    
    //VERY IMPORTANT! Undo the flag for the interruption program and undo the detection of an object in the sensor!
    isr_flag = 0;
    if ( !apds.clearProximityInt() ) {
      Serial.println("Unsuccessful deletion of the interruption routine.");
    }
    
  }
}
void detekcijaBlizine() {     //The interruption program to which it jumps when an object near the sensor is detected.
  isr_flag = 1;               //It serves to set the flag on the condition in the main program as soon as possible, in order to know that there has been the detection of an object.
}

And finally, in the last example, we will se how to use the sensor for the level of light in the room.

#include "Wire.h"                   //Adding Wire library.
#include "SparkFun_APDS9960.h"      //Adding sensor library.
#define APDS9960_INT    2  //Defining Croduino's pin to which we will connect the INT pin of the sensor (has to be an Interrupt pin, on Croduino Basic pins 2 and 3).
#define LED_PIN         13 //Pin to which we want to connect the LED which will inform us when an object near the sensor is detected. We use the already installed LED in our Croduino.
//Defining levels for high and low level of light (i.e. when to let us know that there is a change).
#define LIGHT_INT_HIGH  1000 //The level for high level of light
#define LIGHT_INT_LOW   10   //The level for low level of light
SparkFun_APDS9960 apds = SparkFun_APDS9960(); //Library constructor.
uint16_t svjetlost = 0;                       //Variable for the level of light in the room.
int isr_flag = 0;                             //Variable which serves as a flag so to know that an object near the sensor is detected.
uint16_t prag = 0;                            //Variable for the detection threshold.
void setup() {
  //Setting the pins for input or output
  pinMode(LED_PIN, OUTPUT);       //Setting the pin to which the LED is connected on the output.
  pinMode(APDS9960_INT, INPUT);   //Setting the pin to which the INT pin of the sensor is connected on the Croduino's input.
  //Initialization of serial communication with the computer and adjusting the default communication speed (9600 baud).
  Serial.begin(9600);
  Serial.println();     //Printing the message to know that the communication between the computer and Croduino is ok.
  Serial.println(F("**********Test APDS-99600 Senzora – Senzor kolicine svijetla**********"));
  //Setting the interruption routine. If it happens that on the Croduino's pin number 2
  //there is a fall from logical one to logical zero, the main program is interrupted and it "jumps" to the function "detekcijaSvjetlosti()".
  attachInterrupt(0, detekcijaSvjetlosti, FALLING);
  //Initialization of the sensor library and checking if the sensor is connected to Croduino.
  if ( apds.init() ) {
    Serial.println(F("Initialization of the APDS-9960 sensor library is successful!"));
  } else {
    Serial.println(F("Initialization of the library is unsuccessful. Sensor is not found. Check the connections!"));
  }
  //Setting the level of light detection thresholds
  if ( !apds.setLightIntLowThreshold(LIGHT_INT_LOW) ) {
    Serial.println(F("Unsuccessful setting of the low level of light threshold"));
  }
  if ( !apds.setLightIntHighThreshold(LIGHT_INT_HIGH) ) {
    Serial.println(F("Unsuccessful setting of the high level of light threshold"));
  }
  //Let the sensor start operating (but without main program interruptions for now).
  if ( apds.enableLightSensor(false) ) {
    Serial.println(F("Light sensor is started and activated. Change the intensity of light for the sensor to activate."));
  } else {
    Serial.println(F("Not possible to start the light sensor."));
  }
  // Read the detection threshold levels (whether they are entered correctly).
  if ( !apds.getLightIntLowThreshold(prag) ) {
    Serial.println(F("Not possible to read the level of threshold for low light intensity"));
  } else {
    Serial.print(F("The level of threshold for low light intensity: "));
    Serial.println(prag);
  }
  if ( !apds.getLightIntHighThreshold(prag) ) {
    Serial.println(F("Not possible to read the level of threshold for high light intensity"));
  } else {
    Serial.print(F("The level of threshold for low light intensity: "));
    Serial.println(prag);
  }
  //Enable program interruption for the default light intensity.
  if ( !apds.setAmbientLightIntEnable(1) ) {
    Serial.println(F("Not possible to set the program interruptions to the level of light. "));
  }
  //Wait for the sensor to stabilize and calibrate.
  delay(500);
}
void loop() {
  //If the flag is set to 1, an interruption occurs, and thus the threshold for detecting a certain intensity of light is exceeded.
  if ( isr_flag == 1 ) {
    //Print out what is the light intensity.
    if (  !apds.readAmbientLight(svjetlost)) {
      Serial.println("Unsuccessful reading of the light intensity");
    } else {
      Serial.print("Light intensity: ");
      Serial.println(svjetlost);
    }
    //A LED is necessary to let us know that a certain level of light is detected.
    digitalWrite(LED_PIN, HIGH);
    delay(500);
    digitalWrite(LED_PIN, LOW);
    //VERY IMPORTANT! Undo the flag for the interrupt program and undo the detection of the level of light in the sensor!
    isr_flag = 0;
    if ( !apds.clearAmbientLightInt() ) {
      Serial.println("Unsuccessful deletion of the interrupt routine.");
    }
  }
}
void detekcijaSvjetlosti() {    //An interrupt program to which it jumps when the default level of light is detected.
  isr_flag = 1;                 //It serves to set the flag to the condition in the main program as soon as possible, in order to know that there has been a detection of the default amount of light.
}