Bisher habe ich immer nur mit den größeren Sharp IR Entfernungssensoren gearbeitet, die zwar bis zu 2 Meter weit „sehen“, aber dafür im direkten Nahbereich des Sensors oft problematische Werte zurückliefern.

In diesem Projekt teste ich einen VCNL4000 Sensor für Entfernung (bzw. Näherung) und Helligkeit, integriert in einem Breakout-Board von Adafruit. Der Sensor gibt keine echten Distanzwerte (in Form von Milimeter) zurück, sondern lediglich einen 16-bit Wert, der zwischen sehr hoch (Objekt direkt am Sensor) und ziemlich niedrig (kein Hindernis innerhalb der 20cm über dem Sensor) liegen kann. Der Sensor verfügt über eine eingebaute Infrarot-LED und misst die Intensität des von einem Hindernis zurückgeworfenen Lichts. Zusätzlich verfügt der Sensor über einen sehr guten Sensor für die Umgebungshelligkeit, der auch bei schlechten Lichtbedingungen noch deutlich unterschiedbare Messwerte liefert.

Die Kommunikation mit dem Arduino erfolgt über I²C, beim Arduino über die Analogpins 4 und 5. Zusätzlich zum Sensor habe ich noch 2 LEDs aufgebaut. Die grüne LED lässt sich über den Näherungssensor einschalten (z.B. mit einer lässigen Winkbewegung :)), das Abdecken des Helligkeitssensors aktiviert kurz die rote LED und schaltet die grüne LED dann wieder aus.

Im Video stelle ich den Sensor vor und bespreche kurz den Arduino Sketch.


Der Arduino Sketch besteht zu 98% aus dem Demo-Quellcode zum Artikel bei Adafruit hier: https://github.com/adafruit/VCNL4000
Ich habe lediglich ein paar Zeilen zur Ansteuerung der LEDs und zur Speicherung des aktuellen LED-Status hinzugefügt.

// Example sketch for talking to the VCNL4000 i2c proximity/light sensor
// Written by Adafruit! Public domain.
// To use: Connect VCC to 3.3-5V (5V is best if it is available), GND to
// ground, SCL to i2c clock (on classic arduinos, Analog 5), SDA
// to i2c data (on classic arduinos Analog 4). The 3.3v pin is
// an ouptut if you need 3.3V
// This sensor is 5V compliant so you can use it with 3.3 or 5V micros

// You can pick one up at the Adafruit shop: www.adafruit.com/products/466

#include <Wire.h>

// Example sketch for talking to the VCNL4000 i2c proximity/light sensor
// Written by Adafruit! Public domain.
// To use: Connect VCC to 3.3-5V (5V is best if it is available), GND to
//         ground, SCL to i2c clock (on classic arduinos, Analog 5), SDA
//         to i2c data (on classic arduinos Analog 4). The 3.3v pin is
//         an ouptut if you need 3.3V
// This sensor is 5V compliant so you can use it with 3.3 or 5V micros

// You can pick one up at the Adafruit shop: www.adafruit.com/products/466


// 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


// Winke-Pin leuchtet bei Näherung
const int wavePin = 13;
// Reset-Pin leuchtet bei Dunkelheit
const int resetPin = 12;

// Das Skript gibt Helligkeit und Entfernungswert auch an den seriellen
//  Monitor zurück, damit können die Grenzwerte gut bestimmt werden.

// Schwellenwert für Näherung (anpassen!)
const int minproximity = 2100;
// Schwellenwert für Helligkeit (anpassen!)
const int minambient = 2000;
// Aktueller Zustand der Winke-LED
int waveStatus = LOW;

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.println("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);

  // Die beiden LED-Pins auf OUTPUT setzen  
  pinMode(wavePin, OUTPUT);
  pinMode(resetPin, OUTPUT);

  // arrange for continuous conversion
  //write8(VCNL4000_AMBIENTPARAMETER, 0x89);

}

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 = ");
      unsigned int ambient = read16(VCNL4000_AMBIENTDATA);
      Serial.print(ambient);
      Serial.print("\t\tProximity = ");
      unsigned int prox = read16(VCNL4000_PROXIMITYDATA);
      Serial.println(prox);

      // Wenn die Helligkeit größer als der Schwellenwert ist...
      if (ambient > minambient) {
        // dann Reset-Pin auf jeden Fall ausschalten       
        digitalWrite(resetPin, LOW);
        // Wenn dazu noch der Entfernungswert über die Schwelle steigt,
        // dann WinkePin-Status auf HIGH
        if (prox > minproximity) {
          waveStatus = HIGH;
        }
      }
      else
      {
        // Wenn Helligkeit kleiner als Schwellenwert, dann
        // ResetPin einschalten, WinkePin-Status auf LOW und eine Sekunde warten
        digitalWrite(resetPin, HIGH);
        waveStatus = LOW;
        delay(1000);
      }  
      break;
    }
    delay(10);
  }

  // WinkePin-Status ans wavePin schicken
  digitalWrite(wavePin, waveStatus);

  delay(50);
}

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);
  }
}

// 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();
}

Code-Sprache: Arduino (arduino)

Fragen und Anregungen bitte einfach in die Kommentare. Danke.

4 thoughts on “VCNL4000 Sensor für Entfernung und Helligkeit am Arduino

  • 2. Januar 2015 at 21:39
    Permalink

    Hi

    habe die schaltung so nachgebaut (noch ohne leds) bei mir hängt der code schon bei

    uint8_t rev = read8(VCNL4000_PRODUCTID);

    hast du einen tipp woran das hängen könnte?

    Reply
    • 15. Januar 2015 at 10:17
      Permalink

      Versuch erstmal die Pins anzulöten. Vielleicht ist ohne Lötverbindung die Kommunikation für I2C doch zu wackelig.

      Reply
  • 9. Februar 2015 at 14:59
    Permalink

    Hallo Adi,

    dank Ihrer Hilfe konnte ich eine kleine Wetterstation bauen. Mit dem DHT 22 lese ich Temperatur und Luftfeuchte aus. Nun möchte ich noch den Luftdruck hinzufügen. Kann ich einen entsprechenden Sensor mit dem DHT gleichzeitig auslesen und auf dem LCD Display anzeigen?

    Dann wäre meine kleine Wetterstation komplett.

    Meine Anregung für ein Tutorial: Eine Box als Wetterstation mit DHT 22 und Luftdrucksensor.

    Vielen Dank nochmal für alle Anregungen Ihrerseits.

    Grüße!

    Uwe Seebald

    Reply

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Time limit is exhausted. Please reload the CAPTCHA.

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.