Print this Page

Adafruit Proximity and Ambient Light Sensor

Adafruit VCNL4000 Proximity and Light Ambient sensor

The VCNL4000 looks like it is a single piece of silicon, but it really just is an infrared transmitter and receiver in a package that looks like a chip. The way it works is that it shines a beam of IR light from an LED, and measures the intensity of light that is bounced pack in order to determine the distance to the object in front of it. It also incorporates an ambient light sensor. Also, the VCNL4000 does not have a simple analog output, but instead outputs a 16bit digital reading.

The VCNL4000 data sheet claims a proximity sensing range of 20cm. In reality, a reasonable change is only seen from few centimeters apart. Also note that the sensing is not linear so the closer you get the more rapidly the reading increases. The reading varies between 0 and 65535 (corresponding to a 16bit digital reading, 2^(16) = 65535).

 

Wiring it up

The VCNL4000 is an I2C device and will be connected somehow similar to the TMP102 Temperature Sensor (see http://blog.soton.ac.uk/pi/tmp102-temperature-sensor-breakout-board/), using the Gertboard instead of the Arduino. Again connections need to be done for Atmega programming and for Serial Interfacing (see link above). The 5 connections from the Gertboard to the VCNL4000 Breakout Board are: PC4 on J25 to SDA, PC5 on J25 to SCL, GND on J25 to GND and 3v3 on the Gertboard connected to both 3v3 and Vin on the Breakout Board.

Once all these connections have been done, copy the following code into the Arduino IDE and upload it onto the Atmega. The code is written by Adafruit and makes use of both the proximity and the light ambient sensors. Once the code has been uploaded successfully, open up a terminal and type sudo minicom ama0 to visualise the readings. You can see they update once every second. You can change the speed at which they update by changing the value inside the delay() from inside the loop() function.

Have a bit of play with the sensor in order to see it`s working correctly. Put an object or your hand in front of the sensor and see how the Proximity variable increases as you get closer. Also test the ambient light sensor by putting a source of light in front of the sensor, exposing it to direct sun or by placing in front of it an object which restricts light and see how the Ambient variable modifies

 

#include <Wire.h>

 

// the i2c address

 

#define VCNL4000_ADDRESS 0x13

 

 

// commands and constants

 

#define VCNL4000_COMMAND 0x80

 

#define VCNL4000_PRODUCTID 0x81

 

#define VCNL4000_IRLED 0x83

 

#define VCNL4000_AMBIENTPARAMETER 0x84

 

#define VCNL4000_AMBIENTDATA 0x85

 

#define VCNL4000_PROXIMITYDATA 0x87

 

#define VCNL4000_SIGNALFREQ 0x89

 

#define VCNL4000_PROXINITYADJUST 0x8A

 

 

#define VCNL4000_3M125 0

 

#define VCNL4000_1M5625 1

 

#define VCNL4000_781K25 2

 

#define VCNL4000_390K625 3

 

 

#define VCNL4000_MEASUREAMBIENT 0x10

 

#define VCNL4000_MEASUREPROXIMITY 0x08

 

#define VCNL4000_AMBIENTREADY 0x40

 

#define VCNL4000_PROXIMITYREADY 0x20

 

 

void setup() {

 

  Serial.begin(9600);

 

 

  Serial.println("VCNL");

 

  Wire.begin();

 

 

  uint8_t rev = read8(VCNL4000_PRODUCTID);

 

 

  if ((rev & 0xF0) != 0x10) {

 

    Serial.println("Sensor not found :(");

 

    while (1);

 

  }

 

 

  write8(VCNL4000_IRLED, 20);        // set to 20 * 10mA = 200mA

 

  Serial.print("IR LED current = ");

 

  Serial.print(read8(VCNL4000_IRLED) * 10, DEC);

 

  Serial.println(" mA");

 

 

  //write8(VCNL4000_SIGNALFREQ, 3);

 

  Serial.print("Proximity measurement frequency = ");

 

  uint8_t freq = read8(VCNL4000_SIGNALFREQ);

 

  if (freq == VCNL4000_3M125) Serial.println("3.125 MHz");

 

  if (freq == VCNL4000_1M5625) Serial.pr
#define VCNL4000_ADDRESS 0x13

 

 

// commands and c
intln("1.5625 MHz");

 

  if (freq == VCNL4000_781K25) Serial.println("781.25 KHz");

 

  if (freq == VCNL4000_390K625) Serial.println("390.625 KHz");

 

 

  write8(VCNL4000_PROXINITYADJUST, 0x81);

 

  Serial.print("Proximity adjustment register = ");

 

  Serial.println(read8(VCNL4000_PROXINITYADJUST), HEX);

 

 

  // arrange for continuous conversion

 

  //write8(VCNL4000_AMBIENTPARAMETER, 0x89);

 

 

}

 

 

uint16_t readProximity() {

 

  write8(VCNL4000_COMMAND, VCNL4000_MEASUREPROXIMITY);

 

  while (1) {

 

    uint8_t result = read8(VCNL4000_COMMAND);

 

    //Serial.print("Ready = 0x"); Serial.println(result, HEX);

 

    if (result & VCNL4000_PROXIMITYREADY) {

 

      return read16(VCNL4000_PROXIMITYDATA);

 

    }

 

    delay(1);

 

  }

 

}

 

 

 

 

void loop() {

 

 

  // read ambient light!

 

  write8(VCNL4000_COMMAND, VCNL4000_MEASUREAMBIENT | VCNL4000_MEASUREPROXIMITY);

 

 

  while (1) {

 

    uint8_t result = read8(VCNL4000_COMMAND);

 

    //Serial.print("Ready = 0x"); Serial.println(result, HEX);

 

    if ((result & VCNL4000_AMBIENTREADY)&&(result & VCNL4000_PROXIMITYREADY)) {

 

 

      Serial.print("Ambient = ");

 

      Serial.print(read16(VCNL4000_AMBIENTDATA));

 

      Serial.print("\t\tProximity = ");

 

      Serial.println(read16(VCNL4000_PROXIMITYDATA));

 

      break;

 

    }

 

    delay(10);

 

  }

 

 

   delay(1000);

 

 }

 

 

// Read 1 byte from the VCNL4000 at 'address'

 

uint8_t read8(uint8_t address)

 

{

 

  uint8_t data;

 

 

  Wire.beginTransmission(VCNL4000_ADDRESS);

 

#if ARDUINO >= 100

 

  Wire.write(address);

 

#else

 

  Wire.send(address);

 

#endif

 

  Wire.endTransmission();

 

 

  delayMicroseconds(170);  // delay required

 

 

  Wire.requestFrom(VCNL4000_ADDRESS, 1);

 

  while(!Wire.available());

 

 

#if ARDUINO >= 100

 

  return Wire.read();

 

#else

 

  return Wire.receive();

 

#endif

 

}

 

 

 

// Read 2 byte from the VCNL4000 at 'address'

 

uint16_t read16(uint8_t address)

 

{

 

  uint16_t data;

 

 

  Wire.beginTransmission(VCNL4000_ADDRESS);

 

#if ARDUINO >= 100

 

  Wire.write(address);

 

#else

 

  Wire.send(address);

 

#endif

 

  Wire.endTransmission();

 

 

  Wire.requestFrom(VCNL4000_ADDRESS, 2);

 

  while(!Wire.available());

 

#if ARDUINO >= 100

 

  data = Wire.read();

 

  data <<= 8;

 

  while(!Wire.available());

 

  data |= Wire.read();

 

#else

 

  data = Wire.receive();

 

  data <<= 8;

 

  while(!Wire.available());

 

  data |= Wire.receive();

 

#endif

 

 

  return data;

 

}

 

 

// write 1 byte

 

void write8(uint8_t address, uint8_t data)

 

{

 

  Wire.beginTransmission(VCNL4000_ADDRESS);

 

#if ARDUINO >= 100

 

  Wire.write(address);

 

  Wire.write(data);

 

#else

 

  Wire.send(address);

 

  Wire.send(data);

 

#endif

 

  Wire.endTransmission();

 

}

 

 

 

http://bildr.org/2012/11/vcnl4000-arduino/

 

code: https://github.com/adafruit/VCNL4000/blob/master/vcnl4000.pde

 

Permanent link to this article: https://blog.soton.ac.uk/pi/adafruit-proximity-and-ambient-light-sensor/