From 433eaf027cf329dcb8127bdf1c5cacb82b73edd7 Mon Sep 17 00:00:00 2001 From: Arnd Date: Tue, 25 Apr 2017 06:48:00 -0400 Subject: [PATCH] Changed to allow Mac compilation The Windows IDE / compiler allows default parameter values to be used in the .cpp file, the defaults should only be declared in the library header. --- Examples/DisplayMeasurements/VCNL4010.cpp | 263 ++++++++++++++++++++++ Examples/DisplayMeasurements/VCNL4010.h | 88 ++++++++ 2 files changed, 351 insertions(+) create mode 100644 Examples/DisplayMeasurements/VCNL4010.cpp create mode 100644 Examples/DisplayMeasurements/VCNL4010.h diff --git a/Examples/DisplayMeasurements/VCNL4010.cpp b/Examples/DisplayMeasurements/VCNL4010.cpp new file mode 100644 index 0000000..ddfe3a6 --- /dev/null +++ b/Examples/DisplayMeasurements/VCNL4010.cpp @@ -0,0 +1,263 @@ +/******************************************************************************************************************* +** VCNL4010 class method definitions. See the header file for program details and version information ** +** ** +** This program is free software: you can redistribute it and/or modify it under the terms of the GNU General ** +** Public License as published by the Free Software Foundation, either version 3 of the License, or (at your ** +** option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY ** +** WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** +** GNU General Public License for more details. You should have received a copy of the GNU General Public License ** +** along with this program. If not, see . ** +** ** +*******************************************************************************************************************/ +#include "VCNL4010.h" // Include the header definition // +/******************************************************************************************************************* +** Class Constructor instantiates the class ** +*******************************************************************************************************************/ +VCNL4010::VCNL4010() {} // of class constructor // // +/******************************************************************************************************************* +** Class Destructor currently does nothing and is included for compatibility purposes ** +*******************************************************************************************************************/ +VCNL4010::~VCNL4010() {} // of class destructor // // +/******************************************************************************************************************* +** Method begin starts I2C communications with the device, using a default address if one is not specified and ** +** return true if the device has been detected and false if it was not ** +*******************************************************************************************************************/ +bool VCNL4010::begin( ) { // Start I2C Comms with device // + Wire.begin(); // Start I2C as master device // + if (readByte(VCNL4010_PRODUCT_ID_REG)!=VCNL4010_PRODUCT_VERSION) // If the product doesn't match then// + return false; // return an error // + setProximityHz(2); // Default 2Hz proximity rate // + setLEDmA(20); // Default 20mA IR LED power // + setAmbientLight(2,32); // Default 2/sec and 32 averaged // + setProximityFreq(); // Default to 390kHz frequency // + setInterrupt(); // Default to no interrupts // + uint8_t commandBuffer = readByte(VCNL4010_COMMAND_REG); // get the command register values // + commandBuffer |= B00011000; // Single ALS and Proximity reading // + writeByte(VCNL4010_COMMAND_REG,commandBuffer); // Start the measurement cycle // + return true; // return success // +} // of method begin() // // +/******************************************************************************************************************* +** Method readByte reads 1 byte from the specified address ** +*******************************************************************************************************************/ +uint8_t VCNL4010::readByte(const uint8_t addr) { // // + Wire.beginTransmission(VCNL4010_ADDRESS); // Address the I2C device // + Wire.write(addr); // Send the register address to read// + _TransmissionStatus = Wire.endTransmission(); // Close transmission // + delayMicroseconds(VCNL4010_I2C_DELAY); // delay required for sync // + Wire.requestFrom(VCNL4010_ADDRESS, (uint8_t)1); // Request 1 byte of data // + while(!Wire.available()); // Wait until the byte is ready // + return Wire.read(); // read it and return it // +} // of method readByte() // // +/******************************************************************************************************************* +** Method readWord reads 2 bytes from the specified address ** +*******************************************************************************************************************/ +uint16_t VCNL4010::readWord(const uint8_t addr) { // // + uint16_t returnData; // Store return value // + Wire.beginTransmission(VCNL4010_ADDRESS); // Address the I2C device // + Wire.write(addr); // Send the register address to read// + _TransmissionStatus = Wire.endTransmission(); // Close transmission // + delayMicroseconds(VCNL4010_I2C_DELAY); // delay required for sync // + Wire.requestFrom(VCNL4010_ADDRESS, (uint8_t)2); // Request 2 consecutive bytes // + while(!Wire.available()); // Wait until the byte is ready // + returnData = Wire.read(); // Read the msb // + returnData = returnData<<8; // shift the data over // + returnData |= Wire.read(); // Read the lsb // + return returnData; // read it and return it // +} // of method readWord() // // +/******************************************************************************************************************* +** Method writeByte write 1 byte to the specified address ** +*******************************************************************************************************************/ +void VCNL4010::writeByte(const uint8_t addr, const uint8_t data) { // // + Wire.beginTransmission(VCNL4010_ADDRESS); // Address the I2C device // + Wire.write(addr); // Send the register address to read// + Wire.write(data); // Send the register address to read// + _TransmissionStatus = Wire.endTransmission(); // Close transmission // +} // of method writeByte() // // +/******************************************************************************************************************* +** Method setProximityHz set the frequency with which the proximity sensor pulses are sent/read. The only values ** +** that the VCNL4010 can be set to are: ** +** Bits Measurements/S ** +** ==== =============== ** +** 000 1.95 (DEFAULT) ** +** 001 3.90625 ** +** 010 7.8125 ** +** 011 16.625 ** +** 100 31.25 ** +** 101 62.5 ** +** 110 125 ** +** 111 250 ** +** These roughly equate to Hz (2,4,8,16,32,64,128 and 256) ** +*******************************************************************************************************************/ +void VCNL4010::setProximityHz(const uint8_t Hz) { // // + uint8_t setValue; // temp variable for sampling rate // + if (Hz>250) setValue = 7; // If value is bigger then set max // + else if (Hz>=128) setValue = 6; // // + else if (Hz>=64) setValue = 5; // // + else if (Hz>=32) setValue = 4; // // + else if (Hz>=16) setValue = 3; // // + else if (Hz>=8) setValue = 2; // // + else if (Hz>=4) setValue = 1; // // + else setValue = 0; // // + writeByte(VCNL4010_PROXIMITY_RATE_REG,setValue); // Write result to register // +} // of method setProximityHz() // // +/******************************************************************************************************************* +** Method setLEDmA() sets the IR LED current output in milliamps. Range is between 0mA and 200mA, internally set ** +** in steps of 10mA with input values being truncated down to the next lower value ** +*******************************************************************************************************************/ +void VCNL4010::setLEDmA(const uint8_t mA) { // // + writeByte(VCNL4010_LED_CURRENT_REG,(uint8_t)(mA/10)); // Divide by 10 and write register // +} // of method setLEDmA() // // +/******************************************************************************************************************* +** Method setProximityFreq() sets the proximity modulator timing to one of 4 possible values as follows: ** +** 00 = 390.625 kHz (DEFAULT) ** +** 01 = 781.25 kHz ** +** 10 = 1.5625 MHz ** +** 11 = 3.125 MHz ** +*******************************************************************************************************************/ +void VCNL4010::setProximityFreq(const uint8_t value) { // Set Frequency value from list // + uint8_t registerSetting = readByte(VCNL4010_PROXIMITY_TIMING_REG); // Get the register settings // + registerSetting &= B11100111; // Mask the 2 timing bits // + registerSetting |= (value&B00000011) << 3; // Add in 2 bits from value // + writeByte(VCNL4010_PROXIMITY_TIMING_REG,registerSetting); // Write new buffer back to register// +} // of method setProximityFreq() // // +/******************************************************************************************************************* +** Method setAmbientLight() sets the number of samples taken per second and the number of samples averaged to ** +** make a reading; each reading takes only 300microseconds and the default period for a measurement is 100ms. ** +*******************************************************************************************************************/ +void VCNL4010::setAmbientLight(uint8_t sample, uint8_t avg) { // // + sample--; // subtract one for offset // + if (sample==6) sample==5; // Adjust nonexistent values // + else if (sample==8) sample==6; // // + else if (sample>7) sample==7; // // + if (avg>=128) avg = B111; // // + else if (avg>=64) avg = B110; // // + else if (avg>=32) avg = B101; // // + else if (avg>=16) avg = B100; // // + else if (avg>=8) avg = B011; // // + else if (avg>=4) avg = B010; // // + else if (avg>=2) avg = B001; // // + else avg = B000; // // + uint8_t registerValue = readByte(VCNL4010_AMBIENT_PARAMETER_REG); // retrieve current settings // + registerValue &= B10001000; // Mask current settings // + registerValue |= sample << 4; // Set bits 4,5,6 // + registerValue |= avg; // Set bits 0,1,2 // + writeByte(VCNL4010_AMBIENT_PARAMETER_REG,registerValue); // Write new values to buffer // +} // of method setAmbientLight() // // +/******************************************************************************************************************* +** Method getAmbientLight() retrieves the 16 bit ambient light value. Since we always send a request for another ** +** reading after retrieving the previous results we just need to wait for a result to come back. ** +*******************************************************************************************************************/ +uint16_t VCNL4010::getAmbientLight() { // // + uint8_t commandBuffer = readByte(VCNL4010_COMMAND_REG); // get the register contents // + while (commandBuffer&B01000000==0) // Loop until we have a result // + commandBuffer = readByte(VCNL4010_COMMAND_REG); // get the register contents again // + uint16_t returnValue = readWord(VCNL4010_AMBIENT_LIGHT_REG); // retrieve the reading // + if (!_ContinuousAmbient) { // Only trigger if not continuous // + commandBuffer |= B00010000; // Trigger ambient measurement // + writeByte(VCNL4010_COMMAND_REG,commandBuffer); // Set trigger for next reading // + } // of if-then Continuous mode turned on // // + return returnValue; // Send back the results // +} // of method getAmbientLight() // // +/******************************************************************************************************************* +** Method getProximity() retrieves the 16 bit proximity value. Since we always send a request for another reading ** +** after retrieving the previous results we just need to wait for a result to come back. ** +*******************************************************************************************************************/ +uint16_t VCNL4010::getProximity() { // // + uint8_t commandBuffer = readByte(VCNL4010_COMMAND_REG); // get the register contents // + while (commandBuffer&B00100000==0) // Loop until we have a result // + commandBuffer = readByte(VCNL4010_COMMAND_REG); // get the register contents again // + uint16_t returnValue = readWord(VCNL4010_PROXIMITY_REG); // retrieve the reading // + if (!_ContinuousProximity) { // Only trigger if not continuous // + commandBuffer |= B00001000; // Trigger proximity measurement // + writeByte(VCNL4010_COMMAND_REG,commandBuffer); // Set trigger for next reading // + } // of if-then Continuous mode turned on // // + return returnValue; // Send back the results // +} // of method getProximity() // // +/******************************************************************************************************************* +** Method getInterrupt() retrieves the 4 bits denoting which, if any, interrupts have been triggered. ** +** Bit 3 - proximity interrupt ** +** Bit 2 - ambient light interrupt ** +** Bit 1 - low threshold interrupt ** +** Bit 0 - high threshold interrupt ** +*******************************************************************************************************************/ +uint8_t VCNL4010::getInterrupt() { // // + return readByte(VCNL4010_INTERRUPT_STATUS_REG); // get the register contents // +} // of method getInterrupt() // // +/******************************************************************************************************************* +** Method clearInterrupt() overwrites the 4 bits denoting which, if any, interrupts have been triggered. ** +** Bit 3 - proximity interrupt ** +** Bit 2 - ambient light interrupt ** +** Bit 1 - low threshold interrupt ** +** Bit 0 - high threshold interrupt ** +** The bit needs to be written as "1" in order to clear it, so send the bitwise not value ** +*******************************************************************************************************************/ +void VCNL4010::clearInterrupt(const uint8_t intVal) { // Set Interrupt bits // + writeByte(VCNL4010_INTERRUPT_STATUS_REG,~intVal); // Write value to register // +} // of method clearInterrupt() // // +/******************************************************************************************************************* +** Method setInterrupt() sets the interrupts used. The count is the number of consecutive readings needed in order** +** to trigger an interrupt for threshold low or high being exceeded. Then a boolean to indicate an interrupt on ** +** Proximity reading ready, then the same for an ALS reading to be ready. The next two values indicate whether to ** +** trigger an interrupt on threshold low or high value being exceeded for Proximity and ALS. Since only one can ** +** be used the ALS is chosen when both are set. Finally the low and high threshold values themselves ** +*******************************************************************************************************************/ +void VCNL4010::setInterrupt(const uint8_t count , // // + const bool ProxReady , // // + const bool ALSReady , // // + const bool ProxThreshold , // // + const bool ALSThreshold , // // + const uint16_t lowThreshold , // // + const uint16_t highThreshold ) { // // + uint8_t registerValue = 0; // Default to 1 count // + if (count>=128) registerValue = B111; // Choose setting based on parameter// + else if (count>=64) registerValue = B110; // // + else if (count>=32) registerValue = B101; // // + else if (count>=16) registerValue = B100; // // + else if (count>=8) registerValue = B011; // // + else if (count>=4) registerValue = B010; // // + else if (count>=2) registerValue = B001; // // + registerValue = registerValue << 5; // Move value to position // + if (ProxReady) registerValue |= B00001000; // Set Proximity Ready flag // + if (ALSReady) registerValue |= B00000100; // Set ALS Ready flag // + if (ProxThreshold || ALSThreshold) { // If we are setting a threshold // + registerValue |= B00000010; // Set the flag for threshold // + if (ALSThreshold) registerValue += 1; // Set the flag for ALS // + writeByte(VCNL4010_LOW_THRESHOLD_MSB_REG,(uint8_t)(lowThreshold>>8)); // Write the MSB // + writeByte(VCNL4010_LOW_THRESHOLD_LSB_REG,(uint8_t)lowThreshold); // Write the LSB // + writeByte(VCNL4010_HIGH_THRESHOLD_MSB_REG,(uint8_t)(highThreshold>>8)); // Write the MSB // + writeByte(VCNL4010_HIGH_THRESHOLD_LSB_REG,(uint8_t)highThreshold); // Write the LSB // + } // of if-then we have threshold interrupts to set // // + writeByte(VCNL4010_INTERRUPT_REG,registerValue); // Write the register contents // +} // of method setLEDmA() // // +/******************************************************************************************************************* +** Method setAmbientContinuous() sets or unsets the continuous measurement mode for the ambient light sensor ** +*******************************************************************************************************************/ +void VCNL4010::setAmbientContinuous(const bool ContinuousMode) { // Cont. Ambient sampling on/off // + uint8_t commandBuffer = readByte(VCNL4010_COMMAND_REG); // get the register contents // + commandBuffer &= B11111010; // Mask the 2 relevant bits // + if (ContinuousMode==true) { // If we are turning on then write // + commandBuffer |= B00000101; // the 2 relevant bits and // + _ContinuousAmbient = true; // set flag // + } else { // otherwise if proximity is still // + if(_ContinuousProximity) commandBuffer |= B00000001; // turned on the keep flag or // + else commandBuffer |= B00000000; // turn off both bits // + _ContinuousAmbient = false; // set flag // + } // of if-then-else we are turning on // // + writeByte(VCNL4010_COMMAND_REG,commandBuffer); // Write value back to register // +}// of method setAmbientContinuous() // // +/******************************************************************************************************************* +** Method setProximityContinuous() sets or unsets the continuous measurement mode for the proximity sensor ** +*******************************************************************************************************************/ +void VCNL4010::setProximityContinuous(const bool ContinuousMode) { // Cont. Proximity sampling on/off // + uint8_t commandBuffer = readByte(VCNL4010_COMMAND_REG); // get the register contents // + commandBuffer &= B11111100; // Mask the 2 relevant bits // + if (ContinuousMode==true) { // If we are turning on then write // + commandBuffer |= B00000011; // the 2 relevant bits and // + _ContinuousProximity = true; // set flag // + } else { // otherwise if proximity is still // + if(_ContinuousAmbient) commandBuffer |= B00000001; // turned on the keep flag or // + else commandBuffer |= B00000000; // turn off both bits // + _ContinuousProximity = false; // set flag // + } // of if-then-else we are turning on // // + writeByte(VCNL4010_COMMAND_REG,commandBuffer); // Write value back to register // +} // of method setProximityContinuous() // // diff --git a/Examples/DisplayMeasurements/VCNL4010.h b/Examples/DisplayMeasurements/VCNL4010.h new file mode 100644 index 0000000..43e620f --- /dev/null +++ b/Examples/DisplayMeasurements/VCNL4010.h @@ -0,0 +1,88 @@ +/******************************************************************************************************************* +** Class definition header for the VCNL4010 chip from Vishay Semiconductors. This is a Fully Integrated Proximity ** +** and Ambient Light Sensor with Infrared Emitter, I2C Interface and Interrupt Function. The data sheet for the ** +** VCNL4010 can be found at http://www.vishay.com/docs/83462/vcnl4010.pdf and there is a breakout board from ** +** Adafruit with additional information located at https://www.adafruit.com/product/466. ** +** ** +** When the class is instantiated the default mode is to have triggered readings for the ambient light sensor as ** +** well as for the proximity sensor. In order to speed up processing the class will trigger the two types of ** +** measurements preemptively, meaning that as soon that either of the results have been read the next measurement ** +** is started automatically. If the continuous mode is activated for either of the ambient or proximity sensors ** +** then no specific measurements are triggered since the device takes care of that internally. ** +** ** +** Although programming for the Arduino and in c/c++ is new to me, I'm a professional programmer and have learned,** +** over the years, that it is much easier to ignore superfluous comments than it is to decipher non-existent ones;** +** so both my comments and variable names tend to be verbose. The code is written to fit in the first 80 spaces ** +** and the comments start after that and go to column 117 - allowing the code to be printed in A4 landscape mode. ** +** ** +** This program is free software: you can redistribute it and/or modify it under the terms of the GNU General ** +** Public License as published by the Free Software Foundation, either version 3 of the License, or (at your ** +** option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY ** +** WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** +** GNU General Public License for more details. You should have received a copy of the GNU General Public License ** +** along with this program. If not, see . ** +** ** +** Vers. Date Developer Comments ** +** ====== ========== =================== ======================================================================== ** +** 1.0.2 2017-04-25 Arnd@SV-Zanshin.Com Removed default parameter values from .cpp definitions, kept in header ** +** 1.0.1 2017-01-02 Arnd@SV-Zanshin.Com Moved readByte function back into priate area ** +** 1.0.0 2017-01-01 Arnd@SV-Zanshin.Com Fixed error on continuous mode with proximity, ready for release ** +** 1.0.b2 2016-12-31 Arnd@SV-Zanshin.Com Continued coding ** +** 1.0.b1 2016-12-30 Arnd@SV-Zanshin.Com Created class ** +** ** +*******************************************************************************************************************/ +#include "Arduino.h" // Arduino data type definitions // +#include // Standard I2C "Wire" library // +#ifndef VCNL4010_h // Guard code definition // + #define VCNL4010_h // Define the name inside guard code// + /*************************************************************************************************************** + ** Declare constants used in the class ** + ***************************************************************************************************************/ + const uint8_t VCNL4010_ADDRESS = 0x13; // Device address, fixed value // + const uint8_t VCNL4010_COMMAND_REG = 0x80; // Register containing commands // + const uint8_t VCNL4010_PRODUCT_ID_REG = 0x81; // Register containing product ID // + const uint8_t VCNL4010_PROXIMITY_RATE_REG = 0x82; // Register containing sampling rate// + const uint8_t VCNL4010_LED_CURRENT_REG = 0x83; // Register containing IR LED mA // + const uint8_t VCNL4010_AMBIENT_PARAMETER_REG = 0x84; // Register containing ambient set // + const uint8_t VCNL4010_AMBIENT_LIGHT_REG = 0x85; // Register containing ambient data // + const uint8_t VCNL4010_PROXIMITY_REG = 0x87; // Register containing Proximity // + const uint8_t VCNL4010_INTERRUPT_REG = 0x89; // Register containing Interrupts // + const uint8_t VCNL4010_LOW_THRESHOLD_MSB_REG = 0x8A; // MSB of low threshold value // + const uint8_t VCNL4010_LOW_THRESHOLD_LSB_REG = 0x8B; // LSB of low threshold value // + const uint8_t VCNL4010_HIGH_THRESHOLD_MSB_REG = 0x8C; // MSB of high threshold value // + const uint8_t VCNL4010_HIGH_THRESHOLD_LSB_REG = 0x8D; // LSB of high threshold value // + const uint8_t VCNL4010_INTERRUPT_STATUS_REG = 0x8E; // Interrupt status register // + const uint8_t VCNL4010_PROXIMITY_TIMING_REG = 0x8F; // Register containing ProxTiming // + const uint8_t VCNL4010_PRODUCT_VERSION = 0x21; // Current product ID // + const uint8_t VCNL4010_I2C_DELAY = 0170; // Microseconds delay on I2C write // + class VCNL4010 { // Class definition // + public: // Publicly visible methods // + VCNL4010(); // Class constructor // + ~VCNL4010(); // Class destructor // + bool begin(); // Start I2C Comms with device // + void setProximityHz(const uint8_t Hz=2); // Set proximity Hz sampling rate // + void setLEDmA(const uint8_t mA=20); // Set milliamps used by IR LED // + void setProximityFreq(const uint8_t value=0); // Set Frequency value from list // + void setAmbientLight(const uint8_t sample=2, const uint8_t avg=32); // Set samples and averaging // + void setAmbientContinuous(const bool ContinuousMode=true); // Cont. Ambient sampling on/off // + void setProximityContinuous(const bool ContinuousMode=true); // Cont. Proximity sampling on/off // + void setInterrupt(const uint8_t count = 1, // // + const bool ProxReady = false, // // + const bool ALSReady = false, // // + const bool ProxThreshold = false, // // + const bool ALSThreshold = false, // // + const uint16_t lowThreshold = 0, // // + const uint16_t highThreshold = UINT16_MAX ); // // + uint16_t getAmbientLight(); // Retrieve ambient light reading // + uint16_t getProximity(); // Retrieve proximity reading // + uint8_t getInterrupt(); // Retrieve Interrupt bits // + void clearInterrupt(const uint8_t intVal=0); // Clear Interrupt bits // + private: // Private methods // + uint8_t readByte(const uint8_t addr); // Read 1 byte from address on I2C // + uint16_t readWord(const uint8_t addr); // Read 2 bytes from address on I2C // + void writeByte(const uint8_t addr, const uint8_t data); // Write 1 byte at address to I2C // + uint8_t _TransmissionStatus; // Status of I2C transmission // + bool _ContinuousAmbient = false; // If mode turned on for Ambient // + bool _ContinuousProximity = false; // If mode turned on for Proximity // + }; // of VCNL4010 class definition // // +#endif //----------------------------------//